mirror of
https://github.com/catchorg/Catch2.git
synced 2025-07-29 18:27:41 +02:00
Compare commits
728 Commits
v1.5.6
...
v2.0.0-dev
Author | SHA1 | Date | |
---|---|---|---|
5d6c1f4dd0 | |||
3bc03cd617 | |||
28f11a7149 | |||
24af32f378 | |||
0545de0a31 | |||
ee75b324e7 | |||
597fca3c89 | |||
f99f511155 | |||
9a18ba042f | |||
8e6641c19b | |||
185573e701 | |||
632e023ff4 | |||
b8f482b9aa | |||
aaedae60b4 | |||
ff9aaf3afe | |||
e6ffbb732a | |||
581aaae57e | |||
0b52dbe8bb | |||
8c0a6a4358 | |||
8582780f11 | |||
a36395e2ff | |||
699e571400 | |||
07ded81541 | |||
a988af219c | |||
74dfd0b1e0 | |||
917a51da6b | |||
f06ed856d8 | |||
0aec06f4c3 | |||
7be258536e | |||
94d347b059 | |||
3772f69f0f | |||
ece64c3b3a | |||
fa3535e95e | |||
bb8c1fb17f | |||
c659e0fd3d | |||
1aab791d67 | |||
eed4ae86ad | |||
df5c31bb19 | |||
684cbb2631 | |||
6282999291 | |||
97c06ca6fb | |||
3382312bd8 | |||
5da76bb7be | |||
11295a2663 | |||
aa42dd92d1 | |||
7e4038d848 | |||
ee9b19efd3 | |||
b59e0ed48a | |||
8d21b4a916 | |||
4b5ac4d3d9 | |||
8382d99081 | |||
dc1df297e3 | |||
8c95a81448 | |||
7df290dfc1 | |||
201028d6ec | |||
27fd8f80bd | |||
ef4fa56b71 | |||
9668410b8e | |||
92d714ee12 | |||
705a1bf527 | |||
2832e23aa9 | |||
5f91724368 | |||
8a97beece2 | |||
f033f4f184 | |||
f247ce5bff | |||
f8148ebae1 | |||
59f9bcf1ed | |||
5e60050299 | |||
e658bacb04 | |||
3a409e9fd4 | |||
63392e095e | |||
0a2ce87d32 | |||
b3b29f4b4c | |||
cff3818e68 | |||
519db85758 | |||
4421672fb8 | |||
f45d35c980 | |||
22e9ebef0d | |||
97d6b08087 | |||
a9b6813ad9 | |||
a1e3f0b624 | |||
39d37d9f34 | |||
c7028f7bc7 | |||
5450de2acd | |||
d5613fb18a | |||
3882ac1a19 | |||
e8b785b177 | |||
62875c857e | |||
887fe1d5d2 | |||
eab56d6656 | |||
2212cdfe26 | |||
28741467d5 | |||
7a76ff161b | |||
4f72202c04 | |||
cde987a92e | |||
249bf116e8 | |||
6d4673505d | |||
85e14c5fb5 | |||
feca97dfde | |||
c815ad1d53 | |||
d4e796c138 | |||
ec2074e558 | |||
7575749e56 | |||
8a2ff20982 | |||
d3377c791d | |||
0a3f899d6a | |||
c5dfa73d56 | |||
d118ce191d | |||
d08e31d89e | |||
0ca4cfb743 | |||
35c1301bd5 | |||
d01fe03ba6 | |||
287cc92b2c | |||
446bad752f | |||
307eeefa8f | |||
33fd54a673 | |||
918eca5ee9 | |||
5ebbec7dab | |||
a40add3153 | |||
ab0f1dcde9 | |||
a75eaa3c5a | |||
9de729b515 | |||
1a96175bb2 | |||
1e59ccee41 | |||
b6f62af7d1 | |||
d65091fa06 | |||
46bf7605f4 | |||
cb6963216f | |||
b35225ff3a | |||
c91639e1d7 | |||
3a37f45a97 | |||
6ec7709e07 | |||
58d8bc6985 | |||
93556a1fb3 | |||
d3c7d424fe | |||
224250e2d4 | |||
5c3355ad1b | |||
b2a4dfcda4 | |||
f0890dcdf8 | |||
74ab1cd94b | |||
87a66b8479 | |||
2a586437e8 | |||
cf2678dce6 | |||
d7f754dc49 | |||
a14bd08b27 | |||
efd79aa0bd | |||
4a1e898eae | |||
d7ff62430a | |||
edbe122761 | |||
7a22bad763 | |||
0a614ee5ba | |||
4833932ab2 | |||
cd6f6c021a | |||
b0e3f45a22 | |||
d43024ff6b | |||
c7931f6f18 | |||
01a21f67f7 | |||
7ccf11da29 | |||
cf6f9e3253 | |||
f193698fb3 | |||
c89bdf842e | |||
c874a99c6c | |||
e4456aa243 | |||
d2d5910479 | |||
e01ed48a70 | |||
989222eceb | |||
720fdf1d02 | |||
79627cdcdb | |||
10c36aa74c | |||
bc73189c52 | |||
e3e6453229 | |||
878bd140e6 | |||
d8df83ee2f | |||
8d8f481597 | |||
3f6c078173 | |||
0bb9f52a99 | |||
91c1556078 | |||
4332b84c9b | |||
9c318af987 | |||
8ebe94ca2e | |||
1d3bfa0353 | |||
5f3f19de08 | |||
106d7e2a74 | |||
93f84b5b0d | |||
af05ccfe5d | |||
058b21e604 | |||
a53ea30723 | |||
fc32165d48 | |||
f749347523 | |||
8d380a7399 | |||
3083de9ea6 | |||
bb9f2bb3ad | |||
431e8d06e7 | |||
694fe61ae3 | |||
0016362f69 | |||
63a8017ba7 | |||
03afbdfec9 | |||
f9ce8fd03b | |||
60f25c7ffd | |||
78e7994435 | |||
6f32db35af | |||
7013e388f7 | |||
0270afb21b | |||
df7c5622b9 | |||
cb0a5194af | |||
4c1880b35f | |||
ee67ac6b7c | |||
fae0fa4ec1 | |||
c5bac73cad | |||
1e7000ed55 | |||
9382534d59 | |||
7bcfdf8e94 | |||
8d5f6c8e2e | |||
e62a9aa444 | |||
059a33d555 | |||
8a14af701e | |||
07c6bfc3b9 | |||
616f7235ef | |||
396ecf6021 | |||
3491804598 | |||
6234e3d54d | |||
af66106500 | |||
a6cdcd43aa | |||
0eb101e165 | |||
dcab8a5971 | |||
2462dff088 | |||
0470b300a8 | |||
3bb16e8418 | |||
e0c6c4aee7 | |||
c43d5f673f | |||
d81c1eb006 | |||
da5964af78 | |||
017a63da62 | |||
b90d0b7267 | |||
ee0defb939 | |||
efba988ccc | |||
e62b3beef4 | |||
c41a45e79c | |||
1c223b63ba | |||
6d9171aadb | |||
004228efb2 | |||
ebb3371cbf | |||
e0aaba6cf8 | |||
a09bef23ed | |||
b6d9976fbb | |||
6583284731 | |||
07ef028483 | |||
47eb9b3d68 | |||
8fde7abf31 | |||
c465fbd0ea | |||
950cae9040 | |||
7f6773bb4d | |||
b459bb4c43 | |||
1e16be0b9e | |||
69ff7fcf42 | |||
a6b03031ba | |||
47c8994a61 | |||
860de28b8d | |||
da0edcbe25 | |||
0020747420 | |||
3e018ef131 | |||
adb66f55a7 | |||
a64a0c6f06 | |||
377c9a746d | |||
ea48ae0f75 | |||
2d1739b429 | |||
1c59034be4 | |||
52a84788e0 | |||
169e260e8b | |||
67914d8b86 | |||
3e328f55fc | |||
b18e67522f | |||
4b086bd5b5 | |||
aac594aae3 | |||
a49fa0edbe | |||
d271683c14 | |||
0bb8e1247e | |||
32d97caf42 | |||
bc93b29789 | |||
df5cf2d323 | |||
b62c0256b2 | |||
1ea84cb734 | |||
2a5d3736e8 | |||
3dcc923351 | |||
589c40077b | |||
31f5e2ed81 | |||
d4e0b1d093 | |||
b8443e67da | |||
85aa770701 | |||
f82e312552 | |||
bffef1bffa | |||
7e14232924 | |||
d7eb041ab5 | |||
8c757cc542 | |||
bada67bb72 | |||
4c5af2089a | |||
687437fcd1 | |||
ef8b72c949 | |||
5604ec7266 | |||
a9128d0fac | |||
c5c3d368a2 | |||
33ed1773f4 | |||
6f012f2d1d | |||
98e61c31df | |||
e641485132 | |||
a3ceb8f007 | |||
b819432271 | |||
9ceae8f51f | |||
40130e59b4 | |||
5ffc8a84cd | |||
6e0fa4be68 | |||
316cb28ea8 | |||
51c143b2c6 | |||
d17d94e45d | |||
8ccbf63f28 | |||
e6094a9503 | |||
851e40a4bb | |||
0807a6910f | |||
44cccde8b9 | |||
0844d6e867 | |||
a96f25c716 | |||
dd78824697 | |||
338ba6b9ba | |||
41afd0c3d4 | |||
602b62f037 | |||
de348b9bdd | |||
c1835ec203 | |||
e749724a11 | |||
cc8206f4c3 | |||
e1bca7017d | |||
53864dee7b | |||
b245eaa7d1 | |||
be0fc60c07 | |||
a0ada2e935 | |||
e4694f58da | |||
61ac34045c | |||
569d355b36 | |||
79650e44f4 | |||
5c8ea03cc8 | |||
242022460d | |||
67005d290c | |||
f57f96f190 | |||
71df66365e | |||
97707afae1 | |||
1f3ba8a0b6 | |||
073377a4e4 | |||
6a09425de1 | |||
c6e5738d54 | |||
c6980ec2d8 | |||
7c900660ef | |||
2fdd81a33f | |||
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 | |||
3523c39f44 | |||
2585d280d1 |
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**
|
28
.github/pull_request_template.md
vendored
Normal file
28
.github/pull_request_template.md
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
<!--
|
||||
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.
|
||||
|
||||
Before submitting a PR you should probably read the contributor documentation
|
||||
at docs/contributing.md. It will tell you how to properly test your changes.
|
||||
-->
|
||||
|
||||
|
||||
## 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
|
146
.travis.yml
146
.travis.yml
@ -1,19 +1,6 @@
|
||||
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:
|
||||
|
||||
@ -24,12 +11,12 @@ matrix:
|
||||
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 +25,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,12 +39,12 @@ 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
|
||||
@ -66,12 +53,12 @@ matrix:
|
||||
apt:
|
||||
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
|
||||
@ -81,12 +68,12 @@ matrix:
|
||||
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 +82,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 +96,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 +210,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:
|
||||
|
320
CMakeLists.txt
Normal file
320
CMakeLists.txt
Normal file
@ -0,0 +1,320 @@
|
||||
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_CPP14)
|
||||
message(STATUS "Enabling C++14")
|
||||
set(CMAKE_CXX_FLAGS "-std=c++14 ${CMAKE_CXX_FLAGS}")
|
||||
else()
|
||||
message(STATUS "Enabling C++11")
|
||||
set(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}")
|
||||
|
||||
endif()
|
||||
|
||||
if(USE_WMAIN)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ENTRY:wmainCRTStartup")
|
||||
endif()
|
||||
|
||||
#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}/Benchmark.tests.cpp
|
||||
${SELF_TEST_DIR}/ClassTests.cpp
|
||||
${SELF_TEST_DIR}/CmdLineTests.cpp
|
||||
${SELF_TEST_DIR}/CompilationTests.cpp
|
||||
${SELF_TEST_DIR}/ConditionTests.cpp
|
||||
${SELF_TEST_DIR}/DecompositionTests.cpp
|
||||
${SELF_TEST_DIR}/EnumToString.cpp
|
||||
${SELF_TEST_DIR}/ExceptionTests.cpp
|
||||
${SELF_TEST_DIR}/MessageTests.cpp
|
||||
${SELF_TEST_DIR}/MiscTests.cpp
|
||||
${SELF_TEST_DIR}/PartTrackerTests.cpp
|
||||
${SELF_TEST_DIR}/TagAliasTests.cpp
|
||||
${SELF_TEST_DIR}/TestMain.cpp
|
||||
${SELF_TEST_DIR}/ToStringGeneralTests.cpp
|
||||
${SELF_TEST_DIR}/ToStringPair.cpp
|
||||
${SELF_TEST_DIR}/ToStringTuple.cpp
|
||||
${SELF_TEST_DIR}/ToStringVector.cpp
|
||||
${SELF_TEST_DIR}/ToStringWhich.cpp
|
||||
${SELF_TEST_DIR}/TrickyTests.cpp
|
||||
${SELF_TEST_DIR}/VariadicMacrosTests.cpp
|
||||
${SELF_TEST_DIR}/MatchersTests.cpp
|
||||
${SELF_TEST_DIR}/StringRef.tests.cpp
|
||||
)
|
||||
CheckFileList(TEST_SOURCES ${SELF_TEST_DIR})
|
||||
|
||||
# A set of impl files that just #include a single header
|
||||
# Please keep these ordered alphabetically
|
||||
set(SURROGATE_SOURCES
|
||||
${SELF_TEST_DIR}/SurrogateCpps/catch_console_colour.cpp
|
||||
${SELF_TEST_DIR}/SurrogateCpps/catch_debugger.cpp
|
||||
${SELF_TEST_DIR}/SurrogateCpps/catch_interfaces_capture.cpp
|
||||
${SELF_TEST_DIR}/SurrogateCpps/catch_interfaces_config.cpp
|
||||
${SELF_TEST_DIR}/SurrogateCpps/catch_interfaces_exception.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_option.cpp
|
||||
${SELF_TEST_DIR}/SurrogateCpps/catch_stream.cpp
|
||||
${SELF_TEST_DIR}/SurrogateCpps/catch_streambuf.cpp
|
||||
${SELF_TEST_DIR}/SurrogateCpps/catch_test_case_tracker.cpp
|
||||
${SELF_TEST_DIR}/SurrogateCpps/catch_test_spec.cpp
|
||||
${SELF_TEST_DIR}/SurrogateCpps/catch_xmlwriter.cpp
|
||||
)
|
||||
CheckFileList(SURROGATE_SOURCES ${SELF_TEST_DIR}/SurrogateCpps)
|
||||
|
||||
|
||||
# Please keep these ordered alphabetically
|
||||
set(TOP_LEVEL_HEADERS
|
||||
${HEADER_DIR}/catch.hpp
|
||||
${HEADER_DIR}/catch_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.hpp
|
||||
)
|
||||
CheckFileList(EXTERNAL_HEADERS ${HEADER_DIR}/external)
|
||||
|
||||
|
||||
# Please keep these ordered alphabetically
|
||||
set(INTERNAL_HEADERS
|
||||
${HEADER_DIR}/internal/catch_approx.hpp
|
||||
${HEADER_DIR}/internal/catch_assertionhandler.h
|
||||
${HEADER_DIR}/internal/catch_assertioninfo.h
|
||||
${HEADER_DIR}/internal/catch_assertionresult.h
|
||||
${HEADER_DIR}/internal/catch_capture.hpp
|
||||
${HEADER_DIR}/internal/catch_capture_matchers.h
|
||||
${HEADER_DIR}/internal/catch_clara.h
|
||||
${HEADER_DIR}/internal/catch_commandline.hpp
|
||||
${HEADER_DIR}/internal/catch_common.h
|
||||
${HEADER_DIR}/internal/catch_compiler_capabilities.h
|
||||
${HEADER_DIR}/internal/catch_config.hpp
|
||||
${HEADER_DIR}/internal/catch_console_colour.hpp
|
||||
${HEADER_DIR}/internal/catch_context.h
|
||||
${HEADER_DIR}/internal/catch_debugger.h
|
||||
${HEADER_DIR}/internal/catch_decomposer.h
|
||||
${HEADER_DIR}/internal/catch_default_main.hpp
|
||||
${HEADER_DIR}/internal/catch_enforce.h
|
||||
${HEADER_DIR}/internal/catch_errno_guard.h
|
||||
${HEADER_DIR}/internal/catch_exception_translator_registry.h
|
||||
${HEADER_DIR}/internal/catch_external_interfaces.h
|
||||
${HEADER_DIR}/internal/catch_fatal_condition.h
|
||||
${HEADER_DIR}/internal/catch_impl.hpp
|
||||
${HEADER_DIR}/internal/catch_interfaces_capture.h
|
||||
${HEADER_DIR}/internal/catch_interfaces_config.h
|
||||
${HEADER_DIR}/internal/catch_interfaces_exception.h
|
||||
${HEADER_DIR}/internal/catch_interfaces_registry_hub.h
|
||||
${HEADER_DIR}/internal/catch_interfaces_reporter.h
|
||||
${HEADER_DIR}/internal/catch_interfaces_runner.h
|
||||
${HEADER_DIR}/internal/catch_interfaces_tag_alias_registry.h
|
||||
${HEADER_DIR}/internal/catch_interfaces_testcase.h
|
||||
${HEADER_DIR}/internal/catch_leak_detector.h
|
||||
${HEADER_DIR}/internal/catch_list.h
|
||||
${HEADER_DIR}/internal/catch_matchers.hpp
|
||||
${HEADER_DIR}/internal/catch_matchers_string.h
|
||||
${HEADER_DIR}/internal/catch_matchers_vector.h
|
||||
${HEADER_DIR}/internal/catch_message.h
|
||||
${HEADER_DIR}/internal/catch_notimplemented_exception.h
|
||||
${HEADER_DIR}/internal/catch_objc.hpp
|
||||
${HEADER_DIR}/internal/catch_objc_arc.hpp
|
||||
${HEADER_DIR}/internal/catch_option.hpp
|
||||
${HEADER_DIR}/internal/catch_platform.h
|
||||
${HEADER_DIR}/internal/catch_reenable_warnings.h
|
||||
${HEADER_DIR}/internal/catch_reporter_registrars.hpp
|
||||
${HEADER_DIR}/internal/catch_reporter_registry.hpp
|
||||
${HEADER_DIR}/internal/catch_result_type.h
|
||||
${HEADER_DIR}/internal/catch_run_context.hpp
|
||||
${HEADER_DIR}/internal/catch_benchmark.h
|
||||
${HEADER_DIR}/internal/catch_section.h
|
||||
${HEADER_DIR}/internal/catch_section_info.h
|
||||
${HEADER_DIR}/internal/catch_startup_exception_registry.h
|
||||
${HEADER_DIR}/internal/catch_stream.h
|
||||
${HEADER_DIR}/internal/catch_streambuf.h
|
||||
${HEADER_DIR}/internal/catch_stringref.h
|
||||
${HEADER_DIR}/internal/catch_string_manip.h
|
||||
${HEADER_DIR}/internal/catch_suppress_warnings.h
|
||||
${HEADER_DIR}/internal/catch_tag_alias.h
|
||||
${HEADER_DIR}/internal/catch_tag_alias_autoregistrar.h
|
||||
${HEADER_DIR}/internal/catch_tag_alias_registry.h
|
||||
${HEADER_DIR}/internal/catch_test_case_info.h
|
||||
${HEADER_DIR}/internal/catch_test_case_registry_impl.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_tostring.h
|
||||
${HEADER_DIR}/internal/catch_totals.hpp
|
||||
${HEADER_DIR}/internal/catch_version.h
|
||||
${HEADER_DIR}/internal/catch_wildcard_pattern.hpp
|
||||
${HEADER_DIR}/internal/catch_windows_h_proxy.h
|
||||
${HEADER_DIR}/internal/catch_xmlwriter.hpp
|
||||
)
|
||||
set(IMPL_SOURCES
|
||||
${HEADER_DIR}/internal/catch_approx.cpp
|
||||
${HEADER_DIR}/internal/catch_assertionhandler.cpp
|
||||
${HEADER_DIR}/internal/catch_assertionresult.cpp
|
||||
${HEADER_DIR}/internal/catch_benchmark.cpp
|
||||
${HEADER_DIR}/internal/catch_capture_matchers.cpp
|
||||
${HEADER_DIR}/internal/catch_commandline.cpp
|
||||
${HEADER_DIR}/internal/catch_common.cpp
|
||||
${HEADER_DIR}/internal/catch_config.cpp
|
||||
${HEADER_DIR}/internal/catch_console_colour.cpp
|
||||
${HEADER_DIR}/internal/catch_context.cpp
|
||||
${HEADER_DIR}/internal/catch_debugger.cpp
|
||||
${HEADER_DIR}/internal/catch_decomposer.cpp
|
||||
${HEADER_DIR}/internal/catch_errno_guard.cpp
|
||||
${HEADER_DIR}/internal/catch_exception_translator_registry.cpp
|
||||
${HEADER_DIR}/internal/catch_fatal_condition.cpp
|
||||
${HEADER_DIR}/internal/catch_list.cpp
|
||||
${HEADER_DIR}/internal/catch_leak_detector.cpp
|
||||
${HEADER_DIR}/internal/catch_matchers.cpp
|
||||
${HEADER_DIR}/internal/catch_matchers_string.cpp
|
||||
${HEADER_DIR}/internal/catch_message.cpp
|
||||
${HEADER_DIR}/internal/catch_notimplemented_exception.cpp
|
||||
${HEADER_DIR}/internal/catch_registry_hub.cpp
|
||||
${HEADER_DIR}/internal/catch_interfaces_reporter.cpp
|
||||
${HEADER_DIR}/internal/catch_result_type.cpp
|
||||
${HEADER_DIR}/internal/catch_run_context.cpp
|
||||
${HEADER_DIR}/internal/catch_section.cpp
|
||||
${HEADER_DIR}/internal/catch_section_info.cpp
|
||||
${HEADER_DIR}/internal/catch_startup_exception_registry.cpp
|
||||
${HEADER_DIR}/internal/catch_stream.cpp
|
||||
${HEADER_DIR}/internal/catch_stringref.cpp
|
||||
${HEADER_DIR}/internal/catch_string_manip.cpp
|
||||
${HEADER_DIR}/internal/catch_tag_alias.cpp
|
||||
${HEADER_DIR}/internal/catch_tag_alias_autoregistrar.cpp
|
||||
${HEADER_DIR}/internal/catch_tag_alias_registry.cpp
|
||||
${HEADER_DIR}/internal/catch_test_case_info.cpp
|
||||
${HEADER_DIR}/internal/catch_test_case_registry_impl.cpp
|
||||
${HEADER_DIR}/internal/catch_test_case_tracker.cpp
|
||||
${HEADER_DIR}/internal/catch_test_registry.cpp
|
||||
${HEADER_DIR}/internal/catch_test_spec.cpp
|
||||
${HEADER_DIR}/internal/catch_test_spec_parser.cpp
|
||||
${HEADER_DIR}/internal/catch_timer.cpp
|
||||
${HEADER_DIR}/internal/catch_tostring.cpp
|
||||
${HEADER_DIR}/internal/catch_totals.cpp
|
||||
${HEADER_DIR}/internal/catch_version.cpp
|
||||
${HEADER_DIR}/internal/catch_wildcard_pattern.cpp
|
||||
${HEADER_DIR}/internal/catch_xmlwriter.cpp
|
||||
)
|
||||
set(INTERNAL_FILES ${IMPL_SOURCES} ${INTERNAL_HEADERS})
|
||||
CheckFileList(INTERNAL_FILES ${HEADER_DIR}/internal)
|
||||
|
||||
# Please keep these ordered alphabetically
|
||||
set(REPORTER_HEADERS
|
||||
${HEADER_DIR}/reporters/catch_reporter_automake.hpp
|
||||
${HEADER_DIR}/reporters/catch_reporter_bases.hpp
|
||||
${HEADER_DIR}/reporters/catch_reporter_multi.h
|
||||
${HEADER_DIR}/reporters/catch_reporter_tap.hpp
|
||||
${HEADER_DIR}/reporters/catch_reporter_teamcity.hpp
|
||||
)
|
||||
set(REPORTER_SOURCES
|
||||
${HEADER_DIR}/reporters/catch_reporter_bases.cpp
|
||||
${HEADER_DIR}/reporters/catch_reporter_compact.cpp
|
||||
${HEADER_DIR}/reporters/catch_reporter_console.cpp
|
||||
${HEADER_DIR}/reporters/catch_reporter_junit.cpp
|
||||
${HEADER_DIR}/reporters/catch_reporter_multi.cpp
|
||||
${HEADER_DIR}/reporters/catch_reporter_xml.cpp
|
||||
)
|
||||
set(REPORTER_FILES ${REPORTER_HEADERS} ${REPORTER_SOURCES})
|
||||
CheckFileList(REPORTER_FILES ${HEADER_DIR}/reporters)
|
||||
|
||||
# Specify the headers, too, so CLion recognises them as project files
|
||||
set(HEADERS
|
||||
${TOP_LEVEL_HEADERS}
|
||||
${EXTERNAL_HEADERS}
|
||||
${INTERNAL_HEADERS}
|
||||
${REPORTER_HEADERS}
|
||||
)
|
||||
|
||||
|
||||
set(BENCH_SOURCES
|
||||
${BENCHMARK_DIR}/BenchMain.cpp
|
||||
${BENCHMARK_DIR}/StringificationBench.cpp
|
||||
)
|
||||
CheckFileList(BENCH_SOURCES ${BENCHMARK_DIR})
|
||||
|
||||
# Provide some groupings for IDEs
|
||||
SOURCE_GROUP("Tests" FILES ${TEST_SOURCES})
|
||||
SOURCE_GROUP("Surrogates" FILES ${SURROGATE_SOURCES})
|
||||
SOURCE_GROUP("Benchmarks" FILES ${BENCH_SOURCES})
|
||||
|
||||
# configure the executable
|
||||
include_directories(${HEADER_DIR})
|
||||
|
||||
add_definitions( -DCATCH_CONFIG_FULL_PROJECT )
|
||||
|
||||
# Projects consuming Catch via ExternalProject_Add might want to use install step
|
||||
# without building all of our selftests.
|
||||
if (NOT NO_SELFTEST)
|
||||
add_executable(SelfTest ${TEST_SOURCES} ${IMPL_SOURCES} ${REPORTER_SOURCES} ${SURROGATE_SOURCES} ${HEADERS})
|
||||
add_executable(Benchmark ${BENCH_SOURCES} ${IMPL_SOURCES} ${REPORTER_SOURCES} ${HEADERS})
|
||||
|
||||
# Add desired warnings
|
||||
if ( CMAKE_CXX_COMPILER_ID MATCHES "Clang|AppleClang|GNU" )
|
||||
target_compile_options( SelfTest PRIVATE -Wall -Wextra )
|
||||
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")
|
46
CODE_OF_CONDUCT.md
Normal file
46
CODE_OF_CONDUCT.md
Normal file
@ -0,0 +1,46 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at github@philnash.me. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
|
||||
|
||||
[homepage]: http://contributor-covenant.org
|
||||
[version]: http://contributor-covenant.org/version/1/4/
|
15
README.md
15
README.md
@ -1,14 +1,18 @@
|
||||

