Compare commits

...

621 Commits

Author SHA1 Message Date
2a3606f8e3 v1.11.0 2017-10-31 13:55:48 +01:00
a6cf19abff Make Approx::margin inclusive
Fixes #952, related to #980
2017-10-30 21:33:29 +01:00
06586b7180 Update test-cases-and-sections.md
some clarification and typo correction
2017-10-26 13:57:18 +02:00
93b3d2cb8f Fix very minor typo
it's -> its
2017-10-24 20:00:27 +02:00
a90473df28 Update build-systems.md
typo correction
2017-10-24 19:59:59 +02:00
c9d9699ca8 adds flushes to the output stream of teamcity reporter, making the test output more responsive. 2017-10-17 16:42:05 +02:00
296955c437 RandomNumberGenerator::result_type should be unsigned (#1050)
`result_type` must be unsigned:
http://en.cppreference.com/w/cpp/concept/UniformRandomBitGenerator

Using a signed type causes an infinite loop working with MS Visual Studio 2017, targetting: v140, WindowsTargetPlatformVersion 10.0.15063.0, Debug, x64
2017-10-15 18:30:40 +02:00
664cbf702c added PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS option 2017-10-15 17:58:39 +02:00
fb6700df54 Fix documentation crosslink in configuration.md 2017-10-14 08:36:44 +02:00
da6c2a6914 Fixed expansion of _FALSE binary expression
- see #1051
2017-10-13 19:44:20 +01:00
9c07718b5f Update handling of __JETBRAINS_IDE__ macro
1. Use it to conditionally define CATCH_INTERNAL_CONFIG_COUNTER, not
   CATCH_CONFIG_COUNTER, as __JETBRAINS_IDE__ is similar to
   compiler-provided macros, not to user-provided ones.

2. Since __COUNTER__ will work starting with CLion 2017.3, use it
   when possible (and hopefully remove this check altogether
   at some point).
2017-09-07 18:00:04 +02:00
5ca44b6872 Minor - added header-only flag in conan
See header-only guidelines: 
http://conanio.readthedocs.io/en/latest/howtos/header_only.html?highlight=header%20only
Its borderline cosmetic, but it does have a purpose.
2017-08-28 12:18:54 +02:00
a04bd6d436 Remove duplicate CLI option
The "use-colour" option was accidentally duplicated as part of commit
feaf355 (Implemented libidentify support).
2017-08-28 12:16:23 +02:00
784f6dfb34 Fix updateVcpkgPackage 2017-08-27 11:43:55 +02:00
7818e2666d v1.10.0 2017-08-26 15:34:18 +02:00
cd30dd1a70 Workaround raw string literal bug in VS2017 2017-08-26 15:14:27 +02:00
8e8c0c1675 Tweaked how failedButOk assertions are recorded
- fixes issue where sections in !shouldfail or !mayfail test cases that have failing assertions where marked as failed instead of failedButOk
2017-08-25 11:37:49 +01:00
b6e7c9bd7a Specialise removeConst for nullptr 2017-08-24 23:07:44 +02:00
180d9242f5 Suppress more signed/ unsigned mismatches during Evaluator calls on MSVC 2017-08-24 23:07:03 +02:00
b7bd52cc98 Cherry-picked "evaluate" refactoring from dev-modernize branch
- fixed up NULL comparisons to allow for NULL being a long
- should address #981
2017-08-24 23:07:03 +02:00
b07a2bdf87 Refactor release scripts, automatically update Wandbox on release 2017-08-24 21:59:06 +02:00
c03e8fce92 Explicitly ignore return value of getchar
This silences MSVC warning about ignored return value
2017-08-22 22:06:37 +02:00
27640a5a96 Added Clara and TextFlowCpp to open source users 2017-08-17 10:49:56 +01:00
dd3867bbcd Create CODE_OF_CONDUCT.md 2017-08-17 07:45:12 +01:00
387f8d254d Removed unnecessary single quotes 2017-08-15 19:41:46 +01:00
c65eccd68e Added --libidentify and --wait-for-keypress to docs 2017-08-15 19:39:38 +01:00
61c5675c11 Removed inadvertent use of auto merged from dev-modernise 2017-08-15 19:34:10 +01:00
70e4af9d44 Implemented wait-for-keypress option 2017-08-15 14:12:11 +01:00
8f41bdb92d Add open-source user 2017-08-13 17:55:50 +02:00
7fa5d9ca94 Removed redundant processName argument from libIdentify call 2017-08-11 22:03:09 +01:00
feaf355489 Implemented libidentify support
- see https://github.com/janwilmans/LibIdentify
2017-08-11 19:55:55 +01:00
2ce6c74f8f v1.9.7 2017-08-11 00:01:20 +02:00
9688891868 Fix issue with fatal errors and non-failing assertions
Fixes #990
2017-08-10 21:44:54 +02:00
4f21bb72ff Add tests for #961 2017-08-10 21:38:07 +02:00
b435e0d7c7 Make default reporter configurable at compile time
Closes #978
2017-08-10 16:45:38 +02:00
ba0a09fd9e Update documentation with changes from 7e4038d 2017-08-10 16:43:17 +02:00
7e4038d848 Capture std::clog writes and combine them with std::cerr writes (#989)
This also introduces Catch::clog() method to allow embedded targets
to override std::clog usage with their own stream (presumably null-sink),
similarly to how Catch::cout() and Catch::cerr() are used.

Fixes #989
2017-08-09 15:28:40 +02:00
92d714ee12 Update updateVcpkgPackage script for the new port format 2017-08-08 23:04:39 +02:00
705a1bf527 Add wandbox to release process documentation
Also some formatting and wording changes.
2017-08-08 23:04:10 +02:00
d5613fb18a Update matchers docs to reflect namespace usage 2017-08-03 19:11:21 +02:00
62875c857e Add a landing page link to wandbox with catch preloaded
Idea shamelessly stolen from nlohmann/json
2017-08-01 23:45:35 +02:00
ec2074e558 Adding more flexibility into the cmake catch parsing script (#971)
* Adding more flexibility into the cmake catch parsing script
2017-08-01 17:33:53 +02:00
7575749e56 Fix compilation error on older compilers 2017-08-01 17:21:06 +02:00
8a2ff20982 Address some of the Resharper finds for Catch 1
Closes #957 as the other findings are mostly noise that is pointless
to fix in a branch that will be soon EoLd.
2017-07-31 12:31:45 +02:00
d3377c791d Initial support for native IBM i ILE C++ (#976)
* - Initial support for native IBM i ILE C++

Signed-off-by: zeromem <zeromem2@gmail.com>
2017-07-31 10:47:42 +02:00
c5dfa73d56 Disable build broken by travis changes
It should be reenabled later, but I don't have time to investigate
right now.
2017-07-29 08:45:52 +02:00
d65091fa06 Fix for JUnit reporter when using dynamically generated sections (#963)
* BySectionInfo should also take into account the section name in addition to the source code line
2017-07-23 17:13:44 +02:00
7a22bad763 Addressed some static analysis warnings
Based on findings in #957
2017-07-19 09:50:08 +02:00
8ebe94ca2e Added NOLINT annotations to selectively suppress clang_tidy warnings 2017-07-10 18:43:07 +01:00
106d7e2a74 Initialize JunitReporter::unexpectedExceptions in constructor
This is not needed for correctness, but will prevent PVS warning
from triggering, and there is basically no performance difference.

Closes #951
2017-07-10 10:30:17 +02:00
a53ea30723 Eliminate some work when results won't be reported. 2017-07-07 01:34:12 +02:00
8d380a7399 added 'args' argument parser library 2017-07-05 15:55:28 +02:00
3083de9ea6 Fix typo in README 2017-07-05 15:54:38 +02:00
431e8d06e7 Added survey monkey link 2017-07-04 09:10:36 +01:00
6f32db35af Update tutorial.md 2017-06-28 20:54:31 +02:00
7013e388f7 #926 Update Conan test version by release
Signed-off-by: Uilian Ries <uilianries@gmail.com>
2017-06-28 16:45:42 +01:00
0270afb21b Updated license 2017-06-28 16:44:46 +01:00
df7c5622b9 Merge branch 'feature/conan' of https://github.com/uilianries/Catch 2017-06-27 11:48:55 +01:00
ee67ac6b7c v1.9.6 2017-06-27 12:21:48 +02:00
8a14af701e If --list-extra-info is specified with --list-test-names-only, only output one list 2017-06-25 17:12:29 +02:00
07c6bfc3b9 --extra-info -> --list-extra-info, behaves like other --list-* flags 2017-06-25 17:12:29 +02:00
616f7235ef add --extra-info flag
this will add line info to test lists, and test descriptions to the long
form of the test list
2017-06-25 17:12:29 +02:00
396ecf6021 Cache std::ostringstream between assertions.
This is not thread safe, but I think that was already true of Catch.
The construction/destruction of the std::ostringstream is where the
vast majority of time is spent per assertion.  A simple test of
100000000 CHECK()s is reduced from around 60s to 7.4s
2017-06-25 15:53:59 +02:00
3491804598 #926 Update Conan version by release
- Update release scripts to increment Conan version

Signed-off-by: Uilian Ries <uilianries@gmail.com>
2017-06-23 16:03:36 -03:00
6234e3d54d #926 Conan recipe for Catch single header
- Insert catch.hpp (single header) to package
- Copy BDDTests and TrickyTest to validate Catch package

Signed-off-by: Uilian Ries <uilianries@gmail.com>
2017-06-23 10:34:56 -03:00
a6cdcd43aa Added "How to test changes in PR" section to documentation
Also linked it from PR template.

Closes #936
2017-06-22 18:56:10 +02:00
dcab8a5971 Performance improvement in AssertionInfo.
By using char const * instead of std::string we avoid significant
copying per assertion.  In a simple loop with 10000000 CHECKS on
my system, this reduces the run time from 9.8s to 6s.
2017-06-22 18:03:47 +02:00
017a63da62 v1.9.5 2017-06-15 13:08:26 +02:00
b90d0b7267 Disable deprecation warning of std::uncaught_exception
We might prefer to use `std::uncaught_exceptions` in the future, but I
would prefer not to bring in more configuration into Catch Classic

Closes #927
2017-06-15 11:43:31 +02:00
efba988ccc Fix how GCC version is detected when checking for __COUNTER__
Fixes #928
2017-06-13 18:20:59 +02:00
004228efb2 Merge pull request #855 from kainjow/objc-tostring-link
Fix Catch::toString() linker error when main() is compiled as C++
2017-06-11 23:06:38 +01:00
e0aaba6cf8 Actually link #923 from the documentation 2017-06-06 16:46:46 +02:00
a09bef23ed Refer to #923 in reporter documentation 2017-06-06 16:43:14 +02:00
3e018ef131 Add link to external gcov/lcov example to documentation
An alternate take on #916, that better slots into the existing
documentation.

Closes #916
2017-06-04 12:17:59 +02:00
adb66f55a7 Don't include warning headers from catch_xmlwriter.hpp
This prevents Catch from disabling `Wpadded` for Clang inside test files
(files that do not define either `CATCH_CONFIG_MAIN` or
`CATCH_CONFIG_RUNNER`).

catch_suppress_warnings.h and catch_reenable_warnings.h should be
included only once*, so that the stitching script includes them as the
first and last header respectively, since it only includes each header
once. This caused a bug, where the first one was included properly, but
the second one was included prematurely, from catch_xmlwriter.hpp, and
thus was guarded by `CATCH_IMPL`.

* At least until the stitching script is changed to accomodate common
warning disabling header.

Fixes #871
2017-06-02 19:10:57 +02:00
377c9a746d Cosmetic fixes (whitespace and spelling) 2017-05-27 14:42:54 +02:00
ea48ae0f75 Add test for #914 (stringify truthy exprs in standard way) 2017-05-27 14:42:05 +02:00
2d1739b429 ExpressionLhs reconstruction based on value, not truthiness (#914)
Types which are truthy, but have more information than the truthiness in their string conversion were showing up as 'true' or 'false' instead of showing the underlying type's string value.
2017-05-27 14:09:43 +02:00
1c59034be4 Merge pull request #911 from dvirtz/master
CTest integration script enhancements
2017-05-27 13:52:55 +02:00
52a84788e0 Add Inscopix to commercial users
Closes #918
2017-05-27 12:23:35 +02:00
3e328f55fc Merge pull request #913 from Carrotstrip/master
fixed spelling error in tutorial.md
2017-05-21 11:17:25 +02:00
b18e67522f fixed spelling error 2017-05-20 15:10:42 -04:00
4b086bd5b5 added target name to test name and labels 2017-05-18 16:00:18 +03:00
aac594aae3 add option to print debug messages 2017-05-18 15:53:35 +03:00
a49fa0edbe use absolute path to test files - accroding to CMake docs EXISTS behavior is well-defined only for full paths. 2017-05-18 15:51:44 +03:00
d271683c14 Added release process notes/checklist/explanation 2017-05-16 21:33:58 +02:00
0bb8e1247e Merge branch 'master' of https://github.com/awglyde/Catch 2017-05-16 16:09:51 +02:00
32d97caf42 Fixed missing ` in tag documentation 2017-05-16 15:45:44 +02:00
bc93b29789 Expanded tag documentation
It now mentions that most characters are valid as part of tag and other
details.

Closes  #909
2017-05-16 15:28:53 +02:00
df5cf2d323 Minor fixup in updateVcpkgPackage.py 2017-05-16 14:34:55 +02:00
b62c0256b2 Merge branch 'master' of https://github.com/philsquared/Catch 2017-05-16 14:34:27 +02:00
1ea84cb734 Expanded logging documentation
Closes #884
2017-05-16 14:34:20 +02:00
2a5d3736e8 Merge pull request #908 from pJunger/patch-1
Typo: Added namespace in method testCaseEnded
2017-05-16 14:05:31 +02:00
3dcc923351 v1.9.4 2017-05-16 13:59:29 +02:00
589c40077b Typo fix
Somehow I made that in 5ffc8a84cd without noticing
2017-05-16 13:51:17 +02:00
d4e0b1d093 Added namespace in method testCaseEnded
Did not compile as is
2017-05-14 14:11:47 +02:00
b8443e67da Added Win32 UNICODE wmain support (#903)
* Added wmain support
* Added appveyor.yml wmain configuration
* Added wmain configuration flag to CMake
2017-05-11 13:00:03 +02:00
5604ec7266 Updated toString documentation
It will need another update when Catch 2 goes live.

Closes #741
2017-05-03 21:09:27 +02:00
6f012f2d1d Added warning if source file cannot be found
If source files are defined using relative paths, CMake will compile the tests, but this script will (sometimes) fail to find and parse the tests from the source files.  I have added an explicit warning when ParseAndAddCatchTests fails to find a source file.
2017-05-01 19:55:17 +02:00
98e61c31df Approval tests now see different line endings as ok
This is mostly to deal with WSL, where git will checkout file with CRLF,
but code that uses formatted output will be writing LFs.
2017-04-29 18:06:36 +02:00
e641485132 Updated approval tests 2017-04-29 17:54:10 +02:00
a3ceb8f007 Approval tests now can deal with different expansions of errno 2017-04-29 17:52:12 +02:00
b819432271 Don't clear out all messages upon printing an assertion.
Previously, this would not print out any messages for the last CHECK
```cpp
TEST_CASE("Foo") {
INFO("Test case start");
for (int i = 0; i < 2; ++i) {
INFO("The number is " << i);
CHECK(i == 0);
}
CHECK(false);
}
```

now it does.
2017-04-29 17:50:03 +02:00
9ceae8f51f CMake binaries are now conditionally enabled
Defining NO_SELFTEST=1 when cmake configuration is being done now turns
off SelfTest and Benchmark executables. This is for projects that
consume Catch using ExternalProject_Add and don't want to build our
selftest binaries for their unit test suite.

Closes #897
2017-04-28 20:27:10 +02:00
5ffc8a84cd Fix order of arguments in CATCH_FAIL and nonvariadic INTERNAL_CATCH_MSG
Fixes #896
2017-04-28 18:30:04 +02:00
6e0fa4be68 Update opensource-users.md
Fixed broken link to LICENSE
2017-04-27 10:29:58 +02:00
a0ada2e935 v1.9.3 2017-04-25 14:23:06 +00:00
e4694f58da Removed errant uses of uint64_t
fixes #894
2017-04-25 14:15:59 +00:00
fc7f0a02b8 v1.9.2 2017-04-25 11:08:02 +02:00
211b330346 Don’t unconditionally #include <stdint.h> (as earlier MSVC don’t have it) 2017-04-25 08:43:14 +01:00
d36fe214a6 Further tweaked alignment hack for Option 2017-04-25 08:38:25 +01:00
a34c053f0a All of Approx's member functions now accept strong typedefs
Previously `Approx::operator()`, `Approx::epsilon`, `Approx::margin` and
`Approx::scale` didn't.

Closes #888
2017-04-24 22:01:45 +02:00
4cdb203ec3 Improve documentation about using Catch with CMake
Also added a note about the `contrib/ParseAndAddCatchTests.cmake`
script.

Closes #882
2017-04-24 16:27:43 +02:00
8014bf1124 cmake script to generate ctest definitions from catch tests: fix for test case body bracket 2017-04-24 13:33:04 +02:00
49d87cf182 Add Newsbeuter to OSS users list (#891) 2017-04-22 16:02:55 +02:00
eedcc82d31 Tweaked storage alignment "workaround" a bit more in Option. 2017-04-21 07:19:39 +01:00
8e8259091c Fix .travis.yml syntax 2017-04-20 22:54:17 +02:00
7869e5b007 Enable C++11 and C++14 on OSX on Travis 2017-04-20 22:52:41 +02:00
a49af4648c Minor .travis.yml cleanup
Still could use someone more experienced to clean it up properly...
2017-04-20 22:50:07 +02:00
417b2bcf5c Enable C++14 on Linux on Travis 2017-04-20 22:47:05 +02:00
8f0feaa6d2 Enable /std:c++latest (C++17) for AppVeyor VS 2017 2017-04-20 21:32:50 +02:00
b95163bd3a Don't enable POSIX signals under QNX
Fixes #889
2017-04-20 21:02:25 +02:00
2809be87cc “fixed” alignment in Option 2017-04-20 14:39:07 +01:00
ac369b7b83 Add script that helps with updating the Vcpkg package.
Kind of a hackjob, that assumes vcpkg is already checked out
and is next to the Catch's directory.
2017-04-11 17:25:04 +02:00
1aa3e4abfa Add CMake script to generate ctest definitions from Catch tests (#879)
Added cmake script to parse the source files containing Catch's test and generate ctest definitions.

It generates one ctest test per `TEST_CASE` and labels them, using the `TEST_CASE`'s tags.

Closes #719.
2017-04-11 16:51:02 +02:00
e5c5a636a9 junit reporter does not count exceptions as failures if ok-to-fail 2017-04-11 15:47:42 +01:00
2bf30e9e5a Use (locally defined) UInt64 instead of uint64_t
- typedefs long long for MSVC
- typedefs uint64_t otherwise

Should probably do finer grained compiler checking - but this should at least be better than what was there before
2017-04-11 15:06:25 +01:00
b591cb9a03 Added note about thread safety in assertions
- closes #875
2017-04-11 14:25:19 +01:00
714d01c07c approved tests that were correct the first time (previous approvals were erroneous) 2017-04-09 20:40:11 +01:00
c6990cdf91 v1.9.1 release 2017-04-09 21:25:20 +02:00
da8786b8fd Unexpected exception are no longer ignored by default
What an embarassing bug, I'll have to look into why it wasn't caught by
any of Catch's self-tests.

Fixes #885 and closes #887 (duplicate)
2017-04-09 21:20:58 +02:00
5577322062 Added Nonius to open-sources users 2017-04-08 22:47:13 +01:00
1b03c5ab6a v1.9.0 release 2017-04-07 22:56:36 +02:00
7dd3c19027 Added NASA to commercial users list 2017-04-07 19:12:13 +01:00
29d26d3179 Commented out unused argument 2017-04-07 11:36:54 +01:00
ca764ec8d9 TeamCity reporter “ignores” failures in tests marked “ok to fail”
- also don’t report hidden/ not-selected tests
2017-04-07 11:15:37 +01:00
250f0ee7fb Added approvals for “failed as expected” tests 2017-04-07 09:33:19 +01:00
09e4830199 Added VS2017 to AppVeyor matrix 2017-04-06 11:01:49 +02:00
8f85d08e9f Give up on _Pragma for gcc, force disable Wparentheses in all TUs 2017-04-05 21:37:27 +02:00
3ae076ce8d Updated REQUIRE* documentation under FAST_COMPILE 2017-04-05 10:26:19 +02:00
94425ad59b Add opt-in c++11 stream insertable check. (#877)
* Add opt-in c++11 stream insertable check.

To opt-in, define CATCH_CONFIG_CPP11_STREAM_INSERTABLE_CHECK.

Opt-in fixes #872 and should fix #757 as well.
2017-04-05 09:53:10 +02:00
0354d50278 Added templated constructor to C++11 Approx
When using C++11, comparison operators are already templated to take
anything that can be explicitly converted to double, but constructor
took only doubles. This lead to warnings when an `Approx` was
constructed from floats, which was problematic for some users.

Since just adding float constructor would be a large breaking change, as
suddenly `Approx( 1 )` would become ambiguous, I added a templated
constructor that will take anything that is explicitly convertible to
double. This has the added benefit of allowing constructing `Approx`
instances from instances of strong typedefs, ie allowing
`calculated_temp == Approx( known_temp)`.

Closes #873
2017-04-04 15:19:15 +02:00
cdd83c2e15 Fmt and tag fixup for #876
Github wouldn't let me push to the PR, probably because it was made from
fork of a fork...
2017-04-04 11:31:13 +02:00
9a07dde16d print messages when unexpected exceptions are thrown 2017-04-04 11:27:19 +02:00
6e091d3991 Reset the UnexpectedException report state 2017-04-03 11:48:50 +02:00
95d85fb186 Fixed up CATCH_CONFIG_FAST_COMPILE for REQUIREs
Unexpected exceptions no longer cause abort and there should be no more
potential for false negatives.

The trade-off now is that exceptions are no longer translated.
2017-04-03 11:36:55 +02:00
3a3f152979 Updated documentation of CATCH_CONFIG_FAST_COMPILE 2017-03-29 21:13:51 +02:00
4fe2432e05 Rework of REQUIRE* changes in CATCH_CONFIG_FAST_COMPILE
`ResultBuilder`s destructor now checks for exceptions, preventing false
negatives. The speedup should remain the same give or take a tiny bit.
2017-03-29 21:12:06 +02:00
c3a41e26a7 Suppress -Wexit-time-destructors in Catch code
This is another warning that follows test macros, making it painful to
suppress without leaking outside. Luckily clang's `_Pragma`
implementation works.

Should fix #308
2017-03-29 20:30:59 +02:00
4838039b65 Merge pull request #869 from mloskot/patch-1
Add nanodbc library to Catch users
2017-03-27 07:43:27 +01:00
2a221b8fcd Add nanodbc library to Catch users 2017-03-26 21:26:08 +02:00
79ce6930a2 remove redundant "/"
This "/" is not needed as CMake adds this automatically
2017-03-23 21:18:07 +01:00
d762a7ca6c Expanded documentation about THROWS_AS assertions 2017-03-23 21:16:52 +01:00
f23b6b8b85 Don't sanitize exception type in REQUIRE_THROWS_AS
Effectively a revert of previous commit, fixing #542, where this was
added to stop linters complaining about `REQUIRE_THROWS_AS` used like
`REQUIRE_THROWS_AS(expr, std::exception);`, which would be slicing the
caught exception. Now it is user's responsibility to pass us proper
exception type.

Closes #833 which wanted to add `typename`, so that the construct works
in a template, but that would not work with MSVC and older GCC's, as
having `typename` outside of a template is allowed only from C++11
onward.
2017-03-23 21:11:21 +01:00
4597b43912 Throw instead of calling exit in RegistrarForTagAliases constructor
Caries a problem vis-a-vis Windows, just like previous commit, but that
can be fixed later on.

Closes #866
2017-03-22 18:40:07 +01:00
f64d914bff Throw instead of calling exit in enforceNotReservedTag
Closes #865
2017-03-22 17:53:22 +01:00
d07999ddff Version struct now uses char* for holding branch name
Since the info is constant, and the only use is to write it out during
runtime, there is no need for `std::string`.
2017-03-22 17:45:36 +01:00
e04dc5105b use inline 'libraryVersion()' function (closes #858) 2017-03-22 15:51:02 +01:00
cffb031ce1 Added polymorphic_value to OSS users 2017-03-22 10:33:52 +00:00
f3ec843ba6 Changed all internal forwarding macro usages to put macro name as first argument
(and ‘expression’, if any, last)
This is a first step towards allowing expression arguments to become variadic
2017-03-21 13:23:35 +00:00
55ed17f97b Removed stray define 2017-03-20 10:53:32 +01:00
6a502cc2f5 Renamed licence file, license should now be detected by github 2017-03-20 08:59:25 +01:00
6a009fabcb Documented REQUIRE under CATCH_CONFIG_FAST_COMPILE 2017-03-17 17:02:39 +01:00
7a8a0205b4 CATCH_CONFIG_FAST_COMPILE now disables trys in REQUIRE*
This seems to give about 15% speedup when compiling tests using GCC.

The tradeoff is that under certain circumstances, there is a chance for
false negative result, when the expression under test throws exception
and the test code catches it before it gets to the test runner.

Example:
``` cpp
TEST_CASE("False negative") {
try {
REQUIRE(throws() == "");
} catch (...) {}
}
```
This test case will succeed, reporting no assertions checked, instead of
failing as it would with `CATCH_CONFIG_FAST_COMPILE` disabled. However,
just removing the try-catch block inside client's code will fix this, so
it is worthwhile.

This change does not apply to CHECK* macros, because these are currently
specified as continuing on exception and thus need the local try-catch
to work as intended.
2017-03-17 13:21:40 +01:00
4dc06bdb70 Use bulk vector::insert rather than back_inserter 2017-03-15 15:19:38 +00:00
08b597b3e2 Merge pull request #856 from lightmare/script-exec-perm
Set execute permission on runnable python scripts
2017-03-15 11:44:40 +00:00
46d166406d Set execute permission on runnable python scripts 2017-03-15 12:24:18 +01:00
4ec8d53e91 Tag Alias registry is part of registry hub instead of it’s own singleton
- should now be cleaned up properly
2017-03-15 09:45:37 +00:00
e7984e3711 Reorganised the readme/ ref docs TOC and added link to reporters docs 2017-03-15 09:08:20 +00:00
90d89377ea Added docs on reporters 2017-03-15 09:07:23 +00:00
0692317bc5 Added Obj-C bindings fix to release notes 2017-03-15 09:04:09 +00:00
e8b31108d6 Fix Catch::toString() linker error when main() is compiled as C++
Fixes #278
2017-03-14 11:54:14 -07:00
95fc8d62a2 Fixed up old documentation links in release notes 2017-03-13 21:31:26 +01:00
0c015aa887 v1.8.2 release 2017-03-13 21:29:30 +01:00
f69f821853 Updatecd [!shouldFail] docs with extra explanatory note, 2017-03-13 19:35:17 +00:00
485dbdc0e7 Added link to event listeners docs 2017-03-13 19:27:18 +00:00
0afd52b98d Fix Objective-C Matchers
Fixes #854
2017-03-13 15:40:21 +00:00
38b05f1400 Don’t assume first CL arg (exe name) is present
Fixes #729
2017-03-13 11:00:58 +00:00
db9866677e Don’t ref past end of string
fixes #830
2017-03-13 10:22:02 +00:00
4101ff314a #include <ctype> for std::to lower 2017-03-10 19:25:00 +00:00
68da5a6d19 Docs for Listeners 2017-03-10 19:17:25 +00:00
e4a25ad5ff Added CATCH_REGISTER_LISTENER without the INTERNAL_ prefix 2017-03-10 19:15:03 +00:00
5d6c744d38 Qualified std::tolower in Clara.
Fixes #543
2017-03-10 18:38:52 +00:00
5dd0639520 Added FAIL_CHECK
Works like FAIL, but does not abort test.
As proposed in #765
2017-03-08 15:42:11 +00:00
a2515755c3 Merge pull request #846 from m0ppers/patch-1
Add ArangoDB
2017-03-07 11:34:07 +00:00
807941eb31 Add ArangoDB 2017-03-07 12:29:13 +01:00
a2e20b07f8 "Fix" build by annotating the new test as !shouldfail
The quick test under ctest checks only for no tests failing, not for the
expected output.
2017-03-07 10:17:59 +01:00
ace70407a2 Add tests for #835
Also add ErrnoGuard before `isatty` call, because apparently it can set
errno to 25 (ENOTTY).
2017-03-06 22:07:33 +01:00
613e1466f9 Save errno before using sprintf, ifstream.
std::ifstream in libstdc++ contains a bug, where it sets errno to zero.
To work around it, we manually save the errno before using std::ifstream
in debugger check, and reset it after we are done.

We also preventively save errno before using sprintf.

Fixes #835
2017-03-06 21:51:22 +01:00
d8f45cd5f1 changing tabs to spaces 2017-03-06 10:55:00 -05:00
3afd077b55 teamcity reporter should time durations explicitly 2017-03-06 10:35:03 -05:00
e95bf48445 Take std::string by const-ref where possible
Most places already do, this brings over some forgotten places.

Also close #842
2017-03-06 13:16:43 +01:00
932a405e18 /Wx -> /WX (stupid typo) 2017-03-06 11:29:57 +01:00
9a037204fa Enable /Wx (Warnings as error) for SelfTest builds 2017-03-06 11:21:35 +01:00
374c050a42 benchmarkCompile.py fixup 2017-03-06 10:59:17 +01:00
8b8e3ee117 Disable C4702 in Exception tests self tests
VS 2015 in Release mode sees through our indirection and complains.
There is no reason to make the indirectoin harder to reason about,
instead of just disabling the warning.
2017-03-06 10:52:21 +01:00
af1ed708e4 Copied release note fixes to documentation 2017-03-06 10:46:21 +01:00
041498b221 Fixed unintentional tabs 2017-03-06 09:23:31 +00:00
d5a5883a10 Fixed mssing virtual destructor warnings
In Visual Studio with warning 4265 enabled
Closes #844
2017-03-06 08:59:52 +00:00
6fea473414 Fixed CMake generation of MSVC warning levels 2017-03-06 08:35:14 +00:00
68e7fdce20 Added 4265 to specific warnings in VS 2017-03-06 08:21:52 +00:00
b4c9bf5802 Removed version # from readme
- and script that updates it (as it’s now automatically in a badge)
2017-03-03 15:40:32 +00:00
e952fa8946 Added release badge 2017-03-03 15:25:58 +00:00
84a178f0b0 Add AppVeyor status 2017-03-03 14:38:20 +00:00
f9db24a824 Refactored console reporter include logic to match Xml Reporter’s 2017-03-03 14:19:41 +00:00
9bee606dd6 Tweaked Xml Reporter to follow same success/ info behaviour as Console reporter 2017-03-03 14:12:47 +00:00
be4f6ab8e1 Change reporting of CAPTURE'd variables
Info is not changed, intentionally.

Closes #639
2017-03-03 14:34:50 +01:00
fd6c7aee6d Fixed compile benchmark script
Now it no longer attempts to enter a directory before creating it...
2017-03-02 18:27:31 +01:00
cd6de9cd34 Don't reconstruct expression on encountering fatal error
In some cases, like when given

```cpp
std::vector<char>* str =
reinterpret_cast<std::vector<char>*>(0x1234458);
CHECK(*str == std::vector<char>());
```

reconstructing the expression to report it would cause another fatal
error. Instead we just put together an AssertionResult without
reconstructing the expression fully.

This should fully fix #810
2017-03-02 18:18:28 +01:00
40f6a5b8a4 Added duration reporting to compact reporter
Also made the duration formatting code available to all reporters.

Closes #780
2017-03-02 16:16:17 +01:00
95b0eb2b6c TAP reporter now behaves as if -s was always set
This should fulfill the TAP specification better.
2017-03-02 15:54:08 +01:00
0b28d3daf2 Merge branch 'tap-count-success' of https://github.com/gahr/Catch 2017-03-02 15:23:46 +01:00
8435dcbb61 Resized main logo again 2017-03-01 17:00:33 +00:00
99347df70e Updated artwork 2017-03-01 16:47:04 +00:00
658b5f63ef Updated release notes 2017-03-01 16:06:48 +00:00
c6535a080e v1.8.1 release 2017-03-01 16:04:44 +00:00
673ec550f5 Moved definition of _BSD_SOURCE earlier 2017-03-01 15:59:10 +00:00
ff78e7c45a Fixed typo in test name 2017-03-01 15:59:10 +00:00
da023b2f9a TAP Reporter: count success tests even if not printed
This fixes a bug whereas running the TAP reporter without the -s switch
causes the reporter to print 1..0.
2017-03-01 09:24:58 +00:00
470561cbbd Update release-notes.md
Removed speed up time placeholder
2017-03-01 08:24:16 +00:00
417202b743 Update release-notes.md
Fixed docs/ paths
2017-03-01 08:22:38 +00:00
0952b76e16 v1.8.0 release 2017-02-28 14:19:09 +00:00
bbeb192ec9 Updated baselines 2017-02-27 16:27:43 +01:00
e4f4335b07 Improved Approx documentation 2017-02-27 14:22:17 +01:00
8c07899715 Added tests for using margin with Approx. 2017-02-27 14:15:03 +01:00
d5c623b3b6 Merge branch 'develop' of https://github.com/CNugteren/Catch
This adds an optional absolute margin to the Approx checks.
2017-02-27 13:12:13 +01:00
061a183036 Console reporter now uses fixed decimal formatting
3 decimal places, output in seconds.
2017-02-27 11:34:15 +01:00
70ac6dbb9f Minor output improvements in approvalTests.py 2017-02-24 15:56:26 +01:00
593161ddd8 Documented the new vector matchers 2017-02-24 15:42:11 +01:00
71e500f4b5 Updated reporter documentation 2017-02-24 14:01:38 +01:00
ad942885ce Removed unused exception object from release notes script 2017-02-23 08:11:15 +00:00
e058a37614 Removed stray code 2017-02-23 08:11:15 +00:00
72b72ca937 Fix C++11 dependency in TAP reporter 2017-02-22 17:04:36 +01:00
a8a6b3159d Disabled C4312 in the evaluate layer
We reinterpret cast int to T* (because someone might compare 0 to a
ptr), which causes 4312 to fire when x64 platform is set.

Fixes #148
2017-02-22 14:14:59 +01:00
9e2616aeac Add missing assert.h include to reporter bases.
It being missing caused an error when compiling under MSVC.
2017-02-22 13:31:51 +01:00
c5ffd2e3f0 Fixed up Automake reporter 2017-02-22 13:29:17 +01:00
0f24a8c06f Added Automake and TAP reporters to SelfTest's main 2017-02-22 13:28:36 +01:00
b0260c615d Fixed-up TAP reporter a bit. 2017-02-22 13:28:13 +01:00
a63ce953a0 Add TAP reporter
This is a hackish attempt to add a TAP reporter (see
philsquared/Catch#309 ) by following the TAP 12 specification
<http://testanything.org/tap-specification.html>. I'm unsure how well I
did in following the spec or with following good C++ guidelines.
Comments are appreciated.

Signed-off-by: Colton Wolkins (Ogre) <frostyfrog2@gmail.com>
2017-02-22 11:35:20 +01:00
b753f05d74 Add reporter for Automake (#826)
This allows for integration with Automake's default log compiler.

See #826 for more details.
2017-02-22 11:17:25 +01:00
9bab7c8229 Changed console reporter test duration reporting format
Was
"<section-name> completed in XXX s."
Now is
"XXX s: <section-name>"

Closes #322

(cherry picked from commit 0805539)
2017-02-22 08:35:53 +00:00
d8c4512b25 Removed tabs 2017-02-22 08:26:52 +00:00
2e08bfe9cc Single include generator now handles spaces between # and include 2017-02-22 08:05:31 +00:00
d2a59ad37b Fixed test spec parser issue
- multiple specs in a single string, with escapes in each were erroring out
2017-02-22 07:49:38 +00:00
10dfca34ac Added first vector matchers (Contains and Equals) 2017-02-21 16:05:04 +00:00
45d4096756 Generalised Matchers so objects and comparators can be different types 2017-02-21 15:52:03 +00:00
4e6938d78e Moved matchers tests into their own file 2017-02-21 14:19:09 +00:00
1ca8cefa9a Added #define needed for gettimeofday() to be declared on some versions of Cygwin 2017-02-21 11:32:32 +00:00
ca66dd243c Added a couple more unimplemented assignment operators to silence VS2013 warnings 2017-02-21 09:10:44 +00:00
44632c3d71 Merge branch 'warning-c4512' of https://github.com/gchudnov/Catch into gchudnov-warning-c4512 2017-02-21 08:56:14 +00:00
aa28196e8b Ignore .vs folder 2017-02-21 08:52:08 +00:00
5d8055319e Updated docs to reflect the change to leak checking 2017-02-18 17:24:31 +01:00
b1835e1de9 Moved WIndows leak detector code out of main() 2017-02-17 23:43:31 +00:00
8cd413572a Merge branch 'dev-windows-leakdetection' 2017-02-17 14:25:08 +01:00
30e4dbef1c Report leaks to debugger in addition to stderr
This branch should also close #120.
2017-02-17 14:22:57 +01:00
90b3946e9c Add file/line to TestCase, Section and Failure elements in Xml Reporter 2017-02-17 10:26:17 +00:00
9202a77498 Documentation improvement 2017-02-16 11:11:52 +01:00
d8230a8d4d Add opt-in leak detection under MSVC + Windows.
Closes #439
2017-02-16 11:09:09 +01:00
c6178601c5 Cygwin compatibility fixes 2017-02-15 17:57:22 +01:00
2e0ae01b05 Improve -Wparentheses supression for gcc
If the gcc version supports `_Pragma` properly, we use that to disable
it locally inside assertions.

Otherwise we disable it for the entire TU.

Fixes #674
2017-02-15 17:11:44 +01:00
1f71d1f760 Some minor clean-up to Python script 2017-02-15 11:54:47 +00:00
fe690a68ef push/pop warnings when disabling parentheses warnings within assertion (gcc/ clang) 2017-02-15 10:03:28 +00:00
c9a37c59c4 Added CATCH_CONFIG_FAST_COMPILE to documentation. 2017-02-15 10:42:11 +01:00
3cfef738e7 Merge branch 'dev-performance-round3' 2017-02-15 10:35:01 +01:00
5cb9e47034 Added SOCI to open-source users 2017-02-15 08:39:21 +00:00
044b616127 Added link to matchers docs from readme 2017-02-15 08:30:47 +00:00
f88049169e Fix wrong short option for section 2017-02-15 08:17:43 +01:00
7b13a8f85a Move debug break out of tests, speeds up compilation time
This is hidden behind CATCH_CONFIG_FAST_COMPILE
2017-02-14 15:35:12 +01:00
6da5e0862a Benchmark script: allow passing flags to compiler 2017-02-14 15:34:17 +01:00
2049113935 Benchmark script: use median AND mean of compile time 2017-02-14 15:34:00 +01:00
d4ae1b18c0 Matcher documentation 2017-02-14 09:16:54 +00:00
2081caa452 Import MatcherBase to Catch namespace 2017-02-14 09:16:54 +00:00
a5a013811c Renamed toStringUncached -> describe 2017-02-14 09:16:54 +00:00
1400127d6f Extracted string matchers impl into cpp that is only compiled into main TU 2017-02-14 09:16:54 +00:00
7fed25ad1f New Matchers implementation
- simpler
- less templates and machinery
- no cloning, copying or unnecessary heap allocations
- better factored
2017-02-14 09:16:54 +00:00
5530303be7 Removed test for invoking String Matcher with NULL (this will no longer be supported) 2017-02-14 09:16:54 +00:00
29fa1edcc7 Added appveyor.yml for CI with VS {2013, 2015} for {Win32, x64} 2017-02-14 09:37:37 +01:00
1cb8bafb1f Added missing #include in test file 2017-02-13 17:43:43 +00:00
d08cee288f v1.7.2 build 2017-02-13 16:15:42 +00:00
873ef276b6 XML Reporter closes tag and flushes stream at end of TestCase and Section tags.
This fixes an issue where XML reports on stdout are broken by printf statements
2017-02-13 15:56:25 +00:00
bc68b9f454 More include simplifications 2017-02-13 14:12:22 +01:00
67d513aa73 Removed single char contains()
- had incorrect prototype anyway
2017-02-13 08:20:45 +00:00
9a3486a705 Replaced use of dynamic_cast with static_cast.
It wasn't necessary anyway.
This addresses #821
2017-02-12 22:00:17 +00:00
d890791800 Fixed editing mishap in documentation. 2017-02-12 15:48:32 +01:00
26f6012bb9 Expanded the practical example in slow-compiles documentation 2017-02-12 14:47:25 +01:00
50dee9ae57 Fixed typo in CLI error reporting 2017-02-12 13:50:15 +01:00
b2a6fe971b Couple more includes cleaned out 2017-02-12 12:48:25 +01:00
0837132ce3 Make the benchmarking script Python 2 compatible
Ended up using `time.time()`, even if it supposedly has worse accuracy,
because Python running under WSL supports `time.clock()` very badly.
2017-02-12 12:25:43 +01:00
9012f95964 Moved some std includes out from catch_common.h 2017-02-12 12:17:07 +01:00
324260f253 Removed reference to DEBUG in command line docs 2017-02-11 23:39:38 +00:00
d0620c3495 Added std:: qualification to some functions from C stdlib
This should solve #543, once Clara changes are in as well.
2017-02-11 23:20:09 +01:00
fd7dde10d3 Added example of how to separately compile Catch's main
Closes #632
2017-02-11 19:11:57 +01:00
9a3788d98c Added links to open source users page from general pages 2017-02-10 22:50:40 +00:00
005787f1c5 Marked IConfig implementations in Config CATCH_OVERRIDE
(silences warnings)
2017-02-10 22:39:27 +00:00
d2e814ff23 Tagged a C++11 specific test with [c++11] to exclude from approval tests (for now) 2017-02-10 19:13:45 +00:00
f75a511b5c Fix MSVC /analyze warning about inconsistent annotations 2017-02-10 17:12:41 +01:00
ab44fb6811 The file/ line in sections is now of the section. not the test case 2017-02-10 11:56:46 +00:00
d6b8ac5a4e Added compilation tests to approvals 2017-02-10 11:53:29 +00:00
c72ba93f92 Added file for listing commercial users 2017-02-09 17:54:13 +00:00
73159ace3d REQUIRE_THROWS_AS now catches exception by const&
Prevents some warnings caused by catching complex types by value.

Closes #542
2017-02-09 12:57:01 +01:00
9952dda524 REQUIRE_THROWS_AS is now reported with expected type as well
Also updated tests to reflect this change.
2017-02-09 12:51:43 +01:00
e543cc0646 Removed an obsolete file that somehow got into the previous master. 2017-02-09 11:12:25 +01:00
c1a5391034 Added some more open source projects 2017-02-08 21:47:07 +00:00
a38ccec33a Added 3rd party bug to documentation 2017-02-08 20:53:39 +01:00
1ff56301a1 Corrected formatting 2017-02-08 18:35:30 +00:00
aee3675968 Added ChakraCore, Couchbase-lite and MAME rot OS projects 2017-02-08 18:34:19 +00:00
0579f07092 Added RxCpp to OS page 2017-02-08 18:02:11 +00:00
e9ad954435 Seeded new doc page for tracking open source projects that use Catch 2017-02-08 17:15:37 +00:00
1e87cae8af Documented the _THROWS_WITH macros, as well as slightly expanding the matchers docs. 2017-02-08 16:18:53 +00:00
26df0781a5 Added a script for running synthetic compile time benchmark 2017-02-08 14:15:01 +01:00
4d0cd602e3 Rebased approvals with tags and description attributes in XML report 2017-02-07 23:14:49 +00:00
ab199d9cf9 XmlReporter: Trim test case name; added description and tags attributes to the test case element in the xml report. 2017-02-07 23:12:58 +00:00
97d8003a71 XmlWriter can specify a stylesheet
Provide an extension point on XmlReporter to be able to supply a stylesheet url in a derived implementation
2017-02-07 23:09:43 +00:00
1f271c9944 XmlWriter reverts to XML 1.0.
Character encodings that are not valid in XML 1.0 are instead written using C-style escapes
2017-02-07 22:48:06 +00:00
7db4d8d90c Added tests (single char pretty printing + op overload)
Tests for issue #809 -- Potentional operator overload ambiguity -- and
PR #646 -- Pretty print characters.
2017-02-07 13:32:48 +01:00
a5ce57b346 Improved .travis.yml
* Removed ccache (it was slowing down the compilation for some reason)
* Enabled some C++11 builds (gcc 4.8, gcc 6, clang 3.8 for now)
* Added gcc 4.4, 4.7 and clang 3.4
2017-02-07 11:56:34 +01:00
7b8a27eadb v1.7.1 build 2017-02-07 10:06:52 +01:00
2b74613c54 Revert "First cut of Evaluate refactoring to remove int specialisations, among other things"
This reverts commit 39753558eb.
2017-02-06 22:37:23 +00:00
23600609c0 Deregister SEH handler before reporting SE. 2017-02-06 20:40:46 +01:00
4feb2dbb50 Removed const qualification to disambiguate between operator overloads 2017-02-06 20:39:32 +01:00
84af6bc955 XmllWriter flushes the stream after every endElement now 2017-02-06 16:25:36 +00:00
197bf075c4 Rebased again - against the right executable this time :-s 2017-02-06 16:25:09 +00:00
1f5ec9884c Rebased approvals following previous reversal (d’oh!) 2017-02-06 16:23:34 +00:00
88b760276d Revert "XmlWriter reverts to XML 1.0."
This reverts commit a189387f49.
2017-02-06 16:21:01 +00:00
23eb4cc580 Added stdout and stderr to XML Reporter 2017-02-06 16:14:06 +00:00
a189387f49 XmlWriter reverts to XML 1.0.
Character encodings that are not valid in XML 1.0 are instead written using C-style escapes
2017-02-06 16:00:05 +00:00
f65776890c Merge branch 'master' of https://github.com/philsquared/Catch 2017-02-06 15:17:00 +00:00
39753558eb First cut of Evaluate refactoring to remove int specialisations, among other things 2017-02-06 15:15:43 +00:00
f126d7943a Add explanation of THROW assertion limits + using lambda 2017-02-06 16:08:13 +01:00
cd489d9647 More documentation of known issues.
Closes #315
2017-02-06 15:55:01 +01:00
e991c006b7 Fixes for MinGW compatibility
Some versions of MinGW do not support enough of Win32 API to let us work
with SEH, so SEH is now MSVC only (+ configurable toggle).

Also made use of gmtime_s MSVC only (as oposed to Windows only).

Fixes #805
2017-02-06 01:43:53 +01:00
7e7c813486 New documentation section: "known limitations"
It contains known limitation such as the fact that Catch is not thread
safe, it does not support running tests in forked process or running
multiple tests in parallel

closes #399
closes #681
closes #246
closes #483
2017-02-06 00:53:39 +01:00
712323ab7c Include windows.h proxy header, instead of windows.h itself
Because the signal changes were in a different branch from the windows.h
related changes, the SEH handling code included the header directly.

Fixes #803
2017-02-03 14:09:17 +01:00
ce37f48ffa v1.7.0 build 2017-02-01 21:47:43 +01:00
090fc74cca Scripts intended to be run should now have x bit set. 2017-02-01 21:34:45 +01:00
f58ff0c540 Remove \l, add \f in character pretty printing
I have never head of \l and MSVC warns about unknown escape sequence, so
I changed it into \f that definitely exists and potentially might be
useful.
2017-02-01 21:31:14 +01:00
a600bfeb75 Fix travis build + build warnings
The cmake download was failing, so we were relying on the old cmake,
which I broke recently (in 7ae96c710b).
Now the download should work again.

Also fixed warning that the requested OSX image no longer exists and
that it is automatically substituted for xcode 7.3 image.
2017-02-01 21:01:14 +01:00
8cad76a749 typo 2017-02-01 14:39:06 +00:00
1a3f6d829b Updated command line docs with info on -c for running sections, as well as -# for filenames as tags 2017-02-01 14:37:02 +00:00
b524fa7cd8 Fixed bugs in escape char handling in test names
1. If escape char is first char, sets start of range
2. Multiple escape chars are handled (offsets chars to remove)
2017-02-01 14:13:20 +00:00
5121b5b058 Put quote marks around printed characters; also nicely print some escapes 2017-01-31 21:53:36 +01:00
1e5176bd69 Cap main exit code to 255 (#797)
Changed default main to clamp exit code to 8 bits because of POSIX limitations.

Updated documentation about declaring non-default main.
2017-01-31 20:48:14 +01:00
7dd4f2977a Added INSTALL commands (#788)
Added INSTALL commands - this is especially useful when adding dependencies (such as CATCH) by using the ExternalProject_Add command
2017-01-31 20:22:45 +01:00
50c95a0143 Bumped min cmake version to 3.0
Now we can use target_compile_option to privately add warnings to our
build, without polluting outside CXX_FLAGS.
2017-01-31 20:21:03 +01:00
0dabd951ba expr is now cast to void in THROWS family of assertions.
This prevents Clang from complaining about unused value in expressions
containing explicit casts used in the THROW assertion macro family.

Example:
`REQUIRE_THROWS_AS(static_cast<bool>(object), std::bad_cast);` would
trigger `-Wunused-value` warning. Now it does not.

Credits to Arto Bendiken, who submitted a PR almost 3 years ago, but his
branch has since died and I was unable to merge it.
2017-01-31 18:02:11 +01:00
7ae96c710b Returned basic warnings to CMake generated builds 2017-01-31 17:37:27 +01:00
70d3c937c3 Enable breaking into debugger on Mac
The integrated assembler segment was missing an underscore:
"_asm__". Also we remove the "DEBUG" macro check, so we are consistent
with the linux and windows variant.
Now breaking into gdb on failure should work via:
	gdb --args test_executable --break
2017-01-31 16:00:42 +00:00
38af8d7035 Fixed SEH deregistration on Windows
Should fix #796
2017-01-30 19:54:16 +01:00
c97ada1910 Improved assertion documentation
Mentioned that decomposing `&&` and `||` is not supported, gave examples
+ possible workarounds.

Closes #621, #787, #341 and maybe others I haven't found.
2017-01-30 19:42:27 +01:00
615aa071a8 Merge branch 'dev-performance-round2' 2017-01-30 13:02:48 +01:00
af0b03abd2 Merge branch 'templates' 2017-01-30 12:03:01 +01:00
15816c5760 Revert "use sizeof(expr) for unevaluated syntax check"
Using sizeof(expr) can trigger a compile-time error,
"lambda expressions are not allowed in an unevaluated context", when passing
expression containing lambda, like a std algorithm. This error is considered
a standard defect, as it is meant to prevent lambdas in decltype
or templates, but not in sizeof.

This reverts commit 227598af47.
2017-01-30 11:56:29 +01:00
f11a45aa67 Added benchmark for the char literals change 2017-01-29 23:23:33 +01:00
bcaa2f9646 Use char literal instead of string literal with 1 char
In reality, this is a relatively small performance improvement,
especially with the previous improvements removing lots of superfluous
string handling, but still was measurable.
2017-01-29 23:07:15 +01:00
efab3ca8b2 Added benchmark result for the SourceLineInfo change 2017-01-29 22:10:37 +01:00
60f8ebec49 Use const char* for filename in SourceLineInfo
This is sane, because those `const char*`s are given to us by compiler,
from the text area and thus we do not have to manage their lifetimes. We
also never want to change them.

Also moved copy constructor to compiler-generated methods, not sure why
it wasn't -- even before it was the same as a compiler would generate.
2017-01-29 22:03:27 +01:00
e1dbb7cf64 First draft of issue and PR templates.
Apparently we can also get contributing.md to be linked from
issues and PRs, but it would also have to be in .github folder
or in root of the project.
2017-01-28 11:42:11 +01:00
02a69b449f Compilation warnings fix (#791)
* Compilation warnings fix

* Removed unused argument from reportFatal function
2017-01-27 09:32:58 +01:00
c390c4cb9f Fixed inconsistent and trailing whitespace
This means that all tabs used in indentation are now 4 spaces and that
there should be no more trailing whitespace.

Ill also look into creating a pre-commit hook that will prevent this
from happening in the future.

Fixes #105
2017-01-26 23:13:12 +01:00
60a9ac7e65 Enabled previous commit under MSVC, introduced new feature toggle 2017-01-26 18:47:29 +01:00
c06afe438e Add support for comparison of Approx with strong typedefs
closes #652
2017-01-26 18:44:03 +01:00
73872207db Direct download link now links to latest release version
Also edited releaseCommon script to update the link in readme as well.
2017-01-26 13:12:19 +01:00
51860f1568 Change include -> single_include in CMake example 2017-01-26 10:24:48 +01:00
dab1d9d222 Added CheckFileList in CMake over the benchmark sources 2017-01-25 23:02:25 +01:00
4ce11d63a6 Merge branch 'dev-performance' 2017-01-25 22:56:36 +01:00
99c2ea594c Renamed measurement script for benchmarking 2017-01-25 22:55:11 +01:00
51107d7cbd Added copyright headers to benchmark files. 2017-01-25 22:42:41 +01:00
83f4b39680 Added benchmark for previous commit, added iterations to failure bench. 2017-01-25 22:39:43 +01:00
b1171bd1f2 Merge branch 'dev-signals' 2017-01-25 22:09:52 +01:00
6c23a6582b Mark CHECKed-throw test as [failing] 2017-01-24 09:53:04 +00:00
7bcb42496d Changed exception tests to allow for now throw-from-CHECK behaviour 2017-01-23 17:56:41 +00:00
184865358c CHECK no longer stops running SECTION on exception.
This seems to be much closer to desired behaviour than the current one, where
CHECK(false) lets the execution continue, but CHECK(<throws>) does not.
2017-01-23 17:52:17 +00:00
225e90d8ba Don’t include tests that rely on varying two-phase-lookup behaviour in approval tests 2017-01-23 17:47:58 +00:00
31c23b9489 Added [!nonportable] tag 2017-01-23 17:44:55 +00:00
f347611403 Restated text format loop to avoid out-of-bounds condition 2017-01-23 16:58:49 +00:00
1efd8d3067 Added missing <iterator> #include 2017-01-23 15:19:42 +00:00
876af874f3 Added surrogate cpp for catch_test_case_tracker 2017-01-23 15:18:23 +00:00
e7bcbb35c0 First cut of -c/—section option for running specific sections 2017-01-23 12:36:03 +00:00
4a04682e49 Text formatting rework
Rewrote main wrapping loop. Now uses iterators instead of indices and intermediate strings.
Differentiates between chars to wrap before, after or instead of.
Doesn’t preserve trailing newlines.
Wraps or more characters.
Dropped support for using tab character as an indent setting control char.
Hopefully avoids all the undefined behaviour and other bugs of the previous implementation.
2017-01-23 12:28:40 +00:00
9a56609569 v1.6.1 build 2017-01-20 12:49:59 +01:00
81159838a5 Python scripts can now be run directly from bash 2017-01-20 12:28:40 +01:00
78a2866dc7 Approval tests are now mostly Windows compatible
There are some differences in output between Catch on Windows and
Catch on Linux, that indicate a minor bug, but those have to be fixed separately.
2017-01-19 23:56:31 +01:00
9acc6b9673 Approval tests now use Python std lib instead of call to diff
This needed to change to let it run on Windows as well as on the Unices
2017-01-19 22:52:47 +01:00
c4b5057094 Approval tests now uses path relative to cwd, not the catch folder.
This means that bash's autocompletion is actually helpful.
2017-01-19 22:08:51 +01:00
d38b9266e7 simplify output filtering in approvalTests.py 2017-01-19 22:04:29 +01:00
227598af47 use sizeof(expr) for unevaluated syntax check 2017-01-19 21:25:27 +01:00
cfaf906417 Changed documentation to use standard main function signature 2017-01-19 17:05:01 +01:00
ee0ca512ea Force short-circuited evaluation for types that have overloaded &&.
This fixes #574.
2017-01-17 23:31:03 +01:00
b71a06cf98 JUnit reporter outputs timestamps now
Also extended approval tests script to support the change
2017-01-16 20:21:43 +01:00
531d26739f Added the new proxy header to CMakeLists.txt 2017-01-16 19:56:57 +01:00
2e87f8e328 Merge branch 'windows-header-defines' of https://github.com/horenmar/Catch 2017-01-16 17:00:43 +01:00
afe46ff270 Extracted NOMINMAX and WIN32_LEAN_AND_MEAN guards into a proxy header 2017-01-16 16:52:44 +01:00
c65aeaf25f Clean up generator state 2017-01-16 10:34:16 +00:00
750b52b814 suppress use of __COUNTER__ when being parsed by CLion (or AppCode). 2017-01-16 10:34:16 +00:00
e12fc4aca0 Fix missing CATCH_ for CHECK_THAT in prefixed macro version 2017-01-15 22:11:43 +01:00
99cdc62fef Enabled CMake dev warnings in travis. 2017-01-15 22:08:12 +01:00
e6ef60a2c4 CMake will now warn if a file is in folder, but not in variable 2017-01-15 22:07:36 +01:00
e1c4a4bd9b Use inline assembly with gcc under Linux for CATCH_TRAP
This is more convenient than using the generic portable raise(SIGTRAP) as it
avoids having another stack frame in the debugger when the break happens.
2017-01-15 19:29:34 +01:00
25d017763b Refactor CATCH_BREAK_INTO_DEBUGGER() to avoid repetition
Don't duplicate Catch::isDebuggerActive() check many times, do it just once
in CATCH_BREAK_INTO_DEBUGGER() definition and use a separate CATCH_TRAP()
macro for the really platform-dependent part.
2017-01-15 19:29:34 +01:00
b634e592da Add support for breaking into debugger for Linux
Use Linux-specific /proc/$PID/status file to check whether we're being
debugged and a generic raise(SIGTRAP) to actually break into the debugger.
2017-01-15 19:29:34 +01:00
3b98a0166f Various small string usage performance improvements.
* Empty strings are now direct constructed as `std::string()`, not as empty string literals.
* `startsWith` and `endsWith` no longer construct new a string. This should be an improvement
for libstdc++ when using older standards, as it doesn't use SSO but COW and thus even short
strings are expensive to first create.
* Various places now use char literal instead of string literals containing single char.
** `startsWith` and `endsWith` now also have overload that takes single char.

Generally the performance improvements under VS2015 are small, as going from short string
to char is mostly meaningless because of SSO (Catch doesn't push string handling that hard)
and previous commit removed most string handling if tests pass, which is the expect case.
2017-01-15 10:05:01 +01:00
877fd523bc Added benchmark with Mickey Rose's improvements. 2017-01-14 22:51:44 +01:00
a1e9b841ff lazily stringify expressions 2017-01-14 21:56:16 +01:00
3b7511e564 First commit of benchmarks for Catch runtime perf.
So far its very much a WIP with some problems that are known already and
not very representative tests.
2017-01-14 21:55:37 +01:00
ffc4a9dc14 If we receive a signal, we re-register ALL previous signal handlers.
This fixes the case when we pass signal to previously registered
handler, and it needs to transform the signal into different one.

Still problematic: What if the signal handler we replaced does not
terminate the application? We can end up in a weird state and loop
forever.

Possible solution: Deregister our signal handlers, CALL the previous
signal handler explicitly and if control returns, abort. This would
however complicate our code quite a bit, as we would have to parse the
sigaction we delegate to, decide whether to use signal handler or signal
action, etc...
2017-01-14 15:21:44 +01:00
7c8b93eac3 Removed superfluous comments (bad merge after cherry pick). 2017-01-14 15:08:00 +01:00
e3659cdddd Added single char version of logo 2017-01-13 18:49:49 +00:00
40dbdf6cb2 Reset signals immediately after use and re-raise orginal signal instead of just exiting 2017-01-12 17:31:56 +01:00
70f43d719b Added signal handling under Windows.
Only some "signals" are handled under Windows, because Windows does not
use signals per-se and the mechanics are different. For now, we handle
sigsegv, stack overflow, div-by-zero and sigill. We can also
meaningfully
add various floating point errors, but not sigterm and family, because
sigterm is not a structured exception under Windows.

There is also no catch-all, because that would also catch various
debugger-related exceptions, like EXCEPTION_BREAKPOINT.
2017-01-12 16:40:14 +01:00
a281173099 Fix for sigsegv stack overflow behavior
Also stops Catch from assuming its the only signal user in the binary,
and makes it restore the signal handlers it has replaced. Same goes for
the signal stack.

The signal stack itself probably shouldn't be always reallocated for
fragmentation reasons, but that can be fixed later on.
2017-01-12 16:23:55 +01:00
b3907a78e1 Added NOMINMAX and WIN32_LEAN_AND_MEAN defines before including windows.h
This stops the `windows.h` header from defining `min` and `max` macros
and including lot of Windows APIs that are not needed by Catch.
2017-01-12 16:00:02 +01:00
d5360e8e29 Sorted file lists in CMakeLists.txt for easier maintainence 2017-01-12 11:54:53 +00:00
9062ebe390 Removed make file (now generated from CMake) 2017-01-12 11:22:30 +00:00
e6aa1f4e4e Added note on escaping names on command line to docs 2017-01-11 17:14:28 +00:00
1ff0acfe22 Tweaked release notes page with better formatting 2017-01-11 16:50:35 +00:00
713ec400e8 Fixed type in “Release Notes” link 2017-01-11 16:46:09 +00:00
3b2f206191 v1.6.0 build - including release notes 2017-01-11 16:44:36 +00:00
4e4d733f90 Added \ as escape character in test names on the command line - so you can run tests by name when they contain , or [ 2017-01-11 16:27:16 +00:00
b68e8f9a24 Added missing #include so CATCH_CONFIG_COUNTER properly takes into account the current compiler.
May address #677 and #435 and others.
2017-01-11 16:27:16 +00:00
a7cda91d4d Merge pull request #775 from philsquared/standardizing-feature-toggles
Standardize C++11 feature toggles to follow documentation
2017-01-11 16:27:05 +00:00
a1bed572be Standardize C++11 feature toggles to follow documentation
Closes #774
2017-01-10 22:54:57 +01:00
737f4ea77c Added missing C++11 feature toggle to docs 2017-01-10 22:43:58 +01:00
b0de6c938a Updated docs for contributing 2017-01-10 07:36:06 +00:00
6991549457 Fixed compile error under VS2015 /c++:latest, caused by using random_shuffle
Now if we detect C++11 compiler, or MSVC in version corresponding to VS2015,
we switch from using `std::random_shuffle` to `std::shuffle`.

`std::random_shuffle` was officially deprecated in C++14, and removed in C++17.

Also removed guarded inclusion of `<random>` header, as there was nothing
in the header that used it.
2017-01-09 23:29:13 +01:00
b50572bbfd Renamed missing project explainer filename 2017-01-09 21:59:53 +00:00
5b00fd40ba Merge pull request #767 from hmich/xml-encoder-extended-ascii
Do not encode extended ASCII characters in XML reporter
2017-01-09 18:37:52 +00:00
7bb3e859aa Removed all manually maintained project files in favour of instructions on how to use CMake to generate them 2017-01-09 17:38:42 +00:00
0bcae64d3d Set project name in CMakeLists.txt to CatchSelfTest 2017-01-09 17:38:42 +00:00
8abe17a393 CMake project groups test files separately from surrogate impl files for nicer rendering as XCode/ VS projects 2017-01-09 17:38:42 +00:00
10c44847f4 Make backticks symmetric in markdown 2017-01-09 18:03:40 +01:00
0cde0e90a6 Added approvals for “Greater-than inequalities with different epsilons” test 2017-01-09 14:40:09 +00:00
0f0dcd31eb Excluded two more C++11 tests from Approval tests 2017-01-09 14:37:28 +00:00
62cbde369e Exclude test name from approval tests 2017-01-09 14:37:28 +00:00
1ae84897d4 Marked tests that use C++11 features with [c++11] tag and exclude them from approval tests 2017-01-09 14:37:28 +00:00
976a655496 Approval tests can use Catch path fixed in env. var, and convert nullptr and __null to 0 for comparison 2017-01-09 14:37:28 +00:00
37e1e24309 add support for inequalities 2017-01-08 22:28:53 +01:00
5a4dde4b5d Changed build status to be always taken from master
Before it was taken from whatever last build happened, which led it show
a build error because I took PR against wrong branch.

This should be fixed now.
2017-01-08 21:49:14 +01:00
8d326424f3 Minor typo fix 2017-01-07 22:05:18 +01:00
ccc34b63b6 URL fixed 2017-01-07 14:51:13 +01:00
7255be28cc remove concatenation of m_exprComponents.op in if-branch where op has tested empty in previous line 2017-01-07 13:37:08 +01:00
7d2668fa15 add missing argument to CATCH_CHECK_THROWS (closes #602) 2017-01-07 12:16:06 +01:00
2a4dba177f Merge branch 'philipp-classen-master'
Removed changes to the single-include header.
2017-01-07 10:31:36 +01:00
8d1e240700 Fixed shell color code of "Blue" 2017-01-07 10:30:43 +01:00
e273a3dc88 Fix grammar error in tutorial.md
It's = it is
In the sentence "In fact it is usually a good idea to put the block with the ```#define``` [in it's own source file](slow-compiles.md).", the correct usage is "its", not "it's".
2017-01-07 09:56:21 +01:00
7bff9cb451 own-main.md: fix typo 2017-01-07 09:55:27 +01:00
fd1da4a1d1 Fixing a couple of typos
I tried to make sure I wasn't changing any British spellings so I apologize
if I've mixed any up.
2017-01-07 09:45:38 +01:00
e1fbbe1590 Added headers to CMake project (for CLion) 2017-01-06 16:59:18 +00:00
c8fefc4670 Fixed Travis and CMake after moving CMakeLists.txt 2017-01-06 16:19:20 +00:00
64193078bc Moved CMake into root folder (where it’s much happier - especially for CLion) 2017-01-06 16:00:00 +00:00
8d16d95a99 Do not encode extended ASCII characters in XML reporter 2016-12-26 11:39:19 +00:00
2be372710e Build 1.5.9 2016-11-29 12:15:50 +00:00
0c093bee38 Removed now redundant xml stream initialisation 2016-11-29 12:13:55 +00:00
dedc7c56ce Merge branch 'horenmar-xml-reporter-fix' 2016-11-29 12:11:05 +00:00
a9561ecb31 Merge branch 'xml-reporter-fix' of https://github.com/horenmar/Catch into horenmar-xml-reporter-fix 2016-11-29 12:10:46 +00:00
e4df006568 Merge branch 'horenmar-missing-include-fix' 2016-11-29 12:05:35 +00:00
fb99cc556d Merge branch 'missing-include-fix' of https://github.com/horenmar/Catch into horenmar-missing-include-fix 2016-11-29 12:05:11 +00:00
862d13138c Explicitly convert int to char during transform on string (equivalent of PR #756) 2016-11-29 12:04:09 +00:00
79acc0504b Sort test ordering during Approval testing 2016-11-29 11:32:16 +00:00
f9afa2a68d Ignore CMake and CLion generated files 2016-11-29 11:27:22 +00:00
0c8c6b347a Fixes build error caused by missing include. 2016-11-28 15:47:20 +01:00
40b6ad73df Fix XmlReporter always writing first line to stdout 2016-11-26 12:11:23 +01:00
30cebd6177 Added some missing source files (including all SurrogateCpps) to CMake project.
Fixed up relative include paths to make this work.
2016-11-09 22:55:32 +00:00
e27c4ee042 Build 1.5.8 2016-10-26 12:08:26 +01:00
072114293b Merge branch 'BillyONeal-master' 2016-10-26 12:06:35 +01:00
f90ee9fb37 Merge branch 'master' of https://github.com/BillyONeal/Catch into BillyONeal-master 2016-10-26 12:04:38 +01:00
c17ba0870a Fix transform without a lambda
Catch apparently supports targeting C++03, so use an inline function
instead.
2016-10-14 14:28:15 -07:00
79f01100e3 Fix transform narrowing warnings
Catch passes ::tolower into std::transform with string iterators.
::tolower has the signature int(int), which triggers a stealth narrowing
warning inside std::transform, because transform calls
*_Dest = _Fn(*_First), which implicitly narrows an int to a char.

For this particular application the narrowing is fine, so explicitly
narrow in a lambda.
2016-10-14 14:16:21 -07:00
ccf7f2842a Fix random_shuffle narrowing warnings
Catch passes an RNG which accepts int to random_shuffle. Inside
random_shuffle, the STL tries to call that RNG with the difference_type
of the user provided iterators. For std::vector, this is ptrdiff_t,
which on amd64 builds is wider than int. This triggers a narrowing
warning because the 64 bit difference is being truncated to 32 bits.

Note that this RNG implementation still does not produce a correctly
uniformly shuffled result -- it's currently asserting that std::rand
can produce 1000000 which is false -- but I don't know enough about
how much repeatable shuffles are necessary here, so I'm leaving that
alone for now.
2016-10-14 14:06:45 -07:00
e0302db4a6 Rename element for Fatal Error Condition so it doesn't have spaces
Fixes: #685
2016-10-14 18:45:08 +01:00
88732e85b2 Merge pull request #716 from jbcoe/master
Quick fix for failing travis builds on OS X
2016-10-04 15:57:10 +01:00
1c9a6cab88 Removed XCode6 builds (which were erroring anyway) and added XCode8 builds 2016-09-27 11:20:33 +01:00
40f6068d52 Build 1.5.7 2016-09-27 10:46:22 +01:00
21cbfc107e --list-test-names quotes test names that start with #
- completes #717
2016-09-27 10:43:03 +01:00
31861bbd46 rebased following recent changes 2016-09-27 10:28:11 +01:00
b1eeec7c69 -f supports quoted test names (test name surrounded with " characters).
This is the first part to resolving #717
2016-09-27 10:27:28 +01:00
c23b374f3d Added braces to emphasise the return logic 2016-09-27 09:58:12 +01:00
916317bd81 Merge pull request #680 from nabijaczleweli/master
Fix misindent in internal/catch_test_spec.hpp:70
2016-09-27 09:49:37 +01:00
8c459dd207 Fix misindent
Closes #679
2016-09-27 00:35:26 +02:00
fd7d35464b quick fix for failing travis builds on os x 2016-09-24 19:38:43 +01:00
c47c1797d2 Merge pull request #701 from razeh/master
Fixes for XML encoding.
2016-09-22 17:44:14 +01:00
f5d2b2dce8 Merge pull request #705 from hmich/xml-reporter-trim
Do not trim test case names in the XML reporter.
2016-09-22 17:28:46 +01:00
02c7e41c7c Do not trim test case names in the XML reporter.
SCENARIO does not add leading spaces to the test name (only BDD-style section
names are modified), so the trimming is not necessary. But if the name is
trimmed, it makes it harder to correlate the output of XML reporter with tests
that have leading spaces in their name: e.g. these tests will have the same name
attribute:

TEST_CASE("Test") {}
TEST_CASE(" Test") {}
2016-08-30 11:15:19 +01:00
5095619955 Fixes for XML encoding.
This commit fixes the following scenario:
  * You have a test that compares strings with embedded control
  characters.
  * The test fails.
  * You are using JUnit tests within TeamCity.

Before this commit, the JUnit report watcher fails on parsing the XML
for two reasons: the control characters are missing a semicolon at the
end, and the XML document doesn't specify that it is XML 1.1.

XML 1.0 --- what we get if we don't specify an XML version --- doesn't support embedding control characters --- see
http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml
for all of the gory details.

This is based on PR #588 by @mrpi
2016-08-24 09:38:24 -05:00
35f510545d v1.5.6 2016-06-09 19:21:09 +01:00
742457cbcf Use Clara v0.0.2.4 (updated) - fix for string lengths 2016-06-09 19:19:55 +01:00
1aa6c91e64 Fixed RNG issue with pre C++14 compilers 2016-06-09 19:07:05 +01:00
ac220289a6 v1.5.5:
Deal with auto_ptr and random_shuffle hard deprecations in C++14
2016-06-09 08:19:23 +01:00
be3570ef22 Use std::shuffle instead of (deprecated) std::random_shuffle if C++14 detected 2016-06-09 08:15:57 +01:00
a74d760d74 Switched remaining std::auto_ptrs to use CATCH_AUTO_PTR 2016-06-08 19:14:54 +01:00
f666f5f0ae v1.5.4 2016-05-12 19:18:04 +01:00
7940d58a2f "test" expression using !! instead of static_cast to bool.
This addresses #657 while (hopefully) maintaining fix for #574
2016-05-12 19:17:55 +01:00
ebf9f3bb9d v1.5.3 2016-05-10 19:09:59 +01:00
1ebebd4ab8 Merge branch 'rcdailey-throw-on-duplicate-tests' 2016-05-10 19:07:07 +01:00
b57e734eb4 Merge branch 'throw-on-duplicate-tests' of git://github.com/rcdailey/Catch into rcdailey-throw-on-duplicate-tests 2016-05-10 19:06:47 +01:00
5aa2b82b17 Merge pull request #656 from daniel-j-h/better_travis
Pins LLVM 3.8 (stable) instead of tracking the nightly repository
2016-05-07 23:19:26 +01:00
5c198d85e6 v1.5.2 2016-05-07 23:14:04 +01:00
5a6b291878 Using Clara 0.0.2.4 - fixes issue with spaces in quoted arguments 2016-05-07 23:12:46 +01:00
1706dd4f11 Pins LLVM 3.8 (stable) instead of tracking the nightly repository 2016-05-07 18:55:12 +02:00
92b141ee53 v1.5.1 2016-04-28 08:13:00 +01:00
4f1263d6b4 Removed use of dynamic_cast from test_case_tracker.
(Thanks to #631 and #648)
2016-04-28 08:11:12 +01:00
3b19458fed Removed use of dynamic_cast for MultipleReporters
(Thanks to #630, #636 and #648)
2016-04-28 08:11:12 +01:00
e5537842d0 Regenerated single include
(forgot for previously tagged release)
2016-04-25 18:56:50 +01:00
0fe303b6b7 v1.5.0 (due to new embedded Clara) 2016-04-23 13:25:51 +01:00
1c47fe023a Updated embedded Clara to 0.0.2.3
- has all new, more robust, token parsing.
- eliminates issue with unreachable code
- allows use of forward slashes to introduce short args on Windows
2016-04-23 13:21:29 +01:00
6f3bc629be Merge branch 'AzCopey-hotfix/override-warning' 2016-04-23 13:14:08 +01:00
6de7142d1f Merge pull request #634 from rafaeleyng/patch-1
Update tutorial.md
2016-04-05 18:23:22 +01:00
7544644bb4 Update tutorial.md
Closes #633
2016-04-04 23:04:45 -03:00
86c0ea2999 [#608] Don't use exit() on duplicate test descriptions
Instead of `exit(1)`, it now throws `std::runtime_error` with the details
of the failure. This exception is handled in `run()` at a higher level where
the log is printed to cerr and the test gracefully exits.
2016-04-01 11:56:51 -05:00
7075b7defb Added missing CATCH_OVERRIDE to CumulativeReporterBase::assertionEnded(). This fixes a warning when building in Xcode 7.2+ with default warning settings. 2016-03-29 17:03:09 +01:00
c984fc3ecd v1.4.0
- use __COUNTER__ for unique IDS instead of __LINE__ (where possible)
+ bug fixes
2016-03-15 07:24:26 +00:00
447f53e9e3 Fixed !shouldfail 2016-03-14 19:13:34 +00:00
13a887ad24 Use __COUNTER__ when generating unique names instead of __LINE__, if available.
Based on PR #351
2016-03-14 07:55:00 +00:00
02af70ed0b build v1.3.6 (include's David Grayson's fix for the gcc pragma) 2016-03-11 18:31:52 +00:00
c362894565 Merge branch 'DavidEGrayson-pr_gcc_pragma_typo' 2016-03-11 07:59:20 +00:00
97e335437e Fix CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS: GCC needs to be capitalized.
Fixes issue #600.
2016-03-04 19:24:10 -08:00
ae5ee2cf63 v1.3.5 2016-02-29 08:17:18 +00:00
f895e0d95f Rebased approvals following colour changes 2016-02-29 08:13:27 +00:00
458f37ed57 Merge branch 'explicit-bool-conversion' of git://github.com/seanmiddleditch/Catch into seanmiddleditch-explicit-bool-conversion 2016-02-29 08:05:46 +00:00
91bfe68a75 Suppress parentheses warnings on clang and gcc
- should address #593, #528, #521, #496 (and possibly others)
2016-02-29 08:03:48 +00:00
8ccb18daa9 Added --use-colour option to give finer control over colourisation.
--force-colour is still present but deprecated (will remove in v2)
2016-02-29 08:03:48 +00:00
dce2154474 Merge pull request #598 from luxe/patch-1
removes link to missing readme file
2016-02-27 17:06:57 +00:00
e52ad48fb7 removes link to missing readme file 2016-02-26 10:29:23 -05:00
776247af81 Support explicit operator bool
Fix for issue 596
2016-02-25 00:34:09 -08:00
3b4edd7a48 Build for v1.3.4 2016-02-10 19:24:48 +00:00
880a2046d9 Use Clara v0.0.1.1 2016-02-10 19:21:09 +00:00
ffad3a0a39 Fix as suggested in #574
Cast expression to bool to prevent custom && from defeating short-circuiting
2016-02-10 05:49:56 +00:00
3bd20bf2cd Removed reference to pre 1.0 release from README 2016-01-22 07:59:06 +00:00
c7243562b0 v1.3.3 2016-01-22 07:59:06 +00:00
b84e08ad6f Fix EndsWith Matcher (and refactored EndsWith and StartsWith in terms of endsWith and startsWith) (see Issue #573) 2016-01-22 07:59:06 +00:00
aca16a0f99 Fixed CATCH_REGISTER_TEST_CASE too 2016-01-22 07:50:10 +00:00
f294c98472 Fixed REGISTER_TEST_CASE for VS2013 (hopefully)
- see #549
2016-01-05 08:19:16 +00:00
7424b23bfb v1.3.1 2015-12-28 15:07:32 +00:00
dbd3a84d92 Fixed catch_with_main.hpp (no longer references deleted catch_runner.hpp) 2015-12-28 15:06:04 +00:00
5262e61e9d Approvals for Matcher change (added comma) 2015-12-10 18:43:29 +00:00
a5fba672e1 Add missing comma when in captured expression for matchers
Such that
CHECK_THAT( hex_encode(outbuf) Equals("B5D4045C") )
becomes
CHECK_THAT( hex_encode(outbuf), Equals("B5D4045C") )
2015-12-10 08:09:10 +00:00
2106d82881 Fixed non-variadic version of REGISTER_TEST_CASE 2015-12-09 18:24:29 +00:00
981347b6e4 patch build to include last two fixes 2015-12-09 18:11:48 +00:00
9e341231ba main takes args by non-const char*
- see #548
2015-12-09 06:22:15 +00:00
2b688e1cef Initialise m_currentSortOrder
- as reported in #545
2015-12-09 06:15:52 +00:00
84d1c080d6 Keep Xcode 7.1 happy 2015-12-04 10:21:07 +00:00
722315a1f5 Removed some trailing whitespace 2015-12-04 10:20:33 +00:00
fdc42d0af4 Merged from develop branch
- now v1.3.0
2015-12-04 10:19:08 +00:00
d274fc571c Added noexcept to CustomStdException destructor 2015-11-20 17:09:48 +00:00
7e15d9b20b dev build 4 2015-11-20 16:59:14 +00:00
0e64973f55 Added support for manually registering test functions.
As discussed in #421
2015-11-20 16:58:16 +00:00
e4fa62a14e dev build 3 2015-11-18 08:39:54 +00:00
a49f088032 exception translators considered even for types deriving from std::exception, now
- also added docs for exception translators
- updated approvals
2015-11-18 08:39:21 +00:00
ed6e9128a4 Session's argv now taken by char const* const*
- see #427
2015-11-18 07:57:24 +00:00
3523c39f44 Changed 'auto' into 'bool' for C++98 compatibility 2015-11-12 15:31:42 +01:00
2585d280d1 Added an optional absolute margin to the approximation checks 2015-11-12 15:11:36 +01:00
92356769f1 dev build 2 2015-11-06 18:07:29 +00:00
d10b73f9f1 changed Not struct to a class.
- it was forward declared as a class, which caused warnings on some compilers. It should really have been a class anyway.
- this addresses the same issue as PR #534, albeit from the other angle.
2015-11-06 18:07:29 +00:00
71fd2c2fdf Fixed test names mentioning the new Matcher combinator operators 2015-11-06 18:07:28 +00:00
08844e7e57 build 1.3.0-develop.1
I've incremented the minor release number. This is a slight abuse of semantic versioning so let me explain:
I've slightly changed how matchers are used. The matcher macro (REQUIRE_THAT/ CHECK_THAT) used to introduce the Catch::Matchers namespace before the macro token for the matcher, to save you having import the namespace yourself.
The trouble is if the matcher token is not a simple matcher (can now be an expression) this breaks!
So I've removed that qualification. Now if you use Matchers you'll have to do somethings like using namespace Catch::Matchers to bring them in.
This is a breaking change - but, OTTOH, Matchers are an undocumented "beta' feature that I've stated in the past is not guaranteed to have a stable API - so I don't think this warrants a major version change - but I did want to make it significant enough that people do notice that something is going on - and perhaps lead them to this commit message.
2015-11-05 18:52:18 +00:00
054e3c5b43 Added &&, || and ! operator overloads for matchers
(syntactic sugar for AllOf, AnyOf and Not compositional matchers, respectively)
2015-11-05 18:46:00 +00:00
f3e7722cc6 Don't introduce Catch::Matchers namespace in macro
- this could be a breaking change - fixed up self-test code to compensate
2015-11-05 18:10:33 +00:00
315c83ad87 Removed unnecessary parentheses 2015-11-04 18:49:19 +00:00
9576ad9108 Removed unused parameter
- as per PR #530
2015-11-04 18:11:54 +00:00
e91738103c Stripped trailing whitespace from all source code lines
(replaces need for PRs #310 and #504)
2015-11-04 18:04:15 +00:00
8c32b49d5f Added script to strip trailing whitespace from source files 2015-11-04 07:33:39 +00:00
ece529ae7c Fixed noexcept destructors issue 2015-11-03 17:37:43 +00:00
9e42153fe5 dev build 16 2015-11-03 17:06:54 +00:00
c81778ecd0 Fixed CMake file
(changed SectionTrackerTests.cpp - now deleted - to the new PartTrackerTests.cpp)
2015-11-03 17:06:24 +00:00
f5642be7b4 Fixed reversed logic of NoAssertions warning check
(that explains the previous regressions)
2015-11-03 17:05:08 +00:00
7e34619f03 v1.2.1-develop.15
- includes all new section tracker
2015-11-03 08:01:27 +00:00
4636be9744 Merge branch 'NewSectionTracking' into develop
* NewSectionTracking:
  Added SUCCEEDs to empty leaf sections to avoid failing due to no assertions
  Removed deprecated section tracking implementation and tests
  Approved changes due to "No assertions" warnings now firing correctly on inner sections
  perform startRun() at the start of each test case
  Fitted new section tracking
  Converted all new part tracking tests/ sections to non variadic form
  Moved all new tracking impl into catch_test_case_tracker.pp
  Removed the "part" component of the tracker names
  More minor tweaks
  Added tests for failing a section within a generator - small fixes to implementation to make it work
  more minor clean-ups
  Cleaned tests up a bit
  Added IndexTracker and got it working with a single generator - made some simplifications to state machine
  More name changes
  Tweaks
  First cut of new section/ part tracking
  Refactored stream related stuff - simpler, polymorphic hierarchy-based, approach - less bitty conditionals spread across the code - all resolved up-front so now config class is immutable (it had evolved the way it was and in need of a clean-up sweep for a long time)
  Some small clean-ups and refactorings - removed previous instance saves in RunContext (they were a hang-over from embedded contexts) - started cleaning up config usage
2015-11-03 07:55:29 +00:00
015e07100e Added SUCCEEDs to empty leaf sections to avoid failing due to no assertions 2015-11-03 07:46:37 +00:00
bc8840cbb8 Removed deprecated section tracking implementation and tests 2015-11-03 07:38:14 +00:00
471bd2556a Approved changes due to "No assertions" warnings now firing correctly on inner sections 2015-11-03 07:33:43 +00:00
aa49823bc0 perform startRun() at the start of each test case 2015-11-03 07:29:23 +00:00
52a417df7b Fitted new section tracking 2015-11-02 19:21:46 +00:00
0b523db6b9 Converted all new part tracking tests/ sections to non variadic form 2015-11-02 06:16:09 +00:00
b8515929b8 Moved all new tracking impl into catch_test_case_tracker.pp 2015-11-02 06:14:52 +00:00
3deb3e010f Removed the "part" component of the tracker names 2015-10-29 19:41:50 +00:00
73a140fb9e More minor tweaks 2015-10-29 19:33:25 +00:00
ef62b578e2 Added tests for failing a section within a generator
- small fixes to implementation to make it work
2015-10-29 19:25:27 +00:00
f4389b4fdb more minor clean-ups 2015-10-29 08:33:50 +00:00
4b99be6a9a Cleaned tests up a bit 2015-10-29 08:17:55 +00:00
293e54dcbe Added IndexTracker and got it working with a single generator
- made some simplifications to state machine
2015-10-29 08:02:40 +00:00
d758428fe2 Merge pull request #523 from nabijaczleweli/patch-1
Fix typo in catch_stream.hpp
2015-10-26 14:47:29 +00:00
9a6a0865f2 More name changes 2015-10-23 18:44:48 +01:00
2c6411e70a Tweaks 2015-10-23 18:34:16 +01:00
1cb993970a First cut of new section/ part tracking 2015-10-23 18:20:33 +01:00
bc00d59a4e Fix typo in catch_stream.hpp 2015-10-22 21:49:32 +02:00
b3b2352045 Fixed some missing sentence structure
Thanks to #517
2015-10-19 09:16:16 +01:00
c9a188df45 Merge pull request #512 from daniel-j-h/better_travis
Improves the Travis CI integration
2015-10-07 15:12:17 +01:00
e904aa7f6e Improve the Travis CI integration.
Adding several improvements, such as:

- making use of the container based infrastructure
- using ccache for faster building
- builds for linux, osx
- builds for verious gcc, clang versions
- recent cmake installation
2015-10-06 12:28:18 +02:00
d43a47efca Refactored stream related stuff
- simpler, polymorphic hierarchy-based, approach
- less bitty conditionals spread across the code
- all resolved up-front so now config class is immutable
(it had evolved the way it was and in need of a clean-up sweep for a long time)
2015-09-29 19:23:06 +01:00
a0de07d45b Some small clean-ups and refactorings
- removed previous instance saves in RunContext (they were a hang-over from embedded contexts)
- started cleaning up config usage
2015-09-28 01:09:06 -07:00
0c1c9fa922 dev build 14
- workaround for uncaught_exception issue
- avoid mutating vector while iterating it (due to re-entrancy)
2015-09-27 03:28:14 -07:00
166ca2e819 Do uncaught_exception checking before calling sectionEnded
- split the uncaught handling (adding to unfinishedSections) into separate method
2015-09-26 18:12:21 -07:00
15317632f3 Revert "Fix parentheses warning on expression evaluation when using ccache"
This reverts commit 7da777a4b7.
2015-09-26 18:06:53 -07:00
a28d40e941 Merge pull request #496 from segalaj/master
Fix parentheses warning on expression evaluation when using ccache
2015-09-18 08:12:56 +01:00
7da777a4b7 Fix parentheses warning on expression evaluation when using ccache 2015-09-14 14:28:34 +02:00
d234ed1a67 dev build 13 2015-08-24 06:28:25 +01:00
7fd7c5b8c8 Merge branch 'matcher-not' into develop
* matcher-not:
  Add matcher: Not()
2015-08-24 06:22:03 +01:00
312b94e532 Add matcher: Not() 2015-08-12 11:07:55 +02:00
40d0d2f656 Added unique_ptr detection to compiler_capabilities
- as well as use by C++11 conformant compilers now enabled for VS2013 on too (see #479)
- updated docs with this (and long long and override support)
2015-08-11 08:09:41 +01:00
19520157fb regen single header 2015-08-10 07:32:48 +01:00
ad7edd0680 Replaced some stray overrides with CATCH_OVERRIDE 2015-08-10 07:32:21 +01:00
8a05f46a37 Removed use of std::copy_if (as it's limited to c++11) 2015-08-07 17:53:29 +01:00
e73583d556 dev build 12 2015-08-07 17:30:34 +01:00
afcc38efc5 Fixes for single include 2015-08-07 17:28:48 +01:00
368714e7aa Added Listeners (programatically provided extra reporters) 2015-08-07 08:20:56 +01:00
4cb74761d9 Support for multiple reporters
- can't (yet) specify different targets for each reporter (e.g. different files)
2015-08-05 19:02:17 +01:00
c06e1909ae Refactored test filtering and sorting 2015-08-04 23:11:56 +01:00
8b1b7cd66e dev build 11 2015-08-03 07:40:52 +01:00
34fa25ed2f Removed Runner class
- it served no purpose - split into functions instead
2015-07-28 18:55:11 +01:00
85c8074784 Set group name to -n parameter (or exe name)
- As discussed in #469
2015-07-28 18:26:09 +01:00
0edebf41b0 approvals rebase
- I *think* this fixes an earlier regression, but I'm not 100% sure where that came from!
2015-07-28 18:24:20 +01:00
f3308ed7c4 Let gcc use __cplusplus identifier to decide if nullptr supported
- or, for 4.6, continue to check __GX_EXPERIMENTAL_CXX0X__
See GitHb issue #445 and PR #471
2015-07-27 18:42:36 +01:00
74eef52644 dev build 10 2015-07-24 08:13:52 +01:00
e085d4811a Qualified path to xmlwriter to fix travis error 2015-07-24 08:13:07 +01:00
2f6371f2ec dev build 9 2015-07-23 23:06:26 +01:00
70975517b3 rebased approvals for long long test 2015-07-23 23:05:52 +01:00
733ebb6024 Added CATCH_CONFIG_CPP11_LONG_LONG support 2015-07-23 23:05:05 +01:00
d6e59cd56f Fixed Xml encoding
- don't encode apostrophes
- only encode quotes in attributes
- encode control characters (as in PR #465)
2015-07-23 18:45:31 +01:00
6de135c63a Given, When, Then prefixes are now std::strings
(and so can be prepended to std::strings themselves)
see #455
2015-07-22 18:07:28 +01:00
5bbdc8fd38 Dev build 8 2015-07-15 23:03:11 +01:00
72868920bb Exception message assertions now work with matchers 2015-07-15 23:02:25 +01:00
1dd0d4c61a Force cout/ cerr to be initialised before errors in test registry are printed
- see #461
2015-07-10 07:46:19 +01:00
237 changed files with 29817 additions and 21129 deletions

29
.github/issue_template.md vendored Normal file
View 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
View 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
View File

@ -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

View File

@ -1,19 +1,268 @@
language: cpp
sudo: false
compiler:
- clang
- gcc
matrix:
include:
# 1/ Linux Clang Builds
- os: linux
compiler: clang
addons: &clang34
apt:
sources: ['llvm-toolchain-precise', 'ubuntu-toolchain-r-test']
packages: ['clang']
env: COMPILER='clang++' BUILD_TYPE='Release'
- os: linux
compiler: clang
addons: *clang34
env: COMPILER='clang++' BUILD_TYPE='Debug'
- os: linux
compiler: clang
addons: &clang35
apt:
sources: ['llvm-toolchain-precise-3.5', 'ubuntu-toolchain-r-test']
packages: ['clang-3.5']
env: COMPILER='clang++-3.5' BUILD_TYPE='Release'
- os: linux
compiler: clang
addons: *clang35
env: COMPILER='clang++-3.5' BUILD_TYPE='Debug'
- os: linux
compiler: clang
addons: &clang36
apt:
sources: ['llvm-toolchain-precise-3.6', 'ubuntu-toolchain-r-test']
packages: ['clang-3.6']
env: COMPILER='clang++-3.6' BUILD_TYPE='Release'
- os: linux
compiler: clang
addons: *clang36
env: COMPILER='clang++-3.6' BUILD_TYPE='Debug'
- os: linux
compiler: clang
addons: &clang37
apt:
sources: ['llvm-toolchain-precise-3.7', 'ubuntu-toolchain-r-test']
packages: ['clang-3.7']
env: COMPILER='clang++-3.7' BUILD_TYPE='Release'
- os: linux
compiler: clang
addons: *clang37
env: COMPILER='clang++-3.7' BUILD_TYPE='Debug'
- os: linux
compiler: clang
addons: &clang38
apt:
sources: ['llvm-toolchain-precise-3.8', 'ubuntu-toolchain-r-test']
packages: ['clang-3.8']
env: COMPILER='clang++-3.8' BUILD_TYPE='Release'
- os: linux
compiler: clang
addons: *clang38
env: COMPILER='clang++-3.8' BUILD_TYPE='Debug'
# 2/ Linux GCC Builds
- os: linux
compiler: gcc
addons: &gcc44
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-4.4']
env: COMPILER='g++-4.4' BUILD_TYPE='Release'
- os: linux
compiler: gcc
addons: *gcc44
env: COMPILER='g++-4.4' BUILD_TYPE='Debug'
- os: linux
compiler: gcc
addons: &gcc47
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-4.7']
env: COMPILER='g++-4.7' BUILD_TYPE='Release'
- os: linux
compiler: gcc
addons: *gcc47
env: COMPILER='g++-4.7' BUILD_TYPE='Debug'
- os: linux
compiler: gcc
addons: &gcc48
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-4.8']
env: COMPILER='g++-4.8' BUILD_TYPE='Release'
- os: linux
compiler: gcc
addons: *gcc48
env: COMPILER='g++-4.8' BUILD_TYPE='Debug'
- os: linux
compiler: gcc
addons: &gcc49
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-4.9']
env: COMPILER='g++-4.9' BUILD_TYPE='Release'
- os: linux
compiler: gcc
addons: *gcc49
env: COMPILER='g++-4.9' BUILD_TYPE='Debug'
- os: linux
compiler: gcc
addons: &gcc5
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-5']
env: COMPILER='g++-5' BUILD_TYPE='Release'
- os: linux
compiler: gcc
addons: *gcc5
env: COMPILER='g++-5' BUILD_TYPE='Debug'
- 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
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: xcode7.3
compiler: clang
env: COMPILER='clang++' BUILD_TYPE='Release'
- os: osx
osx_image: xcode8
compiler: clang
env: COMPILER='clang++' BUILD_TYPE='Debug'
- os: osx
osx_image: xcode8
compiler: clang
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
env:
- BUILD_TYPE=Debug
- BUILD_TYPE=Release
install:
- cmake -Hprojects/CMake -BBuild -DCMAKE_BUILD_TYPE=$BUILD_TYPE
- DEPS_DIR="${TRAVIS_BUILD_DIR}/deps"
- mkdir -p ${DEPS_DIR} && cd ${DEPS_DIR}
- |
if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then
CMAKE_URL="http://www.cmake.org/files/v3.3/cmake-3.3.2-Linux-x86_64.tar.gz"
mkdir cmake && travis_retry wget --no-check-certificate --quiet -O - ${CMAKE_URL} | tar --strip-components=1 -xz -C cmake
export PATH=${DEPS_DIR}/cmake/bin:${PATH}
elif [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then
which cmake || brew install cmake
fi
before_script:
- export CXX=${COMPILER}
- cd ${TRAVIS_BUILD_DIR}
- cmake -H. -BBuild -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -Wdev -DUSE_CPP11=${CPP11} -DUSE_CPP14=${CPP14}
- cd Build
- make
- cd ..
script:
- cd Build
- ctest -V
- make -j 2
- ctest -V -j 2

284
CMakeLists.txt Normal file
View File

@ -0,0 +1,284 @@
cmake_minimum_required(VERSION 3.0)
project(CatchSelfTest)
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
# define some folders
set(CATCH_DIR ${CMAKE_CURRENT_SOURCE_DIR})
set(SELF_TEST_DIR ${CATCH_DIR}/projects/SelfTest)
set(BENCHMARK_DIR ${CATCH_DIR}/projects/Benchmark)
set(HEADER_DIR ${CATCH_DIR}/include)
if(USE_CPP11)
## We can't turn this on by default, since it breaks on travis
message(STATUS "Enabling C++11")
set(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}")
elseif(USE_CPP14)
message(STATUS "Enabling C++14")
set(CMAKE_CXX_FLAGS "-std=c++14 ${CMAKE_CXX_FLAGS}")
endif()
if(USE_WMAIN)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ENTRY:wmainCRTStartup")
endif()
#checks that the given hard-coded list contains all headers + sources in the given folder
function(CheckFileList LIST_VAR FOLDER)
set(MESSAGE " should be added to the variable ${LIST_VAR}")
set(MESSAGE "${MESSAGE} in ${CMAKE_CURRENT_LIST_FILE}\n")
file(GLOB GLOBBED_LIST "${FOLDER}/*.cpp"
"${FOLDER}/*.hpp"
"${FOLDER}/*.h")
list(REMOVE_ITEM GLOBBED_LIST ${${LIST_VAR}})
foreach(EXTRA_ITEM ${GLOBBED_LIST})
string(REPLACE "${CATCH_DIR}/" "" RELATIVE_FILE_NAME "${EXTRA_ITEM}")
message(AUTHOR_WARNING "The file \"${RELATIVE_FILE_NAME}\"${MESSAGE}")
endforeach()
endfunction()
function(CheckFileListRec LIST_VAR FOLDER)
set(MESSAGE " should be added to the variable ${LIST_VAR}")
set(MESSAGE "${MESSAGE} in ${CMAKE_CURRENT_LIST_FILE}\n")
file(GLOB_RECURSE GLOBBED_LIST "${FOLDER}/*.cpp"
"${FOLDER}/*.hpp"
"${FOLDER}/*.h")
list(REMOVE_ITEM GLOBBED_LIST ${${LIST_VAR}})
foreach(EXTRA_ITEM ${GLOBBED_LIST})
string(REPLACE "${CATCH_DIR}/" "" RELATIVE_FILE_NAME "${EXTRA_ITEM}")
message(AUTHOR_WARNING "The file \"${RELATIVE_FILE_NAME}\"${MESSAGE}")
endforeach()
endfunction()
# define the sources of the self test
# Please keep these ordered alphabetically
set(TEST_SOURCES
${SELF_TEST_DIR}/ApproxTests.cpp
${SELF_TEST_DIR}/BDDTests.cpp
${SELF_TEST_DIR}/ClassTests.cpp
${SELF_TEST_DIR}/CmdLineTests.cpp
${SELF_TEST_DIR}/CompilationTests.cpp
${SELF_TEST_DIR}/ConditionTests.cpp
${SELF_TEST_DIR}/DecompositionTests.cpp
${SELF_TEST_DIR}/EnumToString.cpp
${SELF_TEST_DIR}/ExceptionTests.cpp
${SELF_TEST_DIR}/GeneratorTests.cpp
${SELF_TEST_DIR}/MessageTests.cpp
${SELF_TEST_DIR}/MiscTests.cpp
${SELF_TEST_DIR}/PartTrackerTests.cpp
${SELF_TEST_DIR}/TagAliasTests.cpp
${SELF_TEST_DIR}/TestMain.cpp
${SELF_TEST_DIR}/ToStringGeneralTests.cpp
${SELF_TEST_DIR}/ToStringPair.cpp
${SELF_TEST_DIR}/ToStringTuple.cpp
${SELF_TEST_DIR}/ToStringVector.cpp
${SELF_TEST_DIR}/ToStringWhich.cpp
${SELF_TEST_DIR}/TrickyTests.cpp
${SELF_TEST_DIR}/VariadicMacrosTests.cpp
${SELF_TEST_DIR}/MatchersTests.cpp
)
CheckFileList(TEST_SOURCES ${SELF_TEST_DIR})
# A set of impl files that just #include a single header
# Please keep these ordered alphabetically
set(IMPL_SOURCES
${SELF_TEST_DIR}/SurrogateCpps/catch_common.cpp
${SELF_TEST_DIR}/SurrogateCpps/catch_console_colour.cpp
${SELF_TEST_DIR}/SurrogateCpps/catch_debugger.cpp
${SELF_TEST_DIR}/SurrogateCpps/catch_interfaces_capture.cpp
${SELF_TEST_DIR}/SurrogateCpps/catch_interfaces_config.cpp
${SELF_TEST_DIR}/SurrogateCpps/catch_interfaces_exception.cpp
${SELF_TEST_DIR}/SurrogateCpps/catch_interfaces_generators.cpp
${SELF_TEST_DIR}/SurrogateCpps/catch_interfaces_registry_hub.cpp
${SELF_TEST_DIR}/SurrogateCpps/catch_interfaces_reporter.cpp
${SELF_TEST_DIR}/SurrogateCpps/catch_interfaces_runner.cpp
${SELF_TEST_DIR}/SurrogateCpps/catch_interfaces_testcase.cpp
${SELF_TEST_DIR}/SurrogateCpps/catch_message.cpp
${SELF_TEST_DIR}/SurrogateCpps/catch_option.cpp
${SELF_TEST_DIR}/SurrogateCpps/catch_ptr.cpp
${SELF_TEST_DIR}/SurrogateCpps/catch_stream.cpp
${SELF_TEST_DIR}/SurrogateCpps/catch_streambuf.cpp
${SELF_TEST_DIR}/SurrogateCpps/catch_test_spec.cpp
${SELF_TEST_DIR}/SurrogateCpps/catch_xmlwriter.cpp
${SELF_TEST_DIR}/SurrogateCpps/catch_test_case_tracker.cpp
)
CheckFileList(IMPL_SOURCES ${SELF_TEST_DIR}/SurrogateCpps)
# Please keep these ordered alphabetically
set(TOP_LEVEL_HEADERS
${HEADER_DIR}/catch.hpp
${HEADER_DIR}/catch_session.hpp
${HEADER_DIR}/catch_with_main.hpp
)
CheckFileList(TOP_LEVEL_HEADERS ${HEADER_DIR})
# Please keep these ordered alphabetically
set(EXTERNAL_HEADERS
${HEADER_DIR}/external/clara.h
${HEADER_DIR}/external/tbc_text_format.h
)
CheckFileList(EXTERNAL_HEADERS ${HEADER_DIR}/external)
# Please keep these ordered alphabetically
set(INTERNAL_HEADERS
${HEADER_DIR}/internal/catch_approx.hpp
${HEADER_DIR}/internal/catch_assertionresult.h
${HEADER_DIR}/internal/catch_assertionresult.hpp
${HEADER_DIR}/internal/catch_capture.hpp
${HEADER_DIR}/internal/catch_clara.h
${HEADER_DIR}/internal/catch_commandline.hpp
${HEADER_DIR}/internal/catch_common.h
${HEADER_DIR}/internal/catch_common.hpp
${HEADER_DIR}/internal/catch_compiler_capabilities.h
${HEADER_DIR}/internal/catch_config.hpp
${HEADER_DIR}/internal/catch_console_colour.hpp
${HEADER_DIR}/internal/catch_console_colour_impl.hpp
${HEADER_DIR}/internal/catch_context.h
${HEADER_DIR}/internal/catch_context_impl.hpp
${HEADER_DIR}/internal/catch_debugger.h
${HEADER_DIR}/internal/catch_debugger.hpp
${HEADER_DIR}/internal/catch_default_main.hpp
${HEADER_DIR}/internal/catch_errno_guard.hpp
${HEADER_DIR}/internal/catch_evaluate.hpp
${HEADER_DIR}/internal/catch_exception_translator_registry.hpp
${HEADER_DIR}/internal/catch_expression_lhs.hpp
${HEADER_DIR}/internal/catch_fatal_condition.hpp
${HEADER_DIR}/internal/catch_generators.hpp
${HEADER_DIR}/internal/catch_generators_impl.hpp
${HEADER_DIR}/internal/catch_impl.hpp
${HEADER_DIR}/internal/catch_interfaces_capture.h
${HEADER_DIR}/internal/catch_interfaces_config.h
${HEADER_DIR}/internal/catch_interfaces_exception.h
${HEADER_DIR}/internal/catch_interfaces_generators.h
${HEADER_DIR}/internal/catch_interfaces_registry_hub.h
${HEADER_DIR}/internal/catch_interfaces_reporter.h
${HEADER_DIR}/internal/catch_interfaces_runner.h
${HEADER_DIR}/internal/catch_interfaces_tag_alias_registry.h
${HEADER_DIR}/internal/catch_interfaces_testcase.h
${HEADER_DIR}/internal/catch_legacy_reporter_adapter.h
${HEADER_DIR}/internal/catch_legacy_reporter_adapter.hpp
${HEADER_DIR}/internal/catch_list.hpp
${HEADER_DIR}/internal/catch_matchers.hpp
${HEADER_DIR}/internal/catch_matchers_string.h
${HEADER_DIR}/internal/catch_matchers_string.hpp
${HEADER_DIR}/internal/catch_matchers_vector.h
${HEADER_DIR}/internal/catch_message.h
${HEADER_DIR}/internal/catch_message.hpp
${HEADER_DIR}/internal/catch_notimplemented_exception.h
${HEADER_DIR}/internal/catch_notimplemented_exception.hpp
${HEADER_DIR}/internal/catch_objc.hpp
${HEADER_DIR}/internal/catch_objc_arc.hpp
${HEADER_DIR}/internal/catch_option.hpp
${HEADER_DIR}/internal/catch_platform.h
${HEADER_DIR}/internal/catch_ptr.hpp
${HEADER_DIR}/internal/catch_reenable_warnings.h
${HEADER_DIR}/internal/catch_registry_hub.hpp
${HEADER_DIR}/internal/catch_reporter_registrars.hpp
${HEADER_DIR}/internal/catch_reporter_registry.hpp
${HEADER_DIR}/internal/catch_result_builder.h
${HEADER_DIR}/internal/catch_result_builder.hpp
${HEADER_DIR}/internal/catch_result_type.h
${HEADER_DIR}/internal/catch_run_context.hpp
${HEADER_DIR}/internal/catch_section.h
${HEADER_DIR}/internal/catch_section.hpp
${HEADER_DIR}/internal/catch_section_info.h
${HEADER_DIR}/internal/catch_section_info.hpp
${HEADER_DIR}/internal/catch_stream.h
${HEADER_DIR}/internal/catch_stream.hpp
${HEADER_DIR}/internal/catch_streambuf.h
${HEADER_DIR}/internal/catch_suppress_warnings.h
${HEADER_DIR}/internal/catch_tag_alias.h
${HEADER_DIR}/internal/catch_tag_alias_registry.h
${HEADER_DIR}/internal/catch_tag_alias_registry.hpp
${HEADER_DIR}/internal/catch_test_case_info.h
${HEADER_DIR}/internal/catch_test_case_info.hpp
${HEADER_DIR}/internal/catch_test_case_registry_impl.hpp
${HEADER_DIR}/internal/catch_test_case_tracker.hpp
${HEADER_DIR}/internal/catch_test_registry.hpp
${HEADER_DIR}/internal/catch_test_spec.hpp
${HEADER_DIR}/internal/catch_test_spec_parser.hpp
${HEADER_DIR}/internal/catch_text.h
${HEADER_DIR}/internal/catch_timer.h
${HEADER_DIR}/internal/catch_timer.hpp
${HEADER_DIR}/internal/catch_tostring.h
${HEADER_DIR}/internal/catch_tostring.hpp
${HEADER_DIR}/internal/catch_totals.hpp
${HEADER_DIR}/internal/catch_type_traits.hpp
${HEADER_DIR}/internal/catch_version.h
${HEADER_DIR}/internal/catch_version.hpp
${HEADER_DIR}/internal/catch_wildcard_pattern.hpp
${HEADER_DIR}/internal/catch_windows_h_proxy.h
${HEADER_DIR}/internal/catch_xmlwriter.hpp
)
CheckFileList(INTERNAL_HEADERS ${HEADER_DIR}/internal)
# Please keep these ordered alphabetically
set(REPORTER_HEADERS
${HEADER_DIR}/reporters/catch_reporter_automake.hpp
${HEADER_DIR}/reporters/catch_reporter_bases.hpp
${HEADER_DIR}/reporters/catch_reporter_compact.hpp
${HEADER_DIR}/reporters/catch_reporter_console.hpp
${HEADER_DIR}/reporters/catch_reporter_junit.hpp
${HEADER_DIR}/reporters/catch_reporter_multi.hpp
${HEADER_DIR}/reporters/catch_reporter_tap.hpp
${HEADER_DIR}/reporters/catch_reporter_teamcity.hpp
${HEADER_DIR}/reporters/catch_reporter_xml.hpp
)
CheckFileList(REPORTER_HEADERS ${HEADER_DIR}/reporters)
# Specify the headers, too, so CLion recognises them as project files
set(HEADERS
${TOP_LEVEL_HEADERS}
${EXTERNAL_HEADERS}
${INTERNAL_HEADERS}
${REPORTER_HEADERS}
)
set(BENCH_SOURCES
${BENCHMARK_DIR}/BenchMain.cpp
${BENCHMARK_DIR}/StringificationBench.cpp
)
CheckFileList(BENCH_SOURCES ${BENCHMARK_DIR})
# Provide some groupings for IDEs
SOURCE_GROUP("Tests" FILES ${TEST_SOURCES})
SOURCE_GROUP("Surrogates" FILES ${IMPL_SOURCES})
SOURCE_GROUP("Benchmarks" FILES ${BENCH_SOURCES})
# configure the executable
include_directories(${HEADER_DIR})
# Projects consuming Catch via ExternalProject_Add might want to use install step
# without building all of our selftests.
if (NOT NO_SELFTEST)
add_executable(SelfTest ${TEST_SOURCES} ${IMPL_SOURCES} ${HEADERS})
add_executable(Benchmark ${BENCH_SOURCES} ${HEADERS})
# Add desired warnings
if ( CMAKE_CXX_COMPILER_ID MATCHES "Clang|AppleClang|GNU" )
target_compile_options( SelfTest PRIVATE -Wall -Wextra )
target_compile_options( Benchmark PRIVATE -Wall -Wextra )
endif()
if ( CMAKE_CXX_COMPILER_ID MATCHES "MSVC" )
target_compile_options( SelfTest PRIVATE /W4 /w44265 /WX )
target_compile_options( Benchmark PRIVATE /W4 )
endif()
# configure unit tests via CTest
enable_testing()
add_test(NAME RunTests COMMAND SelfTest)
add_test(NAME ListTests COMMAND SelfTest --list-tests)
set_tests_properties(ListTests PROPERTIES PASS_REGULAR_EXPRESSION "[0-9]+ test cases")
add_test(NAME ListTags COMMAND SelfTest --list-tags)
set_tests_properties(ListTags PROPERTIES PASS_REGULAR_EXPRESSION "[0-9]+ tags")
endif() # !NO_SELFTEST
install(DIRECTORY "single_include/" DESTINATION "include/catch")

46
CODE_OF_CONDUCT.md Normal file
View 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/

View File

@ -1,12 +1,11 @@
![catch logo](catch-logo-small.png)
*v1.2.1-develop.7*
[![Github Releases](https://img.shields.io/github/release/philsquared/catch.svg)](https://github.com/philsquared/catch/releases)
[![Build Status](https://travis-ci.org/philsquared/Catch.svg?branch=master)](https://travis-ci.org/philsquared/Catch)
[![Build status](https://ci.appveyor.com/api/projects/status/hrtk60hv6tw6fght/branch/master?svg=true)](https://ci.appveyor.com/project/philsquared/catch/branch/master)
[![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/EyEbEIfp8CnnjguW)
Build status (on Travis CI) [![Build Status](https://travis-ci.org/philsquared/Catch.png)](https://travis-ci.org/philsquared/Catch)
[Please see this page if you are updating from a version before 1.0](docs/whats-changed.md)
<a href="https://raw.githubusercontent.com/philsquared/Catch/master/single_include/catch.hpp">[The latest, single header, version can be downloaded directly using this link]</a>
<a href="https://github.com/philsquared/Catch/releases/download/v1.11.0/catch.hpp">The latest, single header, version can be downloaded directly using this link</a>
## What's the Catch?
@ -19,8 +18,11 @@ This documentation comprises these three parts:
* [Tutorial](docs/tutorial.md) - getting started
* [Reference section](docs/Readme.md) - all the details
The documentation will continue until morale improves
## More
* Issues and bugs can be raised on the [Issue tracker on GitHub](https://github.com/philsquared/Catch/issues)
* For discussion or questions please use [the dedicated Google Groups forum](https://groups.google.com/forum/?fromgroups#!forum/catch-forum)
* See [who else is using Catch](docs/opensource-users.md)
## Help us out
We're currently running [a survey](https://www.surveymonkey.co.uk/r/TLLYQJW) to help us shape the future of Catch.
Please take a few moments to fill it out (there's only ten questions).

61
appveyor.yml Normal file
View File

@ -0,0 +1,61 @@
# version string format -- This will be overwritten later anyway
version: "{build}"
os:
- Visual Studio 2017
- Visual Studio 2015
- Visual Studio 2013
environment:
matrix:
- additional_flags: "/permissive- /std:c++latest"
wmain: 0
- additional_flags: ""
wmain: 0
- additional_flags: "/D_UNICODE /DUNICODE"
wmain: 1
matrix:
exclude:
-
additional_flags: "/permissive- /std:c++latest"
os: Visual Studio 2015
-
additional_flags: "/permissive- /std:c++latest"
os: Visual Studio 2013
init:
- git config --global core.autocrlf input
# Set build version to git commit-hash
- ps: Update-AppveyorBuild -Version "$($env:APPVEYOR_REPO_BRANCH) - $($env:APPVEYOR_REPO_COMMIT)"
# fetch repository as zip archive
shallow_clone: true
# Win32 and x64 are CMake-compatible solution platform names.
# This allows us to pass %PLATFORM% to CMake -A.
platform:
- Win32
- x64
# build Configurations, i.e. Debug, Release, etc.
configuration:
- Debug
- Release
#Cmake will autodetect the compiler, but we set the arch
before_build:
- set CXXFLAGS=%additional_flags%
- cmake -H. -BBuild -A%PLATFORM% -DUSE_WMAIN=%wmain%
# build with MSBuild
build:
project: Build\CatchSelfTest.sln # path to Visual Studio solution or project
parallel: true # enable MSBuild parallel builds
verbosity: normal # MSBuild verbosity level {quiet|minimal|normal|detailed}
test_script:
- cd Build
- ctest -V -j 2 -C %CONFIGURATION%

BIN
catch-hand-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

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

19
conanfile.py Normal file
View File

@ -0,0 +1,19 @@
#!/usr/bin/env python
from conans import ConanFile
class CatchConan(ConanFile):
name = "Catch"
version = "1.11.0"
description = "A modern, C++-native, header-only, framework for unit-tests, TDD and BDD"
author = "philsquared"
generators = "cmake"
exports_sources = "single_include/*"
url = "https://github.com/philsquared/Catch"
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")
def package_id(self):
self.info.header_only()

View File

@ -0,0 +1,185 @@
#==================================================================================================#
# 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 #
# PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS (Default OFF) #
# -- causes CMake to rerun when file with tests changes so that new tests will be discovered #
# #
#==================================================================================================#
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)
option(PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS "Add test file to CMAKE_CONFIGURE_DEPENDS property" OFF)
function(PrintDebugMessage)
if(PARSE_CATCH_TESTS_VERBOSE)
message(STATUS "ParseAndAddCatchTests: ${ARGV}")
endif()
endfunction()
# This removes the contents between
# - block comments (i.e. /* ... */)
# - full line comments (i.e. // ... )
# contents have been read into '${CppCode}'.
# !keep partial line comments
function(RemoveComments CppCode)
string(ASCII 2 CMakeBeginBlockComment)
string(ASCII 3 CMakeEndBlockComment)
string(REGEX REPLACE "/\\*" "${CMakeBeginBlockComment}" ${CppCode} "${${CppCode}}")
string(REGEX REPLACE "\\*/" "${CMakeEndBlockComment}" ${CppCode} "${${CppCode}}")
string(REGEX REPLACE "${CMakeBeginBlockComment}[^${CMakeEndBlockComment}]*${CMakeEndBlockComment}" "" ${CppCode} "${${CppCode}}")
string(REGEX REPLACE "\n[ \t]*//+[^\n]+" "\n" ${CppCode} "${${CppCode}}")
set(${CppCode} "${${CppCode}}" PARENT_SCOPE)
endfunction()
# Worker function
function(ParseFile SourceFile TestTarget)
# According to CMake docs EXISTS behavior is well-defined only for full paths.
get_filename_component(SourceFile ${SourceFile} ABSOLUTE)
if(NOT EXISTS ${SourceFile})
message(WARNING "Cannot find source file: ${SourceFile}")
return()
endif()
PrintDebugMessage("parsing ${SourceFile}")
file(STRINGS ${SourceFile} Contents NEWLINE_CONSUME)
# Remove block and fullline comments
RemoveComments(Contents)
# Find definition of test names
string(REGEX MATCHALL "[ \t]*(CATCH_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)[ \t]*\\([^\)]+\\)+[ \t\n]*{+[ \t]*(//[^\n]*[Tt][Ii][Mm][Ee][Oo][Uu][Tt][ \t]*[0-9]+)*" Tests "${Contents}")
if(PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS AND Tests)
PrintDebugMessage("Adding ${SourceFile} to CMAKE_CONFIGURE_DEPENDS property")
set_property(
DIRECTORY
APPEND
PROPERTY CMAKE_CONFIGURE_DEPENDS ${SourceFile}
)
endif()
foreach(TestName ${Tests})
# Strip newlines
string(REGEX REPLACE "\\\\\n|\n" "" TestName "${TestName}")
# 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()

View File

@ -1,20 +1,30 @@
These are the currently documented areas of the framework. There is more to come.
Before looking at this material be sure to read the [tutorial](tutorial.md)
To get the most out of Catch, start with the [tutorial](tutorial.md).
Once you're up and running consider the following reference material.
Writing tests:
* [Assertion macros](assertions.md)
* [Matchers](matchers.md)
* [Logging macros](logging.md)
* [Test cases and sections](test-cases-and-sections.md)
* [Test fixtures](test-fixtures.md)
* [Command line](command-line.md)
* [Build systems](build-systems.md)
* [Reporters](reporters.md)
* [Event Listeners](event-listeners.md)
Fine tuning:
* [Supplying your own main()](own-main.md)
* [Configuration](configuration.md)
* [Compile-time configuration](configuration.md)
* [String Conversions](tostring.md)
Running:
* [Command line](command-line.md)
* [CI and Build system integration](build-systems.md)
FAQ:
* [Why are my tests slow to compile?](slow-compiles.md)
Other
* [Known limitations](limitations.md)
Other:
* [Why Catch?](why-catch.md)
* [What's changed](whats-changed.md)
* [Open Source Projects using Catch](opensource-users.md)
* [Contributing](contributing.md)
* [Release Notes](release-notes.md)

View File

@ -34,6 +34,15 @@ Example:
REQUIRE_FALSE( thisReturnsFalse() );
```
Do note that "overly complex" expressions cannot be decomposed and thus will not compile. This is done partly for practical reasons (to keep the underlying expression template machinery to minimum) and partly for philosophical reasons (assertions should be simple and deterministic).
Examples:
* `CHECK(a == 1 && b == 2);`
This expression is too complex because of the `&&` operator. If you want to check that 2 or more properties hold, you can either put the expression into parenthesis, which stops decomposition from working, or you need to decompose the expression into two assertions: `CHECK( a == 1 ); CHECK( b == 2);`
* `CHECK( a == 2 || b == 1 );`
This expression is too complex because of the `||` operator. If you want to check that one of several properties hold, you can put the expression into parenthesis (unlike with `&&`, expression decomposition into several `CHECK`s is not possible).
### Floating point comparisons
When comparing floating point numbers - especially if at least one of them has been computed - great care must be taken to allow for rounding errors and inexact representations.
@ -44,16 +53,40 @@ Catch provides a way to perform tolerant comparisons of floating point values th
REQUIRE( performComputation() == Approx( 2.1 ) );
```
By default a small epsilon value is used that covers many simple cases of rounding errors. When this is insufficent the epsilon value (the amount within which a difference either way is ignored) can be specified by calling the ```epsilon()``` method on the ```Approx``` instance. e.g.:
This way `Approx` is constructed with reasonable defaults, covering most simple cases of rounding errors. If these are insufficient, each `Approx` instance has 3 tuning knobs, that can be used to customize it for your computation.
```
REQUIRE( 22/7 == Approx( 3.141 ).epsilon( 0.01 ) );
* __epsilon__ - epsilon serves to set the percentage by which a result can be erroneous, before it is rejected. By default set to `std::numeric_limits<float>::epsilon()*100`.
* __margin__ - margin serves to set the the absolute value by which a result can be erroneous before it is rejected. By default set to `0.0`.
* __scale__ - scale serves to adjust the base for comparison used by epsilon, can be used when By default set to `1.0`.
#### epsilon example
```cpp
Approx target = Approx(100).epsilon(0.01);
100.0 == target; // Obviously true
200.0 == target; // Obviously still false
100.5 == target; // True, because we set target to allow up to 1% error
```
When dealing with very large or very small numbers it can be useful to specify a scale, which can be achieved by calling the ```scale()``` method on the ```Approx``` instance.
#### margin example
_Margin check is used only if the relative (epsilon and scale based) check fails._
```cpp
Approx target = Approx(100).margin(5);
100.0 == target; // Obviously true
200.0 == target; // Obviously still false
104.0 == target; // True, because we set target to allow absolute error up to 5
```
#### scale
Scale can be useful if the computation leading to the result worked on different scale, than is used by the results (and thus expected errors are on a different scale than would be expected based on the results alone).
## Exceptions
* **REQUIRE_NOTHROW(** _expression_ **)** and
* **CHECK_NOTHROW(** _expression_ **)**
Expects that no exception is thrown during evaluation of the expression.
* **REQUIRE_THROWS(** _expression_ **)** and
* **CHECK_THROWS(** _expression_ **)**
@ -62,20 +95,46 @@ Expects that an exception (of any type) is be thrown during evaluation of the ex
* **REQUIRE_THROWS_AS(** _expression_, _exception type_ **)** and
* **CHECK_THROWS_AS(** _expression_, _exception type_ **)**
Expects that an exception of the _specified type_ is thrown during evaluation of the expression.
Expects that an exception of the _specified type_ is thrown during evaluation of the expression. Note that the _exception type_ is used verbatim and you should include (const) reference.
* **REQUIRE_NOTHROW(** _expression_ **)** and
* **CHECK_NOTHROW(** _expression_ **)**
* **REQUIRE_THROWS_WITH(** _expression_, _string or string matcher_ **)** and
* **CHECK_THROWS_WITH(** _expression_, _string or string matcher_ **)**
Expects that no exception is thrown during evaluation of the expression.
Expects that an exception is thrown that, when converted to a string, matches the _string_ or _string matcher_ provided (see next section for Matchers).
e.g.
```cpp
REQUIRE_THROWS_WITH( openThePodBayDoors(), Contains( "afraid" ) && Contains( "can't do that" ) );
REQUIRE_THROWS_WITH( dismantleHal(), "My mind is going" );
```
Please note that the `THROW` family of assertions expects to be passed a single expression, not a statement or series of statements. If you want to check a more complicated sequence of operations, you can use a C++11 lambda function.
```cpp
REQUIRE_NOTHROW([&](){
int i = 1;
int j = 2;
auto k = i + j;
if (k == 3) {
throw 1;
}
}());
```
## Matcher expressions
To support Matchers a slightly different form is used. Matchers will be more fully documented elsewhere. *Note that Matchers are still at early stage development and are subject to change.*
To support Matchers a slightly different form is used. Matchers have [their own documentation](matchers.md).
* **REQUIRE_THAT(** _lhs_, _matcher call_ **)** and
* **CHECK_THAT(** _lhs_, _matcher call_ **)**
* **REQUIRE_THAT(** _lhs_, _matcher expression_ **)** and
* **CHECK_THAT(** _lhs_, _matcher expression_ **)**
Matchers can be composed using `&&`, `||` and `!` operators.
## Thread Safety
Currently assertions in Catch are not thread safe.
For more details, along with workarounds, see the section on [the limitations page](limitations.md#thread-safe-assertions).
---

View File

@ -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.
@ -15,7 +15,7 @@ The XML Reporter writes in an XML format that is specific to Catch.
The advantage of this format is that it corresponds well to the way Catch works (especially the more unusual features, such as nested sections) and is a fully streaming format - that is it writes output as it goes, without having to store up all its results before it can start writing.
The disadvantage is that, being specific to Catch, no existing build servers understand the format natively. It can be used as input to an XSLT transformation that could covert it to, say, HTML - although this loses the streaming advantage, of course.
The disadvantage is that, being specific to Catch, no existing build servers understand the format natively. It can be used as input to an XSLT transformation that could convert it to, say, HTML - although this loses the streaming advantage, of course.
## JUnit Reporter
```-r junit```
@ -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)

View File

@ -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,8 @@ 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 />
</br>
@ -66,6 +71,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 +95,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 +121,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 +215,79 @@ 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 &lt;start|exit|both&gt;</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="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 &lt;section name&gt;</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
View 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/)

View File

@ -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,21 +43,34 @@ 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.
# Default reporter
CATCH_CONFIG_DEFAULT_REPORTER <reporter>
The default reporter (reporter used when no reporters are explicitly specified) can be overriden during compilation time by using the above macro. Note that desired value of the macro is a C string and quotes have to be escaped during compilation: `clang++ test.cpp -DCATCH_CONFIG_DEFAULT_REPORTER=\"xml\"`.
# 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_NULLPTR // nullptr is supported?
CATCH_CONFIG_CPP11_NOEXCEPT // noexcept is supported?
CATCH_CONFIG_CPP11_GENERATED_METHODS // delete and default keywords for methods
CATCH_CONFIG_CPP11_IS_ENUM // std::is_enum is supported?
CATCH_CONFIG_CPP11_TUPLE // std::tuple is supported
CATCH_CONFIG_VARIADIC_MACROS // Usually pre-C++11 compiler extensions are sufficient
CATCH_CONFIG_CPP11_LONG_LONG // generates overloads for the long long type
CATCH_CONFIG_CPP11_OVERRIDE // CATCH_OVERRIDE expands to override (for virtual function implementations)
CATCH_CONFIG_CPP11_UNIQUE_PTR // Use std::unique_ptr instead of std::auto_ptr
CATCH_CONFIG_CPP11_SHUFFLE // Use std::shuffle instead of std::random_shuffle
CATCH_CONFIG_CPP11_TYPE_TRAITS // Use std::enable_if and <type_traits>
CATCH_CONFIG_CPP11_STREAM_INSERTABLE_CHECK // Use C++11 expression SFINAE to check if class can be inserted to std::ostream
Catch has some basic compiler detection that will attempt to select the appropriate mix of these macros. However being incomplete - and often without access to the respective compilers - this detection tends to be conservative.
So overriding control is given to the user. If a compiler supports a feature (and Catch does not already detect it) then one or more of these may be defined to enable it (or suppress it, in some cases). If you do do this please raise an issue, specifying your compiler version (ideally with an idea of how to detect it) and stating that it has such support.
@ -65,6 +78,63 @@ You may also suppress any of these features by using the `_NO_` form, e.g. `CATC
All C++11 support can be disabled with `CATCH_CONFIG_NO_CPP11`
## `CATCH_CONFIG_CPP11_STREAM_INSERTABLE_CHECK`
This flag is off by default, but allows you to resolve problems caused by types with private base class that are streamable, but the classes themselves are not. Without it, the following code will cause a compilation error:
```cpp
#define CATCH_CONFIG_MAIN
#include <catch.hpp>
struct A {};
std::ostream &operator<< (std::ostream &o, const A &v) { return o << 0; }
struct B : private A {
bool operator==(int){ return true;}
};
B f ();
std::ostream g ();
TEST_CASE ("Error in streamable check") {
B x;
REQUIRE (x == 4);
}
```
# Other toggles
CATCH_CONFIG_COUNTER // Use __COUNTER__ to generate unique names for test cases
CATCH_CONFIG_WINDOWS_SEH // Enable SEH handling on Windows
CATCH_CONFIG_FAST_COMPILE // Sacrifices some (rather minor) features for compilation speed
CATCH_CONFIG_POSIX_SIGNALS // Enable handling POSIX signals
CATCH_CONFIG_WINDOWS_CRTDBG // Enable leak checking using Windows's CRT Debug Heap
CATCH_CONFIG_DISABLE_STRINGIFICATION // Disable stringifying the original expression
Currently Catch enables `CATCH_CONFIG_WINDOWS_SEH` only when compiled with MSVC, because some versions of MinGW do not have the necessary Win32 API support.
`CATCH_CONFIG_POSIX_SIGNALS` is on by default, except when Catch is compiled under `Cygwin`, where it is disabled by default (but can be force-enabled by defining `CATCH_CONFIG_POSIX_SIGNALS`).
`CATCH_CONFIG_WINDOWS_CRTDBG` is off by default. If enabled, Windows's CRT is used to check for memory leaks, and displays them after the tests finish running.
Just as with the C++11 conformance toggles, these toggles can be disabled by using `_NO_` form of the toggle, e.g. `CATCH_CONFIG_NO_WINDOWS_SEH`.
## `CATCH_CONFIG_FAST_COMPILE`
Defining this flag speeds up compilation of test files by ~20%, by making 2 changes:
* The `-b` (`--break`) flag no longer makes Catch break into debugger in the same stack frame as the failed test, but rather in a stack frame *below*.
* The `REQUIRE` family of macros (`REQUIRE`, `REQUIRE_FALSE` and `REQUIRE_THAT`) no longer uses local try-catch block. This disables exception translation, but should not lead to false negatives.
`CATCH_CONFIG_FAST_COMPILE` has to be either defined, or not defined, in all translation units that are linked into single test binary, or the behaviour of setting `-b` flag and throwing unexpected exceptions will be unpredictable.
## `CATCH_CONFIG_DISABLE_STRINGIFICATION`
This toggle enables a workaround for VS 2017 bug. For details see
[known limitations](limitations.md#visual-studio-2017----raw-string-literal-in-assert-fails-to-compile).
# 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)

View File

@ -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
View 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)

131
docs/limitations.md Normal file
View File

@ -0,0 +1,131 @@
# 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 2017 -- raw string literal in assert fails to compile
There is a known bug in Visual Studio 2017 (VC 15), that causes compilation error when preprocessor attempts to stringize a raw string literal (`#` preprocessor is applied to it). This snippet is sufficient to trigger the compilation error:
```cpp
#define CATCH_CONFIG_MAIN
#include "catch.hpp"
TEST_CASE("test") {
CHECK(std::string(R"("\)") == "\"\\");
}
```
Catch provides a workaround, it is possible to disable stringification of original expressions by defining `CATCH_CONFIG_DISABLE_STRINGIFICATION`:
```cpp
#define CATCH_CONFIG_FAST_COMPILE
#define CATCH_CONFIG_DISABLE_STRINGIFICATION
#include "catch.hpp"
TEST_CASE("test") {
CHECK(std::string(R"("\)") == "\"\\");
}
```
_Do note that this changes the output somewhat_
```
catchwork\test1.cpp(6):
PASSED:
CHECK( Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION )
with expansion:
""\" == ""\"
```
### 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.

View File

@ -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
View 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
View File

@ -0,0 +1,86 @@
# Open Source projects using Catch
Catch is great for open source. With its [liberal license](../LICENSE.txt) and single-header, dependency-free, distribution
it's easy to just drop the header into your project and start writing tests - what's not to like?
As a result Catch is now being used in many Open Source projects, including some quite well known ones.
This page is an attempt to track those projects. Obviously it can never be complete.
This effort largely relies on the maintainers of the projects themselves updating this page and submitting a PR
(or, if you prefer contact one of the maintainers of Catch directly, use the
[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)

View File

@ -16,7 +16,7 @@ If you just need to have code that executes before and/ or after Catch this is t
#define CATCH_CONFIG_RUNNER
#include "catch.hpp"
int main( int argc, char* const argv[] )
int main( int argc, char* argv[] )
{
// global setup...
@ -24,7 +24,7 @@ int main( int argc, char* const argv[] )
// global clean-up...
return result;
return ( result < 0xff ? result : 0xff );
}
```
@ -36,9 +36,9 @@ If you still want Catch to process the command line, but you want to programatic
#define CATCH_CONFIG_RUNNER
#include "catch.hpp"
int main( int argc, char* const argv[] )
int main( int argc, char* argv[] )
{
Catch::Session session; // There must be exactly once instance
Catch::Session session; // There must be exactly one instance
// writing to session.configData() here sets defaults
// this is the preferred way to set them
@ -51,7 +51,11 @@ int main( int argc, char* const argv[] )
// overrides command line args
// only do this if you know you need to
return session.run();
int numFailed = session.run();
// Note that on unices only the lower 8 bits are usually used, clamping
// the return value to 255 prevents false negative when some multiple
// of 256 tests has failed
return ( numFailed < 0xff ? numFailed : 0xff );
}
```
@ -65,4 +69,4 @@ Catch embeds a powerful command line parser which you can also use to parse your
---
[Home](Readme.md)
[Home](Readme.md)

344
docs/release-notes.md Normal file
View File

@ -0,0 +1,344 @@
# 1.11.0
### Fixes
* The original expression in `REQUIRE_FALSE( expr )` is now reporter properly as `!( expr )` (#1051)
* Previously the parentheses were missing and `x != y` would be expanded as `!x != x`
* `Approx::Margin` is now inclusive (#952)
* Previously it was meant and documented as inclusive, but the check itself wasn't
* This means that `REQUIRE( 0.25f == Approx( 0.0f ).margin( 0.25f ) )` passes, instead of fails
* `RandomNumberGenerator::result_type` is now unsigned (#1050)
### Improvements
* `__JETBRAINS_IDE__` macro handling is now CLion version specific (#1017)
* When CLion 2017.3 or newer is detected, `__COUNTER__` is used instead of
* TeamCity reporter now explicitly flushes output stream after each report (#1057)
* On some platforms, output from redirected streams would show up only after the tests finished running
* `ParseAndAddCatchTests` now can add test files as dependency to CMake configuration
* This means you do not have to manually rerun CMake configuration step to detect new tests
# 1.10.0
### Fixes
* Evaluation layer has been rewritten (backported from Catch 2)
* The new layer is much simpler and fixes some issues (#981)
* Implemented workaround for VS 2017 raw string literal stringification bug (#995)
* Fixed interaction between `[!shouldfail]` and `[!mayfail]` tags and sections
* Previously sections with failing assertions would be marked as failed, not failed-but-ok
### Improvements
* Added [libidentify](https://github.com/janwilmans/LibIdentify) support
* Added "wait-for-keypress" option
# 1.9.7
### Fixes
* Various warnings from clang-tidy, Resharper-C++ and PVS Studio have been addressed (#957)
* Dynamically generated sections are now properly reported (#963)
* Writes to `std::clog` are redirected for reporters (#989)
* Previously only `std::cerr` writes were redirected
* Interleaved writes to `std::cerr` and `std::clog` are combined properly
* Assertions failed before signals/structured exceptions fails test case are properly reported as failed (#990)
### Improvements
* Catch's runtime overhead has been decreased further (#940)
* Added support for IBM i ILE c++ compiler (#976)
* This means that AS/400 is now supported.
* The default reporter can be configured at compile time (#978)
* That is, the reporter used if no reporter is explicitly specified
### Other
* `ParseAndAddCatchTests` cmake script has couple new customization options
# 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
View 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
View File

@ -0,0 +1,45 @@
# Reporters
Catch has a modular reporting system and comes bundled with a handful of useful reporters built in.
You can also write your own reporters.
## Using different reporters
The reporter to use can easily be controlled from the command line.
To specify a reporter use [`-r` or `--reporter`](command-line.md#choosing-a-reporter-to-use), followed by the name of the reporter, e.g.:
```
-r xml
```
If you don't specify a reporter then the console reporter is used by default.
There are four reporters built in to the single include:
* `console` writes as lines of text, formatted to a typical terminal width, with colours if a capable terminal is detected.
* `compact` similar to `console` but optimised for minimal output - each entry on one line
* `junit` writes xml that corresponds to Ant's [junitreport](http://help.catchsoftware.com/display/ET/JUnit+Format) target. Useful for build systems that understand Junit. If you are using Jenkins with Catch 1.x, you can improve quality of output by applying changes in [#923](https://github.com/philsquared/Catch/pull/923).
Because of the way the junit format is structured the run must complete before anything is written.
* `xml` writes an xml format tailored to Catch. Unlike `junit` this is a streaming format so results are delivered progressively.
There are a few additional reporters, for specific build systems, in the Catch repository (in `include\reporters`) which you can `#include` in your project if you would like to make use of them.
Do this in one source file - typically the same one you have `CATCH_CONFIG_MAIN` or `CATCH_CONFIG_RUNNER`.
* `teamcity` writes the native, streaming, format that [TeamCity](https://www.jetbrains.com/teamcity/) understands.
Use this when building as part of a TeamCity build to see results as they happen.
* `tap` writes in the TAP ([Test Anything Protocol](https://en.wikipedia.org/wiki/Test_Anything_Protocol)) format.
* `automake` writes in a format that correspond to [automake .trs](https://www.gnu.org/software/automake/manual/html_node/Log-files-generation-and-test-results-recording.html) files
You see what reporters are available from the command line by running with `--list-reporters`.
By default all these reports are written to stdout, but can be redirected to a file with [`-o` or `--out`](command-line.md#sending-output-to-a-file)
## Writing your own reporter
You can write your own custom reporter and register it with Catch.
At time of writing the interface is subject to some changes so is not, yet, documented here.
If you are determined you shouldn't have too much trouble working it out from the existing implementations -
but do keep in mind upcoming changes (these will be minor, simplifying, changes such as not needing to forward calls to the base class).
---
[Home](Readme.md)

View File

@ -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)

View File

@ -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,31 +28,33 @@ 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`.
* `[!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`.
* `[!shouldfail]` - reverse the failing logic of the test: if the test is successful if it fails, and vice-versa.
* `[!mayfail]` - doesn't fail the test if any given assertion fails (but still reports it). This can be useful to flag a work-in-progress, or a known issue that you don't want to immediately fix but still want to track in your tests.
* `[!mayfail]` - doesn't fail the test if any given assertion fails (but still reports it). This can be useful to flag a work-in-progress, or a known issue that you don't want to immediately fix but still want to track in 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.
* `[#<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]`.
* `[!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 to all contained tests, e.g. tests in testfile.cpp would all be tagged `[#testfile]`.
* `[@<alias>]` - tag aliases all begin with `@` (see below).
## Tag aliases
Between tag expressions and wildcarded test names (as well as combinations of the two) quite complex patterns can be constructed to direct which test cases are run. If a complex pattern is used often it is convenient to be able to create an alias for the expression. this can be done, in code, using the following form:
Between tag expressions and wildcarded test names (as well as combinations of the two) quite complex patterns can be constructed to direct which test cases are run. If a complex pattern is used often it is convenient to be able to create an alias for the expression. This can be done, in code, using the following form:
CATCH_REGISTER_TAG_ALIAS( <alias string>, <tag expression> )
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)

View File

@ -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)

View File

@ -16,16 +16,7 @@ std::ostream& operator << ( std::ostream& os, T const& value ) {
(where ```T``` is your type and ```convertMyTypeToString``` is where you'll write whatever code is necessary to make your type printable - it doesn't have to be in another function).
You should put this function in the same namespace as your type.
Alternatively you may prefer to write it as a member function:
```
std::ostream& T::operator << ( std::ostream& os ) const {
os << convertMyTypeToString( *this );
return os;
}
```
You should put this function in the same namespace as your type and it has to be declared before including Catch's header.
## Catch::toString overload
@ -39,11 +30,12 @@ namespace Catch {
}
```
Again ```T``` is your type and ```convertMyTypeToString``` is where you'll write whatever code is necessary to make your type printable. Note that the function must be in the Catch namespace, which itself must be in the global namespace.
Again ```T``` is your type and ```convertMyTypeToString``` is where you'll write whatever code is necessary to make your type printable. Note that the function must be in the Catch namespace, which itself must be in the global namespace and must be declared _before_ Catch's header is included.
**Please note that overloading `Catch::toString` is currently considered legacy and will not be supported in the next major version of Catch.**
## Catch::StringMaker<T> specialisation
There are some cases where overloading toString does not work as expected. Specialising StringMaker<T> gives you more precise, and reliable, control - but at the cost of slightly more code and complexity:
Another way of telling Catch how to convert a type to string is specialising `Catch::StringMaker` template. This allows you to have separate way of stringifying types for Catch, than you have for writing it to a stream and also doesn't require you to declare it before including Catch's header.
```
namespace Catch {
@ -55,6 +47,16 @@ namespace Catch {
}
```
## Exceptions
By default all exceptions deriving from `std::exception` will be translated to strings by calling the `what()` method. For exception types that do not derive from `std::exception` - or if `what()` does not return a suitable string - use `CATCH_TRANSLATE_EXCEPTION`. This defines a function that takes your exception type, by reference, and returns a string. It can appear anywhere in the code - it doesn't have to be in the same translation unit. For example:
```
CATCH_TRANSLATE_EXCEPTION( MyType& ex ) {
return ex.message();
}
```
---
[Home](Readme.md)

View File

@ -1,6 +1,6 @@
# Getting Catch
The simplest way to get Catch is to download the single header version from [http://builds.catch-lib.net](http://builds.catch-lib.net). Don't be put off by the word "builds" there. The single header is generated by merging a set of individual headers but it is still just normal source code in a header file.
The simplest way to get Catch is to download the latest [single header version](https://raw.githubusercontent.com/philsquared/Catch/master/single_include/catch.hpp). The single header is generated by merging a set of individual headers but it is still just normal source code in a header file.
The full source for Catch, including test projects, documentation, and other things, is hosted on GitHub. [http://catch-lib.net](http://catch-lib.net) will redirect you there.
@ -68,7 +68,7 @@ with expansion:
0 == 1
```
Note that we get the actual return value of Factorial(0) printed for us (0) - even though we used a natural expression with the == operator. That let's us immediately see what the problem is.
Note that we get the actual return value of Factorial(0) printed for us (0) - even though we used a natural expression with the == operator. That lets us immediately see what the problem is.
Let's change the factorial function to:
@ -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?
@ -96,7 +96,7 @@ Although this was a simple test it's been enough to demonstrate a few things abo
Most test frameworks have a class-based fixture mechanism. That is, test cases map to methods on a class and common setup and teardown can be performed in ```setup()``` and ```teardown()``` methods (or constructor/ destructor in languages, like C++, that support deterministic destruction).
While Catch fully supports this way of working there are a few problems with the approach. In particular, the way your code must be split up and the blunt granularity of cause problems. You can only have one setup/ teardown pair across a set of methods, but sometimes you want slightly different setup in each method, or you may even want several levels of setup (a concept which we will clarify later on in this tutorial). It was <a href="http://jamesnewkirk.typepad.com/posts/2007/09/why-you-should-.html">problems like these</a> that led James Newkirk, who led the team that built NUnit, to start again from scratch and <a href="http://jamesnewkirk.typepad.com/posts/2007/09/announcing-xuni.html">build xUnit</a>).
While Catch fully supports this way of working there are a few problems with the approach. In particular the way your code must be split up, and the blunt granularity of it, may cause problems. You can only have one setup/ teardown pair across a set of methods, but sometimes you want slightly different setup in each method, or you may even want several levels of setup (a concept which we will clarify later on in this tutorial). It was <a href="http://jamesnewkirk.typepad.com/posts/2007/09/why-you-should-.html">problems like these</a> that led James Newkirk, who led the team that built NUnit, to start again from scratch and <a href="http://jamesnewkirk.typepad.com/posts/2007/09/announcing-xuni.html">build xUnit</a>).
Catch takes a different approach (to both NUnit and xUnit) that is a more natural fit for C++ and the C family of languages. This is best explained through an example:
@ -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!

View File

@ -1,24 +0,0 @@
## What's new in Catch for 1.0
After a long "developer preview" state Catch turned 1.0 in mid-2013. Just prior to this a large number of changes, some of them breaking, where merged from the integration branch and now form part of the 1.0 code-base. If this might affect you please read this summary through so you know what to expect.
* Calling Catch from your own ```main()``` has changed - please review [the updated docs](own-main.md)
* The command line has changed. The biggest change is that test case names and tags should now only be supplied as primary arguments - in fact the ```-t``` option has been repurposed to mean "list tags". There are [updated docs for this too](command-line.md)
* There is a new reporter interface. If you have written a custom reporter you can use the ```LegacyReporterAdapter``` to minimise any differences. Ideally you should update to the new interface - especially as it has been designed to be more robust in the face of future changes (which should be minimal).
* The docs have moved from the wiki to the repository itself. They consist of a set of markdown files in the docs folder and are referenced directly from the README in the root. You can still read them online from GitHub.
* Lots of new goodness - more documentation for which is coming. The existing docs have been updated to account for some of the changes already (e.g. variadic macros). A quick rundown:
* Variadic macros are used, where possible, so that, e.g. you can write a ```TEST_CASE``` with just a name - or even no name at all (making it an anonymous test case).
* The hierarchical naming convention is deprecated in favour of using tags (see next)
* ```TEST_CASE```s (but not ```SECTION```s) can now be tagged by placing keywords in square brackets in the second argument - e.g.: ```TEST_CASE( "A nice name", "[tag1][tag2]")```. The old style is still supported but please consider using this new style.
* Tests can still be "hidden" using the ```./``` prefix as before, but the preferred way now is to give it the ```[hide]``` tag (hidden tests are skipped if you run the test process without specifying any test specs).
* As well as ```TEST_CASE```s and ```SECTION```s you can now also use BDD-style ```SCENARIO``` (in place of ```TEST_CASE```) and ```GIVEN```, ```WHEN``` and ```THEN``` macros (in place of ```SECTION```s).
* New command line parser. Under the hood it is a complete rewrite - now powered by a command line library that will soon be spun out as a separate project: Clara. The options themselves are largely the same but there are some notable differences (as already discussed).
* Completely overhauled output from the textual reporter (now the Console reporter). This now features a much clearer, cleaner format, including good use of indentation.
More information can be found in [this blog post](http://www.levelofindirection.com/journal/2013/6/28/catch-10.html).
If you find any issues please raise issue tickets on the [issue tracker on GitHub](https://github.com/philsquared/Catch/issues) as before. For general questions, comments and suggestions, though, please use the [new forums on Google Groups](https://groups.google.com/forum/?fromgroups#!forum/catch-forum).
---
[Home](Readme.md)

View File

@ -35,6 +35,10 @@ So what does Catch bring to the party that differentiates it from these? Apart f
* Implement test fixtures using Obj-C classes too (like OCUnit)
* Additional built in matchers that work with Obj-C types (e.g. string matchers)
## Who else is using Catch?
See the list of [open source projects using Catch](opensource-users.md).
See the [tutorial](tutorial.md) to get more of a taste of using CATCH in practice
---

View File

@ -36,7 +36,8 @@
#include "internal/catch_generators.hpp"
#include "internal/catch_interfaces_exception.h"
#include "internal/catch_approx.hpp"
#include "internal/catch_matchers.hpp"
#include "internal/catch_matchers_string.h"
#include "internal/catch_matchers_vector.h"
#include "internal/catch_compiler_capabilities.h"
#include "internal/catch_interfaces_tag_alias_registry.h"
@ -50,6 +51,29 @@
#endif
#ifdef CATCH_IMPL
// !TBD: Move the leak detector code into a separate header
#ifdef CATCH_CONFIG_WINDOWS_CRTDBG
#include <crtdbg.h>
class LeakDetector {
public:
LeakDetector() {
int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
flag |= _CRTDBG_LEAK_CHECK_DF;
flag |= _CRTDBG_ALLOC_MEM_DF;
_CrtSetDbgFlag(flag);
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
_CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
// Change this to leaking allocation's number to break there
_CrtSetBreakAlloc(-1);
}
};
#else
class LeakDetector {};
#endif
LeakDetector leakDetector;
#include "internal/catch_impl.hpp"
#endif
@ -67,48 +91,63 @@
// If this config identifier is defined then all CATCH macros are prefixed with CATCH_
#ifdef CATCH_CONFIG_PREFIX_ALL
#define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE" )
#define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "CATCH_REQUIRE_FALSE" )
#if defined(CATCH_CONFIG_FAST_COMPILE)
#define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST_NO_TRY( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, expr )
#define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST_NO_TRY( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, expr )
#else
#define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, expr )
#define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, expr )
#endif
#define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "", "CATCH_REQUIRE_THROWS" )
#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS_AS" )
#define CATCH_REQUIRE_THROWS_WITH( expr, expectedMessage ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, expectedMessage, "CATCH_REQUIRE_THROWS_WITH" )
#define CATCH_REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_NOTHROW" )
#define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, "", expr )
#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr )
#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr )
#define CATCH_REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( "CATCH_REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, expr )
#define CATCH_CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK" )
#define CATCH_CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CATCH_CHECK_FALSE" )
#define CATCH_CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_IF" )
#define CATCH_CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_ELSE" )
#define CATCH_CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CATCH_CHECK_NOFAIL" )
#define CATCH_CHECK( expr ) INTERNAL_CATCH_TEST( "CATCH_CHECK", Catch::ResultDisposition::ContinueOnFailure, expr )
#define CATCH_CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( "CATCH_CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, expr )
#define CATCH_CHECKED_IF( expr ) INTERNAL_CATCH_IF( "CATCH_CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, expr )
#define CATCH_CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( "CATCH_CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, expr )
#define CATCH_CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( "CATCH_CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, expr )
#define CATCH_CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS" )
#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS_AS" )
#define CATCH_CHECK_THROWS_WITH( expr, expectedMessage ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, expectedMessage, "CATCH_CHECK_THROWS_WITH" )
#define CATCH_CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_NOTHROW" )
#define CATCH_CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, "", expr )
#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr )
#define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr )
#define CATCH_CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( "CATCH_CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, expr )
#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THAT" )
#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THAT" )
#define CATCH_CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg )
#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" )
#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "CATCH_WARN", msg )
#define CATCH_SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" )
#define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" )
#define CATCH_SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" )
#if defined(CATCH_CONFIG_FAST_COMPILE)
#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT_NO_TRY( "CATCH_REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg )
#else
#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg )
#endif
#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg )
#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( "CATCH_WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
#define CATCH_SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg )
#define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( "CATCH_CAPTURE", #msg " := " << Catch::toString(msg) )
#define CATCH_SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( "CATCH_CAPTURE", #msg " := " << Catch::toString(msg) )
#ifdef CATCH_CONFIG_VARIADIC_MACROS
#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
#define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
#define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
#define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
#define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", __VA_ARGS__ )
#define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", __VA_ARGS__ )
#define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ )
#define CATCH_FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
#define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
#else
#define CATCH_TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description )
#define CATCH_TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description )
#define CATCH_METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description )
#define CATCH_REGISTER_TEST_CASE( function, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( function, name, description )
#define CATCH_SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description )
#define CATCH_FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", msg )
#define CATCH_SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", msg )
#define CATCH_FAIL( msg ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, msg )
#define CATCH_FAIL_CHECK( msg ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, msg )
#define CATCH_SUCCEED( msg ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, msg )
#endif
#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" )
@ -125,57 +164,73 @@
#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( "Given: " desc, "" )
#define CATCH_WHEN( desc ) CATCH_SECTION( " When: " desc, "" )
#define CATCH_AND_WHEN( desc ) CATCH_SECTION( " And: " desc, "" )
#define CATCH_THEN( desc ) CATCH_SECTION( " Then: " desc, "" )
#define CATCH_AND_THEN( desc ) CATCH_SECTION( " 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" )
#if defined(CATCH_CONFIG_FAST_COMPILE)
#define REQUIRE( expr ) INTERNAL_CATCH_TEST_NO_TRY( "REQUIRE", Catch::ResultDisposition::Normal, expr )
#define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST_NO_TRY( "REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, expr )
#define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "", "REQUIRE_THROWS" )
#define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "REQUIRE_THROWS_AS" )
#define REQUIRE_THROWS_WITH( expr, expectedMessage ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, expectedMessage, "REQUIRE_THROWS_WITH" )
#define REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "REQUIRE_NOTHROW" )
#else
#define REQUIRE( expr ) INTERNAL_CATCH_TEST( "REQUIRE", Catch::ResultDisposition::Normal, expr )
#define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( "REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, expr )
#endif
#define CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK" )
#define CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CHECK_FALSE" )
#define CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_IF" )
#define CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_ELSE" )
#define CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CHECK_NOFAIL" )
#define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( "REQUIRE_THROWS", Catch::ResultDisposition::Normal, "", expr )
#define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr )
#define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( "REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr )
#define REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( "REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, expr )
#define CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "", "CHECK_THROWS" )
#define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS_AS" )
#define CHECK_THROWS_WITH( expr, expectedMessage ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, expectedMessage, "CHECK_THROWS_WITH" )
#define CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_NOTHROW" )
#define CHECK( expr ) INTERNAL_CATCH_TEST( "CHECK", Catch::ResultDisposition::ContinueOnFailure, expr )
#define CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( "CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, expr )
#define CHECKED_IF( expr ) INTERNAL_CATCH_IF( "CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, expr )
#define CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( "CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, expr )
#define CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( "CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, expr )
#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THAT" )
#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "REQUIRE_THAT" )
#define CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( "CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, "", expr )
#define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr )
#define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( "CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr )
#define CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( "CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, expr )
#define INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" )
#define WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "WARN", msg )
#define SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" )
#define CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" )
#define SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" )
#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg )
#if defined(CATCH_CONFIG_FAST_COMPILE)
#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT_NO_TRY( "REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg )
#else
#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg )
#endif
#define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg )
#define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
#define SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg )
#define CAPTURE( msg ) INTERNAL_CATCH_INFO( "CAPTURE", #msg " := " << Catch::toString(msg) )
#define SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( "CAPTURE", #msg " := " << Catch::toString(msg) )
#ifdef CATCH_CONFIG_VARIADIC_MACROS
#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
#define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
#define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
#define FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", __VA_ARGS__ )
#define SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", __VA_ARGS__ )
#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
#define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
#define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
#define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
#define FAIL( ... ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ )
#define FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
#define SUCCEED( ... ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
#else
#define TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description )
#define TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description )
#define TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description )
#define METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description )
#define REGISTER_TEST_CASE( method, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( method, name, description )
#define SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description )
#define FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", msg )
#define SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", msg )
#define FAIL( msg ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, msg )
#define FAIL_CHECK( msg ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, msg )
#define SUCCEED( msg ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, msg )
#endif
#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" )
@ -196,11 +251,11 @@
#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( " Given: " desc, "" )
#define WHEN( desc ) SECTION( " When: " desc, "" )
#define AND_WHEN( desc ) SECTION( "And when: " desc, "" )
#define THEN( desc ) SECTION( " Then: " desc, "" )
#define AND_THEN( desc ) SECTION( " 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;

View File

@ -1,243 +0,0 @@
/*
* Created by Phil on 31/10/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_RUNNER_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED
#include "internal/catch_commandline.hpp"
#include "internal/catch_list.hpp"
#include "internal/catch_runner_impl.hpp"
#include "internal/catch_test_spec.hpp"
#include "internal/catch_version.h"
#include "internal/catch_text.h"
#include <fstream>
#include <stdlib.h>
#include <limits>
namespace Catch {
class Runner {
public:
Runner( Ptr<Config> const& config )
: m_config( config )
{
openStream();
makeReporter();
}
Totals runTests() {
RunContext context( m_config.get(), m_reporter );
Totals totals;
context.testGroupStarting( "all tests", 1, 1 ); // deprecated?
TestSpec testSpec = m_config->testSpec();
if( !testSpec.hasFilters() )
testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests
std::vector<TestCase> testCases;
getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, *m_config, testCases );
int testsRunForGroup = 0;
for( std::vector<TestCase>::const_iterator it = testCases.begin(), itEnd = testCases.end();
it != itEnd;
++it ) {
testsRunForGroup++;
if( m_testsAlreadyRun.find( *it ) == m_testsAlreadyRun.end() ) {
if( context.aborting() )
break;
totals += context.runTest( *it );
m_testsAlreadyRun.insert( *it );
}
}
std::vector<TestCase> skippedTestCases;
getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, *m_config, skippedTestCases, true );
for( std::vector<TestCase>::const_iterator it = skippedTestCases.begin(), itEnd = skippedTestCases.end();
it != itEnd;
++it )
m_reporter->skipTest( *it );
context.testGroupEnded( "all tests", totals, 1, 1 );
return totals;
}
private:
void openStream() {
// Open output file, if specified
if( !m_config->getFilename().empty() ) {
m_ofs.open( m_config->getFilename().c_str() );
if( m_ofs.fail() ) {
std::ostringstream oss;
oss << "Unable to open file: '" << m_config->getFilename() << "'";
throw std::domain_error( oss.str() );
}
m_config->setStreamBuf( m_ofs.rdbuf() );
}
}
void makeReporter() {
std::string reporterName = m_config->getReporterName().empty()
? "console"
: m_config->getReporterName();
m_reporter = getRegistryHub().getReporterRegistry().create( reporterName, m_config.get() );
if( !m_reporter ) {
std::ostringstream oss;
oss << "No reporter registered with name: '" << reporterName << "'";
throw std::domain_error( oss.str() );
}
}
private:
Ptr<Config> m_config;
std::ofstream m_ofs;
Ptr<IStreamingReporter> m_reporter;
std::set<TestCase> m_testsAlreadyRun;
};
void applyFilenamesAsTags() {
std::vector<TestCase> const& tests = getRegistryHub().getTestCaseRegistry().getAllTests();
for(std::size_t i = 0; i < tests.size(); ++i ) {
TestCase& test = const_cast<TestCase&>( tests[i] );
std::set<std::string> tags = test.tags;
std::string filename = test.lineInfo.file;
std::string::size_type lastSlash = filename.find_last_of( "\\/" );
if( lastSlash != std::string::npos )
filename = filename.substr( lastSlash+1 );
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 );
}
}
class Session : NonCopyable {
static bool alreadyInstantiated;
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 );
}
alreadyInstantiated = true;
}
~Session() {
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;
}
int applyCommandLine( int argc, char* const argv[], OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) {
try {
m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail );
m_unusedTokens = m_cli.parseInto( 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)();
}
return 0;
}
void useConfigData( ConfigData const& _configData ) {
m_configData = _configData;
m_config.reset();
}
int run( int argc, char* const argv[] ) {
int returnCode = applyCommandLine( argc, argv );
if( returnCode == 0 )
returnCode = run();
return returnCode;
}
int run() {
if( m_configData.showHelp )
return 0;
try
{
config(); // Force config to be constructed
if( m_configData.filenamesAsTags )
applyFilenamesAsTags();
seedRng( *m_config );
Runner runner( m_config );
// Handle list request
if( Option<std::size_t> listed = list( config() ) )
return static_cast<int>( *listed );
return static_cast<int>( runner.runTests().assertions.failed );
}
catch( std::exception& ex ) {
Catch::cerr() << ex.what() << std::endl;
return (std::numeric_limits<int>::max)();
}
}
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;
ConfigData m_configData;
Ptr<Config> m_config;
};
bool Session::alreadyInstantiated = false;
} // end namespace Catch
#endif // TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED

272
include/catch_session.hpp Normal file
View File

@ -0,0 +1,272 @@
/*
* Created by Phil on 31/10/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_RUNNER_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED
#include "internal/catch_commandline.hpp"
#include "internal/catch_list.hpp"
#include "internal/catch_run_context.hpp"
#include "internal/catch_test_spec.hpp"
#include "internal/catch_version.h"
#include "internal/catch_text.h"
#include <fstream>
#include <stdlib.h>
#include <limits>
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() );
}
return reporter;
}
#if !defined(CATCH_CONFIG_DEFAULT_REPORTER)
#define CATCH_CONFIG_DEFAULT_REPORTER "console"
#endif
Ptr<IStreamingReporter> makeReporter( Ptr<Config> const& config ) {
std::vector<std::string> reporters = config->getReporterNames();
if( reporters.empty() )
reporters.push_back( CATCH_CONFIG_DEFAULT_REPORTER );
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 ) );
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;
}
Totals runTests( Ptr<Config> const& config ) {
Ptr<IConfig const> iconfig = config.get();
Ptr<IStreamingReporter> reporter = makeReporter( config );
reporter = addListeners( iconfig, reporter );
RunContext context( iconfig, reporter );
Totals totals;
context.testGroupStarting( config->name(), 1, 1 );
TestSpec testSpec = config->testSpec();
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 );
else
reporter->skipTest( *it );
}
context.testGroupEnded( iconfig->name(), totals, 1, 1 );
return totals;
}
void applyFilenamesAsTags( IConfig const& config ) {
std::vector<TestCase> const& tests = getAllTestCasesSorted( config );
for(std::size_t i = 0; i < tests.size(); ++i ) {
TestCase& test = const_cast<TestCase&>( tests[i] );
std::set<std::string> tags = test.tags;
std::string filename = test.lineInfo.file;
std::string::size_type lastSlash = filename.find_last_of( "\\/" );
if( lastSlash != std::string::npos )
filename = filename.substr( lastSlash+1 );
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 );
}
}
class Session : NonCopyable {
static bool alreadyInstantiated;
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 );
}
alreadyInstantiated = true;
}
~Session() {
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 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 );
if( m_configData.libIdentify )
libIdentify();
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)();
}
return 0;
}
void useConfigData( ConfigData const& _configData ) {
m_configData = _configData;
m_config.reset();
}
int run( int argc, char const* const* const argv ) {
int returnCode = applyCommandLine( argc, argv );
if( returnCode == 0 )
returnCode = run();
return returnCode;
}
#if defined(WIN32) && defined(UNICODE)
int run( int argc, wchar_t const* const* const argv ) {
char **utf8Argv = new char *[ argc ];
for ( int i = 0; i < argc; ++i ) {
int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, NULL, 0, NULL, NULL );
utf8Argv[ i ] = new char[ bufSize ];
WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, NULL, NULL );
}
int returnCode = applyCommandLine( argc, utf8Argv );
if( returnCode == 0 )
returnCode = run();
for ( int i = 0; i < argc; ++i )
delete [] utf8Argv[ i ];
delete [] utf8Argv;
return returnCode;
}
#endif
int run() {
if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeStart ) != 0 ) {
Catch::cout() << "...waiting for enter/ return before starting" << std::endl;
static_cast<void>(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;
static_cast<void>(std::getchar());
}
return exitCode;
}
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:
int runInternal() {
if( m_configData.showHelp || m_configData.libIdentify )
return 0;
try
{
config(); // Force config to be constructed
seedRng( *m_config );
if( m_configData.filenamesAsTags )
applyFilenamesAsTags( *m_config );
// Handle list request
if( Option<std::size_t> listed = list( config() ) )
return static_cast<int>( *listed );
return static_cast<int>( runTests( m_config ).assertions.failed );
}
catch( std::exception& ex ) {
Catch::cerr() << ex.what() << std::endl;
return (std::numeric_limits<int>::max)();
}
}
Clara::CommandLine<ConfigData> m_cli;
std::vector<Clara::Parser::Token> m_unusedTokens;
ConfigData m_configData;
Ptr<Config> m_config;
};
bool Session::alreadyInstantiated = false;
} // end namespace Catch
#endif // TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED

View File

@ -8,8 +8,7 @@
#ifndef TWOBLUECUBES_CATCH_WITH_MAIN_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_WITH_MAIN_HPP_INCLUDED
#include "catch_runner.hpp"
#define CATCH_CONFIG_MAIN
#include "catch.hpp"
#include "internal/catch_default_main.hpp"
#endif // TWOBLUECUBES_CATCH_WITH_MAIN_HPP_INCLUDED

View File

@ -6,6 +6,8 @@
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
// Version 0.0.2.4
// Only use header guard if we are not using an outer namespace
#if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE)
@ -38,6 +40,8 @@
#include <string>
#include <vector>
#include <sstream>
#include <algorithm>
#include <cctype>
// Use optional outer namespace
#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE
@ -147,7 +151,7 @@ namespace Tbc {
return oss.str();
}
inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) {
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() )
@ -172,16 +176,179 @@ namespace Tbc {
#endif // TBC_TEXT_FORMAT_H_INCLUDED
// ----------- end of #include from tbc_text_format.h -----------
// ........... back in /Users/philnash/Dev/OSS/Clara/srcs/clara.h
// ........... back in clara.h
#undef STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE
// ----------- #included from clara_compilers.h -----------
/*
* Created by Phil on 10/02/2016.
* Copyright 2016 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED
#define TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED
// Detect a number of compiler features - mostly C++11/14 conformance - by compiler
// The following features are defined:
//
// CLARA_CONFIG_CPP11_NULLPTR : is nullptr supported?
// CLARA_CONFIG_CPP11_NOEXCEPT : is noexcept supported?
// CLARA_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods
// CLARA_CONFIG_CPP11_OVERRIDE : is override supported?
// CLARA_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr)
// CLARA_CONFIG_CPP11_OR_GREATER : Is C++11 supported?
// CLARA_CONFIG_VARIADIC_MACROS : are variadic macros supported?
// In general each macro has a _NO_<feature name> form
// (e.g. CLARA_CONFIG_CPP11_NO_NULLPTR) which disables the feature.
// Many features, at point of detection, define an _INTERNAL_ macro, so they
// can be combined, en-mass, with the _NO_ forms later.
// All the C++11 features can be disabled with CLARA_CONFIG_NO_CPP11
#ifdef __clang__
#if __has_feature(cxx_nullptr)
#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR
#endif
#if __has_feature(cxx_noexcept)
#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT
#endif
#endif // __clang__
////////////////////////////////////////////////////////////////////////////////
// GCC
#ifdef __GNUC__
#if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__)
#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR
#endif
// - otherwise more recent versions define __cplusplus >= 201103L
// and will get picked up below
#endif // __GNUC__
////////////////////////////////////////////////////////////////////////////////
// Visual C++
#ifdef _MSC_VER
#if (_MSC_VER >= 1600)
#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR
#define CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR
#endif
#if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015))
#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT
#define CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
#endif
#endif // _MSC_VER
////////////////////////////////////////////////////////////////////////////////
// C++ language feature support
// catch all support for C++11
#if defined(__cplusplus) && __cplusplus >= 201103L
#define CLARA_CPP11_OR_GREATER
#if !defined(CLARA_INTERNAL_CONFIG_CPP11_NULLPTR)
#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR
#endif
#ifndef CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT
#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT
#endif
#ifndef CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
#define CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
#endif
#if !defined(CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE)
#define CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE
#endif
#if !defined(CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR)
#define CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR
#endif
#endif // __cplusplus >= 201103L
// Now set the actual defines based on the above + anything the user has configured
#if defined(CLARA_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CLARA_CONFIG_CPP11_NO_NULLPTR) && !defined(CLARA_CONFIG_CPP11_NULLPTR) && !defined(CLARA_CONFIG_NO_CPP11)
#define CLARA_CONFIG_CPP11_NULLPTR
#endif
#if defined(CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CLARA_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_CONFIG_NO_CPP11)
#define CLARA_CONFIG_CPP11_NOEXCEPT
#endif
#if defined(CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CLARA_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CLARA_CONFIG_CPP11_GENERATED_METHODS) && !defined(CLARA_CONFIG_NO_CPP11)
#define CLARA_CONFIG_CPP11_GENERATED_METHODS
#endif
#if defined(CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CLARA_CONFIG_NO_OVERRIDE) && !defined(CLARA_CONFIG_CPP11_OVERRIDE) && !defined(CLARA_CONFIG_NO_CPP11)
#define CLARA_CONFIG_CPP11_OVERRIDE
#endif
#if defined(CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CLARA_CONFIG_NO_UNIQUE_PTR) && !defined(CLARA_CONFIG_CPP11_UNIQUE_PTR) && !defined(CLARA_CONFIG_NO_CPP11)
#define CLARA_CONFIG_CPP11_UNIQUE_PTR
#endif
// noexcept support:
#if defined(CLARA_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_NOEXCEPT)
#define CLARA_NOEXCEPT noexcept
# define CLARA_NOEXCEPT_IS(x) noexcept(x)
#else
#define CLARA_NOEXCEPT throw()
# define CLARA_NOEXCEPT_IS(x)
#endif
// nullptr support
#ifdef CLARA_CONFIG_CPP11_NULLPTR
#define CLARA_NULL nullptr
#else
#define CLARA_NULL NULL
#endif
// override support
#ifdef CLARA_CONFIG_CPP11_OVERRIDE
#define CLARA_OVERRIDE override
#else
#define CLARA_OVERRIDE
#endif
// unique_ptr support
#ifdef CLARA_CONFIG_CPP11_UNIQUE_PTR
# define CLARA_AUTO_PTR( T ) std::unique_ptr<T>
#else
# define CLARA_AUTO_PTR( T ) std::auto_ptr<T>
#endif
#endif // TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED
// ----------- end of #include from clara_compilers.h -----------
// ........... back in clara.h
#include <map>
#include <algorithm>
#include <stdexcept>
#include <memory>
#if defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER)
#define CLARA_PLATFORM_WINDOWS
#endif
// Use optional outer namespace
#ifdef STITCH_CLARA_OPEN_NAMESPACE
STITCH_CLARA_OPEN_NAMESPACE
@ -230,9 +397,12 @@ namespace Clara {
inline void convertInto( std::string const& _source, std::string& _dest ) {
_dest = _source;
}
char toLowerCh(char c) {
return static_cast<char>( std::tolower( c ) );
}
inline void convertInto( std::string const& _source, bool& _dest ) {
std::string sourceLC = _source;
std::transform( sourceLC.begin(), sourceLC.end(), sourceLC.begin(), ::tolower );
std::transform( sourceLC.begin(), sourceLC.end(), sourceLC.begin(), toLowerCh );
if( sourceLC == "y" || sourceLC == "1" || sourceLC == "true" || sourceLC == "yes" || sourceLC == "on" )
_dest = true;
else if( sourceLC == "n" || sourceLC == "0" || sourceLC == "false" || sourceLC == "no" || sourceLC == "off" )
@ -240,23 +410,16 @@ namespace Clara {
else
throw std::runtime_error( "Expected a boolean value but did not recognise:\n '" + _source + "'" );
}
inline void convertInto( bool _source, bool& _dest ) {
_dest = _source;
}
template<typename T>
inline void convertInto( bool, T& ) {
throw std::runtime_error( "Invalid conversion" );
}
template<typename ConfigT>
struct IArgFunction {
virtual ~IArgFunction() {}
# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
#ifdef CLARA_CONFIG_CPP11_GENERATED_METHODS
IArgFunction() = default;
IArgFunction( IArgFunction const& ) = default;
# endif
#endif
virtual void set( ConfigT& config, std::string const& value ) const = 0;
virtual void setFlag( ConfigT& config ) const = 0;
virtual bool takesArg() const = 0;
virtual IArgFunction* clone() const = 0;
};
@ -264,11 +427,11 @@ namespace Clara {
template<typename ConfigT>
class BoundArgFunction {
public:
BoundArgFunction() : functionObj( CATCH_NULL ) {}
BoundArgFunction() : functionObj( CLARA_NULL ) {}
BoundArgFunction( IArgFunction<ConfigT>* _functionObj ) : functionObj( _functionObj ) {}
BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj ? other.functionObj->clone() : CATCH_NULL ) {}
BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj ? other.functionObj->clone() : CLARA_NULL ) {}
BoundArgFunction& operator = ( BoundArgFunction const& other ) {
IArgFunction<ConfigT>* newFunctionObj = other.functionObj ? other.functionObj->clone() : CATCH_NULL;
IArgFunction<ConfigT>* newFunctionObj = other.functionObj ? other.functionObj->clone() : CLARA_NULL;
delete functionObj;
functionObj = newFunctionObj;
return *this;
@ -278,13 +441,10 @@ namespace Clara {
void set( ConfigT& config, std::string const& value ) const {
functionObj->set( config, value );
}
void setFlag( ConfigT& config ) const {
functionObj->setFlag( config );
}
bool takesArg() const { return functionObj->takesArg(); }
bool isSet() const {
return functionObj != CATCH_NULL;
return functionObj != CLARA_NULL;
}
private:
IArgFunction<ConfigT>* functionObj;
@ -294,7 +454,6 @@ namespace Clara {
template<typename C>
struct NullBinder : IArgFunction<C>{
virtual void set( C&, std::string const& ) const {}
virtual void setFlag( C& ) const {}
virtual bool takesArg() const { return true; }
virtual IArgFunction<C>* clone() const { return new NullBinder( *this ); }
};
@ -305,9 +464,6 @@ namespace Clara {
virtual void set( C& p, std::string const& stringValue ) const {
convertInto( stringValue, p.*member );
}
virtual void setFlag( C& p ) const {
convertInto( true, p.*member );
}
virtual bool takesArg() const { return !IsBool<M>::value; }
virtual IArgFunction<C>* clone() const { return new BoundDataMember( *this ); }
M C::* member;
@ -320,11 +476,6 @@ namespace Clara {
convertInto( stringValue, value );
(p.*member)( value );
}
virtual void setFlag( C& p ) const {
typename RemoveConstRef<M>::type value;
convertInto( true, value );
(p.*member)( value );
}
virtual bool takesArg() const { return !IsBool<M>::value; }
virtual IArgFunction<C>* clone() const { return new BoundUnaryMethod( *this ); }
void (C::*member)( M );
@ -338,9 +489,6 @@ namespace Clara {
if( value )
(p.*member)();
}
virtual void setFlag( C& p ) const {
(p.*member)();
}
virtual bool takesArg() const { return false; }
virtual IArgFunction<C>* clone() const { return new BoundNullaryMethod( *this ); }
void (C::*member)();
@ -355,9 +503,6 @@ namespace Clara {
if( value )
function( obj );
}
virtual void setFlag( C& p ) const {
function( p );
}
virtual bool takesArg() const { return false; }
virtual IArgFunction<C>* clone() const { return new BoundUnaryFunction( *this ); }
void (*function)( C& );
@ -371,11 +516,6 @@ namespace Clara {
convertInto( stringValue, value );
function( obj, value );
}
virtual void setFlag( C& obj ) const {
typename RemoveConstRef<T>::type value;
convertInto( true, value );
function( obj, value );
}
virtual bool takesArg() const { return !IsBool<T>::value; }
virtual IArgFunction<C>* clone() const { return new BoundBinaryFunction( *this ); }
void (*function)( C&, T );
@ -383,8 +523,20 @@ namespace Clara {
} // namespace Detail
struct Parser {
Parser() : separators( " \t=:" ) {}
inline std::vector<std::string> argsToVector( int argc, char const* const* const argv ) {
std::vector<std::string> args( static_cast<std::size_t>( argc ) );
for( std::size_t i = 0; i < static_cast<std::size_t>( argc ); ++i )
args[i] = argv[i];
return args;
}
class Parser {
enum Mode { None, MaybeShortOpt, SlashOpt, ShortOpt, LongOpt, Positional };
Mode mode;
std::size_t from;
bool inQuotes;
public:
struct Token {
enum Type { Positional, ShortOpt, LongOpt };
@ -393,38 +545,77 @@ namespace Clara {
std::string data;
};
void parseIntoTokens( int argc, char const * const * argv, std::vector<Parser::Token>& tokens ) const {
Parser() : mode( None ), from( 0 ), inQuotes( false ){}
void parseIntoTokens( std::vector<std::string> const& args, std::vector<Token>& tokens ) {
const std::string doubleDash = "--";
for( int i = 1; i < argc && argv[i] != doubleDash; ++i )
parseIntoTokens( argv[i] , tokens);
for( std::size_t i = 1; i < args.size() && args[i] != doubleDash; ++i )
parseIntoTokens( args[i], tokens);
}
void parseIntoTokens( std::string arg, std::vector<Parser::Token>& tokens ) const {
while( !arg.empty() ) {
Parser::Token token( Parser::Token::Positional, arg );
arg = "";
if( token.data[0] == '-' ) {
if( token.data.size() > 1 && token.data[1] == '-' ) {
token = Parser::Token( Parser::Token::LongOpt, token.data.substr( 2 ) );
}
else {
token = Parser::Token( Parser::Token::ShortOpt, token.data.substr( 1 ) );
if( token.data.size() > 1 && separators.find( token.data[1] ) == std::string::npos ) {
arg = "-" + token.data.substr( 1 );
token.data = token.data.substr( 0, 1 );
}
}
}
if( token.type != Parser::Token::Positional ) {
std::size_t pos = token.data.find_first_of( separators );
if( pos != std::string::npos ) {
arg = token.data.substr( pos+1 );
token.data = token.data.substr( 0, pos );
}
}
tokens.push_back( token );
void parseIntoTokens( std::string const& arg, std::vector<Token>& tokens ) {
for( std::size_t i = 0; i < arg.size(); ++i ) {
char c = arg[i];
if( c == '"' )
inQuotes = !inQuotes;
mode = handleMode( i, c, arg, tokens );
}
mode = handleMode( arg.size(), '\0', arg, tokens );
}
Mode handleMode( std::size_t i, char c, std::string const& arg, std::vector<Token>& tokens ) {
switch( mode ) {
case None: return handleNone( i, c );
case MaybeShortOpt: return handleMaybeShortOpt( i, c );
case ShortOpt:
case LongOpt:
case SlashOpt: return handleOpt( i, c, arg, tokens );
case Positional: return handlePositional( i, c, arg, tokens );
default: throw std::logic_error( "Unknown mode" );
}
}
std::string separators;
Mode handleNone( std::size_t i, char c ) {
if( inQuotes ) {
from = i;
return Positional;
}
switch( c ) {
case '-': return MaybeShortOpt;
#ifdef CLARA_PLATFORM_WINDOWS
case '/': from = i+1; return SlashOpt;
#endif
default: from = i; return Positional;
}
}
Mode handleMaybeShortOpt( std::size_t i, char c ) {
switch( c ) {
case '-': from = i+1; return LongOpt;
default: from = i; return ShortOpt;
}
}
Mode handleOpt( std::size_t i, char c, std::string const& arg, std::vector<Token>& tokens ) {
if( std::string( ":=\0", 3 ).find( c ) == std::string::npos )
return mode;
std::string optName = arg.substr( from, i-from );
if( mode == ShortOpt )
for( std::size_t j = 0; j < optName.size(); ++j )
tokens.push_back( Token( Token::ShortOpt, optName.substr( j, 1 ) ) );
else if( mode == SlashOpt && optName.size() == 1 )
tokens.push_back( Token( Token::ShortOpt, optName ) );
else
tokens.push_back( Token( Token::LongOpt, optName ) );
return None;
}
Mode handlePositional( std::size_t i, char c, std::string const& arg, std::vector<Token>& tokens ) {
if( inQuotes || std::string( "\0", 1 ).find( c ) == std::string::npos )
return mode;
std::string data = arg.substr( from, i-from );
tokens.push_back( Token( Token::Positional, data ) );
return None;
}
};
template<typename ConfigT>
@ -503,12 +694,7 @@ namespace Clara {
}
};
// NOTE: std::auto_ptr is deprecated in c++11/c++0x
#if defined(__cplusplus) && __cplusplus > 199711L
typedef std::unique_ptr<Arg> ArgAutoPtr;
#else
typedef std::auto_ptr<Arg> ArgAutoPtr;
#endif
typedef CLARA_AUTO_PTR( Arg ) ArgAutoPtr;
friend void addOptName( Arg& arg, std::string const& optName )
{
@ -585,8 +771,8 @@ namespace Clara {
m_arg->description = description;
return *this;
}
ArgBuilder& detail( std::string const& _detail ) {
m_arg->detail = _detail;
ArgBuilder& detail( std::string const& detail ) {
m_arg->detail = detail;
return *this;
}
@ -670,14 +856,14 @@ namespace Clara {
maxWidth = (std::max)( maxWidth, it->commands().size() );
for( it = itBegin; it != itEnd; ++it ) {
Detail::Text usageText( it->commands(), Detail::TextAttributes()
Detail::Text usage( it->commands(), Detail::TextAttributes()
.setWidth( maxWidth+indent )
.setIndent( indent ) );
Detail::Text desc( it->description, Detail::TextAttributes()
.setWidth( width - maxWidth - 3 ) );
for( std::size_t i = 0; i < (std::max)( usageText.size(), desc.size() ); ++i ) {
std::string usageCol = i < usageText.size() ? usageText[i] : "";
for( std::size_t i = 0; i < (std::max)( usage.size(), desc.size() ); ++i ) {
std::string usageCol = i < usage.size() ? usage[i] : "";
os << usageCol;
if( i < desc.size() && !desc[i].empty() )
@ -734,21 +920,21 @@ namespace Clara {
return oss.str();
}
ConfigT parse( int argc, char const * const * argv ) const {
ConfigT parse( std::vector<std::string> const& args ) const {
ConfigT config;
parseInto( argc, argv, config );
parseInto( args, config );
return config;
}
std::vector<Parser::Token> parseInto( int argc, char const * const * argv, ConfigT& config ) const {
std::string processName = argv[0];
std::vector<Parser::Token> parseInto( std::vector<std::string> const& args, ConfigT& config ) const {
std::string processName = args.empty() ? std::string() : args[0];
std::size_t lastSlash = processName.find_last_of( "/\\" );
if( lastSlash != std::string::npos )
processName = processName.substr( lastSlash+1 );
m_boundProcessName.set( config, processName );
std::vector<Parser::Token> tokens;
Parser parser;
parser.parseIntoTokens( argc, argv, tokens );
parser.parseIntoTokens( args, tokens );
return populate( tokens, config );
}
@ -779,7 +965,7 @@ namespace Clara {
arg.boundField.set( config, tokens[++i].data );
}
else {
arg.boundField.setFlag( config );
arg.boundField.set( config, "true" );
}
break;
}

View File

@ -37,19 +37,16 @@ namespace Tbc {
TextAttributes()
: initialIndent( std::string::npos ),
indent( 0 ),
width( consoleWidth-1 ),
tabChar( '\t' )
width( consoleWidth-1 )
{}
TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; }
TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; }
TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; }
TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; }
std::size_t initialIndent; // indent of first line, or npos
std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos
std::size_t width; // maximum width of text, including indent. Longer text will wrap
char tabChar; // If this char is seen the indent is changed to current pos
};
class Text {
@ -57,63 +54,80 @@ namespace Tbc {
Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() )
: attr( _attr )
{
std::string wrappableChars = " [({.,/|\\-";
std::size_t indent = _attr.initialIndent != std::string::npos
? _attr.initialIndent
: _attr.indent;
std::string remainder = _str;
const std::string wrappableBeforeChars = "[({<\t";
const std::string wrappableAfterChars = "])}>-,./|\\";
const std::string wrappableInsteadOfChars = " \n\r";
std::string indent = _attr.initialIndent != std::string::npos
? std::string( _attr.initialIndent, ' ' )
: std::string( _attr.indent, ' ' );
typedef std::string::const_iterator iterator;
iterator it = _str.begin();
const iterator strEnd = _str.end();
while( it != strEnd ) {
while( !remainder.empty() ) {
if( lines.size() >= 1000 ) {
lines.push_back( "... message truncated due to excessive size" );
return;
}
std::size_t tabPos = std::string::npos;
std::size_t width = (std::min)( remainder.size(), _attr.width - indent );
std::size_t pos = remainder.find_first_of( '\n' );
if( pos <= width ) {
width = pos;
}
pos = remainder.find_last_of( _attr.tabChar, width );
if( pos != std::string::npos ) {
tabPos = pos;
if( remainder[width] == '\n' )
width--;
remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 );
}
if( width == remainder.size() ) {
spliceLine( indent, remainder, width );
}
else if( remainder[width] == '\n' ) {
spliceLine( indent, remainder, width );
if( width <= 1 || remainder.size() != 1 )
remainder = remainder.substr( 1 );
indent = _attr.indent;
}
else {
pos = remainder.find_last_of( wrappableChars, width );
if( pos != std::string::npos && pos > 0 ) {
spliceLine( indent, remainder, pos );
if( remainder[0] == ' ' )
remainder = remainder.substr( 1 );
std::string suffix;
std::size_t width = (std::min)( static_cast<size_t>( strEnd-it ), _attr.width-static_cast<size_t>( indent.size() ) );
iterator itEnd = it+width;
iterator itNext = _str.end();
iterator itNewLine = std::find( it, itEnd, '\n' );
if( itNewLine != itEnd )
itEnd = itNewLine;
if( itEnd != strEnd ) {
bool foundWrapPoint = false;
iterator findIt = itEnd;
do {
if( wrappableAfterChars.find( *findIt ) != std::string::npos && findIt != itEnd ) {
itEnd = findIt+1;
itNext = findIt+1;
foundWrapPoint = true;
}
else if( findIt > it && wrappableBeforeChars.find( *findIt ) != std::string::npos ) {
itEnd = findIt;
itNext = findIt;
foundWrapPoint = true;
}
else if( wrappableInsteadOfChars.find( *findIt ) != std::string::npos ) {
itNext = findIt+1;
itEnd = findIt;
foundWrapPoint = true;
}
if( findIt == it )
break;
else
--findIt;
}
while( !foundWrapPoint );
if( !foundWrapPoint ) {
// No good wrap char, so we'll break mid word and add a hyphen
--itEnd;
itNext = itEnd;
suffix = "-";
}
else {
spliceLine( indent, remainder, width-1 );
lines.back() += "-";
while( itEnd > it && wrappableInsteadOfChars.find( *(itEnd-1) ) != std::string::npos )
--itEnd;
}
if( lines.size() == 1 )
indent = _attr.indent;
if( tabPos != std::string::npos )
indent += tabPos;
}
lines.push_back( indent + std::string( it, itEnd ) + suffix );
if( indent.size() != _attr.indent )
indent = std::string( _attr.indent, ' ' );
it = itNext;
}
}
void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) {
lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) );
_remainder = _remainder.substr( _pos );
}
typedef std::vector<std::string>::const_iterator const_iterator;
@ -138,6 +152,7 @@ namespace Tbc {
return _stream;
}
private:
std::string str;
TextAttributes attr;

View File

@ -13,6 +13,10 @@
#include <cmath>
#include <limits>
#if defined(CATCH_CONFIG_CPP11_TYPE_TRAITS)
#include <type_traits>
#endif
namespace Catch {
namespace Detail {
@ -20,30 +24,114 @@ namespace Detail {
public:
explicit Approx ( double value )
: m_epsilon( std::numeric_limits<float>::epsilon()*100 ),
m_margin( 0.0 ),
m_scale( 1.0 ),
m_value( value )
{}
Approx( Approx const& other )
: m_epsilon( other.m_epsilon ),
m_scale( other.m_scale ),
m_value( other.m_value )
{}
static Approx custom() {
return Approx( 0 );
}
Approx operator()( double value ) {
Approx approx( value );
#if defined(CATCH_CONFIG_CPP11_TYPE_TRAITS)
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
Approx operator()( T value ) {
Approx approx( static_cast<double>(value) );
approx.epsilon( m_epsilon );
approx.margin( m_margin );
approx.scale( m_scale );
return approx;
}
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
explicit Approx( T value ): Approx(static_cast<double>(value))
{}
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
friend bool operator == ( const T& lhs, Approx const& rhs ) {
// Thanks to Richard Harris for his help refining this formula
auto lhs_v = double(lhs);
bool relativeOK = std::fabs(lhs_v - rhs.m_value) < rhs.m_epsilon * (rhs.m_scale + (std::max)(std::fabs(lhs_v), std::fabs(rhs.m_value)));
if (relativeOK) {
return true;
}
return std::fabs(lhs_v - rhs.m_value) <= rhs.m_margin;
}
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
friend bool operator == ( Approx const& lhs, const T& rhs ) {
return operator==( rhs, lhs );
}
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
friend bool operator != ( T lhs, Approx const& rhs ) {
return !operator==( lhs, rhs );
}
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
friend bool operator != ( Approx const& lhs, T rhs ) {
return !operator==( rhs, lhs );
}
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
friend bool operator <= ( T lhs, Approx const& rhs ) {
return double(lhs) < rhs.m_value || lhs == rhs;
}
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
friend bool operator <= ( Approx const& lhs, T rhs ) {
return lhs.m_value < double(rhs) || lhs == rhs;
}
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
friend bool operator >= ( T lhs, Approx const& rhs ) {
return double(lhs) > rhs.m_value || lhs == rhs;
}
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
friend bool operator >= ( Approx const& lhs, T rhs ) {
return lhs.m_value > double(rhs) || lhs == rhs;
}
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
Approx& epsilon( T newEpsilon ) {
m_epsilon = double(newEpsilon);
return *this;
}
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
Approx& margin( T newMargin ) {
m_margin = double(newMargin);
return *this;
}
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
Approx& scale( T newScale ) {
m_scale = double(newScale);
return *this;
}
#else
Approx operator()( double value ) {
Approx approx( value );
approx.epsilon( m_epsilon );
approx.margin( m_margin );
approx.scale( m_scale );
return approx;
}
friend bool operator == ( double lhs, Approx const& rhs ) {
// Thanks to Richard Harris for his help refining this formula
return fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( fabs(lhs), fabs(rhs.m_value) ) );
bool relativeOK = std::fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( std::fabs(lhs), std::fabs(rhs.m_value) ) );
if (relativeOK) {
return true;
}
return std::fabs(lhs - rhs.m_value) <= rhs.m_margin;
}
friend bool operator == ( Approx const& lhs, double rhs ) {
@ -58,15 +146,37 @@ namespace Detail {
return !operator==( rhs, lhs );
}
friend bool operator <= ( double lhs, Approx const& rhs ) {
return lhs < rhs.m_value || lhs == rhs;
}
friend bool operator <= ( Approx const& lhs, double rhs ) {
return lhs.m_value < rhs || lhs == rhs;
}
friend bool operator >= ( double lhs, Approx const& rhs ) {
return lhs > rhs.m_value || lhs == rhs;
}
friend bool operator >= ( Approx const& lhs, double rhs ) {
return lhs.m_value > rhs || lhs == rhs;
}
Approx& epsilon( double newEpsilon ) {
m_epsilon = newEpsilon;
return *this;
}
Approx& margin( double newMargin ) {
m_margin = newMargin;
return *this;
}
Approx& scale( double newScale ) {
m_scale = newScale;
return *this;
}
#endif
std::string toString() const {
std::ostringstream oss;
@ -76,6 +186,7 @@ namespace Detail {
private:
double m_epsilon;
double m_margin;
double m_scale;
double m_value;
};

View File

@ -13,27 +13,83 @@
namespace Catch {
struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison;
struct DecomposedExpression
{
virtual ~DecomposedExpression() {}
virtual bool isBinaryExpression() const {
return false;
}
virtual void reconstructExpression( std::string& dest ) const = 0;
// Only simple binary comparisons can be decomposed.
// If more complex check is required then wrap sub-expressions in parentheses.
template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( T const& );
template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( T const& );
template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * ( T const& );
template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / ( T const& );
template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator % ( T const& );
template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( T const& );
template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( T const& );
private:
DecomposedExpression& operator = (DecomposedExpression const&);
};
struct AssertionInfo
{
AssertionInfo() {}
AssertionInfo( std::string const& _macroName,
AssertionInfo();
AssertionInfo( char const * _macroName,
SourceLineInfo const& _lineInfo,
std::string const& _capturedExpression,
ResultDisposition::Flags _resultDisposition );
char const * _capturedExpression,
ResultDisposition::Flags _resultDisposition,
char const * _secondArg = "");
std::string macroName;
char const * macroName;
SourceLineInfo lineInfo;
std::string capturedExpression;
char const * capturedExpression;
ResultDisposition::Flags resultDisposition;
char const * secondArg;
};
struct AssertionResultData
{
AssertionResultData() : resultType( ResultWas::Unknown ) {}
AssertionResultData() : decomposedExpression( CATCH_NULL )
, resultType( ResultWas::Unknown )
, negated( false )
, parenthesized( false ) {}
std::string reconstructedExpression;
void negate( bool parenthesize ) {
negated = !negated;
parenthesized = parenthesize;
if( resultType == ResultWas::Ok )
resultType = ResultWas::ExpressionFailed;
else if( resultType == ResultWas::ExpressionFailed )
resultType = ResultWas::Ok;
}
std::string const& reconstructExpression() const {
if( decomposedExpression != CATCH_NULL ) {
decomposedExpression->reconstructExpression( reconstructedExpression );
if( parenthesized ) {
reconstructedExpression.insert( 0, 1, '(' );
reconstructedExpression.append( 1, ')' );
}
if( negated ) {
reconstructedExpression.insert( 0, 1, '!' );
}
decomposedExpression = CATCH_NULL;
}
return reconstructedExpression;
}
mutable DecomposedExpression const* decomposedExpression;
mutable std::string reconstructedExpression;
std::string message;
ResultWas::OfType resultType;
bool negated;
bool parenthesized;
};
class AssertionResult {
@ -60,6 +116,8 @@ namespace Catch {
std::string getMessage() const;
SourceLineInfo getSourceInfo() const;
std::string getTestMacroName() const;
void discardDecomposedExpression() const;
void expandDecomposedExpression() const;
protected:
AssertionInfo m_info;

View File

@ -13,14 +13,18 @@
namespace Catch {
AssertionInfo::AssertionInfo( std::string const& _macroName,
AssertionInfo::AssertionInfo():macroName(""), capturedExpression(""), resultDisposition(ResultDisposition::Normal), secondArg(""){}
AssertionInfo::AssertionInfo( char const * _macroName,
SourceLineInfo const& _lineInfo,
std::string const& _capturedExpression,
ResultDisposition::Flags _resultDisposition )
char const * _capturedExpression,
ResultDisposition::Flags _resultDisposition,
char const * _secondArg)
: macroName( _macroName ),
lineInfo( _lineInfo ),
capturedExpression( _capturedExpression ),
resultDisposition( _resultDisposition )
resultDisposition( _resultDisposition ),
secondArg( _secondArg )
{}
AssertionResult::AssertionResult() {}
@ -47,24 +51,30 @@ namespace Catch {
}
bool AssertionResult::hasExpression() const {
return !m_info.capturedExpression.empty();
return m_info.capturedExpression[0] != 0;
}
bool AssertionResult::hasMessage() const {
return !m_resultData.message.empty();
}
std::string capturedExpressionWithSecondArgument( char const * capturedExpression, char const * secondArg ) {
return (secondArg[0] == 0 || secondArg[0] == '"' && secondArg[1] == '"')
? capturedExpression
: std::string(capturedExpression) + ", " + secondArg;
}
std::string AssertionResult::getExpression() const {
if( isFalseTest( m_info.resultDisposition ) )
return "!" + m_info.capturedExpression;
return "!(" + capturedExpressionWithSecondArgument(m_info.capturedExpression, m_info.secondArg) + ")";
else
return m_info.capturedExpression;
return capturedExpressionWithSecondArgument(m_info.capturedExpression, m_info.secondArg);
}
std::string AssertionResult::getExpressionInMacro() const {
if( m_info.macroName.empty() )
return m_info.capturedExpression;
if( m_info.macroName[0] == 0 )
return capturedExpressionWithSecondArgument(m_info.capturedExpression, m_info.secondArg);
else
return m_info.macroName + "( " + m_info.capturedExpression + " )";
return std::string(m_info.macroName) + "( " + capturedExpressionWithSecondArgument(m_info.capturedExpression, m_info.secondArg) + " )";
}
bool AssertionResult::hasExpandedExpression() const {
@ -72,7 +82,7 @@ namespace Catch {
}
std::string AssertionResult::getExpandedExpression() const {
return m_resultData.reconstructedExpression;
return m_resultData.reconstructExpression();
}
std::string AssertionResult::getMessage() const {
@ -86,6 +96,14 @@ namespace Catch {
return m_info.macroName;
}
void AssertionResult::discardDecomposedExpression() const {
m_resultData.decomposedExpression = CATCH_NULL;
}
void AssertionResult::expandDecomposedExpression() const {
m_resultData.reconstructExpression();
}
} // end namespace Catch
#endif // TWOBLUECUBES_CATCH_ASSERTIONRESULT_HPP_INCLUDED

View File

@ -18,6 +18,47 @@
#include "catch_compiler_capabilities.h"
#if !defined(CATCH_CONFIG_DISABLE_STRINGIFICATION)
# define CATCH_INTERNAL_STRINGIFY(expr) #expr
#else
# define CATCH_INTERNAL_STRINGIFY(expr) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION"
#endif
#if defined(CATCH_CONFIG_FAST_COMPILE)
///////////////////////////////////////////////////////////////////////////////
// We can speedup compilation significantly by breaking into debugger lower in
// the callstack, because then we don't have to expand CATCH_BREAK_INTO_DEBUGGER
// macro in each assertion
#define INTERNAL_CATCH_REACT( resultBuilder ) \
resultBuilder.react();
///////////////////////////////////////////////////////////////////////////////
// Another way to speed-up compilation is to omit local try-catch for REQUIRE*
// macros.
// This can potentially cause false negative, if the test code catches
// the exception before it propagates back up to the runner.
#define INTERNAL_CATCH_TEST_NO_TRY( macroName, resultDisposition, expr ) \
do { \
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr), resultDisposition ); \
__catchResult.setExceptionGuard(); \
CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
( __catchResult <= expr ).endExpression(); \
CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
__catchResult.unsetExceptionGuard(); \
INTERNAL_CATCH_REACT( __catchResult ) \
} while( Catch::isTrue( false && static_cast<bool>( !!(expr) ) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look
// The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&.
#define INTERNAL_CHECK_THAT_NO_TRY( macroName, matcher, resultDisposition, arg ) \
do { \
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
__catchResult.setExceptionGuard(); \
__catchResult.captureMatch( arg, matcher, CATCH_INTERNAL_STRINGIFY(matcher) ); \
__catchResult.unsetExceptionGuard(); \
INTERNAL_CATCH_REACT( __catchResult ) \
} while( Catch::alwaysFalse() )
#else
///////////////////////////////////////////////////////////////////////////////
// In the event of a failure works out if the debugger needs to be invoked
// and/or an exception thrown and takes appropriate action.
@ -26,37 +67,41 @@
#define INTERNAL_CATCH_REACT( resultBuilder ) \
if( resultBuilder.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \
resultBuilder.react();
#endif
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ) \
#define INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ) \
do { \
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr), resultDisposition ); \
try { \
CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
( __catchResult <= expr ).endExpression(); \
CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
} \
catch( ... ) { \
__catchResult.useActiveException( Catch::ResultDisposition::Normal ); \
__catchResult.useActiveException( resultDisposition ); \
} \
INTERNAL_CATCH_REACT( __catchResult ) \
} while( Catch::isTrue( false && (expr) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look
} while( Catch::isTrue( false && static_cast<bool>( !!(expr) ) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look
// The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&.
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_IF( expr, resultDisposition, macroName ) \
INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \
if( Catch::getResultCapture().getLastResult()->succeeded() )
#define INTERNAL_CATCH_IF( macroName, resultDisposition, expr ) \
INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ); \
if( Catch::getResultCapture().lastAssertionPassed() )
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_ELSE( expr, resultDisposition, macroName ) \
INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \
if( !Catch::getResultCapture().getLastResult()->succeeded() )
#define INTERNAL_CATCH_ELSE( macroName, resultDisposition, expr ) \
INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ); \
if( !Catch::getResultCapture().lastAssertionPassed() )
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_NO_THROW( expr, resultDisposition, macroName ) \
#define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, expr ) \
do { \
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr), resultDisposition ); \
try { \
expr; \
static_cast<void>(expr); \
__catchResult.captureResult( Catch::ResultWas::Ok ); \
} \
catch( ... ) { \
@ -66,16 +111,16 @@
} while( Catch::alwaysFalse() )
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_THROWS( expr, resultDisposition, expectedMessage, macroName ) \
#define INTERNAL_CATCH_THROWS( macroName, resultDisposition, matcher, expr ) \
do { \
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition, expectedMessage ); \
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr), resultDisposition, CATCH_INTERNAL_STRINGIFY(matcher) ); \
if( __catchResult.allowThrows() ) \
try { \
expr; \
static_cast<void>(expr); \
__catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \
} \
catch( ... ) { \
__catchResult.captureExpectedException( expectedMessage ); \
__catchResult.captureExpectedException( matcher ); \
} \
else \
__catchResult.captureResult( Catch::ResultWas::Ok ); \
@ -83,12 +128,12 @@
} while( Catch::alwaysFalse() )
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_THROWS_AS( expr, exceptionType, resultDisposition, macroName ) \
#define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \
do { \
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr) ", " CATCH_INTERNAL_STRINGIFY(exceptionType), resultDisposition ); \
if( __catchResult.allowThrows() ) \
try { \
expr; \
static_cast<void>(expr); \
__catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \
} \
catch( exceptionType ) { \
@ -105,7 +150,7 @@
///////////////////////////////////////////////////////////////////////////////
#ifdef CATCH_CONFIG_VARIADIC_MACROS
#define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, ... ) \
#define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \
do { \
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \
__catchResult << __VA_ARGS__ + ::Catch::StreamEndStop(); \
@ -113,7 +158,7 @@
INTERNAL_CATCH_REACT( __catchResult ) \
} while( Catch::alwaysFalse() )
#else
#define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, log ) \
#define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, log ) \
do { \
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \
__catchResult << log + ::Catch::StreamEndStop(); \
@ -123,21 +168,15 @@
#endif
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_INFO( log, macroName ) \
#define INTERNAL_CATCH_INFO( macroName, log ) \
Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage ) = Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log;
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CHECK_THAT( arg, matcher, resultDisposition, macroName ) \
#define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \
do { \
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg " " #matcher, resultDisposition ); \
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
try { \
std::string matcherAsString = ::Catch::Matchers::matcher.toString(); \
__catchResult \
.setLhs( Catch::toString( arg ) ) \
.setRhs( matcherAsString == Catch::Detail::unprintableString ? #matcher : matcherAsString ) \
.setOp( "matches" ) \
.setResultType( ::Catch::Matchers::matcher.match( arg ) ); \
__catchResult.captureExpression(); \
__catchResult.captureMatch( arg, matcher, CATCH_INTERNAL_STRINGIFY(matcher) ); \
} catch( ... ) { \
__catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \
} \

View File

@ -13,6 +13,7 @@
#include "catch_clara.h"
#include <fstream>
#include <ctime>
namespace Catch {
@ -23,12 +24,14 @@ namespace Catch {
config.abortAfter = x;
}
inline void addTestOrTags( ConfigData& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); }
inline void addSectionToRun( ConfigData& config, std::string const& sectionName ) { config.sectionsToRun.push_back( sectionName ); }
inline void addReporterName( ConfigData& config, std::string const& _reporterName ) { config.reporterNames.push_back( _reporterName ); }
inline void addWarning( ConfigData& config, std::string const& _warning ) {
if( _warning == "NoAssertions" )
config.warnings = static_cast<WarnAbout::What>( config.warnings | WarnAbout::NoAssertions );
else
throw std::runtime_error( "Unrecognised warning: '" + _warning + "'" );
throw std::runtime_error( "Unrecognised warning: '" + _warning + '\'' );
}
inline void setOrder( ConfigData& config, std::string const& order ) {
if( startsWith( "declared", order ) )
@ -38,7 +41,7 @@ namespace Catch {
else if( startsWith( "random", order ) )
config.runOrder = RunTests::InRandomOrder;
else
throw std::runtime_error( "Unrecognised ordering: '" + order + "'" );
throw std::runtime_error( "Unrecognised ordering: '" + order + '\'' );
}
inline void setRngSeed( ConfigData& config, std::string const& seed ) {
if( seed == "time" ) {
@ -49,7 +52,7 @@ namespace Catch {
ss << seed;
ss >> config.rngSeed;
if( ss.fail() )
throw std::runtime_error( "Argment to --rng-seed should be the word 'time' or a number" );
throw std::runtime_error( "Argument to --rng-seed should be the word 'time' or a number" );
}
}
inline void setVerbosity( ConfigData& config, int level ) {
@ -61,6 +64,34 @@ namespace Catch {
? ShowDurations::Always
: ShowDurations::Never;
}
inline void setUseColour( ConfigData& config, std::string const& value ) {
std::string mode = toLower( value );
if( mode == "yes" )
config.useColour = UseColour::Yes;
else if( mode == "no" )
config.useColour = UseColour::No;
else if( mode == "auto" )
config.useColour = UseColour::Auto;
else
throw std::runtime_error( "colour mode must be one of: auto, yes or no" );
}
inline void setWaitForKeypress( ConfigData& config, std::string const& keypress ) {
std::string 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
throw std::runtime_error( "keypress argument must be one of: start, exit or both. '" + keypress + "' not recognised" );
};
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() )
@ -69,8 +100,11 @@ namespace Catch {
std::string line;
while( std::getline( f, line ) ) {
line = trim(line);
if( !line.empty() && !startsWith( line, "#" ) )
addTestOrTags( config, "\"" + line + "\"," );
if( !line.empty() && !startsWith( line, '#' ) ) {
if( !startsWith( line, '"' ) )
line = '"' + line + '"';
addTestOrTags( config, line + ',' );
}
}
}
@ -116,7 +150,7 @@ namespace Catch {
cli["-r"]["--reporter"]
// .placeholder( "name[:filename]" )
.describe( "reporter to use (defaults to console)" )
.bind( &ConfigData::reporterName, "name" );
.bind( &addReporterName, "name" );
cli["-n"]["--name"]
.describe( "suite name" )
@ -147,7 +181,7 @@ namespace Catch {
cli["-d"]["--durations"]
.describe( "show test durations" )
.bind( &setShowDurations, "yes/no" );
.bind( &setShowDurations, "yes|no" );
cli["-f"]["--input-file"]
.describe( "load test names to run from a file" )
@ -157,12 +191,20 @@ namespace Catch {
.describe( "adds a tag for the filename" )
.bind( &ConfigData::filenamesAsTags );
cli["-c"]["--section"]
.describe( "specify section to run" )
.bind( &addSectionToRun, "section name" );
// Less common commands which don't have a short form
cli["--list-test-names-only"]
.describe( "list all/matching test cases names only" )
.bind( &ConfigData::listTestNamesOnly );
cli["--list-reporters"]
cli["--list-extra-info"]
.describe( "list all/matching test cases with more info" )
.bind( &ConfigData::listExtraInfo );
cli["--list-reporters"]
.describe( "list all reporters" )
.bind( &ConfigData::listReporters );
@ -175,9 +217,21 @@ namespace Catch {
.bind( &setRngSeed, "'time'|number" );
cli["--force-colour"]
.describe( "force colourised output" )
.bind( &ConfigData::forceColour );
.describe( "force colourised output (deprecated)" )
.bind( &forceColour );
cli["--use-colour"]
.describe( "should output be colourised" )
.bind( &setUseColour, "yes|no" );
cli["--libidentify"]
.describe( "report name and version according to libidentify standard" )
.bind( &ConfigData::libIdentify );
cli["--wait-for-keypress"]
.describe( "waits for a keypress before exiting" )
.bind( &setWaitForKeypress, "start|exit|both" );
return cli;
}

View File

@ -8,23 +8,31 @@
#ifndef TWOBLUECUBES_CATCH_COMMON_H_INCLUDED
#define TWOBLUECUBES_CATCH_COMMON_H_INCLUDED
#include "catch_compiler_capabilities.h"
#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line
#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line )
#define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ )
#ifdef CATCH_CONFIG_COUNTER
# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ )
#else
# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ )
#endif
#define INTERNAL_CATCH_STRINGIFY2( expr ) #expr
#define INTERNAL_CATCH_STRINGIFY( expr ) INTERNAL_CATCH_STRINGIFY2( expr )
#include <sstream>
#include <stdexcept>
#include <algorithm>
#include "catch_compiler_capabilities.h"
namespace Catch {
struct IConfig;
struct CaseSensitive { enum Choice {
Yes,
No
}; };
class NonCopyable {
#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
NonCopyable( NonCopyable const& ) = delete;
@ -53,14 +61,14 @@ namespace Catch {
};
template<typename ContainerT>
inline void deleteAll( ContainerT& container ) {
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 ) {
void deleteAllValues( AssociativeContainerT& container ) {
typename AssociativeContainerT::const_iterator it = container.begin();
typename AssociativeContainerT::const_iterator itEnd = container.end();
for(; it != itEnd; ++it )
@ -68,7 +76,9 @@ namespace Catch {
}
bool startsWith( std::string const& s, std::string const& prefix );
bool startsWith( std::string const& s, char prefix );
bool endsWith( std::string const& s, std::string const& suffix );
bool endsWith( std::string const& s, char suffix );
bool contains( std::string const& s, std::string const& infix );
void toLowerInPlace( std::string& s );
std::string toLower( std::string const& s );
@ -88,8 +98,8 @@ namespace Catch {
SourceLineInfo();
SourceLineInfo( char const* _file, std::size_t _line );
SourceLineInfo( SourceLineInfo const& other );
# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
SourceLineInfo(SourceLineInfo const& other) = default;
SourceLineInfo( SourceLineInfo && ) = default;
SourceLineInfo& operator = ( SourceLineInfo const& ) = default;
SourceLineInfo& operator = ( SourceLineInfo && ) = default;
@ -98,7 +108,7 @@ namespace Catch {
bool operator == ( SourceLineInfo const& other ) const;
bool operator < ( SourceLineInfo const& other ) const;
std::string file;
char const* file;
std::size_t line;
};
@ -113,7 +123,7 @@ namespace Catch {
void seedRng( IConfig const& config );
unsigned int rngSeed();
// Use this in variadic streaming macros to allow
// >> +StreamEndStop
// as well as

View File

@ -10,19 +10,31 @@
#include "catch_common.h"
#include <cstring>
#include <cctype>
namespace Catch {
bool startsWith( std::string const& s, std::string const& prefix ) {
return s.size() >= prefix.size() && s.substr( 0, prefix.size() ) == prefix;
return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin());
}
bool startsWith( std::string const& s, char prefix ) {
return !s.empty() && s[0] == prefix;
}
bool endsWith( std::string const& s, std::string const& suffix ) {
return s.size() >= suffix.size() && s.substr( s.size()-suffix.size(), suffix.size() ) == suffix;
return s.size() >= suffix.size() && std::equal(suffix.rbegin(), suffix.rend(), s.rbegin());
}
bool endsWith( std::string const& s, char suffix ) {
return !s.empty() && s[s.size()-1] == suffix;
}
bool contains( std::string const& s, std::string const& infix ) {
return s.find( infix ) != std::string::npos;
}
char toLowerCh(char c) {
return static_cast<char>( std::tolower( c ) );
}
void toLowerInPlace( std::string& s ) {
std::transform( s.begin(), s.end(), s.begin(), ::tolower );
std::transform( s.begin(), s.end(), s.begin(), toLowerCh );
}
std::string toLower( std::string const& s ) {
std::string lc = s;
@ -34,9 +46,9 @@ namespace Catch {
std::string::size_type start = str.find_first_not_of( whitespaceChars );
std::string::size_type end = str.find_last_not_of( whitespaceChars );
return start != std::string::npos ? str.substr( start, 1+end-start ) : "";
return start != std::string::npos ? str.substr( start, 1+end-start ) : std::string();
}
bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) {
bool replaced = false;
std::size_t i = str.find( replaceThis );
@ -50,36 +62,32 @@ namespace Catch {
}
return replaced;
}
pluralise::pluralise( std::size_t count, std::string const& label )
: m_count( count ),
m_label( label )
{}
std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) {
os << pluraliser.m_count << " " << pluraliser.m_label;
os << pluraliser.m_count << ' ' << pluraliser.m_label;
if( pluraliser.m_count != 1 )
os << "s";
os << 's';
return os;
}
SourceLineInfo::SourceLineInfo() : line( 0 ){}
SourceLineInfo::SourceLineInfo() : file(""), line( 0 ){}
SourceLineInfo::SourceLineInfo( char const* _file, std::size_t _line )
: file( _file ),
line( _line )
{}
SourceLineInfo::SourceLineInfo( SourceLineInfo const& other )
: file( other.file ),
line( other.line )
{}
bool SourceLineInfo::empty() const {
return file.empty();
return file[0] == '\0';
}
bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const {
return line == other.line && file == other.file;
return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0);
}
bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const {
return line < other.line || ( line == other.line && file < other.file );
return line < other.line || ( line == other.line && (std::strcmp(file, other.file) < 0));
}
void seedRng( IConfig const& config ) {
@ -92,16 +100,16 @@ namespace Catch {
std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) {
#ifndef __GNUG__
os << info.file << "(" << info.line << ")";
os << info.file << '(' << info.line << ')';
#else
os << info.file << ":" << info.line;
os << info.file << ':' << info.line;
#endif
return os;
}
void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ) {
std::ostringstream oss;
oss << locationInfo << ": Internal Catch error: '" << message << "'";
oss << locationInfo << ": Internal Catch error: '" << message << '\'';
if( alwaysTrue() )
throw std::logic_error( oss.str() );
}

View File

@ -16,11 +16,22 @@
// 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_SHUFFLE : is std::shuffle supported?
// CATCH_CONFIG_CPP11_TYPE_TRAITS : are type_traits and enable_if supported?
// CATCH_CONFIG_CPP11_OR_GREATER : Is C++11 supported?
// CATCH_CONFIG_VARIADIC_MACROS : are variadic macros supported?
// CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported?
// CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported?
// CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported?
// ****************
// Note to maintainers: if new toggles are added please document them
// in configuration.md, too
// ****************
// In general each macro has a _NO_<feature name> form
// (e.g. CATCH_CONFIG_CPP11_NO_NULLPTR) which disables the feature.
@ -29,6 +40,18 @@
// All the C++11 features can be disabled with CATCH_CONFIG_NO_CPP11
#ifdef __cplusplus
# if __cplusplus >= 201103L
# define CATCH_CPP11_OR_GREATER
# endif
# if __cplusplus >= 201402L
# define CATCH_CPP14_OR_GREATER
# endif
#endif
#ifdef __clang__
# if __has_feature(cxx_nullptr)
@ -39,8 +62,48 @@
# define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT
# endif
# if defined(CATCH_CPP11_OR_GREATER)
# define CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
_Pragma( "clang diagnostic push" ) \
_Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" )
# define CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \
_Pragma( "clang diagnostic pop" )
# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
_Pragma( "clang diagnostic push" ) \
_Pragma( "clang diagnostic ignored \"-Wparentheses\"" )
# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
_Pragma( "clang diagnostic pop" )
# endif
#endif // __clang__
////////////////////////////////////////////////////////////////////////////////
// We know some environments not to support full POSIX signals
#if defined(__CYGWIN__) || defined(__QNX__)
# if !defined(CATCH_CONFIG_POSIX_SIGNALS)
# define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS
# endif
#endif
#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__
@ -66,9 +129,13 @@
// GCC
#ifdef __GNUC__
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) )
# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR
#endif
# if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__)
# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR
# endif
// - otherwise more recent versions define __cplusplus >= 201103L
// and will get picked up below
#endif // __GNUC__
@ -77,17 +144,24 @@
// Visual C++
#ifdef _MSC_VER
#define CATCH_INTERNAL_CONFIG_WINDOWS_SEH
#if (_MSC_VER >= 1600)
# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR
# define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR
#endif
#if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015))
#define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT
#define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
#define CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE
#define CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS
#endif
#endif // _MSC_VER
////////////////////////////////////////////////////////////////////////////////
// Use variadic macros if the compiler supports them
#if ( defined _MSC_VER && _MSC_VER > 1400 && !defined __EDGE__) || \
( defined __WAVE__ && __WAVE_HAS_VARIADICS ) || \
@ -98,13 +172,25 @@
#endif
// Use __COUNTER__ if the compiler supports it
#if ( defined _MSC_VER && _MSC_VER >= 1300 ) || \
( defined __GNUC__ && ( __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3 )) ) || \
( defined __clang__ && __clang_major__ >= 3 )
// Use of __COUNTER__ is suppressed during code analysis in CLion/AppCode 2017.2.x and former,
// because __COUNTER__ is not properly handled by it.
// This does not affect compilation
#if ( !defined __JETBRAINS_IDE__ || __JETBRAINS_IDE__ >= 20170300L )
#define CATCH_INTERNAL_CONFIG_COUNTER
#endif
#endif
////////////////////////////////////////////////////////////////////////////////
// C++ language feature support
// catch all support for C++11
#if (__cplusplus >= 201103L)
# define CATCH_CPP11_OR_GREATER
#if defined(CATCH_CPP11_OR_GREATER)
# if !defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR)
# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR
@ -130,6 +216,23 @@
# 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
# if !defined(CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE)
# define CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE
# endif
# if !defined(CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS)
# define CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS
# endif
#endif // __cplusplus >= 201103L
// Now set the actual defines based on the above + anything the user has configured
@ -149,9 +252,42 @@
# 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
# define CATCH_CONFIG_VARIADIC_MACROS
#endif
#if defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_NO_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_CPP11)
# define CATCH_CONFIG_CPP11_LONG_LONG
#endif
#if defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_NO_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_CPP11)
# define CATCH_CONFIG_CPP11_OVERRIDE
#endif
#if defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_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)
# define CATCH_CONFIG_COUNTER
#endif
#if defined(CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE) && !defined(CATCH_CONFIG_CPP11_NO_SHUFFLE) && !defined(CATCH_CONFIG_CPP11_SHUFFLE) && !defined(CATCH_CONFIG_NO_CPP11)
# define CATCH_CONFIG_CPP11_SHUFFLE
#endif
# if defined(CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS) && !defined(CATCH_CONFIG_CPP11_NO_TYPE_TRAITS) && !defined(CATCH_CONFIG_CPP11_TYPE_TRAITS) && !defined(CATCH_CONFIG_NO_CPP11)
# define CATCH_CONFIG_CPP11_TYPE_TRAITS
# endif
#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH)
# define CATCH_CONFIG_WINDOWS_SEH
#endif
// This is set by default, because we assume that unix compilers are posix-signal-compatible by default.
#if !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS)
# define CATCH_CONFIG_POSIX_SIGNALS
#endif
#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS)
# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS
# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS
#endif
#if !defined(CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS)
# define CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS
# define CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS
#endif
// noexcept support:
#if defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_NOEXCEPT)
@ -169,5 +305,19 @@
# 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

View File

@ -16,8 +16,7 @@
#include <memory>
#include <vector>
#include <string>
#include <iostream>
#include <ctime>
#include <stdexcept>
#ifndef CATCH_CONFIG_CONSOLE_WIDTH
#define CATCH_CONFIG_CONSOLE_WIDTH 80
@ -32,33 +31,37 @@ namespace Catch {
listTags( false ),
listReporters( false ),
listTestNamesOnly( false ),
listExtraInfo( false ),
showSuccessfulTests( false ),
shouldDebugBreak( false ),
noThrow( false ),
showHelp( false ),
showInvisibles( false ),
forceColour( false ),
filenamesAsTags( false ),
libIdentify( false ),
abortAfter( -1 ),
rngSeed( 0 ),
verbosity( Verbosity::Normal ),
warnings( WarnAbout::Nothing ),
showDurations( ShowDurations::DefaultForReporter ),
runOrder( RunTests::InDeclarationOrder )
runOrder( RunTests::InDeclarationOrder ),
useColour( UseColour::Auto ),
waitForKeypress( WaitForKeypress::Never )
{}
bool listTests;
bool listTags;
bool listReporters;
bool listTestNamesOnly;
bool listExtraInfo;
bool showSuccessfulTests;
bool shouldDebugBreak;
bool noThrow;
bool showHelp;
bool showInvisibles;
bool forceColour;
bool filenamesAsTags;
bool libIdentify;
int abortAfter;
unsigned int rngSeed;
@ -67,13 +70,16 @@ namespace Catch {
WarnAbout::What warnings;
ShowDurations::OrNot showDurations;
RunTests::InWhatOrder runOrder;
UseColour::YesOrNo useColour;
WaitForKeypress::When waitForKeypress;
std::string reporterName;
std::string outputFilename;
std::string name;
std::string processName;
std::vector<std::string> reporterNames;
std::vector<std::string> testsOrTags;
std::vector<std::string> sectionsToRun;
};
@ -85,12 +91,11 @@ namespace Catch {
public:
Config()
: m_os( Catch::cout().rdbuf() )
{}
Config( ConfigData const& data )
: m_data( data ),
m_os( Catch::cout().rdbuf() )
m_stream( openStream() )
{
if( !data.testsOrTags.empty() ) {
TestSpecParser parser( ITagAliasRegistry::get() );
@ -100,14 +105,7 @@ namespace Catch {
}
}
virtual ~Config() {
m_os.rdbuf( Catch::cout().rdbuf() );
m_stream.release();
}
void setFilename( std::string const& filename ) {
m_data.outputFilename = filename;
}
virtual ~Config() {}
std::string const& getFilename() const {
return m_data.outputFilename ;
@ -117,51 +115,51 @@ namespace Catch {
bool listTestNamesOnly() const { return m_data.listTestNamesOnly; }
bool listTags() const { return m_data.listTags; }
bool listReporters() const { return m_data.listReporters; }
bool listExtraInfo() const { return m_data.listExtraInfo; }
std::string getProcessName() const { return m_data.processName; }
bool shouldDebugBreak() const { return m_data.shouldDebugBreak; }
std::vector<std::string> const& getReporterNames() const { return m_data.reporterNames; }
std::vector<std::string> const& getSectionsToRun() const CATCH_OVERRIDE { return m_data.sectionsToRun; }
void setStreamBuf( std::streambuf* buf ) {
m_os.rdbuf( buf ? buf : Catch::cout().rdbuf() );
}
void useStream( std::string const& streamName ) {
Stream stream = createStream( streamName );
setStreamBuf( stream.streamBuf );
m_stream.release();
m_stream = stream;
}
std::string getReporterName() const { return m_data.reporterName; }
int abortAfter() const { return m_data.abortAfter; }
TestSpec const& testSpec() const { return m_testSpec; }
virtual TestSpec const& testSpec() const CATCH_OVERRIDE { return m_testSpec; }
bool showHelp() const { return m_data.showHelp; }
bool showInvisibles() const { return m_data.showInvisibles; }
// IConfig interface
virtual bool allowThrows() const { return !m_data.noThrow; }
virtual std::ostream& stream() const { return m_os; }
virtual std::string name() const { return m_data.name.empty() ? m_data.processName : m_data.name; }
virtual bool includeSuccessfulResults() const { return m_data.showSuccessfulTests; }
virtual bool warnAboutMissingAssertions() const { return m_data.warnings & WarnAbout::NoAssertions; }
virtual ShowDurations::OrNot showDurations() const { return m_data.showDurations; }
virtual RunTests::InWhatOrder runOrder() const { return m_data.runOrder; }
virtual unsigned int rngSeed() const { return m_data.rngSeed; }
virtual bool forceColour() const { return m_data.forceColour; }
virtual bool allowThrows() const CATCH_OVERRIDE { return !m_data.noThrow; }
virtual std::ostream& stream() const CATCH_OVERRIDE { return m_stream->stream(); }
virtual std::string name() const CATCH_OVERRIDE { return m_data.name.empty() ? m_data.processName : m_data.name; }
virtual bool includeSuccessfulResults() const CATCH_OVERRIDE { return m_data.showSuccessfulTests; }
virtual bool warnAboutMissingAssertions() const CATCH_OVERRIDE { return m_data.warnings & WarnAbout::NoAssertions; }
virtual ShowDurations::OrNot showDurations() const CATCH_OVERRIDE { return m_data.showDurations; }
virtual RunTests::InWhatOrder runOrder() const CATCH_OVERRIDE { return m_data.runOrder; }
virtual unsigned int rngSeed() const CATCH_OVERRIDE { return m_data.rngSeed; }
virtual UseColour::YesOrNo useColour() const CATCH_OVERRIDE { return m_data.useColour; }
virtual bool shouldDebugBreak() const CATCH_OVERRIDE { return m_data.shouldDebugBreak; }
virtual int abortAfter() const CATCH_OVERRIDE { return m_data.abortAfter; }
virtual bool showInvisibles() const CATCH_OVERRIDE { return m_data.showInvisibles; }
private:
IStream const* openStream() {
if( m_data.outputFilename.empty() )
return new CoutStream();
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 );
}
ConfigData m_data;
Stream m_stream;
mutable std::ostream m_os;
CATCH_AUTO_PTR( IStream const ) m_stream;
TestSpec m_testSpec;
};
} // end namespace Catch
#endif // TWOBLUECUBES_CATCH_CONFIG_HPP_INCLUDED

View File

@ -9,6 +9,7 @@
#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED
#include "catch_console_colour.hpp"
#include "catch_errno_guard.hpp"
namespace Catch {
namespace {
@ -41,15 +42,7 @@ namespace Catch {
#if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) /////////////////////////////////////////
#ifndef NOMINMAX
#define NOMINMAX
#endif
#ifdef __AFXDLL
#include <AfxWin.h>
#else
#include <windows.h>
#endif
#include "catch_windows_h_proxy.h"
namespace Catch {
namespace {
@ -95,7 +88,18 @@ namespace {
IColourImpl* platformColourInstance() {
static Win32ColourImpl s_instance;
return &s_instance;
Ptr<IConfig const> config = getCurrentContext().getConfig();
UseColour::YesOrNo colourMode = config
? config->useColour()
: UseColour::Auto;
if( colourMode == UseColour::Auto )
colourMode = !isDebuggerActive()
? UseColour::Yes
: UseColour::No;
return colourMode == UseColour::Yes
? &s_instance
: NoColourImpl::instance();
}
} // end anon namespace
@ -120,7 +124,7 @@ namespace {
case Colour::White: return setColour( "[0m" );
case Colour::Red: return setColour( "[0;31m" );
case Colour::Green: return setColour( "[0;32m" );
case Colour::Blue: return setColour( "[0:34m" );
case Colour::Blue: return setColour( "[0;34m" );
case Colour::Cyan: return setColour( "[0;36m" );
case Colour::Yellow: return setColour( "[0;33m" );
case Colour::Grey: return setColour( "[1;30m" );
@ -145,8 +149,16 @@ namespace {
};
IColourImpl* platformColourInstance() {
ErrnoGuard guard;
Ptr<IConfig const> config = getCurrentContext().getConfig();
return (config && config->forceColour()) || isatty(STDOUT_FILENO)
UseColour::YesOrNo colourMode = config
? config->useColour()
: UseColour::Auto;
if( colourMode == UseColour::Auto )
colourMode = (!isDebuggerActive() && isatty(STDOUT_FILENO) )
? UseColour::Yes
: UseColour::No;
return colourMode == UseColour::Yes
? PosixColourImpl::instance()
: NoColourImpl::instance();
}
@ -171,9 +183,7 @@ namespace Catch {
Colour::~Colour(){ if( !m_moved ) use( None ); }
void Colour::use( Code _colourCode ) {
static IColourImpl* impl = isDebuggerActive()
? NoColourImpl::instance()
: platformColourInstance();
static IColourImpl* impl = platformColourInstance();
impl->use( _colourCode );
}

View File

@ -11,9 +11,6 @@
#include "catch_interfaces_generators.h"
#include "catch_ptr.hpp"
#include <memory>
#include <vector>
#include <stdlib.h>
namespace Catch {

View File

@ -8,10 +8,11 @@
#ifndef TWOBLUECUBES_CATCH_CONTEXT_IMPL_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_CONTEXT_IMPL_HPP_INCLUDED
#include "catch_runner_impl.hpp"
#include "catch_run_context.hpp"
#include "catch_context.h"
#include "catch_stream.hpp"
#include "catch_common.h"
namespace Catch {
@ -21,6 +22,11 @@ namespace Catch {
Context( Context const& );
void operator=( Context const& );
public:
virtual ~Context() {
deleteAllValues( m_generatorsByTestName );
}
public: // IContext
virtual IResultCapture* getResultCapture() {
return m_resultCapture;
@ -95,14 +101,6 @@ namespace Catch {
return getCurrentMutableContext();
}
Stream createStream( std::string const& streamName ) {
if( streamName == "stdout" ) return Stream( Catch::cout().rdbuf(), false );
if( streamName == "stderr" ) return Stream( Catch::cerr().rdbuf(), false );
if( streamName == "debug" ) return Stream( new StreamBufImpl<OutputDebugWriter>, true );
throw std::domain_error( "Unknown stream: " + streamName );
}
void cleanUpContext() {
delete currentContext;
currentContext = CATCH_NULL;

View File

@ -23,27 +23,36 @@ namespace Catch{
// The following code snippet based on:
// http://cocoawithlove.com/2008/03/break-into-debugger.html
#ifdef DEBUG
#if defined(__ppc64__) || defined(__ppc__)
#define CATCH_BREAK_INTO_DEBUGGER() \
if( Catch::isDebuggerActive() ) { \
__asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \
: : : "memory","r0","r3","r4" ); \
}
#else
#define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) {__asm__("int $3\n" : : );}
#endif
#if defined(__ppc64__) || defined(__ppc__)
#define CATCH_TRAP() \
__asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \
: : : "memory","r0","r3","r4" ) /* NOLINT */
#else
#define CATCH_TRAP() __asm__("int $3\n" : : /* NOLINT */ )
#endif
#elif defined(CATCH_PLATFORM_LINUX)
// If we can use inline assembler, do it because this allows us to break
// directly at the location of the failing check instead of breaking inside
// raise() called from it, i.e. one stack frame below.
#if defined(__GNUC__) && (defined(__i386) || defined(__x86_64))
#define CATCH_TRAP() asm volatile ("int $3") /* 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

View File

@ -10,8 +10,7 @@
#define TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED
#include "catch_debugger.h"
#include <iostream>
#include "catch_errno_guard.hpp"
#ifdef CATCH_PLATFORM_MAC
@ -61,6 +60,36 @@
}
} // namespace Catch
#elif defined(CATCH_PLATFORM_LINUX)
#include <fstream>
#include <string>
namespace Catch{
// The standard POSIX way of detecting a debugger is to attempt to
// ptrace() the process, but this needs to be done from a child and not
// this process itself to still allow attaching to this process later
// if wanted, so is rather heavy. Under Linux we have the PID of the
// "debugger" (which doesn't need to be gdb, of course, it could also
// be strace, for example) in /proc/$PID/status, so just get it from
// there instead.
bool isDebuggerActive(){
// Libstdc++ has a bug, where std::ifstream sets errno to 0
// This way our users can properly assert over errno values
ErrnoGuard guard;
std::ifstream in("/proc/self/status");
for( std::string line; std::getline(in, line); ) {
static const int PREFIX_LEN = 11;
if( line.compare(0, PREFIX_LEN, "TracerPid:\t") == 0 ) {
// We're traced if the PID is not 0 and no other PID starts
// with 0 digit, so it's enough to check for just a single
// character.
return line.length() > PREFIX_LEN && line[PREFIX_LEN] != '0';
}
}
return false;
}
} // namespace Catch
#elif defined(_MSC_VER)
extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
namespace Catch {
@ -82,7 +111,9 @@
#endif // Platform
#ifdef CATCH_PLATFORM_WINDOWS
extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA( const char* );
#include "catch_windows_h_proxy.h"
namespace Catch {
void writeToDebugConsole( std::string const& text ) {
::OutputDebugStringA( text.c_str() );

View File

@ -10,9 +10,16 @@
#ifndef __OBJC__
#if defined(WIN32) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN)
// Standard C/C++ Win32 Unicode wmain entry point
extern "C" int wmain (int argc, wchar_t * argv[], wchar_t * []) {
#else
// Standard C/C++ main entry point
int main (int argc, char * const argv[]) {
return Catch::Session().run( argc, argv );
int main (int argc, char * argv[]) {
#endif
int result = Catch::Session().run( argc, argv );
return ( result < 0xff ? result : 0xff );
}
#else // __OBJC__
@ -30,7 +37,7 @@ int main (int argc, char * const argv[]) {
[pool drain];
#endif
return result;
return ( result < 0xff ? result : 0xff );
}
#endif // __OBJC__

View File

@ -0,0 +1,25 @@
/*
* Created by Martin on 06/03/2017.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef TWOBLUECUBES_CATCH_ERRNO_GUARD_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_ERRNO_GUARD_HPP_INCLUDED
#include <cerrno>
namespace Catch {
class ErrnoGuard {
public:
ErrnoGuard():m_oldErrno(errno){}
~ErrnoGuard() { errno = m_oldErrno; }
private:
int m_oldErrno;
};
}
#endif // TWOBLUECUBES_CATCH_ERRNO_GUARD_HPP_INCLUDED

View File

@ -11,6 +11,8 @@
#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
#include <cstddef>
@ -36,139 +38,104 @@ namespace Internal {
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
T& removeConst(T const &t) { return const_cast<T&>(t); }
#ifdef CATCH_CONFIG_CPP11_NULLPTR
inline std::nullptr_t opCast(std::nullptr_t) { return nullptr; }
#endif // CATCH_CONFIG_CPP11_NULLPTR
inline std::nullptr_t removeConst(std::nullptr_t) { return nullptr; }
#endif
// 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{};
struct Evaluator{};
template<typename T1, typename T2>
struct Evaluator<T1, T2, IsEqualTo> {
static bool evaluate( T1 const& lhs, T2 const& rhs) {
return opCast( lhs ) == opCast( rhs );
return bool(removeConst(lhs) == removeConst(rhs) );
}
};
template<typename T1, typename T2>
struct Evaluator<T1, T2, IsNotEqualTo> {
static bool evaluate( T1 const& lhs, T2 const& rhs ) {
return opCast( lhs ) != opCast( rhs );
return bool(removeConst(lhs) != removeConst(rhs) );
}
};
template<typename T1, typename T2>
struct Evaluator<T1, T2, IsLessThan> {
static bool evaluate( T1 const& lhs, T2 const& rhs ) {
return opCast( lhs ) < opCast( rhs );
return bool(removeConst(lhs) < removeConst(rhs) );
}
};
template<typename T1, typename T2>
struct Evaluator<T1, T2, IsGreaterThan> {
static bool evaluate( T1 const& lhs, T2 const& rhs ) {
return opCast( lhs ) > opCast( rhs );
return bool(removeConst(lhs) > removeConst(rhs) );
}
};
template<typename T1, typename T2>
struct Evaluator<T1, T2, IsGreaterThanOrEqualTo> {
static bool evaluate( T1 const& lhs, T2 const& rhs ) {
return opCast( lhs ) >= opCast( rhs );
return bool(removeConst(lhs) >= removeConst(rhs) );
}
};
template<typename T1, typename T2>
struct Evaluator<T1, T2, IsLessThanOrEqualTo> {
static bool evaluate( T1 const& lhs, T2 const& rhs ) {
return opCast( lhs ) <= opCast( rhs );
return bool(removeConst(lhs) <= removeConst(rhs) );
}
};
template<Operator Op, typename T1, typename T2>
bool applyEvaluator( T1 const& lhs, T2 const& rhs ) {
return Evaluator<T1, T2, Op>::evaluate( lhs, rhs );
}
// Special case for comparing a pointer to an int (deduced for p==0)
template<typename T>
struct Evaluator<int const&, T* const&, IsEqualTo> {
static bool evaluate( int lhs, T* rhs) {
return reinterpret_cast<void const*>( lhs ) == rhs;
}
};
template<typename T>
struct Evaluator<T* const&, int const&, IsEqualTo> {
static bool evaluate( T* lhs, int rhs) {
return lhs == reinterpret_cast<void const*>( rhs );
}
};
template<typename T>
struct Evaluator<int const&, T* const&, IsNotEqualTo> {
static bool evaluate( int lhs, T* rhs) {
return reinterpret_cast<void const*>( lhs ) != rhs;
}
};
template<typename T>
struct Evaluator<T* const&, int const&, IsNotEqualTo> {
static bool evaluate( T* lhs, int rhs) {
return lhs != reinterpret_cast<void const*>( 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_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( CATCH_NULL, rhs );
}
template<Operator Op, typename T> bool compare( T* lhs, std::nullptr_t ) {
return Evaluator<T*, T*, Op>::evaluate( lhs, CATCH_NULL );
}
#endif // CATCH_CONFIG_CPP11_NULLPTR
template<typename T>
struct Evaluator<long const&, T* const&, IsEqualTo> {
static bool evaluate( long lhs, T* rhs) {
return reinterpret_cast<void const*>( lhs ) == rhs;
}
};
template<typename T>
struct Evaluator<T* const&, long const&, IsEqualTo> {
static bool evaluate( T* lhs, long rhs) {
return lhs == reinterpret_cast<void const*>( rhs );
}
};
template<typename T>
struct Evaluator<long const&, T* const&, IsNotEqualTo> {
static bool evaluate( long lhs, T* rhs) {
return reinterpret_cast<void const*>( lhs ) != rhs;
}
};
template<typename T>
struct Evaluator<T* const&, long const&, IsNotEqualTo> {
static bool evaluate( T* lhs, long rhs) {
return lhs != reinterpret_cast<void const*>( rhs );
}
};
} // end of namespace Internal
} // end of namespace Catch

View File

@ -32,13 +32,13 @@ namespace Catch {
#ifdef __OBJC__
// In Objective-C try objective-c exceptions first
@try {
throw;
return tryTranslators();
}
@catch (NSException *exception) {
return Catch::toString( [exception description] );
}
#else
throw;
return tryTranslators();
#endif
}
catch( TestFailureException& ) {
@ -54,20 +54,15 @@ namespace Catch {
return msg;
}
catch(...) {
return tryTranslators( m_translators.begin() );
return "Unknown exception";
}
}
std::string tryTranslators( std::vector<const IExceptionTranslator*>::const_iterator it ) const {
if( it == m_translators.end() )
return "Unknown exception";
try {
return (*it)->translate();
}
catch(...) {
return tryTranslators( it+1 );
}
std::string tryTranslators() const {
if( m_translators.empty() )
throw;
else
return m_translators[0]->translate( m_translators.begin()+1, m_translators.end() );
}
private:

View File

@ -14,90 +14,159 @@
namespace Catch {
// Wraps the LHS of an expression and captures the operator and RHS (if any) -
// wrapping them all in a ResultBuilder object
template<typename T>
class ExpressionLhs {
ExpressionLhs& operator = ( ExpressionLhs const& );
# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
ExpressionLhs& operator = ( ExpressionLhs && ) = delete;
# endif
template<typename LhsT, Internal::Operator Op, typename RhsT>
class BinaryExpression;
template<typename ArgT, typename MatcherT>
class MatchExpression;
// Wraps the LHS of an expression and overloads comparison operators
// for also capturing those and RHS (if any)
template<typename T>
class ExpressionLhs : public DecomposedExpression {
public:
ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ) {}
# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
ExpressionLhs( ExpressionLhs const& ) = default;
ExpressionLhs( ExpressionLhs && ) = default;
# endif
ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ), m_truthy(false) {}
ExpressionLhs& operator = ( const ExpressionLhs& );
template<typename RhsT>
ResultBuilder& operator == ( RhsT const& rhs ) {
BinaryExpression<T, Internal::IsEqualTo, RhsT const&>
operator == ( RhsT const& rhs ) {
return captureExpression<Internal::IsEqualTo>( rhs );
}
template<typename RhsT>
ResultBuilder& operator != ( RhsT const& rhs ) {
BinaryExpression<T, Internal::IsNotEqualTo, RhsT const&>
operator != ( RhsT const& rhs ) {
return captureExpression<Internal::IsNotEqualTo>( rhs );
}
template<typename RhsT>
ResultBuilder& operator < ( RhsT const& rhs ) {
BinaryExpression<T, Internal::IsLessThan, RhsT const&>
operator < ( RhsT const& rhs ) {
return captureExpression<Internal::IsLessThan>( rhs );
}
template<typename RhsT>
ResultBuilder& operator > ( RhsT const& rhs ) {
BinaryExpression<T, Internal::IsGreaterThan, RhsT const&>
operator > ( RhsT const& rhs ) {
return captureExpression<Internal::IsGreaterThan>( rhs );
}
template<typename RhsT>
ResultBuilder& operator <= ( RhsT const& rhs ) {
BinaryExpression<T, Internal::IsLessThanOrEqualTo, RhsT const&>
operator <= ( RhsT const& rhs ) {
return captureExpression<Internal::IsLessThanOrEqualTo>( rhs );
}
template<typename RhsT>
ResultBuilder& operator >= ( RhsT const& rhs ) {
BinaryExpression<T, Internal::IsGreaterThanOrEqualTo, RhsT const&>
operator >= ( RhsT const& rhs ) {
return captureExpression<Internal::IsGreaterThanOrEqualTo>( rhs );
}
ResultBuilder& operator == ( bool rhs ) {
BinaryExpression<T, Internal::IsEqualTo, bool> operator == ( bool rhs ) {
return captureExpression<Internal::IsEqualTo>( rhs );
}
ResultBuilder& operator != ( bool rhs ) {
BinaryExpression<T, Internal::IsNotEqualTo, bool> operator != ( bool rhs ) {
return captureExpression<Internal::IsNotEqualTo>( rhs );
}
void endExpression() {
bool value = m_lhs ? true : false;
m_truthy = m_lhs ? true : false;
m_rb
.setLhs( Catch::toString( value ) )
.setResultType( value )
.endExpression();
.setResultType( m_truthy )
.endExpression( *this );
}
// Only simple binary expressions are allowed on the LHS.
// If more complex compositions are required then place the sub expression in parentheses
template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( RhsT const& );
template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( RhsT const& );
template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / ( RhsT const& );
template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * ( RhsT const& );
template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& );
template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& );
virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE {
dest = Catch::toString( m_lhs );
}
private:
template<Internal::Operator Op, typename RhsT>
ResultBuilder& captureExpression( RhsT const& rhs ) {
return m_rb
.setResultType( Internal::compare<Op>( m_lhs, rhs ) )
.setLhs( Catch::toString( m_lhs ) )
.setRhs( Catch::toString( rhs ) )
.setOp( Internal::OperatorTraits<Op>::getName() );
BinaryExpression<T, Op, RhsT&> captureExpression( RhsT& rhs ) const {
return BinaryExpression<T, Op, RhsT&>( m_rb, m_lhs, rhs );
}
template<Internal::Operator Op>
BinaryExpression<T, Op, bool> captureExpression( bool rhs ) const {
return BinaryExpression<T, Op, bool>( m_rb, m_lhs, rhs );
}
private:
ResultBuilder& m_rb;
T m_lhs;
bool m_truthy;
};
template<typename LhsT, Internal::Operator Op, typename RhsT>
class BinaryExpression : public DecomposedExpression {
public:
BinaryExpression( ResultBuilder& rb, LhsT lhs, RhsT rhs )
: m_rb( rb ), m_lhs( lhs ), m_rhs( rhs ) {}
BinaryExpression& operator = ( BinaryExpression& );
void endExpression() const {
m_rb
.setResultType( Internal::Evaluator<LhsT, RhsT, Op>::evaluate( m_lhs, m_rhs ) )
.endExpression( *this );
}
virtual bool isBinaryExpression() const CATCH_OVERRIDE {
return true;
}
virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE {
std::string lhs = Catch::toString( m_lhs );
std::string rhs = Catch::toString( m_rhs );
char delim = lhs.size() + rhs.size() < 40 &&
lhs.find('\n') == std::string::npos &&
rhs.find('\n') == std::string::npos ? ' ' : '\n';
dest.reserve( 7 + lhs.size() + rhs.size() );
// 2 for spaces around operator
// 2 for operator
// 2 for parentheses (conditionally added later)
// 1 for negation (conditionally added later)
dest = lhs;
dest += delim;
dest += Internal::OperatorTraits<Op>::getName();
dest += delim;
dest += rhs;
}
private:
ResultBuilder& m_rb;
LhsT m_lhs;
RhsT m_rhs;
};
template<typename ArgT, typename MatcherT>
class MatchExpression : public DecomposedExpression {
public:
MatchExpression( ArgT arg, MatcherT matcher, char const* matcherString )
: m_arg( arg ), m_matcher( matcher ), m_matcherString( matcherString ) {}
virtual bool isBinaryExpression() const CATCH_OVERRIDE {
return true;
}
virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE {
std::string matcherAsString = m_matcher.toString();
dest = Catch::toString( m_arg );
dest += ' ';
if( matcherAsString == Detail::unprintableString )
dest += m_matcherString;
else
dest += matcherAsString;
}
private:
ArgT m_arg;
MatcherT m_matcher;
char const* m_matcherString;
};
} // end namespace Catch

View File

@ -12,35 +12,115 @@
namespace Catch {
// Report the error condition then exit the process
inline void fatal( std::string const& message, int exitCode ) {
// Report the error condition
inline void reportFatal( std::string const& message ) {
IContext& context = Catch::getCurrentContext();
IResultCapture* resultCapture = context.getResultCapture();
resultCapture->handleFatalErrorCondition( message );
if( Catch::alwaysTrue() ) // avoids "no return" warnings
exit( exitCode );
}
} // namespace Catch
#if defined ( CATCH_PLATFORM_WINDOWS ) /////////////////////////////////////////
#include "catch_windows_h_proxy.h"
# if !defined ( CATCH_CONFIG_WINDOWS_SEH )
namespace Catch {
struct FatalConditionHandler {
void reset() {}
};
}
# else // CATCH_CONFIG_WINDOWS_SEH is defined
namespace Catch {
struct SignalDefs { DWORD id; const char* name; };
extern SignalDefs signalDefs[];
// There is no 1-1 mapping between signals and windows exceptions.
// Windows can easily distinguish between SO and SigSegV,
// but SigInt, SigTerm, etc are handled differently.
SignalDefs signalDefs[] = {
{ EXCEPTION_ILLEGAL_INSTRUCTION, "SIGILL - Illegal instruction signal" },
{ EXCEPTION_STACK_OVERFLOW, "SIGSEGV - Stack overflow" },
{ EXCEPTION_ACCESS_VIOLATION, "SIGSEGV - Segmentation violation signal" },
{ EXCEPTION_INT_DIVIDE_BY_ZERO, "Divide by zero error" },
};
struct FatalConditionHandler {
void reset() {}
};
static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) {
for (int i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) {
if (ExceptionInfo->ExceptionRecord->ExceptionCode == signalDefs[i].id) {
reportFatal(signalDefs[i].name);
}
}
// If its not an exception we care about, pass it along.
// This stops us from eating debugger breaks etc.
return EXCEPTION_CONTINUE_SEARCH;
}
FatalConditionHandler() {
isSet = true;
// 32k seems enough for Catch to handle stack overflow,
// but the value was found experimentally, so there is no strong guarantee
guaranteeSize = 32 * 1024;
exceptionHandlerHandle = CATCH_NULL;
// Register as first handler in current chain
exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException);
// Pass in guarantee size to be filled
SetThreadStackGuarantee(&guaranteeSize);
}
static void reset() {
if (isSet) {
// Unregister handler and restore the old guarantee
RemoveVectoredExceptionHandler(exceptionHandlerHandle);
SetThreadStackGuarantee(&guaranteeSize);
exceptionHandlerHandle = CATCH_NULL;
isSet = false;
}
}
~FatalConditionHandler() {
reset();
}
private:
static bool isSet;
static ULONG guaranteeSize;
static PVOID exceptionHandlerHandle;
};
bool FatalConditionHandler::isSet = false;
ULONG FatalConditionHandler::guaranteeSize = 0;
PVOID FatalConditionHandler::exceptionHandlerHandle = CATCH_NULL;
} // namespace Catch
# endif // CATCH_CONFIG_WINDOWS_SEH
#else // Not Windows - assumed to be POSIX compatible //////////////////////////
# if !defined(CATCH_CONFIG_POSIX_SIGNALS)
namespace Catch {
struct FatalConditionHandler {
void reset() {}
};
}
# else // CATCH_CONFIG_POSIX_SIGNALS is defined
#include <signal.h>
namespace Catch {
struct SignalDefs { int id; const char* name; };
struct SignalDefs {
int id;
const char* name;
};
extern SignalDefs signalDefs[];
SignalDefs signalDefs[] = {
{ SIGINT, "SIGINT - Terminal interrupt signal" },
@ -49,37 +129,72 @@ namespace Catch {
{ SIGSEGV, "SIGSEGV - Segmentation violation signal" },
{ SIGTERM, "SIGTERM - Termination request signal" },
{ SIGABRT, "SIGABRT - Abort (abnormal termination) signal" }
};
};
struct FatalConditionHandler {
static bool isSet;
static struct sigaction oldSigActions [sizeof(signalDefs)/sizeof(SignalDefs)];
static stack_t oldSigStack;
static char altStackMem[SIGSTKSZ];
static void handleSignal( int sig ) {
for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i )
if( sig == signalDefs[i].id )
fatal( signalDefs[i].name, -sig );
fatal( "<unknown signal>", -sig );
std::string name = "<unknown signal>";
for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) {
SignalDefs &def = signalDefs[i];
if (sig == def.id) {
name = def.name;
break;
}
}
reset();
reportFatal(name);
raise( sig );
}
FatalConditionHandler() : m_isSet( true ) {
for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i )
signal( signalDefs[i].id, handleSignal );
}
~FatalConditionHandler() {
reset();
}
void reset() {
if( m_isSet ) {
for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i )
signal( signalDefs[i].id, SIG_DFL );
m_isSet = false;
FatalConditionHandler() {
isSet = true;
stack_t sigStack;
sigStack.ss_sp = altStackMem;
sigStack.ss_size = SIGSTKSZ;
sigStack.ss_flags = 0;
sigaltstack(&sigStack, &oldSigStack);
struct sigaction sa = { 0 };
sa.sa_handler = handleSignal;
sa.sa_flags = SA_ONSTACK;
for (std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i) {
sigaction(signalDefs[i].id, &sa, &oldSigActions[i]);
}
}
bool m_isSet;
~FatalConditionHandler() {
reset();
}
static void reset() {
if( isSet ) {
// Set signals back to previous values -- hopefully nobody overwrote them in the meantime
for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) {
sigaction(signalDefs[i].id, &oldSigActions[i], CATCH_NULL);
}
// Return the old stack
sigaltstack(&oldSigStack, CATCH_NULL);
isSet = false;
}
}
};
bool FatalConditionHandler::isSet = false;
struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {};
stack_t FatalConditionHandler::oldSigStack = {};
char FatalConditionHandler::altStackMem[SIGSTKSZ] = {};
} // namespace Catch
# endif // CATCH_CONFIG_POSIX_SIGNALS
#endif // not Windows
#endif // TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED

View File

@ -10,7 +10,6 @@
#include "catch_context.h"
#include <iterator>
#include <vector>
#include <string>
#include <stdlib.h>
@ -124,7 +123,7 @@ public:
private:
void move( CompositeGenerator& other ) {
std::copy( other.m_composed.begin(), other.m_composed.end(), std::back_inserter( m_composed ) );
m_composed.insert( m_composed.end(), other.m_composed.begin(), other.m_composed.end() );
m_totalSize += other.m_totalSize;
other.m_composed.clear();
}

View File

@ -16,7 +16,7 @@
#pragma clang diagnostic ignored "-Wweak-vtables"
#endif
#include "../catch_runner.hpp"
#include "../catch_session.hpp"
#include "catch_registry_hub.hpp"
#include "catch_notimplemented_exception.hpp"
#include "catch_context_impl.hpp"
@ -35,15 +35,24 @@
#include "catch_tostring.hpp"
#include "catch_result_builder.hpp"
#include "catch_tag_alias_registry.hpp"
#include "catch_test_case_tracker.hpp"
#include "catch_matchers_string.hpp"
#include "../reporters/catch_reporter_multi.hpp"
#include "../reporters/catch_reporter_xml.hpp"
#include "../reporters/catch_reporter_junit.hpp"
#include "../reporters/catch_reporter_console.hpp"
#include "../reporters/catch_reporter_compact.hpp"
namespace Catch {
// 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 {}
IContext::~IContext() {}
IResultCapture::~IResultCapture() {}
@ -82,13 +91,16 @@ namespace Catch {
TestSpec::NamePattern::~NamePattern() {}
TestSpec::TagPattern::~TagPattern() {}
TestSpec::ExcludedPattern::~ExcludedPattern() {}
Matchers::Impl::StdString::Equals::~Equals() {}
Matchers::Impl::StdString::Contains::~Contains() {}
Matchers::Impl::StdString::StartsWith::~StartsWith() {}
Matchers::Impl::StdString::EndsWith::~EndsWith() {}
Matchers::Impl::MatcherUntypedBase::~MatcherUntypedBase() {}
void Config::dummy() {}
namespace TestCaseTracking {
ITracker::~ITracker() {}
TrackerBase::~TrackerBase() {}
SectionTracker::~SectionTracker() {}
IndexTracker::~IndexTracker() {}
}
}
#ifdef __clang__

View File

@ -18,6 +18,7 @@ namespace Catch {
class AssertionResult;
struct AssertionInfo;
struct SectionInfo;
struct SectionEndInfo;
struct MessageInfo;
class ScopedMessageBuilder;
struct Counts;
@ -29,14 +30,21 @@ namespace Catch {
virtual void assertionEnded( AssertionResult const& result ) = 0;
virtual bool sectionStarted( SectionInfo const& sectionInfo,
Counts& assertions ) = 0;
virtual void sectionEnded( SectionInfo const& name, Counts const& assertions, double _durationInSeconds ) = 0;
virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0;
virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 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();

View File

@ -8,7 +8,7 @@
#ifndef TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED
#define TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED
#include <iostream>
#include <iosfwd>
#include <string>
#include <vector>
@ -37,6 +37,17 @@ namespace Catch {
InLexicographicalOrder,
InRandomOrder
}; };
struct UseColour { enum YesOrNo {
Auto,
Yes,
No
}; };
struct WaitForKeypress { enum When {
Never,
BeforeStart = 1,
BeforeExit = 2,
BeforeStartAndExit = BeforeStart | BeforeExit
}; };
class TestSpec;
@ -56,7 +67,9 @@ namespace Catch {
virtual TestSpec const& testSpec() const = 0;
virtual RunTests::InWhatOrder runOrder() const = 0;
virtual unsigned int rngSeed() const = 0;
virtual bool forceColour() const = 0;
virtual UseColour::YesOrNo useColour() const = 0;
virtual std::vector<std::string> const& getSectionsToRun() const = 0;
};
}

View File

@ -9,15 +9,20 @@
#define TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED
#include <string>
#include <vector>
#include "catch_interfaces_registry_hub.h"
namespace Catch {
typedef std::string(*exceptionTranslateFunction)();
struct IExceptionTranslator;
typedef std::vector<const IExceptionTranslator*> ExceptionTranslators;
struct IExceptionTranslator {
virtual ~IExceptionTranslator();
virtual std::string translate() const = 0;
virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const = 0;
};
struct IExceptionTranslatorRegistry {
@ -35,9 +40,12 @@ namespace Catch {
: m_translateFunction( translateFunction )
{}
virtual std::string translate() const {
virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const CATCH_OVERRIDE {
try {
throw;
if( it == itEnd )
throw;
else
return (*it)->translate( it+1, itEnd );
}
catch( T& ex ) {
return m_translateFunction( ex );
@ -58,9 +66,11 @@ namespace Catch {
}
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) \
static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ); \
namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ) ); }\
static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature )
#define INTERNAL_CATCH_TRANSLATE_EXCEPTION2( translatorName, signature ) \
static std::string translatorName( signature ); \
namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); }\
static std::string translatorName( signature )
#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION2( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature )
#endif // TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED

View File

@ -8,6 +8,8 @@
#ifndef TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED
#define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED
#include "catch_ptr.hpp"
#include <string>
namespace Catch {
@ -18,20 +20,25 @@ namespace Catch {
struct IExceptionTranslator;
struct IReporterRegistry;
struct IReporterFactory;
struct ITagAliasRegistry;
struct IRegistryHub {
virtual ~IRegistryHub();
virtual IReporterRegistry const& getReporterRegistry() const = 0;
virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0;
virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0;
virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0;
};
struct IMutableRegistryHub {
virtual ~IMutableRegistryHub();
virtual void registerReporter( std::string const& name, IReporterFactory* factory ) = 0;
virtual void registerReporter( std::string const& name, Ptr<IReporterFactory> const& factory ) = 0;
virtual void registerListener( Ptr<IReporterFactory> const& factory ) = 0;
virtual void registerTest( TestCase const& testInfo ) = 0;
virtual void registerTranslator( const IExceptionTranslator* translator ) = 0;
virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) = 0;
};
IRegistryHub& getRegistryHub();

View File

@ -21,23 +21,22 @@
#include <string>
#include <ostream>
#include <map>
#include <assert.h>
namespace Catch
{
struct ReporterConfig {
explicit ReporterConfig( Ptr<IConfig> const& _fullConfig )
explicit ReporterConfig( Ptr<IConfig const> const& _fullConfig )
: m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {}
ReporterConfig( Ptr<IConfig> const& _fullConfig, std::ostream& _stream )
ReporterConfig( Ptr<IConfig const> const& _fullConfig, std::ostream& _stream )
: m_stream( &_stream ), m_fullConfig( _fullConfig ) {}
std::ostream& stream() const { return *m_stream; }
Ptr<IConfig> fullConfig() const { return m_fullConfig; }
Ptr<IConfig const> fullConfig() const { return m_fullConfig; }
private:
std::ostream* m_stream;
Ptr<IConfig> m_fullConfig;
Ptr<IConfig const> m_fullConfig;
};
struct ReporterPreferences {
@ -219,6 +218,7 @@ namespace Catch
bool aborting;
};
class MultipleReporters;
struct IStreamingReporter : IShared {
virtual ~IStreamingReporter();
@ -240,29 +240,36 @@ namespace Catch
// The return value indicates if the messages buffer should be cleared:
virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0;
virtual void sectionEnded( SectionStats const& sectionStats ) = 0;
virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0;
virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0;
virtual void testRunEnded( TestRunStats const& testRunStats ) = 0;
virtual void skipTest( TestCaseInfo const& testInfo ) = 0;
virtual MultipleReporters* tryAsMulti() { return CATCH_NULL; }
};
struct IReporterFactory {
struct IReporterFactory : IShared {
virtual ~IReporterFactory();
virtual IStreamingReporter* create( ReporterConfig const& config ) const = 0;
virtual std::string getDescription() const = 0;
};
struct IReporterRegistry {
typedef std::map<std::string, IReporterFactory*> FactoryMap;
typedef std::map<std::string, Ptr<IReporterFactory> > FactoryMap;
typedef std::vector<Ptr<IReporterFactory> > Listeners;
virtual ~IReporterRegistry();
virtual IStreamingReporter* create( std::string const& name, Ptr<IConfig> const& config ) const = 0;
virtual IStreamingReporter* create( std::string const& name, Ptr<IConfig const> 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 );
}
#endif // TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED

View File

@ -28,9 +28,13 @@ namespace Catch {
struct ITestCaseRegistry {
virtual ~ITestCaseRegistry();
virtual std::vector<TestCase> const& getAllTests() const = 0;
virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector<TestCase>& matchingTestCases, bool negated = false ) const = 0;
virtual std::vector<TestCase> const& getAllTestsSorted( IConfig const& config ) const = 0;
};
bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config );
std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config );
std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config );
}
#endif // TWOBLUECUBES_CATCH_INTERFACES_TESTCASE_H_INCLUDED

View File

@ -30,12 +30,12 @@ namespace Catch {
}
std::size_t matchedTests = 0;
TextAttributes nameAttr, tagsAttr;
TextAttributes nameAttr, descAttr, tagsAttr;
nameAttr.setInitialIndent( 2 ).setIndent( 4 );
descAttr.setIndent( 4 );
tagsAttr.setIndent( 6 );
std::vector<TestCase> matchedTestCases;
getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases );
std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
it != itEnd;
++it ) {
@ -47,14 +47,21 @@ namespace Catch {
Colour colourGuard( colour );
Catch::cout() << Text( testCaseInfo.name, nameAttr ) << std::endl;
if( config.listExtraInfo() ) {
Catch::cout() << " " << testCaseInfo.lineInfo << std::endl;
std::string description = testCaseInfo.description;
if( description.empty() )
description = "(NO DESCRIPTION)";
Catch::cout() << Text( description, descAttr ) << std::endl;
}
if( !testCaseInfo.tags.empty() )
Catch::cout() << Text( testCaseInfo.tagsAsString, tagsAttr ) << std::endl;
}
if( !config.testSpec().hasFilters() )
Catch::cout() << pluralise( matchedTests, "test case" ) << "\n" << std::endl;
Catch::cout() << pluralise( matchedTests, "test case" ) << '\n' << std::endl;
else
Catch::cout() << pluralise( matchedTests, "matching test case" ) << "\n" << std::endl;
Catch::cout() << pluralise( matchedTests, "matching test case" ) << '\n' << std::endl;
return matchedTests;
}
@ -63,14 +70,19 @@ namespace Catch {
if( !config.testSpec().hasFilters() )
testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
std::size_t matchedTests = 0;
std::vector<TestCase> matchedTestCases;
getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases );
std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
it != itEnd;
++it ) {
matchedTests++;
TestCaseInfo const& testCaseInfo = it->getTestCaseInfo();
Catch::cout() << testCaseInfo.name << std::endl;
if( startsWith( testCaseInfo.name, '#' ) )
Catch::cout() << '"' << testCaseInfo.name << '"';
else
Catch::cout() << testCaseInfo.name;
if ( config.listExtraInfo() )
Catch::cout() << "\t@" << testCaseInfo.lineInfo;
Catch::cout() << std::endl;
}
return matchedTests;
}
@ -104,8 +116,7 @@ namespace Catch {
std::map<std::string, TagInfo> tagCounts;
std::vector<TestCase> matchedTestCases;
getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases );
std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
it != itEnd;
++it ) {
@ -132,9 +143,9 @@ namespace Catch {
.setInitialIndent( 0 )
.setIndent( oss.str().size() )
.setWidth( CATCH_CONFIG_CONSOLE_WIDTH-10 ) );
Catch::cout() << oss.str() << wrapper << "\n";
Catch::cout() << oss.str() << wrapper << '\n';
}
Catch::cout() << pluralise( tagCounts.size(), "tag" ) << "\n" << std::endl;
Catch::cout() << pluralise( tagCounts.size(), "tag" ) << '\n' << std::endl;
return tagCounts.size();
}
@ -153,9 +164,9 @@ namespace Catch {
.setWidth( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) );
Catch::cout() << " "
<< it->first
<< ":"
<< ':'
<< std::string( maxNameLen - it->first.size() + 2, ' ' )
<< wrapper << "\n";
<< wrapper << '\n';
}
Catch::cout() << std::endl;
return factories.size();
@ -163,7 +174,7 @@ namespace Catch {
inline Option<std::size_t> list( Config const& config ) {
Option<std::size_t> listedCount;
if( config.listTests() )
if( config.listTests() || ( config.listExtraInfo() && !config.listTestNamesOnly() ) )
listedCount = listedCount.valueOr(0) + listTests( config );
if( config.listTestNamesOnly() )
listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config );

View File

@ -8,225 +8,169 @@
#ifndef TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED
#include "catch_common.h"
namespace Catch {
namespace Matchers {
namespace Impl {
template<typename ExpressionT>
struct Matcher : SharedImpl<IShared>
{
typedef ExpressionT ExpressionType;
template<typename ArgT> struct MatchAllOf;
template<typename ArgT> struct MatchAnyOf;
template<typename ArgT> struct MatchNotOf;
virtual ~Matcher() {}
virtual Ptr<Matcher> clone() const = 0;
virtual bool match( ExpressionT const& expr ) const = 0;
virtual std::string toString() const = 0;
};
template<typename DerivedT, typename ExpressionT>
struct MatcherImpl : Matcher<ExpressionT> {
virtual Ptr<Matcher<ExpressionT> > clone() const {
return Ptr<Matcher<ExpressionT> >( new DerivedT( static_cast<DerivedT const&>( *this ) ) );
}
};
namespace Generic {
template<typename ExpressionT>
class AllOf : public MatcherImpl<AllOf<ExpressionT>, ExpressionT> {
class MatcherUntypedBase {
public:
AllOf() {}
AllOf( AllOf const& other ) : m_matchers( other.m_matchers ) {}
AllOf& add( Matcher<ExpressionT> const& matcher ) {
m_matchers.push_back( matcher.clone() );
return *this;
std::string toString() const {
if( m_cachedToString.empty() )
m_cachedToString = describe();
return m_cachedToString;
}
virtual bool match( ExpressionT const& expr ) const
{
for( std::size_t i = 0; i < m_matchers.size(); ++i )
if( !m_matchers[i]->match( expr ) )
protected:
virtual ~MatcherUntypedBase();
virtual std::string describe() const = 0;
mutable std::string m_cachedToString;
private:
MatcherUntypedBase& operator = ( MatcherUntypedBase const& );
};
template<typename ObjectT>
struct MatcherMethod {
virtual bool match( ObjectT const& arg ) const = 0;
};
template<typename PtrT>
struct MatcherMethod<PtrT*> {
virtual bool match( PtrT* arg ) const = 0;
};
template<typename ObjectT, typename ComparatorT = ObjectT>
struct MatcherBase : MatcherUntypedBase, MatcherMethod<ObjectT> {
MatchAllOf<ComparatorT> operator && ( MatcherBase const& other ) const;
MatchAnyOf<ComparatorT> operator || ( MatcherBase const& other ) const;
MatchNotOf<ComparatorT> operator ! () const;
};
template<typename ArgT>
struct MatchAllOf : MatcherBase<ArgT> {
virtual bool match( ArgT const& arg ) const CATCH_OVERRIDE {
for( std::size_t i = 0; i < m_matchers.size(); ++i ) {
if (!m_matchers[i]->match(arg))
return false;
}
return true;
}
virtual std::string toString() const {
std::ostringstream oss;
oss << "( ";
virtual std::string describe() const CATCH_OVERRIDE {
std::string description;
description.reserve( 4 + m_matchers.size()*32 );
description += "( ";
for( std::size_t i = 0; i < m_matchers.size(); ++i ) {
if( i != 0 )
oss << " and ";
oss << m_matchers[i]->toString();
description += " and ";
description += m_matchers[i]->toString();
}
oss << " )";
return oss.str();
description += " )";
return description;
}
private:
std::vector<Ptr<Matcher<ExpressionT> > > m_matchers;
};
template<typename ExpressionT>
class AnyOf : public MatcherImpl<AnyOf<ExpressionT>, ExpressionT> {
public:
AnyOf() {}
AnyOf( AnyOf const& other ) : m_matchers( other.m_matchers ) {}
AnyOf& add( Matcher<ExpressionT> const& matcher ) {
m_matchers.push_back( matcher.clone() );
MatchAllOf<ArgT>& operator && ( MatcherBase<ArgT> const& other ) {
m_matchers.push_back( &other );
return *this;
}
virtual bool match( ExpressionT const& expr ) const
{
for( std::size_t i = 0; i < m_matchers.size(); ++i )
if( m_matchers[i]->match( expr ) )
std::vector<MatcherBase<ArgT> const*> m_matchers;
};
template<typename ArgT>
struct MatchAnyOf : MatcherBase<ArgT> {
virtual bool match( ArgT const& arg ) const CATCH_OVERRIDE {
for( std::size_t i = 0; i < m_matchers.size(); ++i ) {
if (m_matchers[i]->match(arg))
return true;
}
return false;
}
virtual std::string toString() const {
std::ostringstream oss;
oss << "( ";
virtual std::string describe() const CATCH_OVERRIDE {
std::string description;
description.reserve( 4 + m_matchers.size()*32 );
description += "( ";
for( std::size_t i = 0; i < m_matchers.size(); ++i ) {
if( i != 0 )
oss << " or ";
oss << m_matchers[i]->toString();
description += " or ";
description += m_matchers[i]->toString();
}
oss << " )";
return oss.str();
description += " )";
return description;
}
private:
std::vector<Ptr<Matcher<ExpressionT> > > m_matchers;
MatchAnyOf<ArgT>& operator || ( MatcherBase<ArgT> const& other ) {
m_matchers.push_back( &other );
return *this;
}
std::vector<MatcherBase<ArgT> const*> m_matchers;
};
}
template<typename ArgT>
struct MatchNotOf : MatcherBase<ArgT> {
namespace StdString {
MatchNotOf( MatcherBase<ArgT> const& underlyingMatcher ) : m_underlyingMatcher( underlyingMatcher ) {}
inline std::string makeString( std::string const& str ) { return str; }
inline std::string makeString( const char* str ) { return str ? std::string( str ) : std::string(); }
struct Equals : MatcherImpl<Equals, std::string> {
Equals( std::string const& str ) : m_str( str ){}
Equals( Equals const& other ) : m_str( other.m_str ){}
virtual ~Equals();
virtual bool match( std::string const& expr ) const {
return m_str == expr;
}
virtual std::string toString() const {
return "equals: \"" + m_str + "\"";
virtual bool match( ArgT const& arg ) const CATCH_OVERRIDE {
return !m_underlyingMatcher.match( arg );
}
std::string m_str;
virtual std::string describe() const CATCH_OVERRIDE {
return "not " + m_underlyingMatcher.toString();
}
MatcherBase<ArgT> const& m_underlyingMatcher;
};
struct Contains : MatcherImpl<Contains, std::string> {
Contains( std::string const& substr ) : m_substr( substr ){}
Contains( Contains const& other ) : m_substr( other.m_substr ){}
template<typename ObjectT, typename ComparatorT>
MatchAllOf<ComparatorT> MatcherBase<ObjectT, ComparatorT>::operator && ( MatcherBase const& other ) const {
return MatchAllOf<ComparatorT>() && *this && other;
}
template<typename ObjectT, typename ComparatorT>
MatchAnyOf<ComparatorT> MatcherBase<ObjectT, ComparatorT>::operator || ( MatcherBase const& other ) const {
return MatchAnyOf<ComparatorT>() || *this || other;
}
template<typename ObjectT, typename ComparatorT>
MatchNotOf<ComparatorT> MatcherBase<ObjectT, ComparatorT>::operator ! () const {
return MatchNotOf<ComparatorT>( *this );
}
virtual ~Contains();
virtual bool match( std::string const& expr ) const {
return expr.find( m_substr ) != std::string::npos;
}
virtual std::string toString() const {
return "contains: \"" + m_substr + "\"";
}
std::string m_substr;
};
struct StartsWith : MatcherImpl<StartsWith, std::string> {
StartsWith( std::string const& substr ) : m_substr( substr ){}
StartsWith( StartsWith const& other ) : m_substr( other.m_substr ){}
virtual ~StartsWith();
virtual bool match( std::string const& expr ) const {
return expr.find( m_substr ) == 0;
}
virtual std::string toString() const {
return "starts with: \"" + m_substr + "\"";
}
std::string m_substr;
};
struct EndsWith : MatcherImpl<EndsWith, std::string> {
EndsWith( std::string const& substr ) : m_substr( substr ){}
EndsWith( EndsWith const& other ) : m_substr( other.m_substr ){}
virtual ~EndsWith();
virtual bool match( std::string const& expr ) const {
return expr.find( m_substr ) == expr.size() - m_substr.size();
}
virtual std::string toString() const {
return "ends with: \"" + m_substr + "\"";
}
std::string m_substr;
};
} // namespace StdString
} // namespace Impl
// The following functions create the actual matcher objects.
// This allows the types to be inferred
template<typename ExpressionT>
inline Impl::Generic::AllOf<ExpressionT> AllOf( Impl::Matcher<ExpressionT> const& m1,
Impl::Matcher<ExpressionT> const& m2 ) {
return Impl::Generic::AllOf<ExpressionT>().add( m1 ).add( m2 );
// - deprecated: prefer ||, && and !
template<typename T>
Impl::MatchNotOf<T> Not( Impl::MatcherBase<T> const& underlyingMatcher ) {
return Impl::MatchNotOf<T>( underlyingMatcher );
}
template<typename ExpressionT>
inline Impl::Generic::AllOf<ExpressionT> AllOf( Impl::Matcher<ExpressionT> const& m1,
Impl::Matcher<ExpressionT> const& m2,
Impl::Matcher<ExpressionT> const& m3 ) {
return Impl::Generic::AllOf<ExpressionT>().add( m1 ).add( m2 ).add( m3 );
template<typename T>
Impl::MatchAllOf<T> AllOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2 ) {
return Impl::MatchAllOf<T>() && m1 && m2;
}
template<typename ExpressionT>
inline Impl::Generic::AnyOf<ExpressionT> AnyOf( Impl::Matcher<ExpressionT> const& m1,
Impl::Matcher<ExpressionT> const& m2 ) {
return Impl::Generic::AnyOf<ExpressionT>().add( m1 ).add( m2 );
template<typename T>
Impl::MatchAllOf<T> AllOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2, Impl::MatcherBase<T> const& m3 ) {
return Impl::MatchAllOf<T>() && m1 && m2 && m3;
}
template<typename ExpressionT>
inline Impl::Generic::AnyOf<ExpressionT> AnyOf( Impl::Matcher<ExpressionT> const& m1,
Impl::Matcher<ExpressionT> const& m2,
Impl::Matcher<ExpressionT> const& m3 ) {
return Impl::Generic::AnyOf<ExpressionT>().add( m1 ).add( m2 ).add( m3 );
template<typename T>
Impl::MatchAnyOf<T> AnyOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2 ) {
return Impl::MatchAnyOf<T>() || m1 || m2;
}
inline Impl::StdString::Equals Equals( std::string const& str ) {
return Impl::StdString::Equals( str );
}
inline Impl::StdString::Equals Equals( const char* str ) {
return Impl::StdString::Equals( Impl::StdString::makeString( str ) );
}
inline Impl::StdString::Contains Contains( std::string const& substr ) {
return Impl::StdString::Contains( substr );
}
inline Impl::StdString::Contains Contains( const char* substr ) {
return Impl::StdString::Contains( Impl::StdString::makeString( substr ) );
}
inline Impl::StdString::StartsWith StartsWith( std::string const& substr ) {
return Impl::StdString::StartsWith( substr );
}
inline Impl::StdString::StartsWith StartsWith( const char* substr ) {
return Impl::StdString::StartsWith( Impl::StdString::makeString( substr ) );
}
inline Impl::StdString::EndsWith EndsWith( std::string const& substr ) {
return Impl::StdString::EndsWith( substr );
}
inline Impl::StdString::EndsWith EndsWith( const char* substr ) {
return Impl::StdString::EndsWith( Impl::StdString::makeString( substr ) );
template<typename T>
Impl::MatchAnyOf<T> AnyOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2, Impl::MatcherBase<T> const& m3 ) {
return Impl::MatchAnyOf<T>() || m1 || m2 || m3;
}
} // namespace Matchers
using namespace Matchers;
using Matchers::Impl::MatcherBase;
} // namespace Catch

View File

@ -0,0 +1,67 @@
/*
* Created by Phil Nash on 08/02/2017.
* Copyright (c) 2017 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef TWOBLUECUBES_CATCH_MATCHERS_STRING_H_INCLUDED
#define TWOBLUECUBES_CATCH_MATCHERS_STRING_H_INCLUDED
#include "catch_matchers.hpp"
namespace Catch {
namespace Matchers {
namespace StdString {
struct CasedString
{
CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity );
std::string adjustString( std::string const& str ) const;
std::string caseSensitivitySuffix() const;
CaseSensitive::Choice m_caseSensitivity;
std::string m_str;
};
struct StringMatcherBase : MatcherBase<std::string> {
StringMatcherBase( std::string const& operation, CasedString const& comparator );
virtual std::string describe() const CATCH_OVERRIDE;
CasedString m_comparator;
std::string m_operation;
};
struct EqualsMatcher : StringMatcherBase {
EqualsMatcher( CasedString const& comparator );
virtual bool match( std::string const& source ) const CATCH_OVERRIDE;
};
struct ContainsMatcher : StringMatcherBase {
ContainsMatcher( CasedString const& comparator );
virtual bool match( std::string const& source ) const CATCH_OVERRIDE;
};
struct StartsWithMatcher : StringMatcherBase {
StartsWithMatcher( CasedString const& comparator );
virtual bool match( std::string const& source ) const CATCH_OVERRIDE;
};
struct EndsWithMatcher : StringMatcherBase {
EndsWithMatcher( CasedString const& comparator );
virtual bool match( std::string const& source ) const CATCH_OVERRIDE;
};
} // namespace StdString
// The following functions create the actual matcher objects.
// This allows the types to be inferred
StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes );
StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes );
StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes );
StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes );
} // namespace Matchers
} // namespace Catch
#endif // TWOBLUECUBES_CATCH_MATCHERS_STRING_H_INCLUDED

View File

@ -0,0 +1,93 @@
/*
* Created by Phil Nash on 08/02/2017.
* Copyright (c) 2017 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#include "catch_matchers.hpp"
namespace Catch {
namespace Matchers {
namespace StdString {
CasedString::CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity )
: m_caseSensitivity( caseSensitivity ),
m_str( adjustString( str ) )
{}
std::string CasedString::adjustString( std::string const& str ) const {
return m_caseSensitivity == CaseSensitive::No
? toLower( str )
: str;
}
std::string CasedString::caseSensitivitySuffix() const {
return m_caseSensitivity == CaseSensitive::No
? " (case insensitive)"
: std::string();
}
StringMatcherBase::StringMatcherBase( std::string const& operation, CasedString const& comparator )
: m_comparator( comparator ),
m_operation( operation ) {
}
std::string StringMatcherBase::describe() const {
std::string description;
description.reserve(5 + m_operation.size() + m_comparator.m_str.size() +
m_comparator.caseSensitivitySuffix().size());
description += m_operation;
description += ": \"";
description += m_comparator.m_str;
description += "\"";
description += m_comparator.caseSensitivitySuffix();
return description;
}
EqualsMatcher::EqualsMatcher( CasedString const& comparator ) : StringMatcherBase( "equals", comparator ) {}
bool EqualsMatcher::match( std::string const& source ) const {
return m_comparator.adjustString( source ) == m_comparator.m_str;
}
ContainsMatcher::ContainsMatcher( CasedString const& comparator ) : StringMatcherBase( "contains", comparator ) {}
bool ContainsMatcher::match( std::string const& source ) const {
return contains( m_comparator.adjustString( source ), m_comparator.m_str );
}
StartsWithMatcher::StartsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "starts with", comparator ) {}
bool StartsWithMatcher::match( std::string const& source ) const {
return startsWith( m_comparator.adjustString( source ), m_comparator.m_str );
}
EndsWithMatcher::EndsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "ends with", comparator ) {}
bool EndsWithMatcher::match( std::string const& source ) const {
return endsWith( m_comparator.adjustString( source ), m_comparator.m_str );
}
} // namespace StdString
StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity ) {
return StdString::EqualsMatcher( StdString::CasedString( str, caseSensitivity) );
}
StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity ) {
return StdString::ContainsMatcher( StdString::CasedString( str, caseSensitivity) );
}
StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) {
return StdString::EndsWithMatcher( StdString::CasedString( str, caseSensitivity) );
}
StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) {
return StdString::StartsWithMatcher( StdString::CasedString( str, caseSensitivity) );
}
} // namespace Matchers
} // namespace Catch

View File

@ -0,0 +1,101 @@
/*
* Created by Phil Nash on 21/02/2017.
* Copyright (c) 2017 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef TWOBLUECUBES_CATCH_MATCHERS_VECTOR_H_INCLUDED
#define TWOBLUECUBES_CATCH_MATCHERS_VECTOR_H_INCLUDED
#include "catch_matchers.hpp"
namespace Catch {
namespace Matchers {
namespace Vector {
template<typename T>
struct ContainsElementMatcher : MatcherBase<std::vector<T>, T> {
ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {}
bool match(std::vector<T> const &v) const CATCH_OVERRIDE {
return std::find(v.begin(), v.end(), m_comparator) != v.end();
}
virtual std::string describe() const CATCH_OVERRIDE {
return "Contains: " + Catch::toString( m_comparator );
}
T const& m_comparator;
};
template<typename T>
struct ContainsMatcher : MatcherBase<std::vector<T>, std::vector<T> > {
ContainsMatcher(std::vector<T> const &comparator) : m_comparator( comparator ) {}
bool match(std::vector<T> const &v) const CATCH_OVERRIDE {
// !TBD: see note in EqualsMatcher
if (m_comparator.size() > v.size())
return false;
for (size_t i = 0; i < m_comparator.size(); ++i)
if (std::find(v.begin(), v.end(), m_comparator[i]) == v.end())
return false;
return true;
}
virtual std::string describe() const CATCH_OVERRIDE {
return "Contains: " + Catch::toString( m_comparator );
}
std::vector<T> const& m_comparator;
};
template<typename T>
struct EqualsMatcher : MatcherBase<std::vector<T>, std::vector<T> > {
EqualsMatcher(std::vector<T> const &comparator) : m_comparator( comparator ) {}
bool match(std::vector<T> const &v) const CATCH_OVERRIDE {
// !TBD: This currently works if all elements can be compared using !=
// - a more general approach would be via a compare template that defaults
// to using !=. but could be specialised for, e.g. std::vector<T> etc
// - then just call that directly
if (m_comparator.size() != v.size())
return false;
for (size_t i = 0; i < v.size(); ++i)
if (m_comparator[i] != v[i])
return false;
return true;
}
virtual std::string describe() const CATCH_OVERRIDE {
return "Equals: " + Catch::toString( m_comparator );
}
std::vector<T> const& m_comparator;
};
} // namespace Vector
// The following functions create the actual matcher objects.
// This allows the types to be inferred
template<typename T>
Vector::ContainsMatcher<T> Contains( std::vector<T> const& comparator ) {
return Vector::ContainsMatcher<T>( comparator );
}
template<typename T>
Vector::ContainsElementMatcher<T> VectorContains( T const& comparator ) {
return Vector::ContainsElementMatcher<T>( comparator );
}
template<typename T>
Vector::EqualsMatcher<T> Equals( std::vector<T> const& comparator ) {
return Vector::EqualsMatcher<T>( comparator );
}
} // namespace Matchers
} // namespace Catch
#endif // TWOBLUECUBES_CATCH_MATCHERS_VECTOR_H_INCLUDED

View File

@ -38,7 +38,9 @@ namespace Catch {
{}
ScopedMessage::~ScopedMessage() {
getResultCapture().popScopedMessage( m_info );
if ( !std::uncaught_exception() ){
getResultCapture().popScopedMessage(m_info);
}
}

View File

@ -9,7 +9,6 @@
#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_H_INCLUDED
#include "catch_common.h"
#include <ostream>
namespace Catch {
@ -17,7 +16,6 @@ namespace Catch {
{
public:
NotImplementedException( SourceLineInfo const& lineInfo );
NotImplementedException( NotImplementedException const& ) {}
virtual ~NotImplementedException() CATCH_NOEXCEPT {}

View File

@ -9,7 +9,7 @@
#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_HPP_INCLUDED
#include "catch_notimplemented_exception.h"
#include <ostream>
#include <sstream>
namespace Catch {

View File

@ -105,64 +105,67 @@ namespace Catch {
namespace Impl {
namespace NSStringMatchers {
template<typename MatcherT>
struct StringHolder : MatcherImpl<MatcherT, NSString*>{
struct StringHolder : MatcherBase<NSString*>{
StringHolder( NSString* substr ) : m_substr( [substr copy] ){}
StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){}
StringHolder() {
arcSafeRelease( m_substr );
}
virtual bool match( NSString* arg ) const CATCH_OVERRIDE {
return false;
}
NSString* m_substr;
};
struct Equals : StringHolder<Equals> {
struct Equals : StringHolder {
Equals( NSString* substr ) : StringHolder( substr ){}
virtual bool match( ExpressionType const& str ) const {
virtual bool match( NSString* str ) const CATCH_OVERRIDE {
return (str != nil || m_substr == nil ) &&
[str isEqualToString:m_substr];
}
virtual std::string toString() const {
virtual std::string describe() const CATCH_OVERRIDE {
return "equals string: " + Catch::toString( m_substr );
}
};
struct Contains : StringHolder<Contains> {
struct Contains : StringHolder {
Contains( NSString* substr ) : StringHolder( substr ){}
virtual bool match( ExpressionType const& str ) const {
virtual bool match( NSString* str ) const {
return (str != nil || m_substr == nil ) &&
[str rangeOfString:m_substr].location != NSNotFound;
}
virtual std::string toString() const {
virtual std::string describe() const CATCH_OVERRIDE {
return "contains string: " + Catch::toString( m_substr );
}
};
struct StartsWith : StringHolder<StartsWith> {
struct StartsWith : StringHolder {
StartsWith( NSString* substr ) : StringHolder( substr ){}
virtual bool match( ExpressionType const& str ) const {
virtual bool match( NSString* str ) const {
return (str != nil || m_substr == nil ) &&
[str rangeOfString:m_substr].location == 0;
}
virtual std::string toString() const {
virtual std::string describe() const CATCH_OVERRIDE {
return "starts with: " + Catch::toString( m_substr );
}
};
struct EndsWith : StringHolder<EndsWith> {
struct EndsWith : StringHolder {
EndsWith( NSString* substr ) : StringHolder( substr ){}
virtual bool match( ExpressionType const& str ) const {
virtual bool match( NSString* str ) const {
return (str != nil || m_substr == nil ) &&
[str rangeOfString:m_substr].location == [str length] - [m_substr length];
}
virtual std::string toString() const {
virtual std::string describe() const CATCH_OVERRIDE {
return "ends with: " + Catch::toString( m_substr );
}
};

View File

@ -66,8 +66,18 @@ namespace Catch {
}
private:
T* nullableValue;
char storage[sizeof(T)];
T *nullableValue;
union {
char storage[sizeof(T)];
// These are here to force alignment for the storage
long double dummy1;
void (*dummy2)();
long double dummy3;
#ifdef CATCH_CONFIG_CPP11_LONG_LONG
long long dummy4;
#endif
};
};
} // end namespace Catch

View File

@ -10,11 +10,19 @@
#define TWOBLUECUBES_CATCH_PLATFORM_H_INCLUDED
#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
#define CATCH_PLATFORM_MAC
# define CATCH_PLATFORM_MAC
#elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
#define CATCH_PLATFORM_IPHONE
# define CATCH_PLATFORM_IPHONE
#elif defined(linux) || defined(__linux) || defined(__linux__)
# define CATCH_PLATFORM_LINUX
#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER)
#define CATCH_PLATFORM_WINDOWS
# define CATCH_PLATFORM_WINDOWS
# if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX)
# define CATCH_DEFINES_NOMINMAX
# endif
# if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN)
# define CATCH_DEFINES_WIN32_LEAN_AND_MEAN
# endif
#endif
#endif // TWOBLUECUBES_CATCH_PLATFORM_H_INCLUDED

View File

@ -52,8 +52,7 @@ namespace Catch {
return *this;
}
void swap( Ptr& other ) { std::swap( m_p, other.m_p ); }
T* get() { return m_p; }
const T* get() const{ return m_p; }
T* get() const{ return m_p; }
T& operator*() const { return *m_p; }
T* operator->() const { return m_p; }
bool operator !() const { return m_p == CATCH_NULL; }

View File

@ -13,6 +13,7 @@
#include "catch_test_case_registry_impl.hpp"
#include "catch_reporter_registry.hpp"
#include "catch_exception_translator_registry.hpp"
#include "catch_tag_alias_registry.h"
namespace Catch {
@ -26,31 +27,42 @@ namespace Catch {
public: // IRegistryHub
RegistryHub() {
}
virtual IReporterRegistry const& getReporterRegistry() const {
virtual IReporterRegistry const& getReporterRegistry() const CATCH_OVERRIDE {
return m_reporterRegistry;
}
virtual ITestCaseRegistry const& getTestCaseRegistry() const {
virtual ITestCaseRegistry const& getTestCaseRegistry() const CATCH_OVERRIDE {
return m_testCaseRegistry;
}
virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() {
virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() CATCH_OVERRIDE {
return m_exceptionTranslatorRegistry;
}
virtual ITagAliasRegistry const& getTagAliasRegistry() const CATCH_OVERRIDE {
return m_tagAliasRegistry;
}
public: // IMutableRegistryHub
virtual void registerReporter( std::string const& name, IReporterFactory* factory ) {
virtual void registerReporter( std::string const& name, Ptr<IReporterFactory> const& factory ) CATCH_OVERRIDE {
m_reporterRegistry.registerReporter( name, factory );
}
virtual void registerTest( TestCase const& testInfo ) {
virtual void registerListener( Ptr<IReporterFactory> const& factory ) CATCH_OVERRIDE {
m_reporterRegistry.registerListener( factory );
}
virtual void registerTest( TestCase const& testInfo ) CATCH_OVERRIDE {
m_testCaseRegistry.registerTest( testInfo );
}
virtual void registerTranslator( const IExceptionTranslator* translator ) {
virtual void registerTranslator( const IExceptionTranslator* translator ) CATCH_OVERRIDE {
m_exceptionTranslatorRegistry.registerTranslator( translator );
}
virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) CATCH_OVERRIDE {
m_tagAliasRegistry.add( alias, tag, lineInfo );
}
private:
TestRegistry m_testCaseRegistry;
ReporterRegistry m_reporterRegistry;
ExceptionTranslatorRegistry m_exceptionTranslatorRegistry;
TagAliasRegistry m_tagAliasRegistry;
};
// Single, global, instance

View File

@ -36,7 +36,7 @@ namespace Catch {
template<typename T>
class ReporterRegistrar {
class ReporterFactory : public IReporterFactory {
class ReporterFactory : public SharedImpl<IReporterFactory> {
// *** Please Note ***:
// - If you end up here looking at a compiler error because it's trying to register
@ -64,11 +64,39 @@ namespace Catch {
getMutableRegistryHub().registerReporter( name, new ReporterFactory() );
}
};
template<typename T>
class ListenerRegistrar {
class ListenerFactory : public SharedImpl<IReporterFactory> {
virtual IStreamingReporter* create( ReporterConfig const& config ) const {
return new T( config );
}
virtual std::string getDescription() const {
return std::string();
}
};
public:
ListenerRegistrar() {
getMutableRegistryHub().registerListener( new ListenerFactory() );
}
};
}
#define INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) \
namespace{ Catch::LegacyReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); }
#define INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) \
namespace{ Catch::ReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); }
// Deprecated - use the form without INTERNAL_
#define INTERNAL_CATCH_REGISTER_LISTENER( listenerType ) \
namespace{ Catch::ListenerRegistrar<listenerType> catch_internal_RegistrarFor##listenerType; }
#define CATCH_REGISTER_LISTENER( listenerType ) \
namespace{ Catch::ListenerRegistrar<listenerType> catch_internal_RegistrarFor##listenerType; }
#endif // TWOBLUECUBES_CATCH_REPORTER_REGISTRARS_HPP_INCLUDED

View File

@ -18,27 +18,32 @@ namespace Catch {
public:
virtual ~ReporterRegistry() {
deleteAllValues( m_factories );
}
virtual ~ReporterRegistry() CATCH_OVERRIDE {}
virtual IStreamingReporter* create( std::string const& name, Ptr<IConfig> const& config ) const {
virtual IStreamingReporter* create( std::string const& name, Ptr<IConfig const> const& config ) const CATCH_OVERRIDE {
FactoryMap::const_iterator it = m_factories.find( name );
if( it == m_factories.end() )
return CATCH_NULL;
return it->second->create( ReporterConfig( config ) );
}
void registerReporter( std::string const& name, IReporterFactory* factory ) {
void registerReporter( std::string const& name, Ptr<IReporterFactory> const& factory ) {
m_factories.insert( std::make_pair( name, factory ) );
}
void registerListener( Ptr<IReporterFactory> const& factory ) {
m_listeners.push_back( factory );
}
FactoryMap const& getFactories() const {
virtual FactoryMap const& getFactories() const CATCH_OVERRIDE {
return m_factories;
}
virtual Listeners const& getListeners() const CATCH_OVERRIDE {
return m_listeners;
}
private:
FactoryMap m_factories;
Listeners m_listeners;
};
}

View File

@ -11,6 +11,7 @@
#include "catch_result_type.h"
#include "catch_assertionresult.h"
#include "catch_common.h"
#include "catch_matchers.hpp"
namespace Catch {
@ -18,28 +19,27 @@ namespace Catch {
template<typename T> class ExpressionLhs;
struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison;
struct CopyableStream {
CopyableStream() {}
CopyableStream( CopyableStream const& other ) {
oss << other.oss.str();
}
CopyableStream& operator=( CopyableStream const& other ) {
oss.str("");
oss.str(std::string());
oss << other.oss.str();
return *this;
}
std::ostringstream oss;
};
class ResultBuilder {
class ResultBuilder : public DecomposedExpression {
public:
ResultBuilder( char const* macroName,
SourceLineInfo const& lineInfo,
char const* capturedExpression,
ResultDisposition::Flags resultDisposition,
char const* secondArg = "" );
~ResultBuilder();
template<typename T>
ExpressionLhs<T const&> operator <= ( T const& operand );
@ -47,45 +47,60 @@ namespace Catch {
template<typename T>
ResultBuilder& operator << ( T const& value ) {
m_stream.oss << value;
stream().oss << value;
return *this;
}
template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& );
template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& );
ResultBuilder& setResultType( ResultWas::OfType result );
ResultBuilder& setResultType( bool result );
ResultBuilder& setLhs( std::string const& lhs );
ResultBuilder& setRhs( std::string const& rhs );
ResultBuilder& setOp( std::string const& op );
void endExpression();
void endExpression( DecomposedExpression const& expr );
virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE;
std::string reconstructExpression() const;
AssertionResult build() const;
AssertionResult build( DecomposedExpression const& expr ) const;
void useActiveException( ResultDisposition::Flags resultDisposition = ResultDisposition::Normal );
void captureResult( ResultWas::OfType resultType );
void captureExpression();
void captureExpectedException( std::string const& expectedMessage );
void captureExpectedException( Matchers::Impl::MatcherBase<std::string> const& matcher );
void handleResult( AssertionResult const& result );
void react();
bool shouldDebugBreak() const;
bool allowThrows() const;
template<typename ArgT, typename MatcherT>
void captureMatch( ArgT const& arg, MatcherT const& matcher, char const* matcherString );
void setExceptionGuard();
void unsetExceptionGuard();
private:
AssertionInfo m_assertionInfo;
AssertionResultData m_data;
struct ExprComponents {
ExprComponents() : testFalse( false ) {}
bool testFalse;
std::string lhs, rhs, op;
} m_exprComponents;
CopyableStream m_stream;
CopyableStream &stream()
{
if(!m_usedStream)
{
m_usedStream = true;
m_stream().oss.str("");
}
return m_stream();
}
static CopyableStream &m_stream()
{
static CopyableStream s;
return s;
}
bool m_shouldDebugBreak;
bool m_shouldThrow;
bool m_guardException;
bool m_usedStream;
};
} // namespace Catch
@ -96,7 +111,7 @@ namespace Catch {
namespace Catch {
template<typename T>
inline ExpressionLhs<T const&> ResultBuilder::operator <= ( T const& operand ) {
ExpressionLhs<T const&> ResultBuilder::operator <= ( T const& operand ) {
return ExpressionLhs<T const&>( *this, operand );
}
@ -104,6 +119,15 @@ namespace Catch {
return ExpressionLhs<bool>( *this, value );
}
template<typename ArgT, typename MatcherT>
void ResultBuilder::captureMatch( ArgT const& arg, MatcherT const& matcher,
char const* matcherString ) {
MatchExpression<ArgT const&, MatcherT const&> expr( arg, matcher, matcherString );
setResultType( matcher.match( arg ) );
endExpression( expr );
}
} // namespace Catch
#endif // TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED

View File

@ -18,21 +18,28 @@
namespace Catch {
std::string capturedExpressionWithSecondArgument( std::string const& capturedExpression, std::string const& secondArg ) {
return secondArg.empty()
? capturedExpression
: capturedExpression + ", \"" + secondArg + "\"";
}
ResultBuilder::ResultBuilder( char const* macroName,
SourceLineInfo const& lineInfo,
char const* capturedExpression,
ResultDisposition::Flags resultDisposition,
char const* secondArg )
: m_assertionInfo( macroName, lineInfo, capturedExpressionWithSecondArgument( capturedExpression, secondArg ), resultDisposition ),
: m_assertionInfo( macroName, lineInfo, capturedExpression, resultDisposition, secondArg ),
m_shouldDebugBreak( false ),
m_shouldThrow( false )
m_shouldThrow( false ),
m_guardException( false ),
m_usedStream( false )
{}
ResultBuilder::~ResultBuilder() {
#if defined(CATCH_CONFIG_FAST_COMPILE)
if ( m_guardException ) {
stream().oss << "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE";
captureResult( ResultWas::ThrewException );
getCurrentContext().getResultCapture()->exceptionEarlyReported();
}
#endif
}
ResultBuilder& ResultBuilder::setResultType( ResultWas::OfType result ) {
m_data.resultType = result;
return *this;
@ -41,27 +48,27 @@ namespace Catch {
m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed;
return *this;
}
ResultBuilder& ResultBuilder::setLhs( std::string const& lhs ) {
m_exprComponents.lhs = lhs;
return *this;
}
ResultBuilder& ResultBuilder::setRhs( std::string const& rhs ) {
m_exprComponents.rhs = rhs;
return *this;
}
ResultBuilder& ResultBuilder::setOp( std::string const& op ) {
m_exprComponents.op = op;
return *this;
}
void ResultBuilder::endExpression() {
m_exprComponents.testFalse = isFalseTest( m_assertionInfo.resultDisposition );
captureExpression();
void ResultBuilder::endExpression( DecomposedExpression const& expr ) {
// Flip bool results if FalseTest flag is set
if( isFalseTest( m_assertionInfo.resultDisposition ) ) {
m_data.negate( expr.isBinaryExpression() );
}
getResultCapture().assertionRun();
if(getCurrentContext().getConfig()->includeSuccessfulResults() || m_data.resultType != ResultWas::Ok)
{
AssertionResult result = build( expr );
handleResult( result );
}
else
getResultCapture().assertionPassed();
}
void ResultBuilder::useActiveException( ResultDisposition::Flags resultDisposition ) {
m_assertionInfo.resultDisposition = resultDisposition;
m_stream.oss << Catch::translateActiveException();
stream().oss << Catch::translateActiveException();
captureResult( ResultWas::ThrewException );
}
@ -71,18 +78,24 @@ namespace Catch {
}
void ResultBuilder::captureExpectedException( std::string const& expectedMessage ) {
assert( m_exprComponents.testFalse == false );
if( expectedMessage.empty() )
captureExpectedException( Matchers::Impl::MatchAllOf<std::string>() );
else
captureExpectedException( Matchers::Equals( expectedMessage ) );
}
void ResultBuilder::captureExpectedException( Matchers::Impl::MatcherBase<std::string> const& matcher ) {
assert( !isFalseTest( m_assertionInfo.resultDisposition ) );
AssertionResultData data = m_data;
data.resultType = ResultWas::Ok;
data.reconstructedExpression = m_assertionInfo.capturedExpression;
if( expectedMessage != "" ) {
std::string actualMessage = Catch::translateActiveException();
WildcardPattern pattern( expectedMessage, WildcardPattern::CaseInsensitive );
if( !pattern.matches( actualMessage ) ) {
data.resultType = ResultWas::ExpressionFailed;
data.reconstructedExpression = actualMessage;
}
data.reconstructedExpression = capturedExpressionWithSecondArgument(m_assertionInfo.capturedExpression, m_assertionInfo.secondArg);
std::string actualMessage = Catch::translateActiveException();
if( !matcher.match( actualMessage ) ) {
data.resultType = ResultWas::ExpressionFailed;
data.reconstructedExpression = actualMessage;
}
AssertionResult result( m_assertionInfo, data );
handleResult( result );
@ -92,10 +105,11 @@ namespace Catch {
AssertionResult result = build();
handleResult( result );
}
void ResultBuilder::handleResult( AssertionResult const& result )
{
getResultCapture().assertionEnded( result );
if( !result.isOk() ) {
if( getCurrentContext().getConfig()->shouldDebugBreak() )
m_shouldDebugBreak = true;
@ -103,7 +117,17 @@ namespace Catch {
m_shouldThrow = true;
}
}
void ResultBuilder::react() {
#if defined(CATCH_CONFIG_FAST_COMPILE)
if (m_shouldDebugBreak) {
///////////////////////////////////////////////////////////////////
// To inspect the state during test, you need to go one level up the callstack
// To go back to the test and change execution, jump over the throw statement
///////////////////////////////////////////////////////////////////
CATCH_BREAK_INTO_DEBUGGER();
}
#endif
if( m_shouldThrow )
throw Catch::TestFailureException();
}
@ -113,43 +137,35 @@ namespace Catch {
AssertionResult ResultBuilder::build() const
{
assert( m_data.resultType != ResultWas::Unknown );
return build( *this );
}
// CAVEAT: The returned AssertionResult stores a pointer to the argument expr,
// a temporary DecomposedExpression, which in turn holds references to
// operands, possibly temporary as well.
// It should immediately be passed to handleResult; if the expression
// needs to be reported, its string expansion must be composed before
// the temporaries are destroyed.
AssertionResult ResultBuilder::build( DecomposedExpression const& expr ) const
{
assert( m_data.resultType != ResultWas::Unknown );
AssertionResultData data = m_data;
// Flip bool results if testFalse is set
if( m_exprComponents.testFalse ) {
if( data.resultType == ResultWas::Ok )
data.resultType = ResultWas::ExpressionFailed;
else if( data.resultType == ResultWas::ExpressionFailed )
data.resultType = ResultWas::Ok;
}
data.message = m_stream.oss.str();
data.reconstructedExpression = reconstructExpression();
if( m_exprComponents.testFalse ) {
if( m_exprComponents.op == "" )
data.reconstructedExpression = "!" + data.reconstructedExpression;
else
data.reconstructedExpression = "!(" + data.reconstructedExpression + ")";
}
if(m_usedStream)
data.message = m_stream().oss.str();
data.decomposedExpression = &expr; // for lazy reconstruction
return AssertionResult( m_assertionInfo, data );
}
std::string ResultBuilder::reconstructExpression() const {
if( m_exprComponents.op == "" )
return m_exprComponents.lhs.empty() ? m_assertionInfo.capturedExpression : m_exprComponents.op + m_exprComponents.lhs;
else if( m_exprComponents.op == "matches" )
return m_exprComponents.lhs + " " + m_exprComponents.rhs;
else if( m_exprComponents.op != "!" ) {
if( m_exprComponents.lhs.size() + m_exprComponents.rhs.size() < 40 &&
m_exprComponents.lhs.find("\n") == std::string::npos &&
m_exprComponents.rhs.find("\n") == std::string::npos )
return m_exprComponents.lhs + " " + m_exprComponents.op + " " + m_exprComponents.rhs;
else
return m_exprComponents.lhs + "\n" + m_exprComponents.op + "\n" + m_exprComponents.rhs;
}
else
return "{can't expand - use " + m_assertionInfo.macroName + "_FALSE( " + m_assertionInfo.capturedExpression.substr(1) + " ) instead of " + m_assertionInfo.macroName + "( " + m_assertionInfo.capturedExpression + " ) for better diagnostics}";
void ResultBuilder::reconstructExpression( std::string& dest ) const {
dest = capturedExpressionWithSecondArgument(m_assertionInfo.capturedExpression, m_assertionInfo.secondArg);
}
void ResultBuilder::setExceptionGuard() {
m_guardException = true;
}
void ResultBuilder::unsetExceptionGuard() {
m_guardException = false;
}
} // end namespace Catch

View File

@ -55,7 +55,7 @@ namespace Catch {
inline bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; }
inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; }
inline bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; }
} // end namespace Catch
#endif // TWOBLUECUBES_CATCH_RESULT_TYPE_H_INCLUDED

View File

@ -22,6 +22,7 @@
#include "catch_result_builder.h"
#include "catch_fatal_condition.hpp"
#include <set>
#include <string>
@ -50,6 +51,29 @@ namespace Catch {
std::string& m_targetString;
};
// StdErr has two constituent streams in C++, std::cerr and std::clog
// This means that we need to redirect 2 streams into 1 to keep proper
// order of writes and cannot use StreamRedirect on its own
class StdErrRedirect {
public:
StdErrRedirect(std::string& targetString)
:m_cerrBuf( cerr().rdbuf() ), m_clogBuf(clog().rdbuf()),
m_targetString(targetString){
cerr().rdbuf(m_oss.rdbuf());
clog().rdbuf(m_oss.rdbuf());
}
~StdErrRedirect() {
m_targetString += m_oss.str();
cerr().rdbuf(m_cerrBuf);
clog().rdbuf(m_clogBuf);
}
private:
std::streambuf* m_cerrBuf;
std::streambuf* m_clogBuf;
std::ostringstream m_oss;
std::string& m_targetString;
};
///////////////////////////////////////////////////////////////////////////
class RunContext : public IResultCapture, public IRunner {
@ -65,9 +89,7 @@ namespace Catch {
m_activeTestCase( CATCH_NULL ),
m_config( _config ),
m_reporter( reporter ),
m_prevRunner( m_context.getRunner() ),
m_prevResultCapture( m_context.getResultCapture() ),
m_prevConfig( m_context.getConfig() )
m_shouldReportUnexpected ( true )
{
m_context.setRunner( this );
m_context.setConfig( m_config );
@ -77,10 +99,6 @@ namespace Catch {
virtual ~RunContext() {
m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, aborting() ) );
m_context.setRunner( m_prevRunner );
m_context.setConfig( Ptr<IConfig const>() );
m_context.setResultCapture( m_prevResultCapture );
m_context.setConfig( m_prevConfig );
}
void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ) {
@ -101,17 +119,28 @@ namespace Catch {
m_reporter->testCaseStarting( testInfo );
m_activeTestCase = &testCase;
m_testCaseTracker = TestCaseTracker( testInfo.name );
do {
ITracker& rootTracker = m_trackerContext.startRun();
assert( rootTracker.isSectionTracker() );
static_cast<SectionTracker&>( rootTracker ).addInitialFilters( m_config->getSectionsToRun() );
do {
m_trackerContext.startCycle();
m_testCaseTracker = &SectionTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( testInfo.name, testInfo.lineInfo ) );
runCurrentTest( redirectedCout, redirectedCerr );
}
while( !m_testCaseTracker->isCompleted() && !aborting() );
while( !m_testCaseTracker->isSuccessfullyCompleted() && !aborting() );
}
// !TBD: deprecated - this will be replaced by indexed trackers
while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() );
Totals deltaTotals = m_totals.delta( prevTotals );
if( testInfo.expectedToFail() && deltaTotals.testCases.passed > 0 ) {
deltaTotals.assertions.failed++;
deltaTotals.testCases.passed--;
deltaTotals.testCases.failed++;
}
m_totals.testCases += deltaTotals.testCases;
m_reporter->testCaseEnded( TestCaseStats( testInfo,
deltaTotals,
@ -120,7 +149,7 @@ namespace Catch {
aborting() ) );
m_activeTestCase = CATCH_NULL;
m_testCaseTracker.reset();
m_testCaseTracker = CATCH_NULL;
return deltaTotals;
}
@ -137,27 +166,47 @@ namespace Catch {
m_totals.assertions.passed++;
}
else if( !result.isOk() ) {
m_totals.assertions.failed++;
if( m_activeTestCase->getTestCaseInfo().okToFail() )
m_totals.assertions.failedButOk++;
else
m_totals.assertions.failed++;
}
if( m_reporter->assertionEnded( AssertionStats( result, m_messages, m_totals ) ) )
m_messages.clear();
// We have no use for the return value (whether messages should be cleared), because messages were made scoped
// and should be let to clear themselves out.
static_cast<void>(m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals)));
// Reset working state
m_lastAssertionInfo = AssertionInfo( "", m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}" , m_lastAssertionInfo.resultDisposition );
m_lastResult = result;
}
virtual bool lastAssertionPassed()
{
return m_totals.assertions.passed == (m_prevPassed + 1);
}
virtual void assertionPassed()
{
m_totals.assertions.passed++;
m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}";
m_lastAssertionInfo.macroName = "";
}
virtual void assertionRun()
{
m_prevPassed = m_totals.assertions.passed;
}
virtual bool sectionStarted (
SectionInfo const& sectionInfo,
Counts& assertions
)
{
std::ostringstream oss;
oss << sectionInfo.name << "@" << sectionInfo.lineInfo;
if( !m_testCaseTracker->enterSection( oss.str() ) )
ITracker& sectionTracker = SectionTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( sectionInfo.name, sectionInfo.lineInfo ) );
if( !sectionTracker.isOpen() )
return false;
m_activeSections.push_back( &sectionTracker );
m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo;
@ -168,30 +217,40 @@ namespace Catch {
return true;
}
bool testForMissingAssertions( Counts& assertions ) {
if( assertions.total() != 0 ||
!m_config->warnAboutMissingAssertions() ||
m_testCaseTracker->currentSectionHasChildren() )
if( assertions.total() != 0 )
return false;
if( !m_config->warnAboutMissingAssertions() )
return false;
if( m_trackerContext.currentTracker().hasChildren() )
return false;
m_totals.assertions.failed++;
assertions.failed++;
return true;
}
virtual void sectionEnded( SectionInfo const& info, Counts const& prevAssertions, double _durationInSeconds ) {
if( std::uncaught_exception() ) {
m_unfinishedSections.push_back( UnfinishedSections( info, prevAssertions, _durationInSeconds ) );
return;
}
Counts assertions = m_totals.assertions - prevAssertions;
virtual void sectionEnded( SectionEndInfo const& endInfo ) {
Counts assertions = m_totals.assertions - endInfo.prevAssertions;
bool missingAssertions = testForMissingAssertions( assertions );
m_testCaseTracker->leaveSection();
if( !m_activeSections.empty() ) {
m_activeSections.back()->close();
m_activeSections.pop_back();
}
m_reporter->sectionEnded( SectionStats( info, assertions, _durationInSeconds, missingAssertions ) );
m_reporter->sectionEnded( SectionStats( endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions ) );
m_messages.clear();
}
virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) {
if( m_unfinishedSections.empty() )
m_activeSections.back()->fail();
else
m_activeSections.back()->close();
m_activeSections.pop_back();
m_unfinishedSections.push_back( endInfo );
}
virtual void pushScopedMessage( MessageInfo const& message ) {
m_messages.push_back( message );
}
@ -203,18 +262,26 @@ namespace Catch {
virtual std::string getCurrentTestName() const {
return m_activeTestCase
? m_activeTestCase->getTestCaseInfo().name
: "";
: std::string();
}
virtual const AssertionResult* getLastResult() const {
return &m_lastResult;
}
virtual void exceptionEarlyReported() {
m_shouldReportUnexpected = false;
}
virtual void handleFatalErrorCondition( std::string const& message ) {
ResultBuilder resultBuilder = makeUnexpectedResultBuilder();
resultBuilder.setResultType( ResultWas::FatalErrorCondition );
resultBuilder << message;
resultBuilder.captureExpression();
// Don't rebuild the result -- the stringification itself can cause more fatal errors
// Instead, fake a result data.
AssertionResultData tempResult;
tempResult.resultType = ResultWas::FatalErrorCondition;
tempResult.message = message;
AssertionResult result(m_lastAssertionInfo, tempResult);
getResultCapture().assertionEnded(result);
handleUnfinishedSections();
@ -231,13 +298,14 @@ namespace Catch {
Totals deltaTotals;
deltaTotals.testCases.failed = 1;
deltaTotals.assertions.failed = 1;
m_reporter->testCaseEnded( TestCaseStats( testInfo,
deltaTotals,
"",
"",
std::string(),
std::string(),
false ) );
m_totals.testCases.failed++;
testGroupEnded( "", m_totals, 1, 1 );
testGroupEnded( std::string(), m_totals, 1, 1 );
m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, false ) );
}
@ -255,17 +323,17 @@ namespace Catch {
m_reporter->sectionStarting( testCaseSection );
Counts prevAssertions = m_totals.assertions;
double duration = 0;
m_shouldReportUnexpected = true;
try {
m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal );
TestCaseTracker::Guard guard( *m_testCaseTracker );
seedRng( *m_config );
Timer timer;
timer.start();
if( m_reporter->getPreferences().shouldRedirectStdOut ) {
StreamRedirect coutRedir( Catch::cout(), redirectedCout );
StreamRedirect cerrRedir( Catch::cerr(), redirectedCerr );
StdErrRedirect errRedir( redirectedCerr );
invokeActiveTestCase();
}
else {
@ -277,20 +345,19 @@ namespace Catch {
// This just means the test was aborted due to failure
}
catch(...) {
makeUnexpectedResultBuilder().useActiveException();
// Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions
// are reported without translation at the point of origin.
if (m_shouldReportUnexpected) {
makeUnexpectedResultBuilder().useActiveException();
}
}
m_testCaseTracker->close();
handleUnfinishedSections();
m_messages.clear();
Counts assertions = m_totals.assertions - prevAssertions;
bool missingAssertions = testForMissingAssertions( assertions );
if( testCaseInfo.okToFail() ) {
std::swap( assertions.failedButOk, assertions.failed );
m_totals.assertions.failed -= assertions.failedButOk;
m_totals.assertions.failedButOk += assertions.failedButOk;
}
SectionStats testCaseSectionStats( testCaseSection, assertions, duration, missingAssertions );
m_reporter->sectionEnded( testCaseSectionStats );
}
@ -304,48 +371,40 @@ namespace Catch {
private:
ResultBuilder makeUnexpectedResultBuilder() const {
return ResultBuilder( m_lastAssertionInfo.macroName.c_str(),
return ResultBuilder( m_lastAssertionInfo.macroName,
m_lastAssertionInfo.lineInfo,
m_lastAssertionInfo.capturedExpression.c_str(),
m_lastAssertionInfo.capturedExpression,
m_lastAssertionInfo.resultDisposition );
}
void handleUnfinishedSections() {
// If sections ended prematurely due to an exception we stored their
// infos here so we can tear them down outside the unwind process.
for( std::vector<UnfinishedSections>::const_reverse_iterator it = m_unfinishedSections.rbegin(),
for( std::vector<SectionEndInfo>::const_reverse_iterator it = m_unfinishedSections.rbegin(),
itEnd = m_unfinishedSections.rend();
it != itEnd;
++it )
sectionEnded( it->info, it->prevAssertions, it->durationInSeconds );
sectionEnded( *it );
m_unfinishedSections.clear();
}
struct UnfinishedSections {
UnfinishedSections( SectionInfo const& _info, Counts const& _prevAssertions, double _durationInSeconds )
: info( _info ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds )
{}
SectionInfo info;
Counts prevAssertions;
double durationInSeconds;
};
TestRunInfo m_runInfo;
IMutableContext& m_context;
TestCase const* m_activeTestCase;
Option<TestCaseTracker> m_testCaseTracker;
ITracker* m_testCaseTracker;
ITracker* m_currentSectionTracker;
AssertionResult m_lastResult;
Ptr<IConfig const> m_config;
Totals m_totals;
Ptr<IStreamingReporter> m_reporter;
std::vector<MessageInfo> m_messages;
IRunner* m_prevRunner;
IResultCapture* m_prevResultCapture;
Ptr<IConfig const> m_prevConfig;
AssertionInfo m_lastAssertionInfo;
std::vector<UnfinishedSections> m_unfinishedSections;
std::vector<SectionEndInfo> m_unfinishedSections;
std::vector<ITracker*> m_activeSections;
TrackerContext m_trackerContext;
size_t m_prevPassed;
bool m_shouldReportUnexpected;
};
IResultCapture& getResultCapture() {

View File

@ -11,7 +11,6 @@
#include "catch_section.h"
#include "catch_capture.hpp"
#include "catch_compiler_capabilities.h"
#include "catch_timer.h"
namespace Catch {
@ -31,10 +30,22 @@ namespace Catch {
m_timer.start();
}
#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable:4996) // std::uncaught_exception is deprecated in C++17
#endif
Section::~Section() {
if( m_sectionIncluded )
getResultCapture().sectionEnded( m_info, m_assertions, m_timer.getElapsedSeconds() );
if( m_sectionIncluded ) {
SectionEndInfo endInfo( m_info, m_assertions, m_timer.getElapsedSeconds() );
if( std::uncaught_exception() )
getResultCapture().sectionEndedEarly( endInfo );
else
getResultCapture().sectionEnded( endInfo );
}
}
#if defined(_MSC_VER)
#pragma warning(pop)
#endif
// This indicates whether the section should be executed or not
Section::operator bool() const {

View File

@ -9,6 +9,9 @@
#define TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED
#include "catch_common.h"
#include "catch_totals.hpp"
#include <string>
namespace Catch {
@ -23,6 +26,16 @@ namespace Catch {
SourceLineInfo lineInfo;
};
struct SectionEndInfo {
SectionEndInfo( SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds )
: sectionInfo( _sectionInfo ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds )
{}
SectionInfo sectionInfo;
Counts prevAssertions;
double durationInSeconds;
};
} // end namespace Catch
#endif // TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED

View File

@ -8,10 +8,7 @@
#ifndef TWOBLUECUBES_CATCH_SECTION_INFO_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_SECTION_INFO_HPP_INCLUDED
#include "catch_common.h"
#include <map>
#include <string>
#include "catch_section_info.h"
namespace Catch {

View File

@ -9,28 +9,57 @@
#ifndef TWOBLUECUBES_CATCH_STREAM_H_INCLUDED
#define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED
#include <streambuf>
#include "catch_compiler_capabilities.h"
#include "catch_streambuf.h"
#ifdef __clang__
#pragma clang diagnostic ignored "-Wpadded"
#endif
#include <streambuf>
#include <ostream>
#include <fstream>
#include <memory>
namespace Catch {
class Stream {
public:
Stream();
Stream( std::streambuf* _streamBuf, bool _isOwned );
void release();
std::streambuf* streamBuf;
private:
bool isOwned;
};
std::ostream& cout();
std::ostream& cerr();
std::ostream& clog();
struct IStream {
virtual ~IStream() CATCH_NOEXCEPT;
virtual std::ostream& stream() const = 0;
};
class FileStream : public IStream {
mutable std::ofstream m_ofs;
public:
FileStream( std::string const& filename );
virtual ~FileStream() CATCH_NOEXCEPT;
public: // IStream
virtual std::ostream& stream() const CATCH_OVERRIDE;
};
class CoutStream : public IStream {
mutable std::ostream m_os;
public:
CoutStream();
virtual ~CoutStream() CATCH_NOEXCEPT;
public: // IStream
virtual std::ostream& stream() const CATCH_OVERRIDE;
};
class DebugOutStream : public IStream {
CATCH_AUTO_PTR( StreamBufBase ) m_streamBuf;
mutable std::ostream m_os;
public:
DebugOutStream();
virtual ~DebugOutStream() CATCH_NOEXCEPT;
public: // IStream
virtual std::ostream& stream() const CATCH_OVERRIDE;
};
}
#endif // TWOBLUECUBES_CATCH_STREAM_H_INCLUDED

View File

@ -10,7 +10,6 @@
#define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED
#include "catch_stream.h"
#include "catch_streambuf.h"
#include "catch_debugger.h"
#include <stdexcept>
@ -57,6 +56,20 @@ namespace Catch {
///////////////////////////////////////////////////////////////////////////
FileStream::FileStream( std::string const& filename ) {
m_ofs.open( filename.c_str() );
if( m_ofs.fail() ) {
std::ostringstream oss;
oss << "Unable to open file: '" << filename << '\'';
throw std::domain_error( oss.str() );
}
}
std::ostream& FileStream::stream() const {
return m_ofs;
}
struct OutputDebugWriter {
void operator()( std::string const&str ) {
@ -64,29 +77,35 @@ namespace Catch {
}
};
Stream::Stream()
: streamBuf( CATCH_NULL ), isOwned( false )
DebugOutStream::DebugOutStream()
: m_streamBuf( new StreamBufImpl<OutputDebugWriter>() ),
m_os( m_streamBuf.get() )
{}
Stream::Stream( std::streambuf* _streamBuf, bool _isOwned )
: streamBuf( _streamBuf ), isOwned( _isOwned )
{}
void Stream::release() {
if( isOwned ) {
delete streamBuf;
streamBuf = CATCH_NULL;
isOwned = false;
}
std::ostream& DebugOutStream::stream() const {
return m_os;
}
#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement this functions
// Store the streambuf from cout up-front because
// cout may get redirected when running tests
CoutStream::CoutStream()
: m_os( Catch::cout().rdbuf() )
{}
std::ostream& CoutStream::stream() const {
return m_os;
}
#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement these functions
std::ostream& cout() {
return std::cout;
}
std::ostream& cerr() {
return std::cerr;
}
std::ostream& clog() {
return std::clog;
}
#endif
}

View File

@ -5,9 +5,6 @@
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef TWOBLUECUBES_CATCH_SUPPRESS_WARNINGS_H_INCLUDED
#define TWOBLUECUBES_CATCH_SUPPRESS_WARNINGS_H_INCLUDED
#ifdef __clang__
# ifdef __ICC // icpc defines the __clang__ macro
# pragma warning(push)
@ -22,12 +19,13 @@
# pragma clang diagnostic ignored "-Wc++98-compat"
# pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
# pragma clang diagnostic ignored "-Wswitch-enum"
# pragma clang diagnostic ignored "-Wcovered-switch-default"
# endif
#elif defined __GNUC__
# pragma GCC diagnostic ignored "-Wvariadic-macros"
# pragma GCC diagnostic ignored "-Wunused-variable"
# pragma GCC diagnostic ignored "-Wparentheses"
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wpadded"
#endif
#endif // TWOBLUECUBES_CATCH_SUPPRESS_WARNINGS_H_INCLUDED

View File

@ -15,7 +15,7 @@
namespace Catch {
struct TagAlias {
TagAlias( std::string _tag, SourceLineInfo _lineInfo ) : tag( _tag ), lineInfo( _lineInfo ) {}
TagAlias( std::string const& _tag, SourceLineInfo _lineInfo ) : tag( _tag ), lineInfo( _lineInfo ) {}
std::string tag;
SourceLineInfo lineInfo;

View File

@ -19,8 +19,7 @@ namespace Catch {
virtual ~TagAliasRegistry();
virtual Option<TagAlias> find( std::string const& alias ) const;
virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const;
void add( char const* alias, char const* tag, SourceLineInfo const& lineInfo );
static TagAliasRegistry& get();
void add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo );
private:
std::map<std::string, TagAlias> m_registry;

View File

@ -10,9 +10,8 @@
#include "catch_tag_alias_registry.h"
#include "catch_console_colour.hpp"
#include <map>
#include <iostream>
#include "catch_interfaces_registry_hub.h"
#include "catch_stream.h"
namespace Catch {
@ -41,41 +40,36 @@ namespace Catch {
return expandedTestSpec;
}
void TagAliasRegistry::add( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) {
void TagAliasRegistry::add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) {
if( !startsWith( alias, "[@" ) || !endsWith( alias, "]" ) ) {
if( !startsWith( alias, "[@" ) || !endsWith( alias, ']' ) ) {
std::ostringstream oss;
oss << "error: tag alias, \"" << alias << "\" is not of the form [@alias name].\n" << lineInfo;
oss << Colour( Colour::Red )
<< "error: tag alias, \"" << alias << "\" is not of the form [@alias name].\n"
<< Colour( Colour::FileName )
<< lineInfo << '\n';
throw std::domain_error( oss.str().c_str() );
}
if( !m_registry.insert( std::make_pair( alias, TagAlias( tag, lineInfo ) ) ).second ) {
std::ostringstream oss;
oss << "error: tag alias, \"" << alias << "\" already registered.\n"
<< "\tFirst seen at " << find(alias)->lineInfo << "\n"
<< "\tRedefined at " << lineInfo;
oss << Colour( Colour::Red )
<< "error: tag alias, \"" << alias << "\" already registered.\n"
<< "\tFirst seen at "
<< Colour( Colour::Red ) << find(alias)->lineInfo << '\n'
<< Colour( Colour::Red ) << "\tRedefined at "
<< Colour( Colour::FileName) << lineInfo << '\n';
throw std::domain_error( oss.str().c_str() );
}
}
TagAliasRegistry& TagAliasRegistry::get() {
static TagAliasRegistry instance;
return instance;
ITagAliasRegistry::~ITagAliasRegistry() {}
ITagAliasRegistry const& ITagAliasRegistry::get() {
return getRegistryHub().getTagAliasRegistry();
}
ITagAliasRegistry::~ITagAliasRegistry() {}
ITagAliasRegistry const& ITagAliasRegistry::get() { return TagAliasRegistry::get(); }
RegistrarForTagAliases::RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) {
try {
TagAliasRegistry::get().add( alias, tag, lineInfo );
}
catch( std::exception& ex ) {
Colour colourGuard( Colour::Red );
Catch::cerr() << ex.what() << std::endl;
exit(1);
}
getMutableRegistryHub().registerTagAlias( alias, tag, lineInfo );
}
} // end namespace Catch

View File

@ -29,9 +29,10 @@ namespace Catch {
IsHidden = 1 << 1,
ShouldFail = 1 << 2,
MayFail = 1 << 3,
Throws = 1 << 4
Throws = 1 << 4,
NonPortable = 1 << 5
};
TestCaseInfo( std::string const& _name,
std::string const& _className,
std::string const& _description,
@ -41,7 +42,7 @@ namespace Catch {
TestCaseInfo( TestCaseInfo const& other );
friend void setTags( TestCaseInfo& testCaseInfo, std::set<std::string> const& tags );
bool isHidden() const;
bool throws() const;
bool okToFail() const;

Some files were not shown because too many files have changed in this diff Show More