|
||||
|
||||
*v1.5.6*
|
||||
[](https://github.com/philsquared/catch/releases)
|
||||
[](https://travis-ci.org/philsquared/Catch?branch=catch2)
|
||||
[](https://ci.appveyor.com/project/philsquared/catch/branch/catch2)
|
||||
|
||||
Build status (on Travis CI) [](https://travis-ci.org/philsquared/Catch)
|
||||
|
||||
<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/v2.0.0-develop.1/catch.hpp">The latest version of the single header can be downloaded directly using this link</a>
|
||||
|
||||
## What's the Catch?
|
||||
|
||||
Catch stands for C++ Automated Test Cases in Headers and is a multi-paradigm automated test framework for C++ and Objective-C (and, maybe, C). It is implemented entirely in a set of header files, but is packaged up as a single header for extra convenience.
|
||||
Catch stands for C++ Automated Test Cases in Headers and is a
|
||||
multi-paradigm test framework for C++. which also supports Objective-C
|
||||
and, maybe, C.
|
||||
It is primarily distributed as a single header file, although certain
|
||||
extensions may require additional headers.
|
||||
|
||||
## How to use it
|
||||
This documentation comprises these three parts:
|
||||
@ -20,3 +24,4 @@ This documentation comprises these three parts:
|
||||
## 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)
|
||||
|
60
appveyor.yml
Normal file
60
appveyor.yml
Normal file
@ -0,0 +1,60 @@
|
||||
# version string format -- This will be overwritten later anyway
|
||||
version: "{build}"
|
||||
|
||||
os:
|
||||
- Visual Studio 2017
|
||||
- Visual Studio 2015
|
||||
|
||||
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 |
16
conanfile.py
Normal file
16
conanfile.py
Normal file
@ -0,0 +1,16 @@
|
||||
#!/usr/bin/env python
|
||||
from conans import ConanFile
|
||||
|
||||
|
||||
class CatchConan(ConanFile):
|
||||
name = "Catch"
|
||||
version = "2.0.0-develop.2"
|
||||
description = "A modern, C++-native, header-only, framework for unit-tests, TDD and BDD"
|
||||
author = "philsquared"
|
||||
generators = "cmake"
|
||||
exports_sources = "single_include/*"
|
||||
url = "https://github.com/philsquared/Catch"
|
||||
license = "Boost Software License - Version 1.0. http://www.boost.org/LICENSE_1_0.txt"
|
||||
|
||||
def package(self):
|
||||
self.copy(pattern="catch.hpp", src="single_include", dst="include")
|
173
contrib/ParseAndAddCatchTests.cmake
Normal file
173
contrib/ParseAndAddCatchTests.cmake
Normal file
@ -0,0 +1,173 @@
|
||||
#==================================================================================================#
|
||||
# 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 #
|
||||
# PARSE_CATCH_TESTS_NO_HIDDEN_TESTS (Default OFF) #
|
||||
# -- excludes tests marked with [!hide], [.] or [.foo] tags #
|
||||
# PARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAME (Default ON) #
|
||||
# -- adds fixture class name to the test name #
|
||||
# PARSE_CATCH_TESTS_ADD_TARGET_IN_TEST_NAME (Default ON) #
|
||||
# -- adds cmake target name to the test name #
|
||||
# #
|
||||
#==================================================================================================#
|
||||
|
||||
cmake_minimum_required(VERSION 2.8.8)
|
||||
|
||||
option(PARSE_CATCH_TESTS_VERBOSE "Print Catch to CTest parser debug messages" OFF)
|
||||
option(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS "Exclude tests with [!hide], [.] or [.foo] tags" OFF)
|
||||
option(PARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAME "Add fixture class name to the test name" ON)
|
||||
option(PARSE_CATCH_TESTS_ADD_TARGET_IN_TEST_NAME "Add target name to the test name" ON)
|
||||
|
||||
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(PARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAME AND TestFixture)
|
||||
set(CTestName "${TestFixture}:${Name}")
|
||||
else()
|
||||
set(CTestName "${Name}")
|
||||
endif()
|
||||
if(PARSE_CATCH_TESTS_ADD_TARGET_IN_TEST_NAME)
|
||||
set(CTestName "${TestTarget}:${CTestName}")
|
||||
endif()
|
||||
# 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})
|
||||
|
||||
list(FIND Labels "!hide" IndexOfHideLabel)
|
||||
set(HiddenTagFound OFF)
|
||||
foreach(label ${Labels})
|
||||
string(REGEX MATCH "^!hide|^\\." result ${label})
|
||||
if(result)
|
||||
set(HiddenTagFound ON)
|
||||
break()
|
||||
endif(result)
|
||||
endforeach(label)
|
||||
if(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS AND ${HiddenTagFound})
|
||||
PrintDebugMessage("Skipping test \"${CTestName}\" as it has [!hide], [.] or [.foo] label")
|
||||
else()
|
||||
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}")
|
||||
endif()
|
||||
|
||||
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,19 +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)
|
||||
* [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,53 @@ 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 extended with `const&` and you should not include it yourself.
|
||||
|
||||
* **REQUIRE_THROWS_WITH(** _expression_, _string or string matcher_ **)** and
|
||||
* **CHECK_THROWS_WITH(** _expression_, _string or string matcher_ **)**
|
||||
|
||||
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" );
|
||||
```
|
||||
|
||||
* **REQUIRE_THROWS_MATCHES(** _expression_, _exception type_, _matcher for given exception type_ **)** and
|
||||
* **CHECK_THROWS_MATCHES(** _expression_, _exception type_, _matcher for given exception type_ **)**
|
||||
|
||||
Expects that exception of _exception type_ is thrown and it matches provided matcher (see next section for Matchers).
|
||||
|
||||
|
||||
_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;
|
||||
}
|
||||
}());
|
||||
```
|
||||
|
||||
* **REQUIRE_NOTHROW(** _expression_ **)** and
|
||||
* **CHECK_NOTHROW(** _expression_ **)**
|
||||
|
||||
Expects that no exception is thrown during evaluation of the expression.
|
||||
|
||||
## 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>
|
||||
|
||||
@ -24,6 +27,9 @@ Click one of the followings links to take you straight to that option - or scrol
|
||||
<a href="#listing-available-tests-tags-or-reporters"> ` --list-reporters`</a><br />
|
||||
<a href="#order"> ` --order`</a><br />
|
||||
<a href="#rng-seed"> ` --rng-seed`</a><br />
|
||||
<a href="#libidentify"> ` --libidentify`</a><br />
|
||||
<a href="#wait-for-keypress"> ` --wait-for-keypress`</a><br />
|
||||
<a href="#benchmark-resolution-multiple"> ` --benchmark-resolution-multiple`</a><br />
|
||||
|
||||
</br>
|
||||
|
||||
@ -66,6 +72,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 +96,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 +122,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.
|
||||
@ -209,12 +216,86 @@ Alternatively if the keyword ```time``` is provided then the result of calling `
|
||||
|
||||
In either case the actual value for the seed is printed as part of Catch's output so if an issue is discovered that is sensitive to test ordering the ordering can be reproduced - even if it was originally seeded from ```std::time(0)```.
|
||||
|
||||
<a id="libidentify"></a>
|
||||
## Identify framework and version according to the libIdentify standard
|
||||
<pre>--libidentify</pre>
|
||||
|
||||
See [The LibIdentify repo for more information and examples](https://github.com/janwilmans/LibIdentify).
|
||||
|
||||
<a id="wait-for-keypress"></a>
|
||||
## Wait for key before continuing
|
||||
<pre>--wait-for-keypress <start|exit|both></pre>
|
||||
|
||||
Will cause the executable to print a message and wait until the return/ enter key is pressed before continuing -
|
||||
either before running any tests, after running all tests - or both, depending on the argument.
|
||||
|
||||
<a id="benchmark-resolution-multiple"></a>
|
||||
## Specify multiples of clock resolution to run benchmarks for
|
||||
<pre>--benchmark-resolution-multiple <multiplier></pre>
|
||||
|
||||
When running benchmarks the clock resolution is estimated. Benchmarks are then run for exponentially increasing
|
||||
numbers of iterations until some multiple of the estimated resolution is exceed. By default that multiple is 100, but
|
||||
it can be overriden here.
|
||||
|
||||
<a id="usage"></a>
|
||||
## Usage
|
||||
<pre>-h, -?, --help</pre>
|
||||
|
||||
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
|
||||
|
||||
@ -43,31 +43,54 @@ By default a console width of 80 is assumed but this can be controlled by defini
|
||||
|
||||
CATCH_CONFIG_NOSTDOUT
|
||||
|
||||
Catch does not use ```std::cout``` and ```std::cerr``` directly but gets them from ```Catch::cout()``` and ```Catch::cerr()``` respectively. If the above identifier is defined these functions are left unimplemented and you must implement them yourself. Their signatures are:
|
||||
Catch does not use ```std::cout```, ```std::cerr``` and ```std::clog``` directly but gets them from ```Catch::cout()```, ```Catch::cerr()``` and ```Catch::clog``` respectively. If the above identifier is defined these functions are left unimplemented and you must implement them yourself. Their signatures are:
|
||||
|
||||
std::ostream& cout();
|
||||
std::ostream& cerr();
|
||||
std::ostream& clog();
|
||||
|
||||
This can be useful on certain platforms that do not provide ```std::cout``` and ```std::cerr```, such as certain embedded systems.
|
||||
This can be useful on certain platforms that do not provide the standard iostreams, such as certain embedded systems.
|
||||
|
||||
# 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 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.
|
||||
You may also suppress any of these features by using the `_NO_` form, e.g. `CATCH_CONFIG_CPP11_NO_NULLPTR`.
|
||||
# Other toggles
|
||||
|
||||
All C++11 support can be disabled with `CATCH_CONFIG_NO_CPP11`
|
||||
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_DISABLE_MATCHERS // Do not compile Matchers in this compilation unit
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
## `CATCH_CONFIG_DISABLE_MATCHERS`
|
||||
When `CATCH_CONFIG_DISABLE_MATCHERS` is defined, all mentions of Catch's Matchers are ifdef-ed away from the translation unit. Doing so will speed up compilation of that TU.
|
||||
|
||||
_Note: If you define `CATCH_CONFIG_DISABLE_MATCHERS` in the same file as Catch's main is implemented, your test executable will fail to link if you use Matchers anywhere._
|
||||
|
||||
|
||||
# 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,59 @@
|
||||
# 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,
|
||||
it 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!__
|
||||
|
||||
|
||||
## Testing your changes
|
||||
|
||||
Obviously all changes to Catch's code should be tested. If you added new functionality, you should add tests covering and
|
||||
showcasing it. Even if you have only made changes to Catch internals (ie you implemented some performance improvements),
|
||||
you should still test your changes.
|
||||
|
||||
This means 3 things
|
||||
|
||||
* Compiling Catch's SelfTest project -- code that does not compile is evidently incorrect. Obviously, you are not expected to
|
||||
have access to all compilers and platforms Catch supports, Catch's CI pipeline will compile your code using supported compilers
|
||||
once you open a PR.
|
||||
* Running the SelfTest binary. There should be no unexpected failures on simple run.
|
||||
* Running Catch's approval tests. Approval tests compare current output of the SelfTest binary in various configurations against
|
||||
known good output. Catch's repository provides utility scripts `approvalTests.py` to help you with this. It needs to be passed
|
||||
the SelfTest binary compiled with your changes, like so: `$ ./scripts/approvalTests.py clang-build/SelfTest`. The output should
|
||||
be fairly self-explanatory.
|
||||
|
||||
|
||||
|
||||
*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_ **)**
|
||||
|
104
docs/matchers.md
Normal file
104
docs/matchers.md
Normal file
@ -0,0 +1,104 @@
|
||||
# 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++
|
||||
using Catch::Matchers::EndsWith; // or Catch::EndsWith
|
||||
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. They are in the `Catch::Matchers` and `Catch` namespaces.
|
||||
The string matchers are `StartsWith`, `EndsWith`, `Contains` and `Equals`. Each of them also takes an optional second argument, that decides case sensitivity (by-default, they are case sensitive).
|
||||
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)
|
86
docs/opensource-users.md
Normal file
86
docs/opensource-users.md
Normal file
@ -0,0 +1,86 @@
|
||||
# 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
|
||||
|
||||
### [Clara](https://github.com/philsquared/Clara)
|
||||
A, single-header-only, type-safe, command line parser - which also prints formatted usage strings.
|
||||
|
||||
### [Couchbase-lite-core](https://github.com/couchbase/couchbase-lite-core)
|
||||
The next-generation core storage and query engine for Couchbase Lite/
|
||||
|
||||
### [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
|
||||
|
||||
### [TextFlowCpp](https://github.com/philsquared/textflowcpp)
|
||||
A small, single-header-only, library for wrapping and composing columns of text
|
||||
|
||||
### [Trompeloeil](https://github.com/rollbear/trompeloeil)
|
||||
A thread safe header only mocking framework for C++14
|
||||
|
||||
### [args](https://github.com/Taywee/args)
|
||||
A simple header-only C++ argument parser library.
|
||||
|
||||
## 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.
|
||||
|
||||
### [Giada - Your Hardcore Loop Machine](https://github.com/monocasual/giada)
|
||||
Minimal, open-source and cross-platform audio tool for live music production.
|
||||
|
||||
### [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,8 +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...
|
||||
|
||||
int result = Catch::Session().run( argc, argv );
|
||||
@ -36,13 +35,28 @@ 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
|
||||
|
||||
|
||||
// Verify that all tests, aliases, etc registered properly
|
||||
const auto& exceptions = getRegistryHub().getStartupExceptionRegistry().getExceptions();
|
||||
if ( !exceptions.empty() ) {
|
||||
// iterate over all exceptions and notify user
|
||||
for ( const auto& ex_ptr : exceptions ) {
|
||||
try {
|
||||
std::rethrow_exception(ex_ptr);
|
||||
} catch (std::exception const& ex) {
|
||||
Catch::cerr() << ex.what();
|
||||
}
|
||||
}
|
||||
// Indicate that an error occured before main
|
||||
return 1;
|
||||
}
|
||||
|
||||
int returnCode = session.applyCommandLine( argc, argv );
|
||||
if( returnCode != 0 ) // Indicates a command line error
|
||||
return returnCode;
|
||||
@ -51,7 +65,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();
|
||||
// numFailed is clamped to 255 as some unices only use the lower 8 bits.
|
||||
// This clamping has already been applied, so just return it here
|
||||
// You can also do any post run clean-up here
|
||||
return numFailed;
|
||||
}
|
||||
```
|
||||
|
||||
@ -65,4 +83,4 @@ Catch embeds a powerful command line parser which you can also use to parse your
|
||||
|
||||
---
|
||||
|
||||
[Home](Readme.md)
|
||||
[Home](Readme.md)
|
||||
|
289
docs/release-notes.md
Normal file
289
docs/release-notes.md
Normal file
@ -0,0 +1,289 @@
|
||||
# 1.9.6
|
||||
|
||||
### Improvements
|
||||
* Catch's runtime overhead has been significantly decreased (#937, #939)
|
||||
* Added `--list-extra-info` cli option (#934).
|
||||
* It lists all tests together with extra information, ie filename, line number and description.
|
||||
|
||||
|
||||
|
||||
# 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)
|
63
docs/release-process.md
Normal file
63
docs/release-process.md
Normal file
@ -0,0 +1,63 @@
|
||||
# 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.
|
||||
|
||||
## Neccessary steps
|
||||
|
||||
These steps are neccessary and have to be performed before each new release. They serve to make sure that the new release is correct and linked-to from the standard places.
|
||||
|
||||
|
||||
### 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.
|
||||
|
||||
## Optional steps
|
||||
|
||||
The following steps are optional, and do not have to be performed when releasing new version of Catch. However, they are *should* happen, but they can happen the next day without losing anything significant.
|
||||
|
||||
|
||||
### vcpkg update
|
||||
|
||||
Catch is maintaining its own port in Microsoft's package manager [vcpkg](https://github.com/Microsoft/vcpkg). This means that when new version of Catch is released, it should be posted there as well. `updateVcpkgPackage.py` can do a lot of neccessary work for you, it creates a branch and commits neccessary changes. You should review these changes, push and open a PR against vcpkg's upstream.
|
||||
|
||||
Note that the script assumes you have your fork of vcpkg checked out in a directory next to the directory where you have checked out Catch, like so:
|
||||
```
|
||||
GitHub
|
||||
Catch
|
||||
vcpkg
|
||||
```
|
||||
|
||||
|
||||
### Wandbox update
|
||||
|
||||
Recently we also included a link to wandbox with preloaded Catch on the main page. Strictly speaking it is unneccessary to update this after every release, Catch usually does not change that much between versions, but it should be kept up to date anyway.
|
||||
|
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 - 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)
|
||||
|
@ -1,7 +1,7 @@
|
||||
# String conversions
|
||||
|
||||
Catch needs to be able to convert types you use in assertions and logging expressions into strings (for logging and reporting purposes).
|
||||
Most built-in or std types are supported out of the box but there are three ways that you can tell Catch how to convert your own types (or other, third-party types) into strings.
|
||||
Most built-in or std types are supported out of the box but there are two ways that you can tell Catch how to convert your own types (or other, third-party types) into strings.
|
||||
|
||||
## operator << overload for std::ostream
|
||||
|
||||
@ -16,42 +16,19 @@ 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;
|
||||
}
|
||||
```
|
||||
|
||||
## Catch::toString overload
|
||||
|
||||
If you don't want to provide an ```operator <<``` overload, or you want to convert your type differently for testing purposes, you can provide an overload for ```Catch::toString()``` for your type.
|
||||
|
||||
```
|
||||
namespace Catch {
|
||||
std::string toString( T const& value ) {
|
||||
return convertMyTypeToString( value );
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
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.
|
||||
You should put this function in the same namespace as your type and have it declared before including Catch's header.
|
||||
|
||||
## Catch::StringMaker<T> specialisation
|
||||
|
||||
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:
|
||||
If you don't want to provide an ```operator <<``` overload, or you want to convert your type differently for testing purposes, you can provide a specialization for `Catch::StringMaker<T>`:
|
||||
|
||||
```
|
||||
namespace Catch {
|
||||
template<> struct StringMaker<T> {
|
||||
template<>
|
||||
struct StringMaker<T> {
|
||||
static std::string convert( T const& value ) {
|
||||
return convertMyTypeToString( value );
|
||||
}
|
||||
};
|
||||
return convertMyTypeToString( value );
|
||||
}
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -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:
|
||||
|
||||
@ -80,7 +80,7 @@ unsigned int Factorial( unsigned int number ) {
|
||||
|
||||
Now all the tests pass.
|
||||
|
||||
Of course there are still more issues to do deal with. For example we'll hit problems when the return value starts to exceed the range of an unsigned int. With factorials that can happen quite quickly. You might want to add tests for such cases and decide how to handle them. We'll stop short of doing that here.
|
||||
Of course there are still more issues to deal with. For example we'll hit problems when the return value starts to exceed the range of an unsigned int. With factorials that can happen quite quickly. You might want to add tests for such cases and decide how to handle them. We'll stop short of doing that here.
|
||||
|
||||
## What did we do here?
|
||||
|
||||
@ -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,41 +1,44 @@
|
||||
# Why do we need yet another C++ test framework?
|
||||
|
||||
Good question. For C++ there are quite a number of established frameworks, including (but not limited to), [CppUnit](http://sourceforge.net/apps/mediawiki/cppunit/index.php?title=Main_Page), [Google Test](http://code.google.com/p/googletest/), [Boost.Test](http://www.boost.org/doc/libs/1_49_0/libs/test/doc/html/index.html), [Aeryn](https://launchpad.net/aeryn), [Cute](http://r2.ifs.hsr.ch/cute), [Fructose](http://fructose.sourceforge.net/) and [many, many more](http://en.wikipedia.org/wiki/List_of_unit_testing_frameworks#C.2B.2B). Even for Objective-C there are a few, including OCUnit - which now comes bundled with XCode.
|
||||
Good question. For C++ there are quite a number of established frameworks,
|
||||
including (but not limited to),
|
||||
[Google Test](http://code.google.com/p/googletest/),
|
||||
[Boost.Test](http://www.boost.org/doc/libs/1_49_0/libs/test/doc/html/index.html),
|
||||
[CppUnit](http://sourceforge.net/apps/mediawiki/cppunit/index.php?title=Main_Page),
|
||||
[Cute](http://r2.ifs.hsr.ch/cute),
|
||||
[many, many more](http://en.wikipedia.org/wiki/List_of_unit_testing_frameworks#C.2B.2B).
|
||||
|
||||
So what does Catch bring to the party that differentiates it from these? Apart from a Catchy name, of course.
|
||||
|
||||
## Key Features
|
||||
|
||||
* Really easy to get started. Just download catch.hpp, #include it and you're away.
|
||||
* No external dependencies. As long as you can compile C++98 and have a C++ standard library available.
|
||||
* Write test cases as, self-registering, functions or methods.
|
||||
* Divide test cases into sections, each of which is run in isolation (eliminates the need for fixtures!)
|
||||
* Quick and Really easy to get started. Just download catch.hpp, `#include` it and you're away.
|
||||
* No external dependencies. As long as you can compile C++11 and have a C++ standard library available.
|
||||
* Write test cases as, self-registering, functions (or methods, if you prefer).
|
||||
* Divide test cases into sections, each of which is run in isolation (eliminates the need for fixtures).
|
||||
* Use BDD-style Given-When-Then sections as well as traditional unit test cases.
|
||||
* Only one core assertion macro for comparisons. Standard C/C++ operators are used for the comparison - yet the full expression is decomposed and lhs and rhs values are logged.
|
||||
* Tests are named using free-form strings - no more couching names in legal identifiers.
|
||||
|
||||
## Other core features
|
||||
|
||||
* Tests are named using free-form strings - no more couching names in legal identifiers.
|
||||
* Tests can be tagged for easily running ad-hoc groups of tests.
|
||||
* Failures can (optionally) break into the debugger on Windows and Mac.
|
||||
* Output is through modular reporter objects. Basic textual and XML reporters are included. Custom reporters can easily be added.
|
||||
* JUnit xml output is supported for integration with third-party tools, such as CI servers.
|
||||
* A default main() function is provided (in a header), but you can supply your own for complete control (e.g. integration into your own test runner GUI).
|
||||
* A default main() function is provided, but you can supply your own for complete control (e.g. integration into your own test runner GUI).
|
||||
* A command line parser is provided and can still be used if you choose to provided your own main() function.
|
||||
* Catch can test itself.
|
||||
* Alternative assertion macro(s) report failures but don't abort the test case
|
||||
* Floating point tolerance comparisons are built in using an expressive Approx() syntax.
|
||||
* Internal and friendly macros are isolated so name clashes can be managed
|
||||
* Support for Matchers (early stages)
|
||||
* Matchers
|
||||
|
||||
## Objective-C-specific features
|
||||
## Who else is using Catch?
|
||||
|
||||
* Automatically detects if you are using it from an Objective-C project
|
||||
* Works with and without ARC with no additional configuration
|
||||
* Implement test fixtures using Obj-C classes too (like OCUnit)
|
||||
* Additional built in matchers that work with Obj-C types (e.g. string matchers)
|
||||
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
|
||||
See the [tutorial](tutorial.md) to get more of a taste of using Catch in practice
|
||||
|
||||
---
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
#if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER)
|
||||
# define CATCH_IMPL
|
||||
# define CATCH_CONFIG_EXTERNAL_INTERFACES
|
||||
#endif
|
||||
|
||||
#ifdef CATCH_IMPL
|
||||
@ -28,18 +29,21 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include "internal/catch_notimplemented_exception.h"
|
||||
#include "internal/catch_context.h"
|
||||
#include "internal/catch_tag_alias_autoregistrar.h"
|
||||
#include "internal/catch_test_registry.hpp"
|
||||
#include "internal/catch_capture.hpp"
|
||||
#include "internal/catch_section.h"
|
||||
#include "internal/catch_generators.hpp"
|
||||
#include "internal/catch_benchmark.h"
|
||||
#include "internal/catch_interfaces_exception.h"
|
||||
#include "internal/catch_approx.hpp"
|
||||
#include "internal/catch_matchers.hpp"
|
||||
#include "internal/catch_compiler_capabilities.h"
|
||||
#include "internal/catch_interfaces_tag_alias_registry.h"
|
||||
|
||||
#ifndef CATCH_CONFIG_DISABLE_MATCHERS
|
||||
#include "internal/catch_capture_matchers.h"
|
||||
#endif
|
||||
|
||||
// These files are included here so the single_include script doesn't put them
|
||||
// in the conditionally compiled sections
|
||||
#include "internal/catch_test_case_info.h"
|
||||
@ -49,6 +53,10 @@
|
||||
#include "internal/catch_objc.hpp"
|
||||
#endif
|
||||
|
||||
#ifdef CATCH_CONFIG_EXTERNAL_INTERFACES
|
||||
#include "internal/catch_external_interfaces.h"
|
||||
#endif
|
||||
|
||||
#ifdef CATCH_IMPL
|
||||
#include "internal/catch_impl.hpp"
|
||||
#endif
|
||||
@ -63,148 +71,126 @@
|
||||
#endif
|
||||
|
||||
//////
|
||||
|
||||
// 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" )
|
||||
#define CATCH_REQUIRE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ )
|
||||
#define CATCH_REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ )
|
||||
|
||||
#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( ... ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, "", __VA_ARGS__ )
|
||||
#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_STR_MATCHES( "CATCH_REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr )
|
||||
#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
|
||||
#define CATCH_REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CATCH_REQUIRE_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::Normal, matcher, expr )
|
||||
#endif// CATCH_CONFIG_DISABLE_MATCHERS
|
||||
#define CATCH_REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ )
|
||||
|
||||
#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( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
||||
#define CATCH_CHECK_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, __VA_ARGS__ )
|
||||
#define CATCH_CHECKED_IF( ... ) INTERNAL_CATCH_IF( "CATCH_CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
||||
#define CATCH_CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CATCH_CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
||||
#define CATCH_CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ )
|
||||
|
||||
#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( ... ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, "", __VA_ARGS__ )
|
||||
#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_STR_MATCHES( "CATCH_CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr )
|
||||
#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
|
||||
#define CATCH_CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CATCH_CHECK_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::ContinueOnFailure, matcher, expr )
|
||||
#endif // CATCH_CONFIG_DISABLE_MATCHERS
|
||||
#define CATCH_CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
||||
|
||||
#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" )
|
||||
#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
|
||||
#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" )
|
||||
#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg )
|
||||
#endif // CATCH_CONFIG_DISABLE_MATCHERS
|
||||
|
||||
#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__ )
|
||||
#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 )
|
||||
#endif
|
||||
#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" )
|
||||
#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_CAPTURE( msg ) INTERNAL_CATCH_INFO( "CATCH_CAPTURE", #msg " := " << ::Catch::Detail::stringify(msg) )
|
||||
|
||||
#define CATCH_REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType )
|
||||
#define CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType )
|
||||
#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_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__ )
|
||||
|
||||
#define CATCH_GENERATE( expr) INTERNAL_CATCH_GENERATE( expr )
|
||||
#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE()
|
||||
|
||||
// "BDD-style" convenience wrappers
|
||||
#ifdef CATCH_CONFIG_VARIADIC_MACROS
|
||||
#define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ )
|
||||
#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ )
|
||||
#else
|
||||
#define CATCH_SCENARIO( name, tags ) CATCH_TEST_CASE( "Scenario: " name, tags )
|
||||
#define CATCH_SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags )
|
||||
#endif
|
||||
#define CATCH_GIVEN( desc ) CATCH_SECTION( std::string( "Given: ") + desc, "" )
|
||||
#define CATCH_WHEN( desc ) CATCH_SECTION( std::string( " When: ") + desc, "" )
|
||||
#define CATCH_AND_WHEN( desc ) CATCH_SECTION( std::string( " And: ") + desc, "" )
|
||||
#define CATCH_THEN( desc ) CATCH_SECTION( std::string( " Then: ") + desc, "" )
|
||||
#define CATCH_AND_THEN( desc ) CATCH_SECTION( std::string( " And: ") + desc, "" )
|
||||
#define CATCH_GIVEN( desc ) CATCH_SECTION( std::string( "Given: ") + desc )
|
||||
#define CATCH_WHEN( desc ) CATCH_SECTION( std::string( " When: ") + desc )
|
||||
#define CATCH_AND_WHEN( desc ) CATCH_SECTION( std::string( " And: ") + desc )
|
||||
#define CATCH_THEN( desc ) CATCH_SECTION( std::string( " Then: ") + desc )
|
||||
#define CATCH_AND_THEN( desc ) CATCH_SECTION( std::string( " And: ") + desc )
|
||||
|
||||
// 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" )
|
||||
#define REQUIRE( ... ) INTERNAL_CATCH_TEST( "REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ )
|
||||
#define REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ )
|
||||
|
||||
#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" )
|
||||
#define REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "REQUIRE_THROWS", Catch::ResultDisposition::Normal, __VA_ARGS__ )
|
||||
#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_STR_MATCHES( "REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr )
|
||||
#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
|
||||
#define REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "REQUIRE_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::Normal, matcher, expr )
|
||||
#endif // CATCH_CONFIG_DISABLE_MATCHERS
|
||||
#define REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ )
|
||||
|
||||
#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 CHECK( ... ) INTERNAL_CATCH_TEST( "CHECK", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
||||
#define CHECK_FALSE( ... ) INTERNAL_CATCH_TEST( "CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, __VA_ARGS__ )
|
||||
#define CHECKED_IF( ... ) INTERNAL_CATCH_IF( "CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
||||
#define CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
||||
#define CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ )
|
||||
|
||||
#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_THROWS( ... ) INTERNAL_CATCH_THROWS( "CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
||||
#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_STR_MATCHES( "CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr )
|
||||
#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
|
||||
#define CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CHECK_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::ContinueOnFailure, matcher, expr )
|
||||
#endif // CATCH_CONFIG_DISABLE_MATCHERS
|
||||
#define CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
||||
|
||||
#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 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" )
|
||||
#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
|
||||
#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg )
|
||||
|
||||
#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 REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __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__ )
|
||||
#else
|
||||
#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 )
|
||||
#endif
|
||||
#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" )
|
||||
#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg )
|
||||
#endif // CATCH_CONFIG_DISABLE_MATCHERS
|
||||
|
||||
#define REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType )
|
||||
#define REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType )
|
||||
#define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg )
|
||||
#define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
|
||||
#define CAPTURE( msg ) INTERNAL_CATCH_INFO( "CAPTURE", #msg " := " << ::Catch::Detail::stringify(msg) )
|
||||
|
||||
#define GENERATE( expr) INTERNAL_CATCH_GENERATE( expr )
|
||||
#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__ )
|
||||
#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE()
|
||||
|
||||
#endif
|
||||
|
||||
#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature )
|
||||
|
||||
// "BDD-style" convenience wrappers
|
||||
#ifdef CATCH_CONFIG_VARIADIC_MACROS
|
||||
#define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ )
|
||||
#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ )
|
||||
#else
|
||||
#define SCENARIO( name, tags ) TEST_CASE( "Scenario: " name, tags )
|
||||
#define SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags )
|
||||
#endif
|
||||
#define GIVEN( desc ) SECTION( std::string(" Given: ") + desc, "" )
|
||||
#define WHEN( desc ) SECTION( std::string(" When: ") + desc, "" )
|
||||
#define AND_WHEN( desc ) SECTION( std::string("And when: ") + desc, "" )
|
||||
#define THEN( desc ) SECTION( std::string(" Then: ") + desc, "" )
|
||||
#define AND_THEN( desc ) SECTION( std::string(" And: ") + desc, "" )
|
||||
|
||||
#define GIVEN( desc ) SECTION( std::string(" Given: ") + desc )
|
||||
#define WHEN( desc ) SECTION( std::string(" When: ") + desc )
|
||||
#define AND_WHEN( desc ) SECTION( std::string("And when: ") + desc )
|
||||
#define THEN( desc ) SECTION( std::string(" Then: ") + desc )
|
||||
#define AND_THEN( desc ) SECTION( std::string(" And: ") + desc )
|
||||
|
||||
using Catch::Detail::Approx;
|
||||
|
||||
|
@ -9,58 +9,57 @@
|
||||
#define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED
|
||||
|
||||
#include "internal/catch_commandline.hpp"
|
||||
#include "internal/catch_list.hpp"
|
||||
#include "internal/catch_console_colour.hpp"
|
||||
#include "internal/catch_enforce.h"
|
||||
#include "internal/catch_list.h"
|
||||
#include "internal/catch_run_context.hpp"
|
||||
#include "internal/catch_test_spec.hpp"
|
||||
#include "internal/catch_version.h"
|
||||
#include "internal/catch_interfaces_reporter.h"
|
||||
#include "internal/catch_startup_exception_registry.h"
|
||||
#include "internal/catch_text.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <stdlib.h>
|
||||
#include <cstdlib>
|
||||
#include <limits>
|
||||
#include <iomanip>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
Ptr<IStreamingReporter> createReporter( std::string const& reporterName, Ptr<Config> const& config ) {
|
||||
Ptr<IStreamingReporter> reporter = getRegistryHub().getReporterRegistry().create( reporterName, config.get() );
|
||||
if( !reporter ) {
|
||||
std::ostringstream oss;
|
||||
oss << "No reporter registered with name: '" << reporterName << "'";
|
||||
throw std::domain_error( oss.str() );
|
||||
}
|
||||
IStreamingReporterPtr createReporter( std::string const& reporterName, IConfigPtr const& config ) {
|
||||
auto reporter = getRegistryHub().getReporterRegistry().create( reporterName, config );
|
||||
CATCH_ENFORCE( reporter, "No reporter registered with name: '" << reporterName << "'" );
|
||||
|
||||
return reporter;
|
||||
}
|
||||
|
||||
Ptr<IStreamingReporter> makeReporter( Ptr<Config> const& config ) {
|
||||
std::vector<std::string> reporters = config->getReporterNames();
|
||||
if( reporters.empty() )
|
||||
reporters.push_back( "console" );
|
||||
#ifndef CATCH_CONFIG_DEFAULT_REPORTER
|
||||
#define CATCH_CONFIG_DEFAULT_REPORTER "console"
|
||||
#endif
|
||||
|
||||
Ptr<IStreamingReporter> reporter;
|
||||
for( std::vector<std::string>::const_iterator it = reporters.begin(), itEnd = reporters.end();
|
||||
it != itEnd;
|
||||
++it )
|
||||
reporter = addReporter( reporter, createReporter( *it, config ) );
|
||||
IStreamingReporterPtr makeReporter( std::shared_ptr<Config> const& config ) {
|
||||
auto const& reporterNames = config->getReporterNames();
|
||||
if( reporterNames.empty() )
|
||||
return createReporter(CATCH_CONFIG_DEFAULT_REPORTER, config );
|
||||
|
||||
IStreamingReporterPtr reporter;
|
||||
for( auto const& name : reporterNames )
|
||||
addReporter( reporter, createReporter( name, config ) );
|
||||
return reporter;
|
||||
}
|
||||
Ptr<IStreamingReporter> addListeners( Ptr<IConfig const> const& config, Ptr<IStreamingReporter> reporters ) {
|
||||
IReporterRegistry::Listeners listeners = getRegistryHub().getReporterRegistry().getListeners();
|
||||
for( IReporterRegistry::Listeners::const_iterator it = listeners.begin(), itEnd = listeners.end();
|
||||
it != itEnd;
|
||||
++it )
|
||||
reporters = addReporter(reporters, (*it)->create( ReporterConfig( config ) ) );
|
||||
return reporters;
|
||||
void addListeners( IStreamingReporterPtr& reporters, IConfigPtr const& config ) {
|
||||
auto const& listeners = getRegistryHub().getReporterRegistry().getListeners();
|
||||
for( auto const& listener : listeners )
|
||||
addReporter(reporters, listener->create( ReporterConfig( config ) ) );
|
||||
}
|
||||
|
||||
|
||||
Totals runTests( Ptr<Config> const& config ) {
|
||||
Totals runTests( std::shared_ptr<Config> const& config ) {
|
||||
|
||||
Ptr<IConfig const> iconfig = config.get();
|
||||
IStreamingReporterPtr reporter = makeReporter( config );
|
||||
addListeners( reporter, config );
|
||||
|
||||
Ptr<IStreamingReporter> reporter = makeReporter( config );
|
||||
reporter = addListeners( iconfig, reporter );
|
||||
|
||||
RunContext context( iconfig, reporter );
|
||||
RunContext context( config, std::move( reporter ) );
|
||||
|
||||
Totals totals;
|
||||
|
||||
@ -70,104 +69,165 @@ namespace Catch {
|
||||
if( !testSpec.hasFilters() )
|
||||
testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests
|
||||
|
||||
std::vector<TestCase> const& allTestCases = getAllTestCasesSorted( *iconfig );
|
||||
for( std::vector<TestCase>::const_iterator it = allTestCases.begin(), itEnd = allTestCases.end();
|
||||
it != itEnd;
|
||||
++it ) {
|
||||
if( !context.aborting() && matchTest( *it, testSpec, *iconfig ) )
|
||||
totals += context.runTest( *it );
|
||||
std::vector<TestCase> const& allTestCases = getAllTestCasesSorted( *config );
|
||||
for( auto const& testCase : allTestCases ) {
|
||||
if( !context.aborting() && matchTest( testCase, testSpec, *config ) )
|
||||
totals += context.runTest( testCase );
|
||||
else
|
||||
reporter->skipTest( *it );
|
||||
context.reporter().skipTest( testCase );
|
||||
}
|
||||
|
||||
context.testGroupEnded( iconfig->name(), totals, 1, 1 );
|
||||
context.testGroupEnded( config->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;
|
||||
auto& tests = const_cast<std::vector<TestCase>&>( getAllTestCasesSorted( config ) );
|
||||
for( auto& testCase : tests ) {
|
||||
auto tags = testCase.tags;
|
||||
|
||||
std::string filename = test.lineInfo.file;
|
||||
std::string filename = testCase.lineInfo.file;
|
||||
std::string::size_type lastSlash = filename.find_last_of( "\\/" );
|
||||
if( lastSlash != std::string::npos )
|
||||
filename = filename.substr( lastSlash+1 );
|
||||
|
||||
std::string::size_type lastDot = filename.find_last_of( "." );
|
||||
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 );
|
||||
tags.push_back( '#' + filename );
|
||||
setTags( testCase, tags );
|
||||
}
|
||||
}
|
||||
|
||||
class Session : NonCopyable {
|
||||
static bool alreadyInstantiated;
|
||||
|
||||
class Session : NonCopyable {
|
||||
static const int MaxExitCode;
|
||||
public:
|
||||
|
||||
struct OnUnusedOptions { enum DoWhat { Ignore, Fail }; };
|
||||
|
||||
Session()
|
||||
: m_cli( makeCommandLineParser() ) {
|
||||
if( alreadyInstantiated ) {
|
||||
std::string msg = "Only one instance of Catch::Session can ever be used";
|
||||
Catch::cerr() << msg << std::endl;
|
||||
throw std::logic_error( msg );
|
||||
}
|
||||
Session() {
|
||||
static bool alreadyInstantiated = false;
|
||||
if( alreadyInstantiated )
|
||||
CATCH_INTERNAL_ERROR( "Only one instance of Catch::Session can ever be used" );
|
||||
alreadyInstantiated = true;
|
||||
m_cli = makeCommandLineParser( m_configData );
|
||||
}
|
||||
~Session() {
|
||||
~Session() override {
|
||||
Catch::cleanUp();
|
||||
}
|
||||
|
||||
void showHelp( std::string const& processName ) {
|
||||
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;
|
||||
void showHelp() const {
|
||||
Catch::cout()
|
||||
<< "\nCatch v" << libraryVersion() << "\n"
|
||||
<< m_cli << std::endl
|
||||
<< "For more detailed usage please see the project docs\n" << std::endl;
|
||||
}
|
||||
void libIdentify() {
|
||||
Catch::cout()
|
||||
<< std::left << std::setw(16) << "description: " << "A Catch test executable\n"
|
||||
<< std::left << std::setw(16) << "category: " << "testframework\n"
|
||||
<< std::left << std::setw(16) << "framework: " << "Catch Test\n"
|
||||
<< std::left << std::setw(16) << "version: " << libraryVersion() << std::endl;
|
||||
}
|
||||
|
||||
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( Clara::argsToVector( argc, argv ), m_configData );
|
||||
if( m_configData.showHelp )
|
||||
showHelp( m_configData.processName );
|
||||
m_config.reset();
|
||||
}
|
||||
catch( std::exception& ex ) {
|
||||
{
|
||||
Colour colourGuard( Colour::Red );
|
||||
Catch::cerr()
|
||||
<< "\nError(s) in input:\n"
|
||||
<< Text( ex.what(), TextAttributes().setIndent(2) )
|
||||
<< "\n\n";
|
||||
}
|
||||
m_cli.usage( Catch::cout(), m_configData.processName );
|
||||
return (std::numeric_limits<int>::max)();
|
||||
int applyCommandLine( int argc, char* argv[] ) {
|
||||
auto result = m_cli.parse( clara::Args( argc, argv ) );
|
||||
if( !result ) {
|
||||
Catch::cerr()
|
||||
<< Colour( Colour::Red )
|
||||
<< "\nError(s) in input:\n"
|
||||
<< Column( result.errorMessage() ).indent( 2 )
|
||||
<< "\n\n";
|
||||
Catch::cerr() << "Run with -? for usage\n" << std::endl;
|
||||
return MaxExitCode;
|
||||
}
|
||||
|
||||
if( m_configData.showHelp )
|
||||
showHelp();
|
||||
if( m_configData.libIdentify )
|
||||
libIdentify();
|
||||
m_config.reset();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void useConfigData( ConfigData const& _configData ) {
|
||||
m_configData = _configData;
|
||||
void useConfigData( ConfigData const& configData ) {
|
||||
m_configData = configData;
|
||||
m_config.reset();
|
||||
}
|
||||
|
||||
int run( int argc, char const* const* const argv ) {
|
||||
|
||||
int run( int argc, char* argv[] ) {
|
||||
const auto& exceptions = getRegistryHub().getStartupExceptionRegistry().getExceptions();
|
||||
if ( !exceptions.empty() ) {
|
||||
Catch::cerr() << "Errors occured during startup!" << '\n';
|
||||
// iterate over all exceptions and notify user
|
||||
for ( const auto& ex_ptr : exceptions ) {
|
||||
try {
|
||||
std::rethrow_exception(ex_ptr);
|
||||
} catch ( std::exception const& ex ) {
|
||||
Catch::cerr() << ex.what() << '\n';
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
int returnCode = applyCommandLine( argc, argv );
|
||||
if( returnCode == 0 )
|
||||
returnCode = run();
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
#if defined(WIN32) && defined(UNICODE)
|
||||
int run( int argc, wchar_t* 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 = run( argc, utf8Argv );
|
||||
|
||||
for ( int i = 0; i < argc; ++i )
|
||||
delete [] utf8Argv[ i ];
|
||||
|
||||
delete [] utf8Argv;
|
||||
|
||||
return returnCode;
|
||||
}
|
||||
#endif
|
||||
int run() {
|
||||
if( m_configData.showHelp )
|
||||
if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeStart ) != 0 ) {
|
||||
Catch::cout() << "...waiting for enter/ return before starting" << std::endl;
|
||||
std::getchar();
|
||||
}
|
||||
int exitCode = runInternal();
|
||||
if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeExit ) != 0 ) {
|
||||
Catch::cout() << "...waiting for enter/ return before exiting, with code: " << exitCode << std::endl;
|
||||
std::getchar();
|
||||
}
|
||||
return exitCode;
|
||||
}
|
||||
|
||||
clara::Parser const& cli() const {
|
||||
return m_cli;
|
||||
}
|
||||
void cli( clara::Parser const& newParser ) {
|
||||
m_cli = newParser;
|
||||
}
|
||||
ConfigData& configData() {
|
||||
return m_configData;
|
||||
}
|
||||
Config& config() {
|
||||
if( !m_config )
|
||||
m_config = std::make_shared<Config>( m_configData );
|
||||
return *m_config;
|
||||
}
|
||||
private:
|
||||
int runInternal() {
|
||||
if( m_configData.showHelp || m_configData.libIdentify )
|
||||
return 0;
|
||||
|
||||
try
|
||||
@ -183,36 +243,20 @@ namespace Catch {
|
||||
if( Option<std::size_t> listed = list( config() ) )
|
||||
return static_cast<int>( *listed );
|
||||
|
||||
return static_cast<int>( runTests( m_config ).assertions.failed );
|
||||
return (std::min)( MaxExitCode, static_cast<int>( runTests( m_config ).assertions.failed ) );
|
||||
}
|
||||
catch( std::exception& ex ) {
|
||||
Catch::cerr() << ex.what() << std::endl;
|
||||
return (std::numeric_limits<int>::max)();
|
||||
return MaxExitCode;
|
||||
}
|
||||
}
|
||||
|
||||
Clara::CommandLine<ConfigData> const& cli() const {
|
||||
return m_cli;
|
||||
}
|
||||
std::vector<Clara::Parser::Token> const& unusedTokens() const {
|
||||
return m_unusedTokens;
|
||||
}
|
||||
ConfigData& configData() {
|
||||
return m_configData;
|
||||
}
|
||||
Config& config() {
|
||||
if( !m_config )
|
||||
m_config = new Config( m_configData );
|
||||
return *m_config;
|
||||
}
|
||||
private:
|
||||
Clara::CommandLine<ConfigData> m_cli;
|
||||
std::vector<Clara::Parser::Token> m_unusedTokens;
|
||||
clara::Parser m_cli;
|
||||
ConfigData m_configData;
|
||||
Ptr<Config> m_config;
|
||||
std::shared_ptr<Config> m_config;
|
||||
};
|
||||
|
||||
bool Session::alreadyInstantiated = false;
|
||||
const int Session::MaxExitCode = 255;
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
|
1048
include/external/clara.h
vendored
1048
include/external/clara.h
vendored
File diff suppressed because it is too large
Load Diff
1230
include/external/clara.hpp
vendored
Normal file
1230
include/external/clara.hpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
153
include/external/tbc_text_format.h
vendored
153
include/external/tbc_text_format.h
vendored
@ -1,153 +0,0 @@
|
||||
/*
|
||||
* Created by Phil on 18/4/2013.
|
||||
* Copyright 2013 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)
|
||||
*/
|
||||
// Only use header guard if we are not using an outer namespace
|
||||
#ifndef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
|
||||
# ifdef TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED
|
||||
# ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
|
||||
# define TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
|
||||
# endif
|
||||
# else
|
||||
# define TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED
|
||||
# endif
|
||||
#endif
|
||||
#ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
|
||||
// Use optional outer namespace
|
||||
#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
|
||||
namespace CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE {
|
||||
#endif
|
||||
|
||||
namespace Tbc {
|
||||
|
||||
#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH
|
||||
const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH;
|
||||
#else
|
||||
const unsigned int consoleWidth = 80;
|
||||
#endif
|
||||
|
||||
struct TextAttributes {
|
||||
TextAttributes()
|
||||
: initialIndent( std::string::npos ),
|
||||
indent( 0 ),
|
||||
width( consoleWidth-1 ),
|
||||
tabChar( '\t' )
|
||||
{}
|
||||
|
||||
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 {
|
||||
public:
|
||||
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;
|
||||
|
||||
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 );
|
||||
}
|
||||
else {
|
||||
spliceLine( indent, remainder, width-1 );
|
||||
lines.back() += "-";
|
||||
}
|
||||
if( lines.size() == 1 )
|
||||
indent = _attr.indent;
|
||||
if( tabPos != std::string::npos )
|
||||
indent += tabPos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
const_iterator begin() const { return lines.begin(); }
|
||||
const_iterator end() const { return lines.end(); }
|
||||
std::string const& last() const { return lines.back(); }
|
||||
std::size_t size() const { return lines.size(); }
|
||||
std::string const& operator[]( std::size_t _index ) const { return lines[_index]; }
|
||||
std::string toString() const {
|
||||
std::ostringstream oss;
|
||||
oss << *this;
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) {
|
||||
for( Text::const_iterator it = _text.begin(), itEnd = _text.end();
|
||||
it != itEnd; ++it ) {
|
||||
if( it != _text.begin() )
|
||||
_stream << "\n";
|
||||
_stream << *it;
|
||||
}
|
||||
return _stream;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string str;
|
||||
TextAttributes attr;
|
||||
std::vector<std::string> lines;
|
||||
};
|
||||
|
||||
} // end namespace Tbc
|
||||
|
||||
#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
|
||||
} // end outer namespace
|
||||
#endif
|
||||
|
||||
#endif // TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
|
46
include/internal/catch_approx.cpp
Normal file
46
include/internal/catch_approx.cpp
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Created by Martin on 19/07/2017.
|
||||
* Copyright 2017 Two Blue Cubes Ltd. All rights reserved.
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
|
||||
#include "catch_approx.hpp"
|
||||
|
||||
#include <limits>
|
||||
|
||||
namespace Catch {
|
||||
namespace Detail {
|
||||
|
||||
double max(double lhs, double rhs) {
|
||||
if (lhs < rhs) {
|
||||
return rhs;
|
||||
}
|
||||
return lhs;
|
||||
}
|
||||
|
||||
Approx::Approx ( double value )
|
||||
: m_epsilon( std::numeric_limits<float>::epsilon()*100 ),
|
||||
m_margin( 0.0 ),
|
||||
m_scale( 1.0 ),
|
||||
m_value( value )
|
||||
{}
|
||||
|
||||
Approx Approx::custom() {
|
||||
return Approx( 0 );
|
||||
}
|
||||
|
||||
std::string Approx::toString() const {
|
||||
std::ostringstream oss;
|
||||
oss << "Approx( " << ::Catch::Detail::stringify( m_value ) << " )";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
} // end namespace Detail
|
||||
|
||||
std::string StringMaker<Catch::Detail::Approx>::convert(Catch::Detail::Approx const& value) {
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
} // end namespace Catch
|
@ -11,80 +11,112 @@
|
||||
#include "catch_tostring.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace Catch {
|
||||
namespace Detail {
|
||||
|
||||
double max(double lhs, double rhs);
|
||||
|
||||
class Approx {
|
||||
public:
|
||||
explicit Approx ( double value )
|
||||
: m_epsilon( std::numeric_limits<float>::epsilon()*100 ),
|
||||
m_scale( 1.0 ),
|
||||
m_value( value )
|
||||
{}
|
||||
explicit Approx ( double value );
|
||||
|
||||
Approx( Approx const& other )
|
||||
: m_epsilon( other.m_epsilon ),
|
||||
m_scale( other.m_scale ),
|
||||
m_value( other.m_value )
|
||||
{}
|
||||
static Approx custom();
|
||||
|
||||
static Approx custom() {
|
||||
return Approx( 0 );
|
||||
}
|
||||
|
||||
Approx operator()( double value ) {
|
||||
Approx approx( value );
|
||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
||||
Approx operator()( T const& value ) {
|
||||
Approx approx( static_cast<double>(value) );
|
||||
approx.epsilon( m_epsilon );
|
||||
approx.margin( m_margin );
|
||||
approx.scale( m_scale );
|
||||
return approx;
|
||||
}
|
||||
|
||||
friend bool operator == ( double lhs, Approx const& rhs ) {
|
||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
||||
explicit Approx( T const& 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
|
||||
return fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( fabs(lhs), fabs(rhs.m_value) ) );
|
||||
auto lhs_v = static_cast<double>(lhs);
|
||||
bool relativeOK = std::fabs(lhs_v - rhs.m_value) < rhs.m_epsilon * (rhs.m_scale + (max)(std::fabs(lhs_v), std::fabs(rhs.m_value)));
|
||||
if (relativeOK) {
|
||||
return true;
|
||||
}
|
||||
return std::fabs(lhs_v - rhs.m_value) < rhs.m_margin;
|
||||
}
|
||||
|
||||
friend bool operator == ( Approx const& lhs, double rhs ) {
|
||||
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 );
|
||||
}
|
||||
|
||||
friend bool operator != ( double lhs, Approx const& rhs ) {
|
||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
||||
friend bool operator != ( T const& lhs, Approx const& rhs ) {
|
||||
return !operator==( lhs, rhs );
|
||||
}
|
||||
|
||||
friend bool operator != ( Approx const& lhs, double rhs ) {
|
||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
||||
friend bool operator != ( Approx const& lhs, T const& rhs ) {
|
||||
return !operator==( rhs, lhs );
|
||||
}
|
||||
|
||||
Approx& epsilon( double newEpsilon ) {
|
||||
m_epsilon = newEpsilon;
|
||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
||||
friend bool operator <= ( T const& lhs, Approx const& rhs ) {
|
||||
return static_cast<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 const& rhs ) {
|
||||
return lhs.m_value < static_cast<double>(rhs) || lhs == rhs;
|
||||
}
|
||||
|
||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
||||
friend bool operator >= ( T const& lhs, Approx const& rhs ) {
|
||||
return static_cast<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 const& rhs ) {
|
||||
return lhs.m_value > static_cast<double>(rhs) || lhs == rhs;
|
||||
}
|
||||
|
||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
||||
Approx& epsilon( T const& newEpsilon ) {
|
||||
m_epsilon = static_cast<double>(newEpsilon);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Approx& scale( double newScale ) {
|
||||
m_scale = newScale;
|
||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
||||
Approx& margin( T const& newMargin ) {
|
||||
m_margin = static_cast<double>(newMargin);
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string toString() const {
|
||||
std::ostringstream oss;
|
||||
oss << "Approx( " << Catch::toString( m_value ) << " )";
|
||||
return oss.str();
|
||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
||||
Approx& scale( T const& newScale ) {
|
||||
m_scale = static_cast<double>(newScale);
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string toString() const;
|
||||
|
||||
private:
|
||||
double m_epsilon;
|
||||
double m_margin;
|
||||
double m_scale;
|
||||
double m_value;
|
||||
};
|
||||
}
|
||||
|
||||
template<>
|
||||
inline std::string toString<Detail::Approx>( Detail::Approx const& value ) {
|
||||
return value.toString();
|
||||
}
|
||||
struct StringMaker<Catch::Detail::Approx> {
|
||||
static std::string convert(Catch::Detail::Approx const& value);
|
||||
};
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
|
147
include/internal/catch_assertionhandler.cpp
Normal file
147
include/internal/catch_assertionhandler.cpp
Normal file
@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Created by Phil on 8/8/2017.
|
||||
* Copyright 2017 Two Blue Cubes Ltd. All rights reserved.
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
|
||||
#include "catch_assertionhandler.h"
|
||||
#include "catch_assertionresult.h"
|
||||
#include "catch_interfaces_capture.h"
|
||||
#include "catch_interfaces_runner.h"
|
||||
#include "catch_interfaces_config.h"
|
||||
#include "catch_context.h"
|
||||
#include "catch_debugger.h"
|
||||
#include "catch_interfaces_registry_hub.h"
|
||||
#include "catch_capture_matchers.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
auto operator <<( std::ostream& os, ITransientExpression const& expr ) -> std::ostream& {
|
||||
expr.streamReconstructedExpression( os );
|
||||
return os;
|
||||
}
|
||||
|
||||
LazyExpression::LazyExpression( bool isNegated )
|
||||
: m_isNegated( isNegated )
|
||||
{}
|
||||
|
||||
LazyExpression::LazyExpression( LazyExpression const& other ) : m_isNegated( other.m_isNegated ) {}
|
||||
|
||||
LazyExpression::operator bool() const {
|
||||
return m_transientExpression != nullptr;
|
||||
}
|
||||
|
||||
auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream& {
|
||||
if( lazyExpr.m_isNegated )
|
||||
os << "!";
|
||||
|
||||
if( lazyExpr ) {
|
||||
if( lazyExpr.m_isNegated && lazyExpr.m_transientExpression->isBinaryExpression() )
|
||||
os << "(" << *lazyExpr.m_transientExpression << ")";
|
||||
else
|
||||
os << *lazyExpr.m_transientExpression;
|
||||
}
|
||||
else {
|
||||
os << "{** error - unchecked empty expression requested **}";
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
AssertionHandler::AssertionHandler
|
||||
( StringRef macroName,
|
||||
SourceLineInfo const& lineInfo,
|
||||
StringRef capturedExpression,
|
||||
ResultDisposition::Flags resultDisposition )
|
||||
: m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition }
|
||||
{
|
||||
getCurrentContext().getResultCapture()->assertionStarting( m_assertionInfo );
|
||||
}
|
||||
AssertionHandler::~AssertionHandler() {
|
||||
if ( m_inExceptionGuard ) {
|
||||
handle( ResultWas::ThrewException, "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE" );
|
||||
getCurrentContext().getResultCapture()->exceptionEarlyReported();
|
||||
}
|
||||
}
|
||||
|
||||
void AssertionHandler::handle( ITransientExpression const& expr ) {
|
||||
|
||||
bool negated = isFalseTest( m_assertionInfo.resultDisposition );
|
||||
bool result = expr.getResult() != negated;
|
||||
|
||||
handle( result ? ResultWas::Ok : ResultWas::ExpressionFailed, &expr, negated );
|
||||
}
|
||||
void AssertionHandler::handle( ResultWas::OfType resultType ) {
|
||||
handle( resultType, nullptr, false );
|
||||
}
|
||||
void AssertionHandler::handle( ResultWas::OfType resultType, StringRef const& message ) {
|
||||
AssertionResultData data( resultType, LazyExpression( false ) );
|
||||
data.message = message;
|
||||
handle( data, nullptr );
|
||||
}
|
||||
void AssertionHandler::handle( ResultWas::OfType resultType, ITransientExpression const* expr, bool negated ) {
|
||||
AssertionResultData data( resultType, LazyExpression( negated ) );
|
||||
handle( data, expr );
|
||||
}
|
||||
void AssertionHandler::handle( AssertionResultData const& resultData, ITransientExpression const* expr ) {
|
||||
|
||||
getResultCapture().assertionRun();
|
||||
|
||||
AssertionResult assertionResult{ m_assertionInfo, resultData };
|
||||
assertionResult.m_resultData.lazyExpression.m_transientExpression = expr;
|
||||
|
||||
getResultCapture().assertionEnded( assertionResult );
|
||||
|
||||
if( !assertionResult.isOk() ) {
|
||||
m_shouldDebugBreak = getCurrentContext().getConfig()->shouldDebugBreak();
|
||||
m_shouldThrow =
|
||||
getCurrentContext().getRunner()->aborting() ||
|
||||
(m_assertionInfo.resultDisposition & ResultDisposition::Normal);
|
||||
}
|
||||
}
|
||||
|
||||
auto AssertionHandler::allowThrows() const -> bool {
|
||||
return getCurrentContext().getConfig()->allowThrows();
|
||||
}
|
||||
|
||||
auto AssertionHandler::shouldDebugBreak() const -> bool {
|
||||
return m_shouldDebugBreak;
|
||||
}
|
||||
void AssertionHandler::reactWithDebugBreak() const {
|
||||
if (m_shouldDebugBreak) {
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// To inspect the state during test, you need to go one level up the callstack
|
||||
// To go back to the test and change execution, jump over the reactWithoutDebugBreak() call
|
||||
///////////////////////////////////////////////////////////////////
|
||||
CATCH_BREAK_INTO_DEBUGGER();
|
||||
}
|
||||
reactWithoutDebugBreak();
|
||||
}
|
||||
void AssertionHandler::reactWithoutDebugBreak() const {
|
||||
if( m_shouldThrow )
|
||||
throw Catch::TestFailureException();
|
||||
}
|
||||
|
||||
void AssertionHandler::useActiveException() {
|
||||
handle( ResultWas::ThrewException, Catch::translateActiveException() );
|
||||
}
|
||||
|
||||
void AssertionHandler::setExceptionGuard() {
|
||||
assert( m_inExceptionGuard == false );
|
||||
m_inExceptionGuard = true;
|
||||
}
|
||||
void AssertionHandler::unsetExceptionGuard() {
|
||||
assert( m_inExceptionGuard == true );
|
||||
m_inExceptionGuard = false;
|
||||
}
|
||||
|
||||
// This is the overload that takes a string and infers the Equals matcher from it
|
||||
// The more general overload, that takes any string matcher, is in catch_capture_matchers.cpp
|
||||
void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef matcherString ) {
|
||||
handleExceptionMatchExpr( handler, Matchers::Equals( str ), matcherString );
|
||||
}
|
||||
|
||||
} // namespace Catch
|
73
include/internal/catch_assertionhandler.h
Normal file
73
include/internal/catch_assertionhandler.h
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Created by Phil on 8/8/2017.
|
||||
* Copyright 2017 Two Blue Cubes Ltd. All rights reserved.
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
#ifndef TWOBLUECUBES_CATCH_ASSERTIONHANDLER_H_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_ASSERTIONHANDLER_H_INCLUDED
|
||||
|
||||
#include "catch_decomposer.h"
|
||||
#include "catch_assertioninfo.h"
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct TestFailureException{};
|
||||
struct AssertionResultData;
|
||||
|
||||
class LazyExpression {
|
||||
friend class AssertionHandler;
|
||||
friend struct AssertionStats;
|
||||
|
||||
ITransientExpression const* m_transientExpression = nullptr;
|
||||
bool m_isNegated;
|
||||
public:
|
||||
LazyExpression( bool isNegated );
|
||||
LazyExpression( LazyExpression const& other );
|
||||
LazyExpression& operator = ( LazyExpression const& ) = delete;
|
||||
|
||||
explicit operator bool() const;
|
||||
|
||||
friend auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream&;
|
||||
};
|
||||
|
||||
class AssertionHandler {
|
||||
AssertionInfo m_assertionInfo;
|
||||
bool m_shouldDebugBreak = false;
|
||||
bool m_shouldThrow = false;
|
||||
bool m_inExceptionGuard = false;
|
||||
|
||||
public:
|
||||
AssertionHandler
|
||||
( StringRef macroName,
|
||||
SourceLineInfo const& lineInfo,
|
||||
StringRef capturedExpression,
|
||||
ResultDisposition::Flags resultDisposition );
|
||||
~AssertionHandler();
|
||||
|
||||
void handle( ITransientExpression const& expr );
|
||||
|
||||
template<typename T>
|
||||
void handle( ExprLhs<T> const& expr ) {
|
||||
handle( expr.makeUnaryExpr() );
|
||||
}
|
||||
void handle( ResultWas::OfType resultType );
|
||||
void handle( ResultWas::OfType resultType, StringRef const& message );
|
||||
void handle( ResultWas::OfType resultType, ITransientExpression const* expr, bool negated );
|
||||
void handle( AssertionResultData const& resultData, ITransientExpression const* expr );
|
||||
|
||||
auto shouldDebugBreak() const -> bool;
|
||||
auto allowThrows() const -> bool;
|
||||
void reactWithDebugBreak() const;
|
||||
void reactWithoutDebugBreak() const;
|
||||
void useActiveException();
|
||||
void setExceptionGuard();
|
||||
void unsetExceptionGuard();
|
||||
};
|
||||
|
||||
void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef matcherString );
|
||||
|
||||
} // namespace Catch
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_ASSERTIONHANDLER_H_INCLUDED
|
31
include/internal/catch_assertioninfo.h
Normal file
31
include/internal/catch_assertioninfo.h
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Created by Phil on 8/8/2017.
|
||||
* Copyright 2017 Two Blue Cubes Ltd. All rights reserved.
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
#ifndef TWOBLUECUBES_CATCH_ASSERTIONINFO_H_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_ASSERTIONINFO_H_INCLUDED
|
||||
|
||||
#include "catch_result_type.h"
|
||||
#include "catch_common.h"
|
||||
#include "catch_stringref.h"
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct AssertionInfo
|
||||
{
|
||||
StringRef macroName;
|
||||
SourceLineInfo lineInfo;
|
||||
StringRef capturedExpression;
|
||||
ResultDisposition::Flags resultDisposition;
|
||||
|
||||
// We want to delete this constructor but a compiler bug in 4.8 means
|
||||
// the struct is then treated as non-aggregate
|
||||
//AssertionInfo() = delete;
|
||||
};
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_ASSERTIONINFO_H_INCLUDED
|
@ -5,33 +5,29 @@
|
||||
* 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_ASSERTIONRESULT_HPP_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_HPP_INCLUDED
|
||||
|
||||
#include "catch_assertionresult.h"
|
||||
|
||||
namespace Catch {
|
||||
|
||||
std::string AssertionResultData::reconstructExpression() const {
|
||||
|
||||
AssertionInfo::AssertionInfo( std::string const& _macroName,
|
||||
SourceLineInfo const& _lineInfo,
|
||||
std::string const& _capturedExpression,
|
||||
ResultDisposition::Flags _resultDisposition )
|
||||
: macroName( _macroName ),
|
||||
lineInfo( _lineInfo ),
|
||||
capturedExpression( _capturedExpression ),
|
||||
resultDisposition( _resultDisposition )
|
||||
{}
|
||||
|
||||
AssertionResult::AssertionResult() {}
|
||||
if( reconstructedExpression.empty() ) {
|
||||
if( lazyExpression ) {
|
||||
// !TBD Use stringstream for now, but rework above to pass stream in
|
||||
std::ostringstream oss;
|
||||
oss << lazyExpression;
|
||||
reconstructedExpression = oss.str();
|
||||
}
|
||||
}
|
||||
return reconstructedExpression;
|
||||
}
|
||||
|
||||
AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data )
|
||||
: m_info( info ),
|
||||
m_resultData( data )
|
||||
{}
|
||||
|
||||
AssertionResult::~AssertionResult() {}
|
||||
|
||||
// Result was a success
|
||||
bool AssertionResult::succeeded() const {
|
||||
return Catch::isOk( m_resultData.resultType );
|
||||
@ -47,7 +43,7 @@ namespace Catch {
|
||||
}
|
||||
|
||||
bool AssertionResult::hasExpression() const {
|
||||
return !m_info.capturedExpression.empty();
|
||||
return m_info.capturedExpression[0] != 0;
|
||||
}
|
||||
|
||||
bool AssertionResult::hasMessage() const {
|
||||
@ -55,16 +51,24 @@ namespace Catch {
|
||||
}
|
||||
|
||||
std::string AssertionResult::getExpression() const {
|
||||
if( isFalseTest( m_info.resultDisposition ) )
|
||||
return "!" + m_info.capturedExpression;
|
||||
if (isFalseTest(m_info.resultDisposition))
|
||||
return '!' + std::string(m_info.capturedExpression);
|
||||
else
|
||||
return m_info.capturedExpression;
|
||||
}
|
||||
|
||||
std::string AssertionResult::getExpressionInMacro() const {
|
||||
if( m_info.macroName.empty() )
|
||||
return m_info.capturedExpression;
|
||||
else
|
||||
return m_info.macroName + "( " + m_info.capturedExpression + " )";
|
||||
std::string expr;
|
||||
if( m_info.macroName[0] == 0 )
|
||||
expr = m_info.capturedExpression;
|
||||
else {
|
||||
expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 );
|
||||
expr += m_info.macroName;
|
||||
expr += "( ";
|
||||
expr += m_info.capturedExpression;
|
||||
expr += " )";
|
||||
}
|
||||
return expr;
|
||||
}
|
||||
|
||||
bool AssertionResult::hasExpandedExpression() const {
|
||||
@ -72,7 +76,10 @@ namespace Catch {
|
||||
}
|
||||
|
||||
std::string AssertionResult::getExpandedExpression() const {
|
||||
return m_resultData.reconstructedExpression;
|
||||
std::string expr = m_resultData.reconstructExpression();
|
||||
return expr.empty()
|
||||
? getExpression()
|
||||
: expr;
|
||||
}
|
||||
|
||||
std::string AssertionResult::getMessage() const {
|
||||
@ -87,5 +94,3 @@ namespace Catch {
|
||||
}
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_ASSERTIONRESULT_HPP_INCLUDED
|
@ -9,44 +9,36 @@
|
||||
#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_H_INCLUDED
|
||||
|
||||
#include <string>
|
||||
#include "catch_assertioninfo.h"
|
||||
#include "catch_result_type.h"
|
||||
#include "catch_common.h"
|
||||
#include "catch_stringref.h"
|
||||
#include "catch_assertionhandler.h"
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct AssertionInfo
|
||||
{
|
||||
AssertionInfo() {}
|
||||
AssertionInfo( std::string const& _macroName,
|
||||
SourceLineInfo const& _lineInfo,
|
||||
std::string const& _capturedExpression,
|
||||
ResultDisposition::Flags _resultDisposition );
|
||||
|
||||
std::string macroName;
|
||||
SourceLineInfo lineInfo;
|
||||
std::string capturedExpression;
|
||||
ResultDisposition::Flags resultDisposition;
|
||||
};
|
||||
|
||||
struct AssertionResultData
|
||||
{
|
||||
AssertionResultData() : resultType( ResultWas::Unknown ) {}
|
||||
AssertionResultData() = delete;
|
||||
|
||||
std::string reconstructedExpression;
|
||||
AssertionResultData( ResultWas::OfType _resultType, LazyExpression const& _lazyExpression )
|
||||
: resultType( _resultType ),
|
||||
lazyExpression( _lazyExpression )
|
||||
{}
|
||||
|
||||
ResultWas::OfType resultType = ResultWas::Unknown;
|
||||
std::string message;
|
||||
ResultWas::OfType resultType;
|
||||
|
||||
LazyExpression lazyExpression;
|
||||
|
||||
std::string reconstructExpression() const;
|
||||
mutable std::string reconstructedExpression;
|
||||
};
|
||||
|
||||
class AssertionResult {
|
||||
public:
|
||||
AssertionResult();
|
||||
AssertionResult() = delete;
|
||||
AssertionResult( AssertionInfo const& info, AssertionResultData const& data );
|
||||
~AssertionResult();
|
||||
# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
|
||||
AssertionResult( AssertionResult const& ) = default;
|
||||
AssertionResult( AssertionResult && ) = default;
|
||||
AssertionResult& operator = ( AssertionResult const& ) = default;
|
||||
AssertionResult& operator = ( AssertionResult && ) = default;
|
||||
# endif
|
||||
|
||||
bool isOk() const;
|
||||
bool succeeded() const;
|
||||
@ -61,7 +53,7 @@ namespace Catch {
|
||||
SourceLineInfo getSourceInfo() const;
|
||||
std::string getTestMacroName() const;
|
||||
|
||||
protected:
|
||||
//protected:
|
||||
AssertionInfo m_info;
|
||||
AssertionResultData m_resultData;
|
||||
};
|
||||
|
35
include/internal/catch_benchmark.cpp
Normal file
35
include/internal/catch_benchmark.cpp
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Created by Phil on 04/07/2017.
|
||||
* Copyright 2017 Two Blue Cubes Ltd. All rights reserved.
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
|
||||
#include "catch_benchmark.h"
|
||||
#include "catch_capture.hpp"
|
||||
#include "catch_interfaces_reporter.h"
|
||||
|
||||
namespace Catch {
|
||||
|
||||
auto BenchmarkLooper::getResolution() -> uint64_t {
|
||||
return getEstimatedClockResolution() * getCurrentContext().getConfig()->benchmarkResolutionMultiple();
|
||||
}
|
||||
|
||||
void BenchmarkLooper::reportStart() {
|
||||
getResultCapture().benchmarkStarting( { m_name } );
|
||||
}
|
||||
auto BenchmarkLooper::needsMoreIterations() -> bool {
|
||||
auto elapsed = m_timer.getElapsedNanoseconds();
|
||||
|
||||
// Exponentially increasing iterations until we're confident in our timer resolution
|
||||
if( elapsed < m_resolution ) {
|
||||
m_iterationsToRun *= 10;
|
||||
return true;
|
||||
}
|
||||
|
||||
getResultCapture().benchmarkEnded( { { m_name }, m_count, elapsed } );
|
||||
return false;
|
||||
}
|
||||
|
||||
} // end namespace Catch
|
57
include/internal/catch_benchmark.h
Normal file
57
include/internal/catch_benchmark.h
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Created by Phil on 04/07/2017.
|
||||
* Copyright 2017 Two Blue Cubes Ltd. All rights reserved.
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
#ifndef TWOBLUECUBES_CATCH_BENCHMARK_H_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_BENCHMARK_H_INCLUDED
|
||||
|
||||
#include "catch_stringref.h"
|
||||
#include "catch_timer.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
class BenchmarkLooper {
|
||||
|
||||
std::string m_name;
|
||||
size_t m_count = 0;
|
||||
size_t m_iterationsToRun = 1;
|
||||
uint64_t m_resolution;
|
||||
Timer m_timer;
|
||||
|
||||
static auto getResolution() -> uint64_t;
|
||||
public:
|
||||
// Keep most of this inline as it's on the code path that is being timed
|
||||
BenchmarkLooper( StringRef name )
|
||||
: m_name( name ),
|
||||
m_resolution( getResolution() )
|
||||
{
|
||||
reportStart();
|
||||
m_timer.start();
|
||||
}
|
||||
|
||||
explicit operator bool() {
|
||||
if( m_count < m_iterationsToRun )
|
||||
return true;
|
||||
return needsMoreIterations();
|
||||
}
|
||||
|
||||
void increment() {
|
||||
++m_count;
|
||||
}
|
||||
|
||||
void reportStart();
|
||||
auto needsMoreIterations() -> bool;
|
||||
};
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#define BENCHMARK( name ) \
|
||||
for( Catch::BenchmarkLooper looper( name ); looper; looper.increment() )
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_BENCHMARK_H_INCLUDED
|
@ -8,141 +8,149 @@
|
||||
#ifndef TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED
|
||||
|
||||
#include "catch_result_builder.h"
|
||||
#include "catch_assertionhandler.h"
|
||||
#include "catch_message.h"
|
||||
#include "catch_interfaces_capture.h"
|
||||
#include "catch_debugger.h"
|
||||
#include "catch_common.h"
|
||||
#include "catch_tostring.h"
|
||||
#include "catch_interfaces_runner.h"
|
||||
#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( handler ) \
|
||||
handler.reactWithDebugBreak();
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Another way to speed-up compilation is to omit local try-catch for REQUIRE*
|
||||
// macros.
|
||||
// This can potentially cause false negative, if the test code catches
|
||||
// the exception before it propagates back up to the runner.
|
||||
#define INTERNAL_CATCH_TRY( capturer ) capturer.setExceptionGuard();
|
||||
#define INTERNAL_CATCH_CATCH( capturer ) capturer.unsetExceptionGuard();
|
||||
|
||||
#else // CATCH_CONFIG_FAST_COMPILE
|
||||
|
||||
#include "catch_debugger.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// In the event of a failure works out if the debugger needs to be invoked
|
||||
// and/or an exception thrown and takes appropriate action.
|
||||
// This needs to be done as a macro so the debugger will stop in the user
|
||||
// source code rather than in Catch library code
|
||||
#define INTERNAL_CATCH_REACT( resultBuilder ) \
|
||||
if( resultBuilder.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \
|
||||
resultBuilder.react();
|
||||
#define INTERNAL_CATCH_REACT( handler ) \
|
||||
if( handler.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \
|
||||
handler.reactWithoutDebugBreak();
|
||||
|
||||
#define INTERNAL_CATCH_TRY( capturer ) try
|
||||
#define INTERNAL_CATCH_CATCH( capturer ) catch(...) { capturer.useActiveException(); }
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ) \
|
||||
do { \
|
||||
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
|
||||
try { \
|
||||
CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
|
||||
( __catchResult <= expr ).endExpression(); \
|
||||
} \
|
||||
catch( ... ) { \
|
||||
__catchResult.useActiveException( Catch::ResultDisposition::Normal ); \
|
||||
} \
|
||||
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
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_IF( expr, resultDisposition, macroName ) \
|
||||
INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \
|
||||
if( Catch::getResultCapture().getLastResult()->succeeded() )
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_ELSE( expr, resultDisposition, macroName ) \
|
||||
INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \
|
||||
if( !Catch::getResultCapture().getLastResult()->succeeded() )
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_NO_THROW( expr, resultDisposition, macroName ) \
|
||||
do { \
|
||||
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
|
||||
try { \
|
||||
expr; \
|
||||
__catchResult.captureResult( Catch::ResultWas::Ok ); \
|
||||
} \
|
||||
catch( ... ) { \
|
||||
__catchResult.useActiveException( resultDisposition ); \
|
||||
} \
|
||||
INTERNAL_CATCH_REACT( __catchResult ) \
|
||||
} while( Catch::alwaysFalse() )
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_THROWS( expr, resultDisposition, matcher, macroName ) \
|
||||
do { \
|
||||
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition, #matcher ); \
|
||||
if( __catchResult.allowThrows() ) \
|
||||
try { \
|
||||
expr; \
|
||||
__catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \
|
||||
} \
|
||||
catch( ... ) { \
|
||||
__catchResult.captureExpectedException( matcher ); \
|
||||
} \
|
||||
else \
|
||||
__catchResult.captureResult( Catch::ResultWas::Ok ); \
|
||||
INTERNAL_CATCH_REACT( __catchResult ) \
|
||||
} while( Catch::alwaysFalse() )
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_THROWS_AS( expr, exceptionType, resultDisposition, macroName ) \
|
||||
do { \
|
||||
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
|
||||
if( __catchResult.allowThrows() ) \
|
||||
try { \
|
||||
expr; \
|
||||
__catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \
|
||||
} \
|
||||
catch( exceptionType ) { \
|
||||
__catchResult.captureResult( Catch::ResultWas::Ok ); \
|
||||
} \
|
||||
catch( ... ) { \
|
||||
__catchResult.useActiveException( resultDisposition ); \
|
||||
} \
|
||||
else \
|
||||
__catchResult.captureResult( Catch::ResultWas::Ok ); \
|
||||
INTERNAL_CATCH_REACT( __catchResult ) \
|
||||
} while( Catch::alwaysFalse() )
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#ifdef CATCH_CONFIG_VARIADIC_MACROS
|
||||
#define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, ... ) \
|
||||
do { \
|
||||
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \
|
||||
__catchResult << __VA_ARGS__ + ::Catch::StreamEndStop(); \
|
||||
__catchResult.captureResult( messageType ); \
|
||||
INTERNAL_CATCH_REACT( __catchResult ) \
|
||||
} while( Catch::alwaysFalse() )
|
||||
#else
|
||||
#define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, log ) \
|
||||
do { \
|
||||
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \
|
||||
__catchResult << log + ::Catch::StreamEndStop(); \
|
||||
__catchResult.captureResult( messageType ); \
|
||||
INTERNAL_CATCH_REACT( __catchResult ) \
|
||||
} while( Catch::alwaysFalse() )
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_INFO( log, macroName ) \
|
||||
#define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \
|
||||
do { \
|
||||
Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, #__VA_ARGS__, resultDisposition ); \
|
||||
INTERNAL_CATCH_TRY( catchAssertionHandler ) { \
|
||||
CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
|
||||
catchAssertionHandler.handle( Catch::Decomposer() <= __VA_ARGS__ ); \
|
||||
CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
|
||||
} INTERNAL_CATCH_CATCH( catchAssertionHandler ) \
|
||||
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
|
||||
} while( Catch::isTrue( false && static_cast<bool>( !!(__VA_ARGS__) ) ) ) // the expression here is never evaluated at runtime but it forces the compiler to give it a look
|
||||
// The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&.
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_IF( macroName, resultDisposition, ... ) \
|
||||
INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \
|
||||
if( Catch::getResultCapture().lastAssertionPassed() )
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_ELSE( macroName, resultDisposition, ... ) \
|
||||
INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \
|
||||
if( !Catch::getResultCapture().lastAssertionPassed() )
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, ... ) \
|
||||
do { \
|
||||
Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, #__VA_ARGS__, resultDisposition ); \
|
||||
try { \
|
||||
static_cast<void>(__VA_ARGS__); \
|
||||
catchAssertionHandler.handle( Catch::ResultWas::Ok ); \
|
||||
} \
|
||||
catch( ... ) { \
|
||||
catchAssertionHandler.useActiveException(); \
|
||||
} \
|
||||
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
|
||||
} while( Catch::alwaysFalse() )
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_THROWS( macroName, resultDisposition, ... ) \
|
||||
do { \
|
||||
Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, #__VA_ARGS__, resultDisposition); \
|
||||
if( catchAssertionHandler.allowThrows() ) \
|
||||
try { \
|
||||
static_cast<void>(__VA_ARGS__); \
|
||||
catchAssertionHandler.handle( Catch::ResultWas::DidntThrowException ); \
|
||||
} \
|
||||
catch( ... ) { \
|
||||
catchAssertionHandler.handle( Catch::ResultWas::Ok ); \
|
||||
} \
|
||||
else \
|
||||
catchAssertionHandler.handle( Catch::ResultWas::Ok ); \
|
||||
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
|
||||
} while( Catch::alwaysFalse() )
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \
|
||||
do { \
|
||||
Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, #expr ", " #exceptionType, resultDisposition ); \
|
||||
if( catchAssertionHandler.allowThrows() ) \
|
||||
try { \
|
||||
static_cast<void>(expr); \
|
||||
catchAssertionHandler.handle( Catch::ResultWas::DidntThrowException ); \
|
||||
} \
|
||||
catch( exceptionType const& ) { \
|
||||
catchAssertionHandler.handle( Catch::ResultWas::Ok ); \
|
||||
} \
|
||||
catch( ... ) { \
|
||||
catchAssertionHandler.useActiveException(); \
|
||||
} \
|
||||
else \
|
||||
catchAssertionHandler.handle( Catch::ResultWas::Ok ); \
|
||||
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
|
||||
} while( Catch::alwaysFalse() )
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \
|
||||
do { \
|
||||
Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \
|
||||
catchAssertionHandler.handle( messageType, ( Catch::MessageStream() << __VA_ARGS__ + ::Catch::StreamEndStop() ).m_stream.str() ); \
|
||||
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
|
||||
} while( Catch::alwaysFalse() )
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#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 ) \
|
||||
// Although this is matcher-based, it can be used with just a string
|
||||
#define INTERNAL_CATCH_THROWS_STR_MATCHES( macroName, resultDisposition, matcher, ... ) \
|
||||
do { \
|
||||
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition ); \
|
||||
try { \
|
||||
std::string matcherAsString = (matcher).toString(); \
|
||||
__catchResult \
|
||||
.setLhs( Catch::toString( arg ) ) \
|
||||
.setRhs( matcherAsString == Catch::Detail::unprintableString ? #matcher : matcherAsString ) \
|
||||
.setOp( "matches" ) \
|
||||
.setResultType( (matcher).match( arg ) ); \
|
||||
__catchResult.captureExpression(); \
|
||||
} catch( ... ) { \
|
||||
__catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \
|
||||
} \
|
||||
INTERNAL_CATCH_REACT( __catchResult ) \
|
||||
Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, #__VA_ARGS__ ", " #matcher, resultDisposition ); \
|
||||
if( catchAssertionHandler.allowThrows() ) \
|
||||
try { \
|
||||
static_cast<void>(__VA_ARGS__); \
|
||||
catchAssertionHandler.handle( Catch::ResultWas::DidntThrowException ); \
|
||||
} \
|
||||
catch( ... ) { \
|
||||
handleExceptionMatchExpr( catchAssertionHandler, matcher, #matcher ); \
|
||||
} \
|
||||
else \
|
||||
catchAssertionHandler.handle( Catch::ResultWas::Ok ); \
|
||||
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
|
||||
} while( Catch::alwaysFalse() )
|
||||
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED
|
||||
|
24
include/internal/catch_capture_matchers.cpp
Normal file
24
include/internal/catch_capture_matchers.cpp
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Created by Phil on 9/8/2017.
|
||||
* Copyright 2017 Two Blue Cubes Ltd. All rights reserved.
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
#include "catch_capture_matchers.h"
|
||||
#include "catch_interfaces_registry_hub.h"
|
||||
|
||||
namespace Catch {
|
||||
|
||||
using StringMatcher = Matchers::Impl::MatcherBase<std::string>;
|
||||
|
||||
// This is the general overload that takes a any string matcher
|
||||
// There is another overload, in catch_assertinhandler.h/.cpp, that only takes a string and infers
|
||||
// the Equals matcher (so the header does not mention matchers)
|
||||
void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef matcherString ) {
|
||||
std::string exceptionMessage = Catch::translateActiveException();
|
||||
MatchExpr<std::string, StringMatcher const&> expr( exceptionMessage, matcher, matcherString );
|
||||
handler.handle( expr );
|
||||
}
|
||||
|
||||
} // namespace Catch
|
88
include/internal/catch_capture_matchers.h
Normal file
88
include/internal/catch_capture_matchers.h
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Created by Phil on 9/8/2017
|
||||
* Copyright 2017 Two Blue Cubes Ltd. All rights reserved.
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
#ifndef TWOBLUECUBES_CATCH_CAPTURE_MATCHERS_HPP_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_CAPTURE_MATCHERS_HPP_INCLUDED
|
||||
|
||||
#include "catch_capture.hpp"
|
||||
#include "catch_matchers.hpp"
|
||||
#include "catch_matchers_string.h"
|
||||
#include "catch_matchers_vector.h"
|
||||
|
||||
namespace Catch {
|
||||
|
||||
template<typename ArgT, typename MatcherT>
|
||||
class MatchExpr : public ITransientExpression {
|
||||
ArgT const& m_arg;
|
||||
MatcherT m_matcher;
|
||||
StringRef m_matcherString;
|
||||
bool m_result;
|
||||
public:
|
||||
MatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef matcherString )
|
||||
: m_arg( arg ),
|
||||
m_matcher( matcher ),
|
||||
m_matcherString( matcherString ),
|
||||
m_result( matcher.match( arg ) )
|
||||
{}
|
||||
|
||||
auto isBinaryExpression() const -> bool override { return true; }
|
||||
auto getResult() const -> bool override { return m_result; }
|
||||
|
||||
void streamReconstructedExpression( std::ostream &os ) const override {
|
||||
auto matcherAsString = m_matcher.toString();
|
||||
os << Catch::Detail::stringify( m_arg ) << ' ';
|
||||
if( matcherAsString == Detail::unprintableString )
|
||||
os << m_matcherString;
|
||||
else
|
||||
os << matcherAsString;
|
||||
}
|
||||
};
|
||||
|
||||
using StringMatcher = Matchers::Impl::MatcherBase<std::string>;
|
||||
|
||||
void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef matcherString );
|
||||
|
||||
template<typename ArgT, typename MatcherT>
|
||||
auto makeMatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef matcherString ) -> MatchExpr<ArgT, MatcherT> {
|
||||
return MatchExpr<ArgT, MatcherT>( arg, matcher, matcherString );
|
||||
}
|
||||
|
||||
} // namespace Catch
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \
|
||||
do { \
|
||||
Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition ); \
|
||||
INTERNAL_CATCH_TRY( catchAssertionHandler ) { \
|
||||
catchAssertionHandler.handle( Catch::makeMatchExpr( arg, matcher, #matcher ) ); \
|
||||
} INTERNAL_CATCH_CATCH( catchAssertionHandler ) \
|
||||
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
|
||||
} while( Catch::alwaysFalse() )
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_THROWS_MATCHES( macroName, exceptionType, resultDisposition, matcher, ... ) \
|
||||
do { \
|
||||
Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, #__VA_ARGS__ ", " #exceptionType ", " #matcher, resultDisposition ); \
|
||||
if( catchAssertionHandler.allowThrows() ) \
|
||||
try { \
|
||||
static_cast<void>(__VA_ARGS__ ); \
|
||||
catchAssertionHandler.handle( Catch::ResultWas::DidntThrowException ); \
|
||||
} \
|
||||
catch( exceptionType const& ex ) { \
|
||||
catchAssertionHandler.handle( Catch::makeMatchExpr( ex, matcher, #matcher ) ); \
|
||||
} \
|
||||
catch( ... ) { \
|
||||
catchAssertionHandler.useActiveException(); \
|
||||
} \
|
||||
else \
|
||||
catchAssertionHandler.handle( Catch::ResultWas::Ok ); \
|
||||
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
|
||||
} while( Catch::alwaysFalse() )
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_CAPTURE_MATCHERS_HPP_INCLUDED
|
@ -11,21 +11,18 @@
|
||||
|
||||
// Use Catch's value for console width (store Clara's off to the side, if present)
|
||||
#ifdef CLARA_CONFIG_CONSOLE_WIDTH
|
||||
#define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CLARA_CONFIG_CONSOLE_WIDTH
|
||||
#undef CLARA_CONFIG_CONSOLE_WIDTH
|
||||
#define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH
|
||||
#undef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH
|
||||
#endif
|
||||
#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH
|
||||
#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH-1
|
||||
|
||||
|
||||
// Declare Clara inside the Catch namespace
|
||||
#define STITCH_CLARA_OPEN_NAMESPACE namespace Catch {
|
||||
#include "../external/clara.h"
|
||||
#undef STITCH_CLARA_OPEN_NAMESPACE
|
||||
#include "../external/clara.hpp"
|
||||
|
||||
|
||||
// Restore Clara's value for console width, if present
|
||||
#ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
|
||||
#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
|
||||
#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
|
||||
#undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
|
||||
#endif
|
||||
|
||||
|
184
include/internal/catch_commandline.cpp
Normal file
184
include/internal/catch_commandline.cpp
Normal file
@ -0,0 +1,184 @@
|
||||
/*
|
||||
* Created by Phil on 02/11/2010.
|
||||
* Copyright 2010 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_commandline.hpp"
|
||||
|
||||
#include "catch_string_manip.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <ctime>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
clara::Parser makeCommandLineParser( ConfigData& config ) {
|
||||
|
||||
using namespace clara;
|
||||
|
||||
auto const setWarning = [&]( std::string const& warning ) {
|
||||
if( warning != "NoAssertions" )
|
||||
return ParserResult::runtimeError( "Unrecognised warning: '" + warning + "'" );
|
||||
config.warnings = static_cast<WarnAbout::What>( config.warnings | WarnAbout::NoAssertions );
|
||||
return ParserResult::ok( ParseResultType::Matched );
|
||||
};
|
||||
auto const loadTestNamesFromFile = [&]( std::string const& filename ) {
|
||||
std::ifstream f( filename.c_str() );
|
||||
if( !f.is_open() )
|
||||
return ParserResult::runtimeError( "Unable to load input file: '" + filename + "'" );
|
||||
|
||||
std::string line;
|
||||
while( std::getline( f, line ) ) {
|
||||
line = trim(line);
|
||||
if( !line.empty() && !startsWith( line, '#' ) ) {
|
||||
if( !startsWith( line, '"' ) )
|
||||
line = '"' + line + '"';
|
||||
config.testsOrTags.push_back( line + ',' );
|
||||
}
|
||||
}
|
||||
return ParserResult::ok( ParseResultType::Matched );
|
||||
};
|
||||
auto const setTestOrder = [&]( std::string const& order ) {
|
||||
if( startsWith( "declared", order ) )
|
||||
config.runOrder = RunTests::InDeclarationOrder;
|
||||
else if( startsWith( "lexical", order ) )
|
||||
config.runOrder = RunTests::InLexicographicalOrder;
|
||||
else if( startsWith( "random", order ) )
|
||||
config.runOrder = RunTests::InRandomOrder;
|
||||
else
|
||||
return clara::ParserResult::runtimeError( "Unrecognised ordering: '" + order + "'" );
|
||||
return ParserResult::ok( ParseResultType::Matched );
|
||||
};
|
||||
auto const setRngSeed = [&]( std::string const& seed ) {
|
||||
if( seed != "time" )
|
||||
return clara::detail::convertInto( seed, config.rngSeed );
|
||||
config.rngSeed = static_cast<unsigned int>( std::time(nullptr) );
|
||||
return ParserResult::ok( ParseResultType::Matched );
|
||||
};
|
||||
auto const setColourUsage = [&]( std::string const& useColour ) {
|
||||
auto mode = toLower( useColour );
|
||||
|
||||
if( mode == "yes" )
|
||||
config.useColour = UseColour::Yes;
|
||||
else if( mode == "no" )
|
||||
config.useColour = UseColour::No;
|
||||
else if( mode == "auto" )
|
||||
config.useColour = UseColour::Auto;
|
||||
else
|
||||
return ParserResult::runtimeError( "colour mode must be one of: auto, yes or no. '" + useColour + "' not recognised" );
|
||||
return ParserResult::ok( ParseResultType::Matched );
|
||||
};
|
||||
auto const setWaitForKeypress = [&]( std::string const& keypress ) {
|
||||
auto keypressLc = toLower( keypress );
|
||||
if( keypressLc == "start" )
|
||||
config.waitForKeypress = WaitForKeypress::BeforeStart;
|
||||
else if( keypressLc == "exit" )
|
||||
config.waitForKeypress = WaitForKeypress::BeforeExit;
|
||||
else if( keypressLc == "both" )
|
||||
config.waitForKeypress = WaitForKeypress::BeforeStartAndExit;
|
||||
else
|
||||
return ParserResult::runtimeError( "keypress argument must be one of: start, exit or both. '" + keypress + "' not recognised" );
|
||||
return ParserResult::ok( ParseResultType::Matched );
|
||||
};
|
||||
auto const setVerbosity = [&]( std::string const& verbosity ) {
|
||||
auto lcVerbosity = toLower( verbosity );
|
||||
if( lcVerbosity == "quiet" )
|
||||
config.verbosity = Verbosity::Quiet;
|
||||
else if( lcVerbosity == "normal" )
|
||||
config.verbosity = Verbosity::Normal;
|
||||
else if( lcVerbosity == "high" )
|
||||
config.verbosity = Verbosity::High;
|
||||
else
|
||||
return ParserResult::runtimeError( "Unrecognised verbosity, '" + verbosity + "'" );
|
||||
return ParserResult::ok( ParseResultType::Matched );
|
||||
};
|
||||
|
||||
auto cli
|
||||
= ExeName( config.processName )
|
||||
+ Help( config.showHelp )
|
||||
+ Opt( config.listTests )
|
||||
["-l"]["--list-tests"]
|
||||
( "list all/matching test cases" )
|
||||
+ Opt( config.listTags )
|
||||
["-t"]["--list-tags"]
|
||||
( "list all/matching tags" )
|
||||
+ Opt( config.showSuccessfulTests )
|
||||
["-s"]["--success"]
|
||||
( "include successful tests in output" )
|
||||
+ Opt( config.shouldDebugBreak )
|
||||
["-b"]["--break"]
|
||||
( "break into debugger on failure" )
|
||||
+ Opt( config.noThrow )
|
||||
["-e"]["--nothrow"]
|
||||
( "skip exception tests" )
|
||||
+ Opt( config.showInvisibles )
|
||||
["-i"]["--invisibles"]
|
||||
( "show invisibles (tabs, newlines)" )
|
||||
+ Opt( config.outputFilename, "filename" )
|
||||
["-o"]["--out"]
|
||||
( "output filename" )
|
||||
+ Opt( config.reporterNames, "name" )
|
||||
["-r"]["--reporter"]
|
||||
( "reporter to use (defaults to console)" )
|
||||
+ Opt( config.name, "name" )
|
||||
["-n"]["--name"]
|
||||
( "suite name" )
|
||||
+ Opt( [&]( bool ){ config.abortAfter = 1; } )
|
||||
["-a"]["--abort"]
|
||||
( "abort at first failure" )
|
||||
+ Opt( [&]( int x ){ config.abortAfter = x; }, "no. failures" )
|
||||
["-x"]["--abortx"]
|
||||
( "abort after x failures" )
|
||||
+ Opt( setWarning, "warning name" )
|
||||
["-w"]["--warn"]
|
||||
( "enable warnings" )
|
||||
+ Opt( [&]( bool flag ) { config.showDurations = flag ? ShowDurations::Always : ShowDurations::Never; }, "yes|no" )
|
||||
["-d"]["--durations"]
|
||||
( "show test durations" )
|
||||
+ Opt( loadTestNamesFromFile, "filename" )
|
||||
["-f"]["--input-file"]
|
||||
( "load test names to run from a file" )
|
||||
+ Opt( config.filenamesAsTags )
|
||||
["-#"]["--filenames-as-tags"]
|
||||
( "adds a tag for the filename" )
|
||||
+ Opt( config.sectionsToRun, "section name" )
|
||||
["-c"]["--section"]
|
||||
( "specify section to run" )
|
||||
+ Opt( setVerbosity, "quiet|normal|high" )
|
||||
["-v"]["--verbosity"]
|
||||
( "set output verbosity" )
|
||||
+ Opt( config.listTestNamesOnly )
|
||||
["--list-test-names-only"]
|
||||
( "list all/matching test cases names only" )
|
||||
+ Opt( config.listReporters )
|
||||
["--list-reporters"]
|
||||
( "list all reporters" )
|
||||
+ Opt( setTestOrder, "decl|lex|rand" )
|
||||
["--order"]
|
||||
( "test case order (defaults to decl)" )
|
||||
+ Opt( setRngSeed, "'time'|number" )
|
||||
["--rng-seed"]
|
||||
( "set a specific seed for random numbers" )
|
||||
+ Opt( setColourUsage, "yes|no" )
|
||||
["--use-colour"]
|
||||
( "should output be colourised" )
|
||||
+ Opt( config.libIdentify )
|
||||
["--libidentify"]
|
||||
( "report name and version according to libidentify standard" )
|
||||
+ Opt( setWaitForKeypress, "start|exit|both" )
|
||||
["--wait-for-keypress"]
|
||||
( "waits for a keypress before exiting" )
|
||||
+ Opt( config.benchmarkResolutionMultiple, "multiplier" )
|
||||
["--benchmark-resolution-multiple"]
|
||||
( "multiple of clock resolution to run benchmarks" )
|
||||
|
||||
+ Arg( config.testsOrTags, "test name|pattern|tags" )
|
||||
( "which test or tests to use" );
|
||||
|
||||
return cli;
|
||||
}
|
||||
|
||||
} // end namespace Catch
|
@ -9,197 +9,11 @@
|
||||
#define TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED
|
||||
|
||||
#include "catch_config.hpp"
|
||||
#include "catch_common.h"
|
||||
#include "catch_clara.h"
|
||||
|
||||
#include <fstream>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
inline void abortAfterFirst( ConfigData& config ) { config.abortAfter = 1; }
|
||||
inline void abortAfterX( ConfigData& config, int x ) {
|
||||
if( x < 1 )
|
||||
throw std::runtime_error( "Value after -x or --abortAfter must be greater than zero" );
|
||||
config.abortAfter = x;
|
||||
}
|
||||
inline void addTestOrTags( ConfigData& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); }
|
||||
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 + "'" );
|
||||
}
|
||||
inline void setOrder( ConfigData& config, std::string const& order ) {
|
||||
if( startsWith( "declared", order ) )
|
||||
config.runOrder = RunTests::InDeclarationOrder;
|
||||
else if( startsWith( "lexical", order ) )
|
||||
config.runOrder = RunTests::InLexicographicalOrder;
|
||||
else if( startsWith( "random", order ) )
|
||||
config.runOrder = RunTests::InRandomOrder;
|
||||
else
|
||||
throw std::runtime_error( "Unrecognised ordering: '" + order + "'" );
|
||||
}
|
||||
inline void setRngSeed( ConfigData& config, std::string const& seed ) {
|
||||
if( seed == "time" ) {
|
||||
config.rngSeed = static_cast<unsigned int>( std::time(0) );
|
||||
}
|
||||
else {
|
||||
std::stringstream ss;
|
||||
ss << seed;
|
||||
ss >> config.rngSeed;
|
||||
if( ss.fail() )
|
||||
throw std::runtime_error( "Argment to --rng-seed should be the word 'time' or a number" );
|
||||
}
|
||||
}
|
||||
inline void setVerbosity( ConfigData& config, int level ) {
|
||||
// !TBD: accept strings?
|
||||
config.verbosity = static_cast<Verbosity::Level>( level );
|
||||
}
|
||||
inline void setShowDurations( ConfigData& config, bool _showDurations ) {
|
||||
config.showDurations = _showDurations
|
||||
? 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() )
|
||||
throw std::domain_error( "Unable to load input file: " + _filename );
|
||||
|
||||
std::string line;
|
||||
while( std::getline( f, line ) ) {
|
||||
line = trim(line);
|
||||
if( !line.empty() && !startsWith( line, "#" ) )
|
||||
addTestOrTags( config, "\"" + line + "\"," );
|
||||
}
|
||||
}
|
||||
|
||||
inline Clara::CommandLine<ConfigData> makeCommandLineParser() {
|
||||
|
||||
using namespace Clara;
|
||||
CommandLine<ConfigData> cli;
|
||||
|
||||
cli.bindProcessName( &ConfigData::processName );
|
||||
|
||||
cli["-?"]["-h"]["--help"]
|
||||
.describe( "display usage information" )
|
||||
.bind( &ConfigData::showHelp );
|
||||
|
||||
cli["-l"]["--list-tests"]
|
||||
.describe( "list all/matching test cases" )
|
||||
.bind( &ConfigData::listTests );
|
||||
|
||||
cli["-t"]["--list-tags"]
|
||||
.describe( "list all/matching tags" )
|
||||
.bind( &ConfigData::listTags );
|
||||
|
||||
cli["-s"]["--success"]
|
||||
.describe( "include successful tests in output" )
|
||||
.bind( &ConfigData::showSuccessfulTests );
|
||||
|
||||
cli["-b"]["--break"]
|
||||
.describe( "break into debugger on failure" )
|
||||
.bind( &ConfigData::shouldDebugBreak );
|
||||
|
||||
cli["-e"]["--nothrow"]
|
||||
.describe( "skip exception tests" )
|
||||
.bind( &ConfigData::noThrow );
|
||||
|
||||
cli["-i"]["--invisibles"]
|
||||
.describe( "show invisibles (tabs, newlines)" )
|
||||
.bind( &ConfigData::showInvisibles );
|
||||
|
||||
cli["-o"]["--out"]
|
||||
.describe( "output filename" )
|
||||
.bind( &ConfigData::outputFilename, "filename" );
|
||||
|
||||
cli["-r"]["--reporter"]
|
||||
// .placeholder( "name[:filename]" )
|
||||
.describe( "reporter to use (defaults to console)" )
|
||||
.bind( &addReporterName, "name" );
|
||||
|
||||
cli["-n"]["--name"]
|
||||
.describe( "suite name" )
|
||||
.bind( &ConfigData::name, "name" );
|
||||
|
||||
cli["-a"]["--abort"]
|
||||
.describe( "abort at first failure" )
|
||||
.bind( &abortAfterFirst );
|
||||
|
||||
cli["-x"]["--abortx"]
|
||||
.describe( "abort after x failures" )
|
||||
.bind( &abortAfterX, "no. failures" );
|
||||
|
||||
cli["-w"]["--warn"]
|
||||
.describe( "enable warnings" )
|
||||
.bind( &addWarning, "warning name" );
|
||||
|
||||
// - needs updating if reinstated
|
||||
// cli.into( &setVerbosity )
|
||||
// .describe( "level of verbosity (0=no output)" )
|
||||
// .shortOpt( "v")
|
||||
// .longOpt( "verbosity" )
|
||||
// .placeholder( "level" );
|
||||
|
||||
cli[_]
|
||||
.describe( "which test or tests to use" )
|
||||
.bind( &addTestOrTags, "test name, pattern or tags" );
|
||||
|
||||
cli["-d"]["--durations"]
|
||||
.describe( "show test durations" )
|
||||
.bind( &setShowDurations, "yes|no" );
|
||||
|
||||
cli["-f"]["--input-file"]
|
||||
.describe( "load test names to run from a file" )
|
||||
.bind( &loadTestNamesFromFile, "filename" );
|
||||
|
||||
cli["-#"]["--filenames-as-tags"]
|
||||
.describe( "adds a tag for the filename" )
|
||||
.bind( &ConfigData::filenamesAsTags );
|
||||
|
||||
// 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"]
|
||||
.describe( "list all reporters" )
|
||||
.bind( &ConfigData::listReporters );
|
||||
|
||||
cli["--order"]
|
||||
.describe( "test case order (defaults to decl)" )
|
||||
.bind( &setOrder, "decl|lex|rand" );
|
||||
|
||||
cli["--rng-seed"]
|
||||
.describe( "set a specific seed for random numbers" )
|
||||
.bind( &setRngSeed, "'time'|number" );
|
||||
|
||||
cli["--force-colour"]
|
||||
.describe( "force colourised output (deprecated)" )
|
||||
.bind( &forceColour );
|
||||
|
||||
cli["--use-colour"]
|
||||
.describe( "should output be colourised" )
|
||||
.bind( &setUseColour, "yes|no" );
|
||||
|
||||
return cli;
|
||||
}
|
||||
clara::Parser makeCommandLineParser( ConfigData& config );
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
|
57
include/internal/catch_common.cpp
Normal file
57
include/internal/catch_common.cpp
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Created by Phil on 27/11/2013.
|
||||
* Copyright 2013 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_common.h"
|
||||
#include "catch_context.h"
|
||||
#include "catch_interfaces_config.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <ostream>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
SourceLineInfo::SourceLineInfo( char const* _file, std::size_t _line ) noexcept
|
||||
: file( _file ),
|
||||
line( _line )
|
||||
{}
|
||||
bool SourceLineInfo::empty() const noexcept {
|
||||
return file[0] == '\0';
|
||||
}
|
||||
bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const noexcept {
|
||||
return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0);
|
||||
}
|
||||
bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const noexcept {
|
||||
return line < other.line || ( line == other.line && (std::strcmp(file, other.file) < 0));
|
||||
}
|
||||
|
||||
void seedRng( IConfig const& config ) {
|
||||
if( config.rngSeed() != 0 )
|
||||
std::srand( config.rngSeed() );
|
||||
}
|
||||
unsigned int rngSeed() {
|
||||
return getCurrentContext().getConfig()->rngSeed();
|
||||
}
|
||||
|
||||
std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) {
|
||||
#ifndef __GNUG__
|
||||
os << info.file << '(' << info.line << ')';
|
||||
#else
|
||||
os << info.file << ':' << info.line;
|
||||
#endif
|
||||
return os;
|
||||
}
|
||||
|
||||
bool isTrue( bool value ){ return value; }
|
||||
bool alwaysTrue() { return true; }
|
||||
bool alwaysFalse() { return false; }
|
||||
|
||||
std::string StreamEndStop::operator+() const {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
}
|
@ -8,6 +8,8 @@
|
||||
#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 )
|
||||
#ifdef CATCH_CONFIG_COUNTER
|
||||
@ -19,11 +21,9 @@
|
||||
#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"
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
@ -35,90 +35,40 @@ namespace Catch {
|
||||
}; };
|
||||
|
||||
class NonCopyable {
|
||||
#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
|
||||
NonCopyable( NonCopyable const& ) = delete;
|
||||
NonCopyable( NonCopyable && ) = delete;
|
||||
NonCopyable& operator = ( NonCopyable const& ) = delete;
|
||||
NonCopyable& operator = ( NonCopyable && ) = delete;
|
||||
#else
|
||||
NonCopyable( NonCopyable const& info );
|
||||
NonCopyable& operator = ( NonCopyable const& );
|
||||
#endif
|
||||
|
||||
protected:
|
||||
NonCopyable() {}
|
||||
virtual ~NonCopyable();
|
||||
};
|
||||
|
||||
class SafeBool {
|
||||
public:
|
||||
typedef void (SafeBool::*type)() const;
|
||||
|
||||
static type makeSafe( bool value ) {
|
||||
return value ? &SafeBool::trueValue : 0;
|
||||
}
|
||||
private:
|
||||
void trueValue() const {}
|
||||
};
|
||||
|
||||
template<typename ContainerT>
|
||||
inline void deleteAll( ContainerT& container ) {
|
||||
typename ContainerT::const_iterator it = container.begin();
|
||||
typename ContainerT::const_iterator itEnd = container.end();
|
||||
for(; it != itEnd; ++it )
|
||||
delete *it;
|
||||
}
|
||||
template<typename AssociativeContainerT>
|
||||
inline void deleteAllValues( AssociativeContainerT& container ) {
|
||||
typename AssociativeContainerT::const_iterator it = container.begin();
|
||||
typename AssociativeContainerT::const_iterator itEnd = container.end();
|
||||
for(; it != itEnd; ++it )
|
||||
delete it->second;
|
||||
}
|
||||
|
||||
bool startsWith( std::string const& s, std::string const& prefix );
|
||||
bool endsWith( std::string const& s, std::string const& suffix );
|
||||
bool contains( std::string const& s, std::string const& infix );
|
||||
void toLowerInPlace( std::string& s );
|
||||
std::string toLower( std::string const& s );
|
||||
std::string trim( std::string const& str );
|
||||
bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis );
|
||||
|
||||
struct pluralise {
|
||||
pluralise( std::size_t count, std::string const& label );
|
||||
|
||||
friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser );
|
||||
|
||||
std::size_t m_count;
|
||||
std::string m_label;
|
||||
};
|
||||
|
||||
struct SourceLineInfo {
|
||||
|
||||
SourceLineInfo();
|
||||
SourceLineInfo( char const* _file, std::size_t _line );
|
||||
SourceLineInfo( SourceLineInfo const& other );
|
||||
# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
|
||||
SourceLineInfo() = delete;
|
||||
SourceLineInfo( char const* _file, std::size_t _line ) noexcept;
|
||||
|
||||
SourceLineInfo( SourceLineInfo const& other ) = default;
|
||||
SourceLineInfo( SourceLineInfo && ) = default;
|
||||
SourceLineInfo& operator = ( SourceLineInfo const& ) = default;
|
||||
SourceLineInfo& operator = ( SourceLineInfo && ) = default;
|
||||
# endif
|
||||
bool empty() const;
|
||||
bool operator == ( SourceLineInfo const& other ) const;
|
||||
bool operator < ( SourceLineInfo const& other ) const;
|
||||
|
||||
std::string file;
|
||||
bool empty() const noexcept;
|
||||
bool operator == ( SourceLineInfo const& other ) const noexcept;
|
||||
bool operator < ( SourceLineInfo const& other ) const noexcept;
|
||||
|
||||
char const* file;
|
||||
std::size_t line;
|
||||
};
|
||||
|
||||
std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info );
|
||||
|
||||
// This is just here to avoid compiler warnings with macro constants and boolean literals
|
||||
inline bool isTrue( bool value ){ return value; }
|
||||
inline bool alwaysTrue() { return true; }
|
||||
inline bool alwaysFalse() { return false; }
|
||||
|
||||
void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo );
|
||||
bool isTrue( bool value );
|
||||
bool alwaysTrue();
|
||||
bool alwaysFalse();
|
||||
|
||||
void seedRng( IConfig const& config );
|
||||
unsigned int rngSeed();
|
||||
@ -128,9 +78,7 @@ namespace Catch {
|
||||
// as well as
|
||||
// >> stuff +StreamEndStop
|
||||
struct StreamEndStop {
|
||||
std::string operator+() {
|
||||
return std::string();
|
||||
}
|
||||
std::string operator+() const;
|
||||
};
|
||||
template<typename T>
|
||||
T const& operator + ( T const& value, StreamEndStop ) {
|
||||
@ -138,8 +86,8 @@ namespace Catch {
|
||||
}
|
||||
}
|
||||
|
||||
#define CATCH_INTERNAL_LINEINFO ::Catch::SourceLineInfo( __FILE__, static_cast<std::size_t>( __LINE__ ) )
|
||||
#define CATCH_INTERNAL_ERROR( msg ) ::Catch::throwLogicError( msg, CATCH_INTERNAL_LINEINFO );
|
||||
#define CATCH_INTERNAL_LINEINFO \
|
||||
::Catch::SourceLineInfo( __FILE__, static_cast<std::size_t>( __LINE__ ) )
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_COMMON_H_INCLUDED
|
||||
|
||||
|
@ -1,111 +0,0 @@
|
||||
/*
|
||||
* Created by Phil on 27/11/2013.
|
||||
* Copyright 2013 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_COMMON_HPP_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_COMMON_HPP_INCLUDED
|
||||
|
||||
#include "catch_common.h"
|
||||
|
||||
namespace Catch {
|
||||
|
||||
bool startsWith( std::string const& s, std::string const& prefix ) {
|
||||
return s.size() >= prefix.size() && s.substr( 0, prefix.size() ) == 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;
|
||||
}
|
||||
bool contains( std::string const& s, std::string const& infix ) {
|
||||
return s.find( infix ) != std::string::npos;
|
||||
}
|
||||
void toLowerInPlace( std::string& s ) {
|
||||
std::transform( s.begin(), s.end(), s.begin(), ::tolower );
|
||||
}
|
||||
std::string toLower( std::string const& s ) {
|
||||
std::string lc = s;
|
||||
toLowerInPlace( lc );
|
||||
return lc;
|
||||
}
|
||||
std::string trim( std::string const& str ) {
|
||||
static char const* whitespaceChars = "\n\r\t ";
|
||||
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 ) : "";
|
||||
}
|
||||
|
||||
bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) {
|
||||
bool replaced = false;
|
||||
std::size_t i = str.find( replaceThis );
|
||||
while( i != std::string::npos ) {
|
||||
replaced = true;
|
||||
str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() );
|
||||
if( i < str.size()-withThis.size() )
|
||||
i = str.find( replaceThis, i+withThis.size() );
|
||||
else
|
||||
i = std::string::npos;
|
||||
}
|
||||
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;
|
||||
if( pluraliser.m_count != 1 )
|
||||
os << "s";
|
||||
return os;
|
||||
}
|
||||
|
||||
SourceLineInfo::SourceLineInfo() : 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();
|
||||
}
|
||||
bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const {
|
||||
return line == other.line && file == other.file;
|
||||
}
|
||||
bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const {
|
||||
return line < other.line || ( line == other.line && file < other.file );
|
||||
}
|
||||
|
||||
void seedRng( IConfig const& config ) {
|
||||
if( config.rngSeed() != 0 )
|
||||
std::srand( config.rngSeed() );
|
||||
}
|
||||
unsigned int rngSeed() {
|
||||
return getCurrentContext().getConfig()->rngSeed();
|
||||
}
|
||||
|
||||
std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) {
|
||||
#ifndef __GNUG__
|
||||
os << info.file << "(" << info.line << ")";
|
||||
#else
|
||||
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 << "'";
|
||||
if( alwaysTrue() )
|
||||
throw std::logic_error( oss.str() );
|
||||
}
|
||||
}
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_COMMON_HPP_INCLUDED
|
||||
|
@ -8,40 +8,25 @@
|
||||
#ifndef TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED
|
||||
|
||||
// Detect a number of compiler features - mostly C++11/14 conformance - by compiler
|
||||
// Detect a number of compiler features - by compiler
|
||||
// The following features are defined:
|
||||
//
|
||||
// CATCH_CONFIG_CPP11_NULLPTR : is nullptr supported?
|
||||
// CATCH_CONFIG_CPP11_NOEXCEPT : is noexcept supported?
|
||||
// CATCH_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods
|
||||
// CATCH_CONFIG_CPP11_IS_ENUM : std::is_enum is supported?
|
||||
// CATCH_CONFIG_CPP11_TUPLE : std::tuple is supported
|
||||
// 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_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
|
||||
// ****************
|
||||
|
||||
// In general each macro has a _NO_<feature name> form
|
||||
// (e.g. CATCH_CONFIG_CPP11_NO_NULLPTR) which disables the feature.
|
||||
// (e.g. CATCH_CONFIG_NO_POSIX_SIGNALS) 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 CATCH_CONFIG_NO_CPP11
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
# if __cplusplus >= 201103L
|
||||
# define CATCH_CPP11_OR_GREATER
|
||||
# endif
|
||||
|
||||
# if __cplusplus >= 201402L
|
||||
# define CATCH_CPP14_OR_GREATER
|
||||
# endif
|
||||
@ -50,20 +35,47 @@
|
||||
|
||||
#ifdef __clang__
|
||||
|
||||
# if __has_feature(cxx_nullptr)
|
||||
# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR
|
||||
# endif
|
||||
|
||||
# if __has_feature(cxx_noexcept)
|
||||
# define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT
|
||||
# endif
|
||||
# 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" )
|
||||
|
||||
# if defined(CATCH_CPP11_OR_GREATER)
|
||||
# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS _Pragma( "clang diagnostic ignored \"-Wparentheses\"" )
|
||||
# endif
|
||||
# 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 // __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
|
||||
|
||||
#ifdef __OS400__
|
||||
# define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS
|
||||
# define CATCH_CONFIG_COLOUR_NONE
|
||||
#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__
|
||||
@ -89,17 +101,6 @@
|
||||
// GCC
|
||||
#ifdef __GNUC__
|
||||
|
||||
# if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||
# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR
|
||||
# endif
|
||||
|
||||
# if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) && defined(CATCH_CPP11_OR_GREATER)
|
||||
# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS _Pragma( "GCC diagnostic ignored \"-Wparentheses\"" )
|
||||
# endif
|
||||
|
||||
// - otherwise more recent versions define __cplusplus >= 201103L
|
||||
// and will get picked up below
|
||||
|
||||
|
||||
#endif // __GNUC__
|
||||
|
||||
@ -107,148 +108,47 @@
|
||||
// Visual C++
|
||||
#ifdef _MSC_VER
|
||||
|
||||
#if (_MSC_VER >= 1600)
|
||||
# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR
|
||||
# define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR
|
||||
#endif
|
||||
|
||||
#if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015))
|
||||
#define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT
|
||||
#define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
|
||||
#endif
|
||||
#define CATCH_INTERNAL_CONFIG_WINDOWS_SEH
|
||||
|
||||
#endif // _MSC_VER
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Use variadic macros if the compiler supports them
|
||||
#if ( defined _MSC_VER && _MSC_VER > 1400 && !defined __EDGE__) || \
|
||||
( defined __WAVE__ && __WAVE_HAS_VARIADICS ) || \
|
||||
( defined __GNUC__ && __GNUC__ >= 3 ) || \
|
||||
( !defined __cplusplus && __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L )
|
||||
|
||||
#define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS
|
||||
|
||||
#endif
|
||||
|
||||
// Use __COUNTER__ if the compiler supports it
|
||||
#if ( defined _MSC_VER && _MSC_VER >= 1300 ) || \
|
||||
( defined __GNUC__ && __GNUC__ >= 4 && __GNUC_MINOR__ >= 3 ) || \
|
||||
( 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(CATCH_CPP11_OR_GREATER)
|
||||
|
||||
# if !defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR)
|
||||
# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR
|
||||
# endif
|
||||
|
||||
# ifndef CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT
|
||||
# define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT
|
||||
# endif
|
||||
|
||||
# ifndef CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
|
||||
# define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
|
||||
# endif
|
||||
|
||||
# ifndef CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM
|
||||
# define CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM
|
||||
# endif
|
||||
|
||||
# ifndef CATCH_INTERNAL_CONFIG_CPP11_TUPLE
|
||||
# define CATCH_INTERNAL_CONFIG_CPP11_TUPLE
|
||||
# endif
|
||||
|
||||
# ifndef CATCH_INTERNAL_CONFIG_VARIADIC_MACROS
|
||||
# define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS
|
||||
# endif
|
||||
|
||||
# if !defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG)
|
||||
# define CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG
|
||||
# endif
|
||||
|
||||
# if !defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE)
|
||||
# define CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE
|
||||
# endif
|
||||
# if !defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR)
|
||||
# define CATCH_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(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NO_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_NO_CPP11)
|
||||
# define CATCH_CONFIG_CPP11_NULLPTR
|
||||
#endif
|
||||
#if defined(CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_NO_CPP11)
|
||||
# define CATCH_CONFIG_CPP11_NOEXCEPT
|
||||
#endif
|
||||
#if defined(CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_NO_CPP11)
|
||||
# define CATCH_CONFIG_CPP11_GENERATED_METHODS
|
||||
#endif
|
||||
#if defined(CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_NO_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_NO_CPP11)
|
||||
# define CATCH_CONFIG_CPP11_IS_ENUM
|
||||
#endif
|
||||
#if defined(CATCH_INTERNAL_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_CPP11_NO_TUPLE) && !defined(CATCH_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_NO_CPP11)
|
||||
# define CATCH_CONFIG_CPP11_TUPLE
|
||||
#endif
|
||||
#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)
|
||||
# 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)
|
||||
# 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)
|
||||
# define CATCH_CONFIG_CPP11_UNIQUE_PTR
|
||||
#endif
|
||||
#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER)
|
||||
|
||||
// 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_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)
|
||||
# define CATCH_NOEXCEPT noexcept
|
||||
# define CATCH_NOEXCEPT_IS(x) noexcept(x)
|
||||
#else
|
||||
# define CATCH_NOEXCEPT throw()
|
||||
# define CATCH_NOEXCEPT_IS(x)
|
||||
#endif
|
||||
|
||||
// nullptr support
|
||||
#ifdef CATCH_CONFIG_CPP11_NULLPTR
|
||||
# define CATCH_NULL nullptr
|
||||
#else
|
||||
# define CATCH_NULL NULL
|
||||
#endif
|
||||
|
||||
// override support
|
||||
#ifdef CATCH_CONFIG_CPP11_OVERRIDE
|
||||
# define CATCH_OVERRIDE override
|
||||
#else
|
||||
# define CATCH_OVERRIDE
|
||||
#endif
|
||||
|
||||
// unique_ptr support
|
||||
#ifdef CATCH_CONFIG_CPP11_UNIQUE_PTR
|
||||
# define CATCH_AUTO_PTR( T ) std::unique_ptr<T>
|
||||
#else
|
||||
# define CATCH_AUTO_PTR( T ) std::auto_ptr<T>
|
||||
#endif
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED
|
||||
|
||||
|
72
include/internal/catch_config.cpp
Normal file
72
include/internal/catch_config.cpp
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Created by Martin on 19/07/2017.
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
|
||||
#include "catch_config.hpp"
|
||||
#include "catch_enforce.h"
|
||||
|
||||
namespace Catch {
|
||||
|
||||
Config::Config( ConfigData const& data )
|
||||
: m_data( data ),
|
||||
m_stream( openStream() )
|
||||
{
|
||||
if( !data.testsOrTags.empty() ) {
|
||||
TestSpecParser parser( ITagAliasRegistry::get() );
|
||||
for( auto const& testOrTags : data.testsOrTags )
|
||||
parser.parse( testOrTags );
|
||||
m_testSpec = parser.testSpec();
|
||||
}
|
||||
}
|
||||
|
||||
std::string const& Config::getFilename() const {
|
||||
return m_data.outputFilename ;
|
||||
}
|
||||
|
||||
bool Config::listTests() const { return m_data.listTests; }
|
||||
bool Config::listTestNamesOnly() const { return m_data.listTestNamesOnly; }
|
||||
bool Config::listTags() const { return m_data.listTags; }
|
||||
bool Config::listReporters() const { return m_data.listReporters; }
|
||||
|
||||
std::string Config::getProcessName() const { return m_data.processName; }
|
||||
|
||||
std::vector<std::string> const& Config::getReporterNames() const { return m_data.reporterNames; }
|
||||
std::vector<std::string> const& Config::getSectionsToRun() const { return m_data.sectionsToRun; }
|
||||
|
||||
TestSpec const& Config::testSpec() const { return m_testSpec; }
|
||||
|
||||
bool Config::showHelp() const { return m_data.showHelp; }
|
||||
|
||||
// IConfig interface
|
||||
bool Config::allowThrows() const { return !m_data.noThrow; }
|
||||
std::ostream& Config::stream() const { return m_stream->stream(); }
|
||||
std::string Config::name() const { return m_data.name.empty() ? m_data.processName : m_data.name; }
|
||||
bool Config::includeSuccessfulResults() const { return m_data.showSuccessfulTests; }
|
||||
bool Config::warnAboutMissingAssertions() const { return m_data.warnings & WarnAbout::NoAssertions; }
|
||||
ShowDurations::OrNot Config::showDurations() const { return m_data.showDurations; }
|
||||
RunTests::InWhatOrder Config::runOrder() const { return m_data.runOrder; }
|
||||
unsigned int Config::rngSeed() const { return m_data.rngSeed; }
|
||||
int Config::benchmarkResolutionMultiple() const { return m_data.benchmarkResolutionMultiple; }
|
||||
UseColour::YesOrNo Config::useColour() const { return m_data.useColour; }
|
||||
bool Config::shouldDebugBreak() const { return m_data.shouldDebugBreak; }
|
||||
int Config::abortAfter() const { return m_data.abortAfter; }
|
||||
bool Config::showInvisibles() const { return m_data.showInvisibles; }
|
||||
Verbosity Config::verbosity() const { return m_data.verbosity; }
|
||||
|
||||
IStream const* Config::openStream() {
|
||||
if( m_data.outputFilename.empty() )
|
||||
return new CoutStream();
|
||||
else if( m_data.outputFilename[0] == '%' ) {
|
||||
if( m_data.outputFilename == "%debug" )
|
||||
return new DebugOutStream();
|
||||
else
|
||||
CATCH_ERROR( "Unrecognised stream: '" << m_data.outputFilename << "'" );
|
||||
}
|
||||
else
|
||||
return new FileStream( m_data.outputFilename );
|
||||
}
|
||||
|
||||
} // end namespace Catch
|
@ -16,8 +16,6 @@
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <ctime>
|
||||
|
||||
#ifndef CATCH_CONFIG_CONSOLE_WIDTH
|
||||
#define CATCH_CONFIG_CONSOLE_WIDTH 80
|
||||
@ -26,47 +24,29 @@
|
||||
namespace Catch {
|
||||
|
||||
struct ConfigData {
|
||||
bool listTests = false;
|
||||
bool listTags = false;
|
||||
bool listReporters = false;
|
||||
bool listTestNamesOnly = false;
|
||||
|
||||
ConfigData()
|
||||
: listTests( false ),
|
||||
listTags( false ),
|
||||
listReporters( false ),
|
||||
listTestNamesOnly( false ),
|
||||
showSuccessfulTests( false ),
|
||||
shouldDebugBreak( false ),
|
||||
noThrow( false ),
|
||||
showHelp( false ),
|
||||
showInvisibles( false ),
|
||||
filenamesAsTags( false ),
|
||||
abortAfter( -1 ),
|
||||
rngSeed( 0 ),
|
||||
verbosity( Verbosity::Normal ),
|
||||
warnings( WarnAbout::Nothing ),
|
||||
showDurations( ShowDurations::DefaultForReporter ),
|
||||
runOrder( RunTests::InDeclarationOrder ),
|
||||
useColour( UseColour::Auto )
|
||||
{}
|
||||
bool showSuccessfulTests = false;
|
||||
bool shouldDebugBreak = false;
|
||||
bool noThrow = false;
|
||||
bool showHelp = false;
|
||||
bool showInvisibles = false;
|
||||
bool filenamesAsTags = false;
|
||||
bool libIdentify = false;
|
||||
|
||||
bool listTests;
|
||||
bool listTags;
|
||||
bool listReporters;
|
||||
bool listTestNamesOnly;
|
||||
int abortAfter = -1;
|
||||
unsigned int rngSeed = 0;
|
||||
int benchmarkResolutionMultiple = 100;
|
||||
|
||||
bool showSuccessfulTests;
|
||||
bool shouldDebugBreak;
|
||||
bool noThrow;
|
||||
bool showHelp;
|
||||
bool showInvisibles;
|
||||
bool filenamesAsTags;
|
||||
|
||||
int abortAfter;
|
||||
unsigned int rngSeed;
|
||||
|
||||
Verbosity::Level verbosity;
|
||||
WarnAbout::What warnings;
|
||||
ShowDurations::OrNot showDurations;
|
||||
RunTests::InWhatOrder runOrder;
|
||||
UseColour::YesOrNo useColour;
|
||||
Verbosity verbosity = Verbosity::Normal;
|
||||
WarnAbout::What warnings = WarnAbout::Nothing;
|
||||
ShowDurations::OrNot showDurations = ShowDurations::DefaultForReporter;
|
||||
RunTests::InWhatOrder runOrder = RunTests::InDeclarationOrder;
|
||||
UseColour::YesOrNo useColour = UseColour::Auto;
|
||||
WaitForKeypress::When waitForKeypress = WaitForKeypress::Never;
|
||||
|
||||
std::string outputFilename;
|
||||
std::string name;
|
||||
@ -74,84 +54,56 @@ namespace Catch {
|
||||
|
||||
std::vector<std::string> reporterNames;
|
||||
std::vector<std::string> testsOrTags;
|
||||
std::vector<std::string> sectionsToRun;
|
||||
};
|
||||
|
||||
|
||||
class Config : public SharedImpl<IConfig> {
|
||||
private:
|
||||
Config( Config const& other );
|
||||
Config& operator = ( Config const& other );
|
||||
class Config : public IConfig {
|
||||
virtual void dummy();
|
||||
public:
|
||||
|
||||
Config()
|
||||
{}
|
||||
Config() = default;
|
||||
Config( ConfigData const& data );
|
||||
virtual ~Config() = default;
|
||||
|
||||
Config( ConfigData const& data )
|
||||
: m_data( data ),
|
||||
m_stream( openStream() )
|
||||
{
|
||||
if( !data.testsOrTags.empty() ) {
|
||||
TestSpecParser parser( ITagAliasRegistry::get() );
|
||||
for( std::size_t i = 0; i < data.testsOrTags.size(); ++i )
|
||||
parser.parse( data.testsOrTags[i] );
|
||||
m_testSpec = parser.testSpec();
|
||||
}
|
||||
}
|
||||
std::string const& getFilename() const;
|
||||
|
||||
virtual ~Config() {
|
||||
}
|
||||
bool listTests() const;
|
||||
bool listTestNamesOnly() const;
|
||||
bool listTags() const;
|
||||
bool listReporters() const;
|
||||
|
||||
std::string const& getFilename() const {
|
||||
return m_data.outputFilename ;
|
||||
}
|
||||
std::string getProcessName() const;
|
||||
|
||||
bool listTests() const { return m_data.listTests; }
|
||||
bool listTestNamesOnly() const { return m_data.listTestNamesOnly; }
|
||||
bool listTags() const { return m_data.listTags; }
|
||||
bool listReporters() const { return m_data.listReporters; }
|
||||
std::vector<std::string> const& getReporterNames() const;
|
||||
std::vector<std::string> const& getSectionsToRun() const override;
|
||||
|
||||
std::string getProcessName() const { return m_data.processName; }
|
||||
virtual TestSpec const& testSpec() const override;
|
||||
|
||||
bool shouldDebugBreak() const { return m_data.shouldDebugBreak; }
|
||||
|
||||
std::vector<std::string> getReporterNames() const { return m_data.reporterNames; }
|
||||
|
||||
int abortAfter() const { return m_data.abortAfter; }
|
||||
|
||||
TestSpec const& testSpec() const { return m_testSpec; }
|
||||
|
||||
bool showHelp() const { return m_data.showHelp; }
|
||||
bool showInvisibles() const { return m_data.showInvisibles; }
|
||||
bool showHelp() const;
|
||||
|
||||
// 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 UseColour::YesOrNo useColour() const { return m_data.useColour; }
|
||||
bool allowThrows() const override;
|
||||
std::ostream& stream() const override;
|
||||
std::string name() const override;
|
||||
bool includeSuccessfulResults() const override;
|
||||
bool warnAboutMissingAssertions() const override;
|
||||
ShowDurations::OrNot showDurations() const override;
|
||||
RunTests::InWhatOrder runOrder() const override;
|
||||
unsigned int rngSeed() const override;
|
||||
int benchmarkResolutionMultiple() const override;
|
||||
UseColour::YesOrNo useColour() const override;
|
||||
bool shouldDebugBreak() const override;
|
||||
int abortAfter() const override;
|
||||
bool showInvisibles() const override;
|
||||
Verbosity verbosity() const override;
|
||||
|
||||
private:
|
||||
|
||||
IStream const* openStream() {
|
||||
if( m_data.outputFilename.empty() )
|
||||
return new CoutStream();
|
||||
else if( m_data.outputFilename[0] == '%' ) {
|
||||
if( m_data.outputFilename == "%debug" )
|
||||
return new DebugOutStream();
|
||||
else
|
||||
throw std::domain_error( "Unrecognised stream: " + m_data.outputFilename );
|
||||
}
|
||||
else
|
||||
return new FileStream( m_data.outputFilename );
|
||||
}
|
||||
IStream const* openStream();
|
||||
ConfigData m_data;
|
||||
|
||||
CATCH_AUTO_PTR( IStream const ) m_stream;
|
||||
std::unique_ptr<IStream const> m_stream;
|
||||
TestSpec m_testSpec;
|
||||
};
|
||||
|
||||
|
@ -5,16 +5,20 @@
|
||||
* 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_CONSOLE_COLOUR_IMPL_HPP_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED
|
||||
|
||||
#include "catch_console_colour.hpp"
|
||||
#include "catch_enforce.h"
|
||||
#include "catch_errno_guard.h"
|
||||
#include "catch_interfaces_config.h"
|
||||
#include "catch_stream.h"
|
||||
#include "catch_context.h"
|
||||
#include "catch_platform.h"
|
||||
|
||||
namespace Catch {
|
||||
namespace {
|
||||
|
||||
struct IColourImpl {
|
||||
virtual ~IColourImpl() {}
|
||||
virtual ~IColourImpl() = default;
|
||||
virtual void use( Colour::Code _colourCode ) = 0;
|
||||
};
|
||||
|
||||
@ -41,15 +45,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 {
|
||||
@ -64,7 +60,7 @@ namespace {
|
||||
originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY );
|
||||
}
|
||||
|
||||
virtual void use( Colour::Code _colourCode ) {
|
||||
virtual void use( Colour::Code _colourCode ) override {
|
||||
switch( _colourCode ) {
|
||||
case Colour::None: return setTextAttribute( originalForegroundAttributes );
|
||||
case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
|
||||
@ -80,7 +76,7 @@ namespace {
|
||||
case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN );
|
||||
case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
|
||||
|
||||
case Colour::Bright: throw std::logic_error( "not a colour" );
|
||||
case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" );
|
||||
}
|
||||
}
|
||||
|
||||
@ -96,14 +92,12 @@ namespace {
|
||||
IColourImpl* platformColourInstance() {
|
||||
static Win32ColourImpl s_instance;
|
||||
|
||||
Ptr<IConfig const> config = getCurrentContext().getConfig();
|
||||
IConfigPtr config = getCurrentContext().getConfig();
|
||||
UseColour::YesOrNo colourMode = config
|
||||
? config->useColour()
|
||||
: UseColour::Auto;
|
||||
if( colourMode == UseColour::Auto )
|
||||
colourMode = !isDebuggerActive()
|
||||
? UseColour::Yes
|
||||
: UseColour::No;
|
||||
colourMode = UseColour::Yes;
|
||||
return colourMode == UseColour::Yes
|
||||
? &s_instance
|
||||
: NoColourImpl::instance();
|
||||
@ -125,13 +119,13 @@ namespace {
|
||||
// https://github.com/philsquared/Catch/pull/131
|
||||
class PosixColourImpl : public IColourImpl {
|
||||
public:
|
||||
virtual void use( Colour::Code _colourCode ) {
|
||||
virtual void use( Colour::Code _colourCode ) override {
|
||||
switch( _colourCode ) {
|
||||
case Colour::None:
|
||||
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" );
|
||||
@ -141,7 +135,7 @@ namespace {
|
||||
case Colour::BrightGreen: return setColour( "[1;32m" );
|
||||
case Colour::BrightWhite: return setColour( "[1;37m" );
|
||||
|
||||
case Colour::Bright: throw std::logic_error( "not a colour" );
|
||||
case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" );
|
||||
}
|
||||
}
|
||||
static IColourImpl* instance() {
|
||||
@ -156,12 +150,13 @@ namespace {
|
||||
};
|
||||
|
||||
IColourImpl* platformColourInstance() {
|
||||
Ptr<IConfig const> config = getCurrentContext().getConfig();
|
||||
ErrnoGuard guard;
|
||||
IConfigPtr config = getCurrentContext().getConfig();
|
||||
UseColour::YesOrNo colourMode = config
|
||||
? config->useColour()
|
||||
: UseColour::Auto;
|
||||
if( colourMode == UseColour::Auto )
|
||||
colourMode = (!isDebuggerActive() && isatty(STDOUT_FILENO) )
|
||||
colourMode = isatty(STDOUT_FILENO)
|
||||
? UseColour::Yes
|
||||
: UseColour::No;
|
||||
return colourMode == UseColour::Yes
|
||||
@ -184,8 +179,17 @@ namespace Catch {
|
||||
|
||||
namespace Catch {
|
||||
|
||||
Colour::Colour( Code _colourCode ) : m_moved( false ) { use( _colourCode ); }
|
||||
Colour::Colour( Colour const& _other ) : m_moved( false ) { const_cast<Colour&>( _other ).m_moved = true; }
|
||||
Colour::Colour( Code _colourCode ) { use( _colourCode ); }
|
||||
Colour::Colour( Colour&& rhs ) noexcept {
|
||||
m_moved = rhs.m_moved;
|
||||
rhs.m_moved = true;
|
||||
}
|
||||
Colour& Colour::operator=( Colour&& rhs ) noexcept {
|
||||
m_moved = rhs.m_moved;
|
||||
rhs.m_moved = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Colour::~Colour(){ if( !m_moved ) use( None ); }
|
||||
|
||||
void Colour::use( Code _colourCode ) {
|
||||
@ -193,6 +197,8 @@ namespace Catch {
|
||||
impl->use( _colourCode );
|
||||
}
|
||||
|
||||
} // end namespace Catch
|
||||
std::ostream& operator << ( std::ostream& os, Colour const& ) {
|
||||
return os;
|
||||
}
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED
|
||||
} // end namespace Catch
|
@ -50,17 +50,18 @@ namespace Catch {
|
||||
|
||||
// Use constructed object for RAII guard
|
||||
Colour( Code _colourCode );
|
||||
Colour( Colour const& other );
|
||||
Colour( Colour&& other ) noexcept;
|
||||
Colour& operator=( Colour&& other ) noexcept;
|
||||
~Colour();
|
||||
|
||||
// Use static method for one-shot changes
|
||||
static void use( Code _colourCode );
|
||||
|
||||
private:
|
||||
bool m_moved;
|
||||
bool m_moved = false;
|
||||
};
|
||||
|
||||
inline std::ostream& operator << ( std::ostream& os, Colour const& ) { return os; }
|
||||
std::ostream& operator << ( std::ostream& os, Colour const& );
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
|
62
include/internal/catch_context.cpp
Normal file
62
include/internal/catch_context.cpp
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Created by Phil on 31/12/2010.
|
||||
* Copyright 2010 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_context.h"
|
||||
#include "catch_common.h"
|
||||
|
||||
namespace Catch {
|
||||
|
||||
class Context : public IMutableContext, NonCopyable {
|
||||
|
||||
public: // IContext
|
||||
virtual IResultCapture* getResultCapture() override {
|
||||
return m_resultCapture;
|
||||
}
|
||||
virtual IRunner* getRunner() override {
|
||||
return m_runner;
|
||||
}
|
||||
|
||||
virtual IConfigPtr getConfig() const override {
|
||||
return m_config;
|
||||
}
|
||||
|
||||
public: // IMutableContext
|
||||
virtual void setResultCapture( IResultCapture* resultCapture ) override {
|
||||
m_resultCapture = resultCapture;
|
||||
}
|
||||
virtual void setRunner( IRunner* runner ) override {
|
||||
m_runner = runner;
|
||||
}
|
||||
virtual void setConfig( IConfigPtr const& config ) override {
|
||||
m_config = config;
|
||||
}
|
||||
|
||||
friend IMutableContext& getCurrentMutableContext();
|
||||
|
||||
private:
|
||||
IConfigPtr m_config;
|
||||
IRunner* m_runner = nullptr;
|
||||
IResultCapture* m_resultCapture = nullptr;
|
||||
};
|
||||
|
||||
namespace {
|
||||
Context* currentContext = nullptr;
|
||||
}
|
||||
IMutableContext& getCurrentMutableContext() {
|
||||
if( !currentContext )
|
||||
currentContext = new Context();
|
||||
return *currentContext;
|
||||
}
|
||||
IContext& getCurrentContext() {
|
||||
return getCurrentMutableContext();
|
||||
}
|
||||
|
||||
void cleanUpContext() {
|
||||
delete currentContext;
|
||||
currentContext = nullptr;
|
||||
}
|
||||
}
|
@ -8,12 +8,7 @@
|
||||
#ifndef TWOBLUECUBES_CATCH_CONTEXT_H_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_CONTEXT_H_INCLUDED
|
||||
|
||||
#include "catch_interfaces_generators.h"
|
||||
#include "catch_ptr.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <stdlib.h>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
@ -21,18 +16,17 @@ namespace Catch {
|
||||
class Stream;
|
||||
struct IResultCapture;
|
||||
struct IRunner;
|
||||
struct IGeneratorsForTest;
|
||||
struct IConfig;
|
||||
|
||||
using IConfigPtr = std::shared_ptr<IConfig const>;
|
||||
|
||||
struct IContext
|
||||
{
|
||||
virtual ~IContext();
|
||||
|
||||
virtual IResultCapture* getResultCapture() = 0;
|
||||
virtual IRunner* getRunner() = 0;
|
||||
virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) = 0;
|
||||
virtual bool advanceGeneratorsForCurrentTest() = 0;
|
||||
virtual Ptr<IConfig const> getConfig() const = 0;
|
||||
virtual IConfigPtr getConfig() const = 0;
|
||||
};
|
||||
|
||||
struct IMutableContext : IContext
|
||||
@ -40,14 +34,12 @@ namespace Catch {
|
||||
virtual ~IMutableContext();
|
||||
virtual void setResultCapture( IResultCapture* resultCapture ) = 0;
|
||||
virtual void setRunner( IRunner* runner ) = 0;
|
||||
virtual void setConfig( Ptr<IConfig const> const& config ) = 0;
|
||||
virtual void setConfig( IConfigPtr const& config ) = 0;
|
||||
};
|
||||
|
||||
IContext& getCurrentContext();
|
||||
IMutableContext& getCurrentMutableContext();
|
||||
void cleanUpContext();
|
||||
Stream createStream( std::string const& streamName );
|
||||
|
||||
}
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_CONTEXT_H_INCLUDED
|
||||
|
@ -1,104 +0,0 @@
|
||||
/*
|
||||
* Created by Phil on 31/12/2010.
|
||||
* Copyright 2010 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_CONTEXT_IMPL_HPP_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_CONTEXT_IMPL_HPP_INCLUDED
|
||||
|
||||
#include "catch_run_context.hpp"
|
||||
|
||||
#include "catch_context.h"
|
||||
#include "catch_stream.hpp"
|
||||
|
||||
namespace Catch {
|
||||
|
||||
class Context : public IMutableContext {
|
||||
|
||||
Context() : m_config( CATCH_NULL ), m_runner( CATCH_NULL ), m_resultCapture( CATCH_NULL ) {}
|
||||
Context( Context const& );
|
||||
void operator=( Context const& );
|
||||
|
||||
public: // IContext
|
||||
virtual IResultCapture* getResultCapture() {
|
||||
return m_resultCapture;
|
||||
}
|
||||
virtual IRunner* getRunner() {
|
||||
return m_runner;
|
||||
}
|
||||
virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) {
|
||||
return getGeneratorsForCurrentTest()
|
||||
.getGeneratorInfo( fileInfo, totalSize )
|
||||
.getCurrentIndex();
|
||||
}
|
||||
virtual bool advanceGeneratorsForCurrentTest() {
|
||||
IGeneratorsForTest* generators = findGeneratorsForCurrentTest();
|
||||
return generators && generators->moveNext();
|
||||
}
|
||||
|
||||
virtual Ptr<IConfig const> getConfig() const {
|
||||
return m_config;
|
||||
}
|
||||
|
||||
public: // IMutableContext
|
||||
virtual void setResultCapture( IResultCapture* resultCapture ) {
|
||||
m_resultCapture = resultCapture;
|
||||
}
|
||||
virtual void setRunner( IRunner* runner ) {
|
||||
m_runner = runner;
|
||||
}
|
||||
virtual void setConfig( Ptr<IConfig const> const& config ) {
|
||||
m_config = config;
|
||||
}
|
||||
|
||||
friend IMutableContext& getCurrentMutableContext();
|
||||
|
||||
private:
|
||||
IGeneratorsForTest* findGeneratorsForCurrentTest() {
|
||||
std::string testName = getResultCapture()->getCurrentTestName();
|
||||
|
||||
std::map<std::string, IGeneratorsForTest*>::const_iterator it =
|
||||
m_generatorsByTestName.find( testName );
|
||||
return it != m_generatorsByTestName.end()
|
||||
? it->second
|
||||
: CATCH_NULL;
|
||||
}
|
||||
|
||||
IGeneratorsForTest& getGeneratorsForCurrentTest() {
|
||||
IGeneratorsForTest* generators = findGeneratorsForCurrentTest();
|
||||
if( !generators ) {
|
||||
std::string testName = getResultCapture()->getCurrentTestName();
|
||||
generators = createGeneratorsForTest();
|
||||
m_generatorsByTestName.insert( std::make_pair( testName, generators ) );
|
||||
}
|
||||
return *generators;
|
||||
}
|
||||
|
||||
private:
|
||||
Ptr<IConfig const> m_config;
|
||||
IRunner* m_runner;
|
||||
IResultCapture* m_resultCapture;
|
||||
std::map<std::string, IGeneratorsForTest*> m_generatorsByTestName;
|
||||
};
|
||||
|
||||
namespace {
|
||||
Context* currentContext = CATCH_NULL;
|
||||
}
|
||||
IMutableContext& getCurrentMutableContext() {
|
||||
if( !currentContext )
|
||||
currentContext = new Context();
|
||||
return *currentContext;
|
||||
}
|
||||
IContext& getCurrentContext() {
|
||||
return getCurrentMutableContext();
|
||||
}
|
||||
|
||||
void cleanUpContext() {
|
||||
delete currentContext;
|
||||
currentContext = CATCH_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_CONTEXT_IMPL_HPP_INCLUDED
|
@ -6,12 +6,11 @@
|
||||
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
#ifndef TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED
|
||||
|
||||
#include "catch_debugger.h"
|
||||
|
||||
#include <iostream>
|
||||
#include "catch_errno_guard.h"
|
||||
#include "catch_stream.h"
|
||||
#include "catch_platform.h"
|
||||
|
||||
#ifdef CATCH_PLATFORM_MAC
|
||||
|
||||
@ -50,7 +49,7 @@
|
||||
// Call sysctl.
|
||||
|
||||
size = sizeof(info);
|
||||
if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, CATCH_NULL, 0) != 0 ) {
|
||||
if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, nullptr, 0) != 0 ) {
|
||||
Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl;
|
||||
return false;
|
||||
}
|
||||
@ -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 {
|
||||
@ -77,12 +106,14 @@
|
||||
}
|
||||
#else
|
||||
namespace Catch {
|
||||
inline bool isDebuggerActive() { return false; }
|
||||
bool isDebuggerActive() { return false; }
|
||||
}
|
||||
#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() );
|
||||
@ -96,5 +127,3 @@
|
||||
}
|
||||
}
|
||||
#endif // Platform
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED
|
@ -21,29 +21,30 @@ namespace Catch{
|
||||
|
||||
#ifdef CATCH_PLATFORM_MAC
|
||||
|
||||
// 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
|
||||
#endif
|
||||
#define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */
|
||||
|
||||
#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") /* NOLINT */
|
||||
#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
|
||||
|
22
include/internal/catch_decomposer.cpp
Normal file
22
include/internal/catch_decomposer.cpp
Normal file
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Created by Phil Nash on 8/8/2017.
|
||||
* Copyright 2017 Two Blue Cubes Ltd. All rights reserved.
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
|
||||
#include "catch_decomposer.h"
|
||||
#include "catch_config.hpp"
|
||||
|
||||
namespace Catch {
|
||||
|
||||
void formatReconstructedExpression( std::ostream &os, std::string const& lhs, std::string const& op, std::string const& rhs ) {
|
||||
if( lhs.size() + rhs.size() < 40 &&
|
||||
lhs.find('\n') == std::string::npos &&
|
||||
rhs.find('\n') == std::string::npos )
|
||||
os << lhs << " " << op << " " << rhs;
|
||||
else
|
||||
os << lhs << "\n" << op << "\n" << rhs;
|
||||
}
|
||||
}
|
164
include/internal/catch_decomposer.h
Normal file
164
include/internal/catch_decomposer.h
Normal file
@ -0,0 +1,164 @@
|
||||
/*
|
||||
* Created by Phil Nash on 8/8/2017.
|
||||
* Copyright 2017 Two Blue Cubes Ltd. All rights reserved.
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
#ifndef TWOBLUECUBES_CATCH_DECOMPOSER_H_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_DECOMPOSER_H_INCLUDED
|
||||
|
||||
#include "catch_tostring.h"
|
||||
#include "catch_stringref.h"
|
||||
|
||||
#include <ostream>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4389) // '==' : signed/unsigned mismatch
|
||||
#pragma warning(disable:4018) // more "signed/unsigned mismatch"
|
||||
#pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform)
|
||||
#endif
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct ITransientExpression {
|
||||
virtual auto isBinaryExpression() const -> bool = 0;
|
||||
virtual auto getResult() const -> bool = 0;
|
||||
virtual void streamReconstructedExpression( std::ostream &os ) const = 0;
|
||||
|
||||
// We don't actually need a virtual destructore, but many static analysers
|
||||
// complain if it's not here :-(
|
||||
virtual ~ITransientExpression() = default;
|
||||
};
|
||||
|
||||
void formatReconstructedExpression( std::ostream &os, std::string const& lhs, std::string const& op, std::string const& rhs );
|
||||
|
||||
template<typename LhsT, typename RhsT>
|
||||
class BinaryExpr : public ITransientExpression {
|
||||
bool m_result;
|
||||
LhsT m_lhs;
|
||||
std::string m_op;
|
||||
RhsT m_rhs;
|
||||
|
||||
auto isBinaryExpression() const -> bool override { return true; }
|
||||
auto getResult() const -> bool override { return m_result; }
|
||||
|
||||
void streamReconstructedExpression( std::ostream &os ) const override {
|
||||
formatReconstructedExpression
|
||||
( os, Catch::Detail::stringify( m_lhs ), m_op, Catch::Detail::stringify( m_rhs ) );
|
||||
}
|
||||
|
||||
public:
|
||||
BinaryExpr( bool comparisionResult, LhsT lhs, StringRef op, RhsT rhs )
|
||||
: m_result( comparisionResult ),
|
||||
m_lhs( lhs ),
|
||||
m_op( op ),
|
||||
m_rhs( rhs )
|
||||
{}
|
||||
};
|
||||
|
||||
template<typename LhsT>
|
||||
class UnaryExpr : public ITransientExpression {
|
||||
LhsT m_lhs;
|
||||
|
||||
auto isBinaryExpression() const -> bool override { return false; }
|
||||
auto getResult() const -> bool override { return m_lhs ? true : false; }
|
||||
|
||||
void streamReconstructedExpression( std::ostream &os ) const override {
|
||||
os << Catch::Detail::stringify( m_lhs );
|
||||
}
|
||||
|
||||
public:
|
||||
UnaryExpr( LhsT lhs ) : m_lhs( lhs ) {}
|
||||
};
|
||||
|
||||
|
||||
// Specialised comparison functions to handle equality comparisons between ints and pointers (NULL deduces as an int)
|
||||
template<typename LhsT, typename RhsT>
|
||||
auto compareEqual( LhsT const& lhs, RhsT&& rhs ) -> bool { return const_cast<LhsT&>( lhs ) == rhs; };
|
||||
template<typename T>
|
||||
auto compareEqual( T* const& lhs, int rhs ) -> bool { return lhs == reinterpret_cast<void const*>( rhs ); };
|
||||
template<typename T>
|
||||
auto compareEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) == rhs; };
|
||||
|
||||
template<typename LhsT, typename RhsT>
|
||||
auto compareNotEqual( LhsT const& lhs, RhsT&& rhs ) -> bool { return const_cast<LhsT&>( lhs ) != rhs; };
|
||||
template<typename T>
|
||||
auto compareNotEqual( T* const& lhs, int rhs ) -> bool { return lhs != reinterpret_cast<void const*>( rhs ); };
|
||||
template<typename T>
|
||||
auto compareNotEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) != rhs; };
|
||||
|
||||
|
||||
template<typename LhsT>
|
||||
class ExprLhs {
|
||||
LhsT m_lhs;
|
||||
public:
|
||||
ExprLhs( LhsT lhs ) : m_lhs( lhs ) {}
|
||||
|
||||
template<typename RhsT>
|
||||
auto operator == ( RhsT&& rhs ) -> BinaryExpr<LhsT, RhsT&> const {
|
||||
return BinaryExpr<LhsT, RhsT&>( compareEqual( m_lhs, rhs ), m_lhs, "==", rhs );
|
||||
}
|
||||
auto operator == ( bool rhs ) -> BinaryExpr<LhsT, bool> const {
|
||||
return BinaryExpr<LhsT, bool>( m_lhs == rhs, m_lhs, "==", rhs );
|
||||
}
|
||||
|
||||
template<typename RhsT>
|
||||
auto operator != ( RhsT&& rhs ) -> BinaryExpr<LhsT, RhsT&> const {
|
||||
return BinaryExpr<LhsT, RhsT&>( compareNotEqual( m_lhs, rhs ), m_lhs, "!=", rhs );
|
||||
}
|
||||
auto operator != ( bool rhs ) -> BinaryExpr<LhsT, bool> const {
|
||||
return BinaryExpr<LhsT, bool>( m_lhs != rhs, m_lhs, "!=", rhs );
|
||||
}
|
||||
|
||||
template<typename RhsT>
|
||||
auto operator > ( RhsT&& rhs ) -> BinaryExpr<LhsT, RhsT&> const {
|
||||
return BinaryExpr<LhsT, RhsT&>( m_lhs > rhs, m_lhs, ">", rhs );
|
||||
}
|
||||
template<typename RhsT>
|
||||
auto operator < ( RhsT&& rhs ) -> BinaryExpr<LhsT, RhsT&> const {
|
||||
return BinaryExpr<LhsT, RhsT&>( m_lhs < rhs, m_lhs, "<", rhs );
|
||||
}
|
||||
template<typename RhsT>
|
||||
auto operator >= ( RhsT&& rhs ) -> BinaryExpr<LhsT, RhsT&> const {
|
||||
return BinaryExpr<LhsT, RhsT&>( m_lhs >= rhs, m_lhs, ">=", rhs );
|
||||
}
|
||||
template<typename RhsT>
|
||||
auto operator <= ( RhsT&& rhs ) -> BinaryExpr<LhsT, RhsT&> const {
|
||||
return BinaryExpr<LhsT, RhsT&>( m_lhs <= rhs, m_lhs, "<=", rhs );
|
||||
}
|
||||
|
||||
auto makeUnaryExpr() const -> UnaryExpr<LhsT> {
|
||||
return UnaryExpr<LhsT>( m_lhs );
|
||||
}
|
||||
};
|
||||
|
||||
void handleExpression( ITransientExpression const& expr );
|
||||
|
||||
template<typename T>
|
||||
void handleExpression( ExprLhs<T> const& expr ) {
|
||||
handleExpression( expr.makeUnaryExpr() );
|
||||
}
|
||||
|
||||
struct Decomposer {
|
||||
template<typename T>
|
||||
auto operator <= ( T& lhs ) -> ExprLhs<T&> {
|
||||
return ExprLhs<T&>( lhs );
|
||||
}
|
||||
template<typename T>
|
||||
auto operator <= ( T const& lhs ) -> ExprLhs<T const&> {
|
||||
return ExprLhs<T const&>( lhs );
|
||||
}
|
||||
auto operator <=( bool value ) -> ExprLhs<bool> {
|
||||
return ExprLhs<bool>( value );
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_DECOMPOSER_H_INCLUDED
|
@ -10,8 +10,14 @@
|
||||
|
||||
#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 * argv[]) {
|
||||
#endif
|
||||
|
||||
return Catch::Session().run( argc, argv );
|
||||
}
|
||||
|
||||
|
24
include/internal/catch_enforce.h
Normal file
24
include/internal/catch_enforce.h
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Created by Martin on 01/08/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_ENFORCE_H_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_ENFORCE_H_INCLUDED
|
||||
|
||||
#include "catch_common.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
|
||||
#define CATCH_PREPARE_EXCEPTION( type, msg ) \
|
||||
type( static_cast<std::ostringstream&&>( std::ostringstream() << msg ).str() )
|
||||
#define CATCH_INTERNAL_ERROR( msg ) \
|
||||
throw CATCH_PREPARE_EXCEPTION( std::logic_error, CATCH_INTERNAL_LINEINFO << ": Internal Catch error: " << msg);
|
||||
#define CATCH_ERROR( msg ) \
|
||||
throw CATCH_PREPARE_EXCEPTION( std::domain_error, msg )
|
||||
#define CATCH_ENFORCE( condition, msg ) \
|
||||
do{ if( !(condition) ) CATCH_ERROR( msg ); } while(false)
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_ENFORCE_H_INCLUDED
|
15
include/internal/catch_errno_guard.cpp
Normal file
15
include/internal/catch_errno_guard.cpp
Normal file
@ -0,0 +1,15 @@
|
||||
/*
|
||||
* 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)
|
||||
*/
|
||||
|
||||
#include "catch_errno_guard.h"
|
||||
|
||||
#include <cerrno>
|
||||
|
||||
namespace Catch {
|
||||
ErrnoGuard::ErrnoGuard():m_oldErrno(errno){}
|
||||
ErrnoGuard::~ErrnoGuard() { errno = m_oldErrno; }
|
||||
}
|
22
include/internal/catch_errno_guard.h
Normal file
22
include/internal/catch_errno_guard.h
Normal file
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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_H_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_ERRNO_GUARD_H_INCLUDED
|
||||
|
||||
namespace Catch {
|
||||
|
||||
class ErrnoGuard {
|
||||
public:
|
||||
ErrnoGuard();
|
||||
~ErrnoGuard();
|
||||
private:
|
||||
int m_oldErrno;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_ERRNO_GUARD_H_INCLUDED
|
@ -1,218 +0,0 @@
|
||||
/*
|
||||
* Created by Phil on 04/03/2011.
|
||||
* Copyright 2011 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_EVALUATE_HPP_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4389) // '==' : signed/unsigned mismatch
|
||||
#endif
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
namespace Catch {
|
||||
namespace Internal {
|
||||
|
||||
enum Operator {
|
||||
IsEqualTo,
|
||||
IsNotEqualTo,
|
||||
IsLessThan,
|
||||
IsGreaterThan,
|
||||
IsLessThanOrEqualTo,
|
||||
IsGreaterThanOrEqualTo
|
||||
};
|
||||
|
||||
template<Operator Op> struct OperatorTraits { static const char* getName(){ return "*error*"; } };
|
||||
template<> struct OperatorTraits<IsEqualTo> { static const char* getName(){ return "=="; } };
|
||||
template<> struct OperatorTraits<IsNotEqualTo> { static const char* getName(){ return "!="; } };
|
||||
template<> struct OperatorTraits<IsLessThan> { static const char* getName(){ return "<"; } };
|
||||
template<> struct OperatorTraits<IsGreaterThan> { static const char* getName(){ return ">"; } };
|
||||
template<> struct OperatorTraits<IsLessThanOrEqualTo> { static const char* getName(){ return "<="; } };
|
||||
template<> struct OperatorTraits<IsGreaterThanOrEqualTo>{ static const char* getName(){ return ">="; } };
|
||||
|
||||
template<typename T>
|
||||
inline T& opCast(T const& t) { return const_cast<T&>(t); }
|
||||
|
||||
// nullptr_t support based on pull request #154 from Konstantin Baumann
|
||||
#ifdef CATCH_CONFIG_CPP11_NULLPTR
|
||||
inline std::nullptr_t opCast(std::nullptr_t) { return nullptr; }
|
||||
#endif // CATCH_CONFIG_CPP11_NULLPTR
|
||||
|
||||
|
||||
// So the compare overloads can be operator agnostic we convey the operator as a template
|
||||
// enum, which is used to specialise an Evaluator for doing the comparison.
|
||||
template<typename T1, typename T2, Operator Op>
|
||||
class Evaluator{};
|
||||
|
||||
template<typename T1, typename T2>
|
||||
struct Evaluator<T1, T2, IsEqualTo> {
|
||||
static bool evaluate( T1 const& lhs, T2 const& 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 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 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 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 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 bool( opCast( lhs ) <= opCast( rhs ) );
|
||||
}
|
||||
};
|
||||
|
||||
template<Operator Op, typename T1, typename T2>
|
||||
bool applyEvaluator( T1 const& lhs, T2 const& rhs ) {
|
||||
return Evaluator<T1, T2, Op>::evaluate( lhs, rhs );
|
||||
}
|
||||
|
||||
// This level of indirection allows us to specialise for integer types
|
||||
// to avoid signed/ unsigned warnings
|
||||
|
||||
// "base" overload
|
||||
template<Operator Op, typename T1, typename T2>
|
||||
bool compare( T1 const& lhs, T2 const& rhs ) {
|
||||
return Evaluator<T1, T2, Op>::evaluate( lhs, rhs );
|
||||
}
|
||||
|
||||
// unsigned X to int
|
||||
template<Operator Op> bool compare( unsigned int lhs, int rhs ) {
|
||||
return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) );
|
||||
}
|
||||
template<Operator Op> bool compare( unsigned long lhs, int rhs ) {
|
||||
return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) );
|
||||
}
|
||||
template<Operator Op> bool compare( unsigned char lhs, int rhs ) {
|
||||
return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) );
|
||||
}
|
||||
|
||||
// unsigned X to long
|
||||
template<Operator Op> bool compare( unsigned int lhs, long rhs ) {
|
||||
return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) );
|
||||
}
|
||||
template<Operator Op> bool compare( unsigned long lhs, long rhs ) {
|
||||
return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) );
|
||||
}
|
||||
template<Operator Op> bool compare( unsigned char lhs, long rhs ) {
|
||||
return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) );
|
||||
}
|
||||
|
||||
// int to unsigned X
|
||||
template<Operator Op> bool compare( int lhs, unsigned int rhs ) {
|
||||
return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs );
|
||||
}
|
||||
template<Operator Op> bool compare( int lhs, unsigned long rhs ) {
|
||||
return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs );
|
||||
}
|
||||
template<Operator Op> bool compare( int lhs, unsigned char rhs ) {
|
||||
return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs );
|
||||
}
|
||||
|
||||
// long to unsigned X
|
||||
template<Operator Op> bool compare( long lhs, unsigned int rhs ) {
|
||||
return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
|
||||
}
|
||||
template<Operator Op> bool compare( long lhs, unsigned long rhs ) {
|
||||
return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
|
||||
}
|
||||
template<Operator Op> bool compare( long lhs, unsigned char rhs ) {
|
||||
return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
|
||||
}
|
||||
|
||||
// pointer to long (when comparing against NULL)
|
||||
template<Operator Op, typename T> bool compare( long lhs, T* rhs ) {
|
||||
return Evaluator<T*, T*, Op>::evaluate( reinterpret_cast<T*>( lhs ), rhs );
|
||||
}
|
||||
template<Operator Op, typename T> bool compare( T* lhs, long rhs ) {
|
||||
return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) );
|
||||
}
|
||||
|
||||
// pointer to int (when comparing against NULL)
|
||||
template<Operator Op, typename T> bool compare( int lhs, T* rhs ) {
|
||||
return Evaluator<T*, T*, Op>::evaluate( reinterpret_cast<T*>( lhs ), rhs );
|
||||
}
|
||||
template<Operator Op, typename T> bool compare( T* lhs, int rhs ) {
|
||||
return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) );
|
||||
}
|
||||
|
||||
#ifdef CATCH_CONFIG_CPP11_LONG_LONG
|
||||
// long long to unsigned X
|
||||
template<Operator Op> bool compare( long long lhs, unsigned int rhs ) {
|
||||
return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
|
||||
}
|
||||
template<Operator Op> bool compare( long long lhs, unsigned long rhs ) {
|
||||
return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
|
||||
}
|
||||
template<Operator Op> bool compare( long long lhs, unsigned long long rhs ) {
|
||||
return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
|
||||
}
|
||||
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 );
|
||||
}
|
||||
template<Operator Op> bool compare( unsigned long long lhs, long rhs ) {
|
||||
return applyEvaluator<Op>( static_cast<long>( lhs ), rhs );
|
||||
}
|
||||
template<Operator Op> bool compare( unsigned long long lhs, long long rhs ) {
|
||||
return applyEvaluator<Op>( static_cast<long>( lhs ), rhs );
|
||||
}
|
||||
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 );
|
||||
}
|
||||
template<Operator Op, typename T> bool compare( T* lhs, long long rhs ) {
|
||||
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 ) {
|
||||
return Evaluator<T*, T*, Op>::evaluate( nullptr, rhs );
|
||||
}
|
||||
template<Operator Op, typename T> bool compare( T* lhs, std::nullptr_t ) {
|
||||
return Evaluator<T*, T*, Op>::evaluate( lhs, nullptr );
|
||||
}
|
||||
#endif // CATCH_CONFIG_CPP11_NULLPTR
|
||||
|
||||
} // end of namespace Internal
|
||||
} // end of namespace Catch
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED
|
62
include/internal/catch_exception_translator_registry.cpp
Normal file
62
include/internal/catch_exception_translator_registry.cpp
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Created by Phil on 20/04/2011.
|
||||
* Copyright 2011 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_assertionhandler.h"
|
||||
#include "catch_exception_translator_registry.h"
|
||||
|
||||
#ifdef __OBJC__
|
||||
#import "Foundation/Foundation.h"
|
||||
#endif
|
||||
|
||||
namespace Catch {
|
||||
|
||||
ExceptionTranslatorRegistry::~ExceptionTranslatorRegistry() {
|
||||
}
|
||||
|
||||
void ExceptionTranslatorRegistry::registerTranslator( const IExceptionTranslator* translator ) {
|
||||
m_translators.push_back( std::unique_ptr<const IExceptionTranslator>( translator ) );
|
||||
}
|
||||
|
||||
std::string ExceptionTranslatorRegistry::translateActiveException() const {
|
||||
try {
|
||||
#ifdef __OBJC__
|
||||
// In Objective-C try objective-c exceptions first
|
||||
@try {
|
||||
return tryTranslators();
|
||||
}
|
||||
@catch (NSException *exception) {
|
||||
return Catch::toString( [exception description] );
|
||||
}
|
||||
#else
|
||||
return tryTranslators();
|
||||
#endif
|
||||
}
|
||||
catch( TestFailureException& ) {
|
||||
throw;
|
||||
}
|
||||
catch( std::exception& ex ) {
|
||||
return ex.what();
|
||||
}
|
||||
catch( std::string& msg ) {
|
||||
return msg;
|
||||
}
|
||||
catch( const char* msg ) {
|
||||
return msg;
|
||||
}
|
||||
catch(...) {
|
||||
return "Unknown exception";
|
||||
}
|
||||
}
|
||||
|
||||
std::string ExceptionTranslatorRegistry::tryTranslators() const {
|
||||
if( m_translators.empty() )
|
||||
throw;
|
||||
else
|
||||
return m_translators[0]->translate( m_translators.begin()+1, m_translators.end() );
|
||||
}
|
||||
}
|
30
include/internal/catch_exception_translator_registry.h
Normal file
30
include/internal/catch_exception_translator_registry.h
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Created by Phil on 20/04/2011.
|
||||
* Copyright 2011 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_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED
|
||||
|
||||
#include "catch_interfaces_exception.h"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry {
|
||||
public:
|
||||
~ExceptionTranslatorRegistry();
|
||||
virtual void registerTranslator( const IExceptionTranslator* translator );
|
||||
virtual std::string translateActiveException() const override;
|
||||
std::string tryTranslators() const;
|
||||
|
||||
private:
|
||||
std::vector<std::unique_ptr<IExceptionTranslator const>> m_translators;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED
|
@ -1,73 +0,0 @@
|
||||
/*
|
||||
* Created by Phil on 20/04/2011.
|
||||
* Copyright 2011 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_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED
|
||||
|
||||
#include "catch_interfaces_exception.h"
|
||||
#include "catch_tostring.h"
|
||||
|
||||
#ifdef __OBJC__
|
||||
#import "Foundation/Foundation.h"
|
||||
#endif
|
||||
|
||||
namespace Catch {
|
||||
|
||||
class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry {
|
||||
public:
|
||||
~ExceptionTranslatorRegistry() {
|
||||
deleteAll( m_translators );
|
||||
}
|
||||
|
||||
virtual void registerTranslator( const IExceptionTranslator* translator ) {
|
||||
m_translators.push_back( translator );
|
||||
}
|
||||
|
||||
virtual std::string translateActiveException() const {
|
||||
try {
|
||||
#ifdef __OBJC__
|
||||
// In Objective-C try objective-c exceptions first
|
||||
@try {
|
||||
return tryTranslators();
|
||||
}
|
||||
@catch (NSException *exception) {
|
||||
return Catch::toString( [exception description] );
|
||||
}
|
||||
#else
|
||||
return tryTranslators();
|
||||
#endif
|
||||
}
|
||||
catch( TestFailureException& ) {
|
||||
throw;
|
||||
}
|
||||
catch( std::exception& ex ) {
|
||||
return ex.what();
|
||||
}
|
||||
catch( std::string& msg ) {
|
||||
return msg;
|
||||
}
|
||||
catch( const char* msg ) {
|
||||
return msg;
|
||||
}
|
||||
catch(...) {
|
||||
return "Unknown exception";
|
||||
}
|
||||
}
|
||||
|
||||
std::string tryTranslators() const {
|
||||
if( m_translators.empty() )
|
||||
throw;
|
||||
else
|
||||
return m_translators[0]->translate( m_translators.begin()+1, m_translators.end() );
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<const IExceptionTranslator*> m_translators;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED
|
@ -1,105 +0,0 @@
|
||||
/*
|
||||
* Created by Phil on 11/5/2012.
|
||||
* Copyright 2012 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_EXPRESSION_LHS_HPP_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_EXPRESSION_LHS_HPP_INCLUDED
|
||||
|
||||
#include "catch_result_builder.h"
|
||||
#include "catch_evaluate.hpp"
|
||||
#include "catch_tostring.h"
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
template<typename RhsT>
|
||||
ResultBuilder& operator == ( RhsT const& rhs ) {
|
||||
return captureExpression<Internal::IsEqualTo>( rhs );
|
||||
}
|
||||
|
||||
template<typename RhsT>
|
||||
ResultBuilder& operator != ( RhsT const& rhs ) {
|
||||
return captureExpression<Internal::IsNotEqualTo>( rhs );
|
||||
}
|
||||
|
||||
template<typename RhsT>
|
||||
ResultBuilder& operator < ( RhsT const& rhs ) {
|
||||
return captureExpression<Internal::IsLessThan>( rhs );
|
||||
}
|
||||
|
||||
template<typename RhsT>
|
||||
ResultBuilder& operator > ( RhsT const& rhs ) {
|
||||
return captureExpression<Internal::IsGreaterThan>( rhs );
|
||||
}
|
||||
|
||||
template<typename RhsT>
|
||||
ResultBuilder& operator <= ( RhsT const& rhs ) {
|
||||
return captureExpression<Internal::IsLessThanOrEqualTo>( rhs );
|
||||
}
|
||||
|
||||
template<typename RhsT>
|
||||
ResultBuilder& operator >= ( RhsT const& rhs ) {
|
||||
return captureExpression<Internal::IsGreaterThanOrEqualTo>( rhs );
|
||||
}
|
||||
|
||||
ResultBuilder& operator == ( bool rhs ) {
|
||||
return captureExpression<Internal::IsEqualTo>( rhs );
|
||||
}
|
||||
|
||||
ResultBuilder& operator != ( bool rhs ) {
|
||||
return captureExpression<Internal::IsNotEqualTo>( rhs );
|
||||
}
|
||||
|
||||
void endExpression() {
|
||||
bool value = m_lhs ? true : false;
|
||||
m_rb
|
||||
.setLhs( Catch::toString( value ) )
|
||||
.setResultType( value )
|
||||
.endExpression();
|
||||
}
|
||||
|
||||
// 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& );
|
||||
|
||||
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() );
|
||||
}
|
||||
|
||||
private:
|
||||
ResultBuilder& m_rb;
|
||||
T m_lhs;
|
||||
};
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_EXPRESSION_LHS_HPP_INCLUDED
|
13
include/internal/catch_external_interfaces.h
Normal file
13
include/internal/catch_external_interfaces.h
Normal file
@ -0,0 +1,13 @@
|
||||
/*
|
||||
* Created by Martin on 17/08/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_EXTERNAL_INTERFACES_H
|
||||
#define TWOBLUECUBES_CATCH_EXTERNAL_INTERFACES_H
|
||||
|
||||
#include "../reporters/catch_reporter_bases.hpp"
|
||||
#include "catch_reporter_registrars.hpp"
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_EXTERNAL_INTERFACES_H
|
181
include/internal/catch_fatal_condition.cpp
Normal file
181
include/internal/catch_fatal_condition.cpp
Normal file
@ -0,0 +1,181 @@
|
||||
/*
|
||||
* Created by Phil on 21/08/2014
|
||||
* Copyright 2014 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_fatal_condition.h"
|
||||
|
||||
#include "catch_context.h"
|
||||
#include "catch_interfaces_capture.h"
|
||||
|
||||
namespace Catch {
|
||||
|
||||
// Report the error condition
|
||||
void reportFatal( std::string const& message ) {
|
||||
IContext& context = Catch::getCurrentContext();
|
||||
IResultCapture* resultCapture = context.getResultCapture();
|
||||
resultCapture->handleFatalErrorCondition( message );
|
||||
}
|
||||
|
||||
} // namespace Catch
|
||||
|
||||
#if defined ( CATCH_PLATFORM_WINDOWS ) /////////////////////////////////////////
|
||||
|
||||
# if !defined ( CATCH_CONFIG_WINDOWS_SEH )
|
||||
|
||||
namespace Catch {
|
||||
void FatalConditionHandler::reset() {}
|
||||
}
|
||||
|
||||
# else // CATCH_CONFIG_WINDOWS_SEH is defined
|
||||
|
||||
namespace Catch {
|
||||
struct SignalDefs { DWORD id; const char* name; };
|
||||
|
||||
// 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" },
|
||||
};
|
||||
|
||||
LONG CALLBACK FatalConditionHandler::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::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 = nullptr;
|
||||
// Register as first handler in current chain
|
||||
exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException);
|
||||
// Pass in guarantee size to be filled
|
||||
SetThreadStackGuarantee(&guaranteeSize);
|
||||
}
|
||||
|
||||
void FatalConditionHandler::reset() {
|
||||
if (isSet) {
|
||||
// Unregister handler and restore the old guarantee
|
||||
RemoveVectoredExceptionHandler(exceptionHandlerHandle);
|
||||
SetThreadStackGuarantee(&guaranteeSize);
|
||||
exceptionHandlerHandle = nullptr;
|
||||
isSet = false;
|
||||
}
|
||||
}
|
||||
|
||||
FatalConditionHandler::~FatalConditionHandler() {
|
||||
reset();
|
||||
}
|
||||
|
||||
bool FatalConditionHandler::isSet = false;
|
||||
ULONG FatalConditionHandler::guaranteeSize = 0;
|
||||
PVOID FatalConditionHandler::exceptionHandlerHandle = nullptr;
|
||||
|
||||
|
||||
} // namespace Catch
|
||||
|
||||
# endif // CATCH_CONFIG_WINDOWS_SEH
|
||||
|
||||
#else // Not Windows - assumed to be POSIX compatible //////////////////////////
|
||||
|
||||
# if !defined(CATCH_CONFIG_POSIX_SIGNALS)
|
||||
|
||||
namespace Catch {
|
||||
void FatalConditionHandler::reset() {}
|
||||
}
|
||||
|
||||
|
||||
# else // CATCH_CONFIG_POSIX_SIGNALS is defined
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct SignalDefs {
|
||||
int id;
|
||||
const char* name;
|
||||
};
|
||||
SignalDefs signalDefs[] = {
|
||||
{ SIGINT, "SIGINT - Terminal interrupt signal" },
|
||||
{ SIGILL, "SIGILL - Illegal instruction signal" },
|
||||
{ SIGFPE, "SIGFPE - Floating point error signal" },
|
||||
{ SIGSEGV, "SIGSEGV - Segmentation violation signal" },
|
||||
{ SIGTERM, "SIGTERM - Termination request signal" },
|
||||
{ SIGABRT, "SIGABRT - Abort (abnormal termination) signal" }
|
||||
};
|
||||
|
||||
|
||||
void FatalConditionHandler::handleSignal( int 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::FatalConditionHandler() {
|
||||
isSet = true;
|
||||
stack_t sigStack;
|
||||
sigStack.ss_sp = altStackMem;
|
||||
sigStack.ss_size = SIGSTKSZ;
|
||||
sigStack.ss_flags = 0;
|
||||
sigaltstack(&sigStack, &oldSigStack);
|
||||
struct sigaction sa = { };
|
||||
|
||||
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]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FatalConditionHandler::~FatalConditionHandler() {
|
||||
reset();
|
||||
}
|
||||
|
||||
void FatalConditionHandler::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], nullptr);
|
||||
}
|
||||
// Return the old stack
|
||||
sigaltstack(&oldSigStack, nullptr);
|
||||
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
|
92
include/internal/catch_fatal_condition.h
Normal file
92
include/internal/catch_fatal_condition.h
Normal file
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Created by Phil on 21/08/2014
|
||||
* Copyright 2014 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_FATAL_CONDITION_H_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED
|
||||
|
||||
#include <string>
|
||||
#include "catch_platform.h"
|
||||
#include "catch_compiler_capabilities.h"
|
||||
|
||||
namespace Catch {
|
||||
|
||||
// Report the error condition
|
||||
void reportFatal( std::string const& message );
|
||||
|
||||
} // 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 FatalConditionHandler {
|
||||
|
||||
static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo);
|
||||
FatalConditionHandler();
|
||||
static void reset();
|
||||
~FatalConditionHandler();
|
||||
|
||||
private:
|
||||
static bool isSet;
|
||||
static ULONG guaranteeSize;
|
||||
static PVOID exceptionHandlerHandle;
|
||||
};
|
||||
|
||||
} // 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 FatalConditionHandler {
|
||||
|
||||
static bool isSet;
|
||||
static struct sigaction oldSigActions[];// [sizeof(signalDefs) / sizeof(SignalDefs)];
|
||||
static stack_t oldSigStack;
|
||||
static char altStackMem[];
|
||||
|
||||
static void handleSignal( int sig );
|
||||
|
||||
FatalConditionHandler();
|
||||
~FatalConditionHandler();
|
||||
static void reset();
|
||||
};
|
||||
|
||||
} // namespace Catch
|
||||
|
||||
# endif // CATCH_CONFIG_POSIX_SIGNALS
|
||||
|
||||
#endif // not Windows
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED
|
@ -1,85 +0,0 @@
|
||||
/*
|
||||
* Created by Phil on 21/08/2014
|
||||
* Copyright 2014 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_FATAL_CONDITION_H_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED
|
||||
|
||||
|
||||
namespace Catch {
|
||||
|
||||
// Report the error condition then exit the process
|
||||
inline void fatal( std::string const& message, int exitCode ) {
|
||||
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 ) /////////////////////////////////////////
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct FatalConditionHandler {
|
||||
void reset() {}
|
||||
};
|
||||
|
||||
} // namespace Catch
|
||||
|
||||
#else // Not Windows - assumed to be POSIX compatible //////////////////////////
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct SignalDefs { int id; const char* name; };
|
||||
extern SignalDefs signalDefs[];
|
||||
SignalDefs signalDefs[] = {
|
||||
{ SIGINT, "SIGINT - Terminal interrupt signal" },
|
||||
{ SIGILL, "SIGILL - Illegal instruction signal" },
|
||||
{ SIGFPE, "SIGFPE - Floating point error signal" },
|
||||
{ SIGSEGV, "SIGSEGV - Segmentation violation signal" },
|
||||
{ SIGTERM, "SIGTERM - Termination request signal" },
|
||||
{ SIGABRT, "SIGABRT - Abort (abnormal termination) signal" }
|
||||
};
|
||||
|
||||
struct FatalConditionHandler {
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
bool m_isSet;
|
||||
};
|
||||
|
||||
} // namespace Catch
|
||||
|
||||
#endif // not Windows
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED
|
@ -1,190 +0,0 @@
|
||||
/*
|
||||
* Created by Phil on 27/01/2011.
|
||||
* Copyright 2011 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_GENERATORS_HPP_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED
|
||||
|
||||
#include "catch_context.h"
|
||||
|
||||
#include <iterator>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <stdlib.h>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
template<typename T>
|
||||
struct IGenerator {
|
||||
virtual ~IGenerator() {}
|
||||
virtual T getValue( std::size_t index ) const = 0;
|
||||
virtual std::size_t size () const = 0;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class BetweenGenerator : public IGenerator<T> {
|
||||
public:
|
||||
BetweenGenerator( T from, T to ) : m_from( from ), m_to( to ){}
|
||||
|
||||
virtual T getValue( std::size_t index ) const {
|
||||
return m_from+static_cast<int>( index );
|
||||
}
|
||||
|
||||
virtual std::size_t size() const {
|
||||
return static_cast<std::size_t>( 1+m_to-m_from );
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
T m_from;
|
||||
T m_to;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class ValuesGenerator : public IGenerator<T> {
|
||||
public:
|
||||
ValuesGenerator(){}
|
||||
|
||||
void add( T value ) {
|
||||
m_values.push_back( value );
|
||||
}
|
||||
|
||||
virtual T getValue( std::size_t index ) const {
|
||||
return m_values[index];
|
||||
}
|
||||
|
||||
virtual std::size_t size() const {
|
||||
return m_values.size();
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<T> m_values;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class CompositeGenerator {
|
||||
public:
|
||||
CompositeGenerator() : m_totalSize( 0 ) {}
|
||||
|
||||
// *** Move semantics, similar to auto_ptr ***
|
||||
CompositeGenerator( CompositeGenerator& other )
|
||||
: m_fileInfo( other.m_fileInfo ),
|
||||
m_totalSize( 0 )
|
||||
{
|
||||
move( other );
|
||||
}
|
||||
|
||||
CompositeGenerator& setFileInfo( const char* fileInfo ) {
|
||||
m_fileInfo = fileInfo;
|
||||
return *this;
|
||||
}
|
||||
|
||||
~CompositeGenerator() {
|
||||
deleteAll( m_composed );
|
||||
}
|
||||
|
||||
operator T () const {
|
||||
size_t overallIndex = getCurrentContext().getGeneratorIndex( m_fileInfo, m_totalSize );
|
||||
|
||||
typename std::vector<const IGenerator<T>*>::const_iterator it = m_composed.begin();
|
||||
typename std::vector<const IGenerator<T>*>::const_iterator itEnd = m_composed.end();
|
||||
for( size_t index = 0; it != itEnd; ++it )
|
||||
{
|
||||
const IGenerator<T>* generator = *it;
|
||||
if( overallIndex >= index && overallIndex < index + generator->size() )
|
||||
{
|
||||
return generator->getValue( overallIndex-index );
|
||||
}
|
||||
index += generator->size();
|
||||
}
|
||||
CATCH_INTERNAL_ERROR( "Indexed past end of generated range" );
|
||||
return T(); // Suppress spurious "not all control paths return a value" warning in Visual Studio - if you know how to fix this please do so
|
||||
}
|
||||
|
||||
void add( const IGenerator<T>* generator ) {
|
||||
m_totalSize += generator->size();
|
||||
m_composed.push_back( generator );
|
||||
}
|
||||
|
||||
CompositeGenerator& then( CompositeGenerator& other ) {
|
||||
move( other );
|
||||
return *this;
|
||||
}
|
||||
|
||||
CompositeGenerator& then( T value ) {
|
||||
ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
|
||||
valuesGen->add( value );
|
||||
add( valuesGen );
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void move( CompositeGenerator& other ) {
|
||||
std::copy( other.m_composed.begin(), other.m_composed.end(), std::back_inserter( m_composed ) );
|
||||
m_totalSize += other.m_totalSize;
|
||||
other.m_composed.clear();
|
||||
}
|
||||
|
||||
std::vector<const IGenerator<T>*> m_composed;
|
||||
std::string m_fileInfo;
|
||||
size_t m_totalSize;
|
||||
};
|
||||
|
||||
namespace Generators
|
||||
{
|
||||
template<typename T>
|
||||
CompositeGenerator<T> between( T from, T to ) {
|
||||
CompositeGenerator<T> generators;
|
||||
generators.add( new BetweenGenerator<T>( from, to ) );
|
||||
return generators;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
CompositeGenerator<T> values( T val1, T val2 ) {
|
||||
CompositeGenerator<T> generators;
|
||||
ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
|
||||
valuesGen->add( val1 );
|
||||
valuesGen->add( val2 );
|
||||
generators.add( valuesGen );
|
||||
return generators;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
CompositeGenerator<T> values( T val1, T val2, T val3 ){
|
||||
CompositeGenerator<T> generators;
|
||||
ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
|
||||
valuesGen->add( val1 );
|
||||
valuesGen->add( val2 );
|
||||
valuesGen->add( val3 );
|
||||
generators.add( valuesGen );
|
||||
return generators;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
CompositeGenerator<T> values( T val1, T val2, T val3, T val4 ) {
|
||||
CompositeGenerator<T> generators;
|
||||
ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
|
||||
valuesGen->add( val1 );
|
||||
valuesGen->add( val2 );
|
||||
valuesGen->add( val3 );
|
||||
valuesGen->add( val4 );
|
||||
generators.add( valuesGen );
|
||||
return generators;
|
||||
}
|
||||
|
||||
} // end namespace Generators
|
||||
|
||||
using namespace Generators;
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#define INTERNAL_CATCH_LINESTR2( line ) #line
|
||||
#define INTERNAL_CATCH_LINESTR( line ) INTERNAL_CATCH_LINESTR2( line )
|
||||
|
||||
#define INTERNAL_CATCH_GENERATE( expr ) expr.setFileInfo( __FILE__ "(" INTERNAL_CATCH_LINESTR( __LINE__ ) ")" )
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED
|
@ -1,86 +0,0 @@
|
||||
/*
|
||||
* Created by Phil on 28/01/2011.
|
||||
* Copyright 2011 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_GENERATORS_IMPL_HPP_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_GENERATORS_IMPL_HPP_INCLUDED
|
||||
|
||||
#include "catch_interfaces_generators.h"
|
||||
|
||||
#include "catch_common.h"
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct GeneratorInfo : IGeneratorInfo {
|
||||
|
||||
GeneratorInfo( std::size_t size )
|
||||
: m_size( size ),
|
||||
m_currentIndex( 0 )
|
||||
{}
|
||||
|
||||
bool moveNext() {
|
||||
if( ++m_currentIndex == m_size ) {
|
||||
m_currentIndex = 0;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::size_t getCurrentIndex() const {
|
||||
return m_currentIndex;
|
||||
}
|
||||
|
||||
std::size_t m_size;
|
||||
std::size_t m_currentIndex;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class GeneratorsForTest : public IGeneratorsForTest {
|
||||
|
||||
public:
|
||||
~GeneratorsForTest() {
|
||||
deleteAll( m_generatorsInOrder );
|
||||
}
|
||||
|
||||
IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) {
|
||||
std::map<std::string, IGeneratorInfo*>::const_iterator it = m_generatorsByName.find( fileInfo );
|
||||
if( it == m_generatorsByName.end() ) {
|
||||
IGeneratorInfo* info = new GeneratorInfo( size );
|
||||
m_generatorsByName.insert( std::make_pair( fileInfo, info ) );
|
||||
m_generatorsInOrder.push_back( info );
|
||||
return *info;
|
||||
}
|
||||
return *it->second;
|
||||
}
|
||||
|
||||
bool moveNext() {
|
||||
std::vector<IGeneratorInfo*>::const_iterator it = m_generatorsInOrder.begin();
|
||||
std::vector<IGeneratorInfo*>::const_iterator itEnd = m_generatorsInOrder.end();
|
||||
for(; it != itEnd; ++it ) {
|
||||
if( (*it)->moveNext() )
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
std::map<std::string, IGeneratorInfo*> m_generatorsByName;
|
||||
std::vector<IGeneratorInfo*> m_generatorsInOrder;
|
||||
};
|
||||
|
||||
IGeneratorsForTest* createGeneratorsForTest()
|
||||
{
|
||||
return new GeneratorsForTest();
|
||||
}
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_GENERATORS_IMPL_HPP_INCLUDED
|
@ -16,94 +16,49 @@
|
||||
#pragma clang diagnostic ignored "-Wweak-vtables"
|
||||
#endif
|
||||
|
||||
|
||||
#include "internal/catch_notimplemented_exception.h"
|
||||
|
||||
|
||||
// Temporary hack to fix separately provided reporters
|
||||
#include "../reporters/catch_reporter_bases.hpp"
|
||||
#include "catch_reporter_registrars.hpp"
|
||||
//
|
||||
|
||||
#include "internal/catch_leak_detector.h"
|
||||
|
||||
|
||||
#include "../catch_session.hpp"
|
||||
#include "catch_registry_hub.hpp"
|
||||
#include "catch_notimplemented_exception.hpp"
|
||||
#include "catch_context_impl.hpp"
|
||||
#include "catch_console_colour_impl.hpp"
|
||||
#include "catch_generators_impl.hpp"
|
||||
#include "catch_assertionresult.hpp"
|
||||
#include "catch_test_case_info.hpp"
|
||||
#include "catch_test_spec.hpp"
|
||||
#include "catch_version.hpp"
|
||||
#include "catch_message.hpp"
|
||||
#include "catch_legacy_reporter_adapter.hpp"
|
||||
#include "catch_timer.hpp"
|
||||
#include "catch_common.hpp"
|
||||
#include "catch_section.hpp"
|
||||
#include "catch_debugger.hpp"
|
||||
#include "catch_tostring.hpp"
|
||||
#include "catch_result_builder.hpp"
|
||||
#include "catch_tag_alias_registry.hpp"
|
||||
#include "catch_test_case_tracker.hpp"
|
||||
|
||||
#include "../reporters/catch_reporter_multi.hpp"
|
||||
#include "../reporters/catch_reporter_xml.hpp"
|
||||
#include "../reporters/catch_reporter_junit.hpp"
|
||||
#include "../reporters/catch_reporter_console.hpp"
|
||||
#include "../reporters/catch_reporter_compact.hpp"
|
||||
// Cpp files will be included in the single-header file here
|
||||
// ~*~* CATCH_CPP_STITCH_PLACE *~*~
|
||||
|
||||
namespace Catch {
|
||||
LeakDetector leakDetector;
|
||||
|
||||
// These are all here to avoid warnings about not having any out of line
|
||||
// virtual methods
|
||||
NonCopyable::~NonCopyable() {}
|
||||
IShared::~IShared() {}
|
||||
IStream::~IStream() CATCH_NOEXCEPT {}
|
||||
FileStream::~FileStream() CATCH_NOEXCEPT {}
|
||||
CoutStream::~CoutStream() CATCH_NOEXCEPT {}
|
||||
DebugOutStream::~DebugOutStream() CATCH_NOEXCEPT {}
|
||||
StreamBufBase::~StreamBufBase() CATCH_NOEXCEPT {}
|
||||
IStream::~IStream() noexcept {}
|
||||
FileStream::~FileStream() noexcept {}
|
||||
CoutStream::~CoutStream() noexcept {}
|
||||
DebugOutStream::~DebugOutStream() noexcept {}
|
||||
StreamBufBase::~StreamBufBase() noexcept {}
|
||||
IContext::~IContext() {}
|
||||
IResultCapture::~IResultCapture() {}
|
||||
ITestCase::~ITestCase() {}
|
||||
ITestInvoker::~ITestInvoker() {}
|
||||
ITestCaseRegistry::~ITestCaseRegistry() {}
|
||||
IRegistryHub::~IRegistryHub() {}
|
||||
IMutableRegistryHub::~IMutableRegistryHub() {}
|
||||
IExceptionTranslator::~IExceptionTranslator() {}
|
||||
IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() {}
|
||||
IReporter::~IReporter() {}
|
||||
IReporterFactory::~IReporterFactory() {}
|
||||
IReporterRegistry::~IReporterRegistry() {}
|
||||
IStreamingReporter::~IStreamingReporter() {}
|
||||
AssertionStats::~AssertionStats() {}
|
||||
SectionStats::~SectionStats() {}
|
||||
TestCaseStats::~TestCaseStats() {}
|
||||
TestGroupStats::~TestGroupStats() {}
|
||||
TestRunStats::~TestRunStats() {}
|
||||
CumulativeReporterBase::SectionNode::~SectionNode() {}
|
||||
CumulativeReporterBase::~CumulativeReporterBase() {}
|
||||
|
||||
StreamingReporterBase::~StreamingReporterBase() {}
|
||||
ConsoleReporter::~ConsoleReporter() {}
|
||||
CompactReporter::~CompactReporter() {}
|
||||
IRunner::~IRunner() {}
|
||||
IMutableContext::~IMutableContext() {}
|
||||
IConfig::~IConfig() {}
|
||||
XmlReporter::~XmlReporter() {}
|
||||
JunitReporter::~JunitReporter() {}
|
||||
TestRegistry::~TestRegistry() {}
|
||||
FreeFunctionTestCase::~FreeFunctionTestCase() {}
|
||||
IGeneratorInfo::~IGeneratorInfo() {}
|
||||
IGeneratorsForTest::~IGeneratorsForTest() {}
|
||||
WildcardPattern::~WildcardPattern() {}
|
||||
TestSpec::Pattern::~Pattern() {}
|
||||
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() {}
|
||||
|
||||
void Config::dummy() {}
|
||||
|
||||
namespace TestCaseTracking {
|
||||
ITracker::~ITracker() {}
|
||||
TrackerBase::~TrackerBase() {}
|
||||
SectionTracker::~SectionTracker() {}
|
||||
IndexTracker::~IndexTracker() {}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __clang__
|
||||
|
@ -9,8 +9,6 @@
|
||||
#define TWOBLUECUBES_CATCH_INTERFACES_CAPTURE_H_INCLUDED
|
||||
|
||||
#include <string>
|
||||
#include "catch_result_type.h"
|
||||
#include "catch_common.h"
|
||||
|
||||
namespace Catch {
|
||||
|
||||
@ -22,23 +20,36 @@ namespace Catch {
|
||||
struct MessageInfo;
|
||||
class ScopedMessageBuilder;
|
||||
struct Counts;
|
||||
struct BenchmarkInfo;
|
||||
struct BenchmarkStats;
|
||||
|
||||
struct IResultCapture {
|
||||
|
||||
virtual ~IResultCapture();
|
||||
|
||||
virtual void assertionStarting( AssertionInfo const& info ) = 0;
|
||||
virtual void assertionEnded( AssertionResult const& result ) = 0;
|
||||
virtual bool sectionStarted( SectionInfo const& sectionInfo,
|
||||
Counts& assertions ) = 0;
|
||||
virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0;
|
||||
virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0;
|
||||
|
||||
virtual void benchmarkStarting( BenchmarkInfo const& info ) = 0;
|
||||
virtual void benchmarkEnded( BenchmarkStats const& stats ) = 0;
|
||||
|
||||
virtual void pushScopedMessage( MessageInfo const& message ) = 0;
|
||||
virtual void popScopedMessage( MessageInfo const& message ) = 0;
|
||||
|
||||
virtual std::string getCurrentTestName() const = 0;
|
||||
virtual const AssertionResult* getLastResult() const = 0;
|
||||
|
||||
virtual void exceptionEarlyReported() = 0;
|
||||
|
||||
virtual void handleFatalErrorCondition( std::string const& message ) = 0;
|
||||
|
||||
virtual bool lastAssertionPassed() = 0;
|
||||
virtual void assertionPassed() = 0;
|
||||
virtual void assertionRun() = 0;
|
||||
};
|
||||
|
||||
IResultCapture& getResultCapture();
|
||||
|
@ -8,19 +8,20 @@
|
||||
#ifndef TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED
|
||||
|
||||
#include <iostream>
|
||||
#include "catch_common.h"
|
||||
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "catch_ptr.hpp"
|
||||
#include <memory>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct Verbosity { enum Level {
|
||||
NoOutput = 0,
|
||||
Quiet,
|
||||
Normal
|
||||
}; };
|
||||
enum class Verbosity {
|
||||
Quiet = 0,
|
||||
Normal,
|
||||
High
|
||||
};
|
||||
|
||||
struct WarnAbout { enum What {
|
||||
Nothing = 0x00,
|
||||
@ -41,11 +42,17 @@ namespace Catch {
|
||||
Auto,
|
||||
Yes,
|
||||
No
|
||||
}; };
|
||||
}; };
|
||||
struct WaitForKeypress { enum When {
|
||||
Never,
|
||||
BeforeStart = 1,
|
||||
BeforeExit = 2,
|
||||
BeforeStartAndExit = BeforeStart | BeforeExit
|
||||
}; };
|
||||
|
||||
class TestSpec;
|
||||
|
||||
struct IConfig : IShared {
|
||||
struct IConfig : NonCopyable {
|
||||
|
||||
virtual ~IConfig();
|
||||
|
||||
@ -61,8 +68,13 @@ namespace Catch {
|
||||
virtual TestSpec const& testSpec() const = 0;
|
||||
virtual RunTests::InWhatOrder runOrder() const = 0;
|
||||
virtual unsigned int rngSeed() const = 0;
|
||||
virtual int benchmarkResolutionMultiple() const = 0;
|
||||
virtual UseColour::YesOrNo useColour() const = 0;
|
||||
virtual std::vector<std::string> const& getSectionsToRun() const = 0;
|
||||
virtual Verbosity verbosity() const = 0;
|
||||
};
|
||||
|
||||
using IConfigPtr = std::shared_ptr<IConfig const>;
|
||||
}
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED
|
||||
|
@ -14,11 +14,10 @@
|
||||
#include "catch_interfaces_registry_hub.h"
|
||||
|
||||
namespace Catch {
|
||||
|
||||
typedef std::string(*exceptionTranslateFunction)();
|
||||
using exceptionTranslateFunction = std::string(*)();
|
||||
|
||||
struct IExceptionTranslator;
|
||||
typedef std::vector<const IExceptionTranslator*> ExceptionTranslators;
|
||||
using ExceptionTranslators = std::vector<std::unique_ptr<IExceptionTranslator const>>;
|
||||
|
||||
struct IExceptionTranslator {
|
||||
virtual ~IExceptionTranslator();
|
||||
@ -40,7 +39,7 @@ namespace Catch {
|
||||
: m_translateFunction( translateFunction )
|
||||
{}
|
||||
|
||||
virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const CATCH_OVERRIDE {
|
||||
std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const override {
|
||||
try {
|
||||
if( it == itEnd )
|
||||
throw;
|
||||
|
@ -1,32 +0,0 @@
|
||||
/*
|
||||
* Created by Phil on 7/8/2012.
|
||||
* Copyright 2011 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_INTERFACES_GENERATORS_H_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_INTERFACES_GENERATORS_H_INCLUDED
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct IGeneratorInfo {
|
||||
virtual ~IGeneratorInfo();
|
||||
virtual bool moveNext() = 0;
|
||||
virtual std::size_t getCurrentIndex() const = 0;
|
||||
};
|
||||
|
||||
struct IGeneratorsForTest {
|
||||
virtual ~IGeneratorsForTest();
|
||||
|
||||
virtual IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) = 0;
|
||||
virtual bool moveNext() = 0;
|
||||
};
|
||||
|
||||
IGeneratorsForTest* createGeneratorsForTest();
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_INTERFACES_GENERATORS_H_INCLUDED
|
@ -8,9 +8,10 @@
|
||||
#ifndef TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED
|
||||
|
||||
#include "catch_ptr.hpp"
|
||||
#include "catch_common.h"
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
@ -20,21 +21,32 @@ namespace Catch {
|
||||
struct IExceptionTranslator;
|
||||
struct IReporterRegistry;
|
||||
struct IReporterFactory;
|
||||
struct ITagAliasRegistry;
|
||||
class StartupExceptionRegistry;
|
||||
|
||||
using IReporterFactoryPtr = std::shared_ptr<IReporterFactory>;
|
||||
|
||||
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;
|
||||
|
||||
|
||||
virtual StartupExceptionRegistry const& getStartupExceptionRegistry() const = 0;
|
||||
};
|
||||
|
||||
struct IMutableRegistryHub {
|
||||
virtual ~IMutableRegistryHub();
|
||||
virtual void registerReporter( std::string const& name, Ptr<IReporterFactory> const& factory ) = 0;
|
||||
virtual void registerListener( Ptr<IReporterFactory> const& factory ) = 0;
|
||||
virtual void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) = 0;
|
||||
virtual void registerListener( IReporterFactoryPtr 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;
|
||||
virtual void registerStartupException() noexcept = 0;
|
||||
};
|
||||
|
||||
IRegistryHub& getRegistryHub();
|
||||
|
122
include/internal/catch_interfaces_reporter.cpp
Normal file
122
include/internal/catch_interfaces_reporter.cpp
Normal file
@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Created by Martin on 19/07/2017.
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
|
||||
#include "catch_interfaces_reporter.h"
|
||||
#include "../reporters/catch_reporter_multi.h"
|
||||
|
||||
namespace Catch {
|
||||
|
||||
ReporterConfig::ReporterConfig( IConfigPtr const& _fullConfig )
|
||||
: m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {}
|
||||
|
||||
ReporterConfig::ReporterConfig( IConfigPtr const& _fullConfig, std::ostream& _stream )
|
||||
: m_stream( &_stream ), m_fullConfig( _fullConfig ) {}
|
||||
|
||||
std::ostream& ReporterConfig::stream() const { return *m_stream; }
|
||||
IConfigPtr ReporterConfig::fullConfig() const { return m_fullConfig; }
|
||||
|
||||
|
||||
TestRunInfo::TestRunInfo( std::string const& _name ) : name( _name ) {}
|
||||
|
||||
GroupInfo::GroupInfo( std::string const& _name,
|
||||
std::size_t _groupIndex,
|
||||
std::size_t _groupsCount )
|
||||
: name( _name ),
|
||||
groupIndex( _groupIndex ),
|
||||
groupsCounts( _groupsCount )
|
||||
{}
|
||||
|
||||
AssertionStats::AssertionStats( AssertionResult const& _assertionResult,
|
||||
std::vector<MessageInfo> const& _infoMessages,
|
||||
Totals const& _totals )
|
||||
: assertionResult( _assertionResult ),
|
||||
infoMessages( _infoMessages ),
|
||||
totals( _totals )
|
||||
{
|
||||
assertionResult.m_resultData.lazyExpression.m_transientExpression = _assertionResult.m_resultData.lazyExpression.m_transientExpression;
|
||||
|
||||
if( assertionResult.hasMessage() ) {
|
||||
// Copy message into messages list.
|
||||
// !TBD This should have been done earlier, somewhere
|
||||
MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() );
|
||||
builder << assertionResult.getMessage();
|
||||
builder.m_info.message = builder.m_stream.str();
|
||||
|
||||
infoMessages.push_back( builder.m_info );
|
||||
}
|
||||
}
|
||||
|
||||
SectionStats::SectionStats( SectionInfo const& _sectionInfo,
|
||||
Counts const& _assertions,
|
||||
double _durationInSeconds,
|
||||
bool _missingAssertions )
|
||||
: sectionInfo( _sectionInfo ),
|
||||
assertions( _assertions ),
|
||||
durationInSeconds( _durationInSeconds ),
|
||||
missingAssertions( _missingAssertions )
|
||||
{}
|
||||
|
||||
|
||||
TestCaseStats::TestCaseStats( TestCaseInfo const& _testInfo,
|
||||
Totals const& _totals,
|
||||
std::string const& _stdOut,
|
||||
std::string const& _stdErr,
|
||||
bool _aborting )
|
||||
: testInfo( _testInfo ),
|
||||
totals( _totals ),
|
||||
stdOut( _stdOut ),
|
||||
stdErr( _stdErr ),
|
||||
aborting( _aborting )
|
||||
{}
|
||||
|
||||
|
||||
TestGroupStats::TestGroupStats( GroupInfo const& _groupInfo,
|
||||
Totals const& _totals,
|
||||
bool _aborting )
|
||||
: groupInfo( _groupInfo ),
|
||||
totals( _totals ),
|
||||
aborting( _aborting )
|
||||
{}
|
||||
|
||||
TestGroupStats::TestGroupStats( GroupInfo const& _groupInfo )
|
||||
: groupInfo( _groupInfo ),
|
||||
aborting( false )
|
||||
{}
|
||||
|
||||
TestRunStats::TestRunStats( TestRunInfo const& _runInfo,
|
||||
Totals const& _totals,
|
||||
bool _aborting )
|
||||
: runInfo( _runInfo ),
|
||||
totals( _totals ),
|
||||
aborting( _aborting )
|
||||
{}
|
||||
|
||||
|
||||
bool IStreamingReporter::isMulti() const { return false; }
|
||||
|
||||
void addReporter( IStreamingReporterPtr& existingReporter, IStreamingReporterPtr&& additionalReporter ) {
|
||||
|
||||
if( !existingReporter ) {
|
||||
existingReporter = std::move( additionalReporter );
|
||||
return;
|
||||
}
|
||||
|
||||
MultipleReporters* multi = nullptr;
|
||||
|
||||
if( existingReporter->isMulti() ) {
|
||||
multi = static_cast<MultipleReporters*>( existingReporter.get() );
|
||||
}
|
||||
else {
|
||||
auto newMulti = std::unique_ptr<MultipleReporters>( new MultipleReporters );
|
||||
newMulti->add( std::move( existingReporter ) );
|
||||
multi = newMulti.get();
|
||||
existingReporter = std::move( newMulti );
|
||||
}
|
||||
multi->add( std::move( additionalReporter ) );
|
||||
}
|
||||
|
||||
} // end namespace Catch
|
@ -10,47 +10,42 @@
|
||||
|
||||
#include "catch_section_info.h"
|
||||
#include "catch_common.h"
|
||||
#include "catch_totals.hpp"
|
||||
#include "catch_ptr.hpp"
|
||||
#include "catch_config.hpp"
|
||||
#include "catch_context.h"
|
||||
#include "catch_totals.hpp"
|
||||
#include "catch_test_case_info.h"
|
||||
#include "catch_assertionresult.h"
|
||||
#include "catch_message.h"
|
||||
#include "catch_option.hpp"
|
||||
|
||||
|
||||
#include <string>
|
||||
#include <ostream>
|
||||
#include <iosfwd>
|
||||
#include <map>
|
||||
#include <assert.h>
|
||||
#include <set>
|
||||
#include <memory>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
namespace Catch
|
||||
{
|
||||
struct ReporterConfig {
|
||||
explicit ReporterConfig( Ptr<IConfig const> const& _fullConfig )
|
||||
: m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {}
|
||||
explicit ReporterConfig( IConfigPtr const& _fullConfig );
|
||||
|
||||
ReporterConfig( Ptr<IConfig const> const& _fullConfig, std::ostream& _stream )
|
||||
: m_stream( &_stream ), m_fullConfig( _fullConfig ) {}
|
||||
ReporterConfig( IConfigPtr const& _fullConfig, std::ostream& _stream );
|
||||
|
||||
std::ostream& stream() const { return *m_stream; }
|
||||
Ptr<IConfig const> fullConfig() const { return m_fullConfig; }
|
||||
std::ostream& stream() const;
|
||||
IConfigPtr fullConfig() const;
|
||||
|
||||
private:
|
||||
std::ostream* m_stream;
|
||||
Ptr<IConfig const> m_fullConfig;
|
||||
IConfigPtr m_fullConfig;
|
||||
};
|
||||
|
||||
struct ReporterPreferences {
|
||||
ReporterPreferences()
|
||||
: shouldRedirectStdOut( false )
|
||||
{}
|
||||
|
||||
bool shouldRedirectStdOut;
|
||||
bool shouldRedirectStdOut = false;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct LazyStat : Option<T> {
|
||||
LazyStat() : used( false ) {}
|
||||
LazyStat& operator=( T const& _value ) {
|
||||
Option<T>::operator=( _value );
|
||||
used = false;
|
||||
@ -60,21 +55,17 @@ namespace Catch
|
||||
Option<T>::reset();
|
||||
used = false;
|
||||
}
|
||||
bool used;
|
||||
bool used = false;
|
||||
};
|
||||
|
||||
struct TestRunInfo {
|
||||
TestRunInfo( std::string const& _name ) : name( _name ) {}
|
||||
TestRunInfo( std::string const& _name );
|
||||
std::string name;
|
||||
};
|
||||
struct GroupInfo {
|
||||
GroupInfo( std::string const& _name,
|
||||
std::size_t _groupIndex,
|
||||
std::size_t _groupsCount )
|
||||
: name( _name ),
|
||||
groupIndex( _groupIndex ),
|
||||
groupsCounts( _groupsCount )
|
||||
{}
|
||||
std::size_t _groupsCount );
|
||||
|
||||
std::string name;
|
||||
std::size_t groupIndex;
|
||||
@ -84,29 +75,13 @@ namespace Catch
|
||||
struct AssertionStats {
|
||||
AssertionStats( AssertionResult const& _assertionResult,
|
||||
std::vector<MessageInfo> const& _infoMessages,
|
||||
Totals const& _totals )
|
||||
: assertionResult( _assertionResult ),
|
||||
infoMessages( _infoMessages ),
|
||||
totals( _totals )
|
||||
{
|
||||
if( assertionResult.hasMessage() ) {
|
||||
// Copy message into messages list.
|
||||
// !TBD This should have been done earlier, somewhere
|
||||
MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() );
|
||||
builder << assertionResult.getMessage();
|
||||
builder.m_info.message = builder.m_stream.str();
|
||||
Totals const& _totals );
|
||||
|
||||
infoMessages.push_back( builder.m_info );
|
||||
}
|
||||
}
|
||||
virtual ~AssertionStats();
|
||||
|
||||
# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
|
||||
AssertionStats( AssertionStats const& ) = default;
|
||||
AssertionStats( AssertionStats && ) = default;
|
||||
AssertionStats& operator = ( AssertionStats const& ) = default;
|
||||
AssertionStats& operator = ( AssertionStats && ) = default;
|
||||
# endif
|
||||
virtual ~AssertionStats() = default;
|
||||
|
||||
AssertionResult assertionResult;
|
||||
std::vector<MessageInfo> infoMessages;
|
||||
@ -117,19 +92,12 @@ namespace Catch
|
||||
SectionStats( SectionInfo const& _sectionInfo,
|
||||
Counts const& _assertions,
|
||||
double _durationInSeconds,
|
||||
bool _missingAssertions )
|
||||
: sectionInfo( _sectionInfo ),
|
||||
assertions( _assertions ),
|
||||
durationInSeconds( _durationInSeconds ),
|
||||
missingAssertions( _missingAssertions )
|
||||
{}
|
||||
virtual ~SectionStats();
|
||||
# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
|
||||
bool _missingAssertions );
|
||||
SectionStats( SectionStats const& ) = default;
|
||||
SectionStats( SectionStats && ) = default;
|
||||
SectionStats& operator = ( SectionStats const& ) = default;
|
||||
SectionStats& operator = ( SectionStats && ) = default;
|
||||
# endif
|
||||
virtual ~SectionStats() = default;
|
||||
|
||||
SectionInfo sectionInfo;
|
||||
Counts assertions;
|
||||
@ -142,21 +110,13 @@ namespace Catch
|
||||
Totals const& _totals,
|
||||
std::string const& _stdOut,
|
||||
std::string const& _stdErr,
|
||||
bool _aborting )
|
||||
: testInfo( _testInfo ),
|
||||
totals( _totals ),
|
||||
stdOut( _stdOut ),
|
||||
stdErr( _stdErr ),
|
||||
aborting( _aborting )
|
||||
{}
|
||||
virtual ~TestCaseStats();
|
||||
bool _aborting );
|
||||
|
||||
# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
|
||||
TestCaseStats( TestCaseStats const& ) = default;
|
||||
TestCaseStats( TestCaseStats && ) = default;
|
||||
TestCaseStats& operator = ( TestCaseStats const& ) = default;
|
||||
TestCaseStats& operator = ( TestCaseStats && ) = default;
|
||||
# endif
|
||||
virtual ~TestCaseStats() = default;
|
||||
|
||||
TestCaseInfo testInfo;
|
||||
Totals totals;
|
||||
@ -168,23 +128,14 @@ namespace Catch
|
||||
struct TestGroupStats {
|
||||
TestGroupStats( GroupInfo const& _groupInfo,
|
||||
Totals const& _totals,
|
||||
bool _aborting )
|
||||
: groupInfo( _groupInfo ),
|
||||
totals( _totals ),
|
||||
aborting( _aborting )
|
||||
{}
|
||||
TestGroupStats( GroupInfo const& _groupInfo )
|
||||
: groupInfo( _groupInfo ),
|
||||
aborting( false )
|
||||
{}
|
||||
virtual ~TestGroupStats();
|
||||
bool _aborting );
|
||||
TestGroupStats( GroupInfo const& _groupInfo );
|
||||
|
||||
# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
|
||||
TestGroupStats( TestGroupStats const& ) = default;
|
||||
TestGroupStats( TestGroupStats && ) = default;
|
||||
TestGroupStats& operator = ( TestGroupStats const& ) = default;
|
||||
TestGroupStats& operator = ( TestGroupStats && ) = default;
|
||||
# endif
|
||||
virtual ~TestGroupStats() = default;
|
||||
|
||||
GroupInfo groupInfo;
|
||||
Totals totals;
|
||||
@ -194,38 +145,35 @@ namespace Catch
|
||||
struct TestRunStats {
|
||||
TestRunStats( TestRunInfo const& _runInfo,
|
||||
Totals const& _totals,
|
||||
bool _aborting )
|
||||
: runInfo( _runInfo ),
|
||||
totals( _totals ),
|
||||
aborting( _aborting )
|
||||
{}
|
||||
virtual ~TestRunStats();
|
||||
bool _aborting );
|
||||
|
||||
# ifndef CATCH_CONFIG_CPP11_GENERATED_METHODS
|
||||
TestRunStats( TestRunStats const& _other )
|
||||
: runInfo( _other.runInfo ),
|
||||
totals( _other.totals ),
|
||||
aborting( _other.aborting )
|
||||
{}
|
||||
# else
|
||||
TestRunStats( TestRunStats const& ) = default;
|
||||
TestRunStats( TestRunStats && ) = default;
|
||||
TestRunStats& operator = ( TestRunStats const& ) = default;
|
||||
TestRunStats& operator = ( TestRunStats && ) = default;
|
||||
# endif
|
||||
virtual ~TestRunStats() = default;
|
||||
|
||||
TestRunInfo runInfo;
|
||||
Totals totals;
|
||||
bool aborting;
|
||||
};
|
||||
|
||||
struct BenchmarkInfo {
|
||||
std::string name;
|
||||
};
|
||||
struct BenchmarkStats {
|
||||
BenchmarkInfo info;
|
||||
size_t iterations;
|
||||
uint64_t elapsedTimeInNanoseconds;
|
||||
};
|
||||
class MultipleReporters;
|
||||
|
||||
struct IStreamingReporter : IShared {
|
||||
virtual ~IStreamingReporter();
|
||||
struct IStreamingReporter {
|
||||
virtual ~IStreamingReporter() = default;
|
||||
|
||||
// Implementing class must also provide the following static method:
|
||||
// Implementing class must also provide the following static methods:
|
||||
// static std::string getDescription();
|
||||
// static std::set<Verbosity> getSupportedVerbosities()
|
||||
|
||||
virtual ReporterPreferences getPreferences() const = 0;
|
||||
|
||||
@ -237,40 +185,47 @@ namespace Catch
|
||||
virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0;
|
||||
virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0;
|
||||
|
||||
// *** experimental ***
|
||||
virtual void benchmarkStarting( BenchmarkInfo const& ) {}
|
||||
|
||||
virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0;
|
||||
|
||||
// The return value indicates if the messages buffer should be cleared:
|
||||
virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0;
|
||||
|
||||
// *** experimental ***
|
||||
virtual void benchmarkEnded( BenchmarkStats const& ) {}
|
||||
|
||||
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; }
|
||||
|
||||
virtual bool isMulti() const;
|
||||
};
|
||||
using IStreamingReporterPtr = std::unique_ptr<IStreamingReporter>;
|
||||
|
||||
|
||||
struct IReporterFactory : IShared {
|
||||
virtual ~IReporterFactory();
|
||||
virtual IStreamingReporter* create( ReporterConfig const& config ) const = 0;
|
||||
struct IReporterFactory {
|
||||
virtual ~IReporterFactory() = default;
|
||||
virtual IStreamingReporterPtr create( ReporterConfig const& config ) const = 0;
|
||||
virtual std::string getDescription() const = 0;
|
||||
};
|
||||
using IReporterFactoryPtr = std::shared_ptr<IReporterFactory>;
|
||||
|
||||
struct IReporterRegistry {
|
||||
typedef std::map<std::string, Ptr<IReporterFactory> > FactoryMap;
|
||||
typedef std::vector<Ptr<IReporterFactory> > Listeners;
|
||||
using FactoryMap = std::map<std::string, IReporterFactoryPtr>;
|
||||
using Listeners = std::vector<IReporterFactoryPtr>;
|
||||
|
||||
virtual ~IReporterRegistry();
|
||||
virtual IStreamingReporter* create( std::string const& name, Ptr<IConfig const> const& config ) const = 0;
|
||||
virtual ~IReporterRegistry() = default;
|
||||
virtual IStreamingReporterPtr create( std::string const& name, IConfigPtr const& config ) const = 0;
|
||||
virtual FactoryMap const& getFactories() const = 0;
|
||||
virtual Listeners const& getListeners() const = 0;
|
||||
};
|
||||
|
||||
Ptr<IStreamingReporter> addReporter( Ptr<IStreamingReporter> const& existingReporter, Ptr<IStreamingReporter> const& additionalReporter );
|
||||
void addReporter( IStreamingReporterPtr& existingReporter, IStreamingReporterPtr&& additionalReporter );
|
||||
|
||||
}
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED
|
||||
|
@ -8,14 +8,16 @@
|
||||
#ifndef TWOBLUECUBES_CATCH_INTERFACES_TAG_ALIAS_REGISTRY_H_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_INTERFACES_TAG_ALIAS_REGISTRY_H_INCLUDED
|
||||
|
||||
#include "catch_tag_alias.h"
|
||||
#include "catch_option.hpp"
|
||||
#include <string>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct TagAlias;
|
||||
|
||||
struct ITagAliasRegistry {
|
||||
virtual ~ITagAliasRegistry();
|
||||
virtual Option<TagAlias> find( std::string const& alias ) const = 0;
|
||||
// Nullptr if not present
|
||||
virtual TagAlias const* find( std::string const& alias ) const = 0;
|
||||
virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0;
|
||||
|
||||
static ITagAliasRegistry const& get();
|
||||
|
@ -8,20 +8,20 @@
|
||||
#ifndef TWOBLUECUBES_CATCH_INTERFACES_TESTCASE_H_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_INTERFACES_TESTCASE_H_INCLUDED
|
||||
|
||||
#include "catch_ptr.hpp"
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
class TestSpec;
|
||||
|
||||
struct ITestCase : IShared {
|
||||
struct ITestInvoker {
|
||||
virtual void invoke () const = 0;
|
||||
protected:
|
||||
virtual ~ITestCase();
|
||||
virtual ~ITestInvoker();
|
||||
};
|
||||
|
||||
using ITestCasePtr = std::shared_ptr<ITestInvoker>;
|
||||
|
||||
class TestCase;
|
||||
struct IConfig;
|
||||
|
||||
|
33
include/internal/catch_leak_detector.cpp
Normal file
33
include/internal/catch_leak_detector.cpp
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Created by Martin on 12/07/2017.
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
|
||||
#include "catch_leak_detector.h"
|
||||
|
||||
|
||||
namespace Catch {
|
||||
|
||||
#ifdef CATCH_CONFIG_WINDOWS_CRTDBG
|
||||
#include <crtdbg.h>
|
||||
|
||||
LeakDetector::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
|
||||
|
||||
LeakDetector::LeakDetector(){}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
17
include/internal/catch_leak_detector.h
Normal file
17
include/internal/catch_leak_detector.h
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Created by Martin on 12/07/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_LEAK_DETECTOR_H_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_LEAK_DETECTOR_H_INCLUDED
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct LeakDetector {
|
||||
LeakDetector();
|
||||
};
|
||||
|
||||
}
|
||||
#endif // TWOBLUECUBES_CATCH_LEAK_DETECTOR_H_INCLUDED
|
@ -1,60 +0,0 @@
|
||||
/*
|
||||
* Created by Phil on 6th April 2013.
|
||||
* Copyright 2013 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_LEGACY_REPORTER_ADAPTER_H_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_H_INCLUDED
|
||||
|
||||
#include "catch_interfaces_reporter.h"
|
||||
|
||||
namespace Catch
|
||||
{
|
||||
// Deprecated
|
||||
struct IReporter : IShared {
|
||||
virtual ~IReporter();
|
||||
|
||||
virtual bool shouldRedirectStdout() const = 0;
|
||||
|
||||
virtual void StartTesting() = 0;
|
||||
virtual void EndTesting( Totals const& totals ) = 0;
|
||||
virtual void StartGroup( std::string const& groupName ) = 0;
|
||||
virtual void EndGroup( std::string const& groupName, Totals const& totals ) = 0;
|
||||
virtual void StartTestCase( TestCaseInfo const& testInfo ) = 0;
|
||||
virtual void EndTestCase( TestCaseInfo const& testInfo, Totals const& totals, std::string const& stdOut, std::string const& stdErr ) = 0;
|
||||
virtual void StartSection( std::string const& sectionName, std::string const& description ) = 0;
|
||||
virtual void EndSection( std::string const& sectionName, Counts const& assertions ) = 0;
|
||||
virtual void NoAssertionsInSection( std::string const& sectionName ) = 0;
|
||||
virtual void NoAssertionsInTestCase( std::string const& testName ) = 0;
|
||||
virtual void Aborted() = 0;
|
||||
virtual void Result( AssertionResult const& result ) = 0;
|
||||
};
|
||||
|
||||
class LegacyReporterAdapter : public SharedImpl<IStreamingReporter>
|
||||
{
|
||||
public:
|
||||
LegacyReporterAdapter( Ptr<IReporter> const& legacyReporter );
|
||||
virtual ~LegacyReporterAdapter();
|
||||
|
||||
virtual ReporterPreferences getPreferences() const;
|
||||
virtual void noMatchingTestCases( std::string const& );
|
||||
virtual void testRunStarting( TestRunInfo const& );
|
||||
virtual void testGroupStarting( GroupInfo const& groupInfo );
|
||||
virtual void testCaseStarting( TestCaseInfo const& testInfo );
|
||||
virtual void sectionStarting( SectionInfo const& sectionInfo );
|
||||
virtual void assertionStarting( AssertionInfo const& );
|
||||
virtual bool assertionEnded( AssertionStats const& assertionStats );
|
||||
virtual void sectionEnded( SectionStats const& sectionStats );
|
||||
virtual void testCaseEnded( TestCaseStats const& testCaseStats );
|
||||
virtual void testGroupEnded( TestGroupStats const& testGroupStats );
|
||||
virtual void testRunEnded( TestRunStats const& testRunStats );
|
||||
virtual void skipTest( TestCaseInfo const& );
|
||||
|
||||
private:
|
||||
Ptr<IReporter> m_legacyReporter;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_H_INCLUDED
|
@ -1,84 +0,0 @@
|
||||
/*
|
||||
* Created by Phil on 6th April 2013.
|
||||
* Copyright 2013 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_LEGACY_REPORTER_ADAPTER_HPP_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_HPP_INCLUDED
|
||||
|
||||
#include "catch_legacy_reporter_adapter.h"
|
||||
|
||||
namespace Catch
|
||||
{
|
||||
LegacyReporterAdapter::LegacyReporterAdapter( Ptr<IReporter> const& legacyReporter )
|
||||
: m_legacyReporter( legacyReporter )
|
||||
{}
|
||||
LegacyReporterAdapter::~LegacyReporterAdapter() {}
|
||||
|
||||
ReporterPreferences LegacyReporterAdapter::getPreferences() const {
|
||||
ReporterPreferences prefs;
|
||||
prefs.shouldRedirectStdOut = m_legacyReporter->shouldRedirectStdout();
|
||||
return prefs;
|
||||
}
|
||||
|
||||
void LegacyReporterAdapter::noMatchingTestCases( std::string const& ) {}
|
||||
void LegacyReporterAdapter::testRunStarting( TestRunInfo const& ) {
|
||||
m_legacyReporter->StartTesting();
|
||||
}
|
||||
void LegacyReporterAdapter::testGroupStarting( GroupInfo const& groupInfo ) {
|
||||
m_legacyReporter->StartGroup( groupInfo.name );
|
||||
}
|
||||
void LegacyReporterAdapter::testCaseStarting( TestCaseInfo const& testInfo ) {
|
||||
m_legacyReporter->StartTestCase( testInfo );
|
||||
}
|
||||
void LegacyReporterAdapter::sectionStarting( SectionInfo const& sectionInfo ) {
|
||||
m_legacyReporter->StartSection( sectionInfo.name, sectionInfo.description );
|
||||
}
|
||||
void LegacyReporterAdapter::assertionStarting( AssertionInfo const& ) {
|
||||
// Not on legacy interface
|
||||
}
|
||||
|
||||
bool LegacyReporterAdapter::assertionEnded( AssertionStats const& assertionStats ) {
|
||||
if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) {
|
||||
for( std::vector<MessageInfo>::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end();
|
||||
it != itEnd;
|
||||
++it ) {
|
||||
if( it->type == ResultWas::Info ) {
|
||||
ResultBuilder rb( it->macroName.c_str(), it->lineInfo, "", ResultDisposition::Normal );
|
||||
rb << it->message;
|
||||
rb.setResultType( ResultWas::Info );
|
||||
AssertionResult result = rb.build();
|
||||
m_legacyReporter->Result( result );
|
||||
}
|
||||
}
|
||||
}
|
||||
m_legacyReporter->Result( assertionStats.assertionResult );
|
||||
return true;
|
||||
}
|
||||
void LegacyReporterAdapter::sectionEnded( SectionStats const& sectionStats ) {
|
||||
if( sectionStats.missingAssertions )
|
||||
m_legacyReporter->NoAssertionsInSection( sectionStats.sectionInfo.name );
|
||||
m_legacyReporter->EndSection( sectionStats.sectionInfo.name, sectionStats.assertions );
|
||||
}
|
||||
void LegacyReporterAdapter::testCaseEnded( TestCaseStats const& testCaseStats ) {
|
||||
m_legacyReporter->EndTestCase
|
||||
( testCaseStats.testInfo,
|
||||
testCaseStats.totals,
|
||||
testCaseStats.stdOut,
|
||||
testCaseStats.stdErr );
|
||||
}
|
||||
void LegacyReporterAdapter::testGroupEnded( TestGroupStats const& testGroupStats ) {
|
||||
if( testGroupStats.aborting )
|
||||
m_legacyReporter->Aborted();
|
||||
m_legacyReporter->EndGroup( testGroupStats.groupInfo.name, testGroupStats.totals );
|
||||
}
|
||||
void LegacyReporterAdapter::testRunEnded( TestRunStats const& testRunStats ) {
|
||||
m_legacyReporter->EndTesting( testRunStats.totals );
|
||||
}
|
||||
void LegacyReporterAdapter::skipTest( TestCaseInfo const& ) {
|
||||
}
|
||||
}
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_H_INCLUDED
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user