Compare commits

...

220 Commits

Author SHA1 Message Date
Martin Hořeňovský
7c9f92bc1c v2.10.0 2019-10-13 23:44:18 +02:00
Martin Hořeňovský
a92a7d0229 Rewrite documentation for floating point matchers 2019-10-13 21:31:48 +02:00
Martin Hořeňovský
e4d61e4cd8 Fix baselines 2019-10-13 21:26:51 +02:00
Martin Hořeňovský
9ba48e2c9b Remove superfluous includes in exception matchers 2019-10-13 20:49:36 +02:00
Martin Hořeňovský
2cc0c71856 Add a matcher that checks exception's message
Only works for exceptions that publicly derive from `std::exception`
and the matching is done exactly, including case and whitespace.

Closes #1649
Closes #1728

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# On branch master
# Your branch is up-to-date with 'origin/master'.
#
# Changes to be committed:
#	modified:   ../docs/matchers.md
#	modified:   ../include/internal/catch_capture_matchers.h
#	modified:   ../projects/CMakeLists.txt
#	modified:   ../projects/SelfTest/Baselines/compact.sw.approved.txt
#	modified:   ../projects/SelfTest/Baselines/console.std.approved.txt
#	modified:   ../projects/SelfTest/Baselines/console.sw.approved.txt
#	modified:   ../projects/SelfTest/Baselines/junit.sw.approved.txt
#	modified:   ../projects/SelfTest/Baselines/xml.sw.approved.txt
#	modified:   ../projects/SelfTest/UsageTests/Matchers.tests.cpp
#
# Untracked files:
#	./
#	../clang-full/
#	../clang-test/
#	../clang10-build/
#	../coverage-build/
#	../gcc-build/
#	../gcc-full/
#	../include/internal/catch_matchers_exception.cpp
#	../include/internal/catch_matchers_exception.hpp
#	../misc-build/
#	../msvc-sln/
#	../notes.txt
#	../test-install/
#
2019-10-13 20:37:07 +02:00
Martin Hořeňovský
28663fb959 Use the right overload of std::nextafter in tests 2019-10-13 13:36:22 +02:00
Martin Hořeňovský
d2d418a9cb Add a Relative Comparison matcher for floating point numbers
It checks Knuth's _close enough with tolerance_ relationship, that
is `|lhs - rhs| <= epsilon * max(|lhs|, |rhs|)`, rather then the
_very close with tolerance_ relationship that can be written down as
`|lhs - rhs| <= epsilon * min(|lhs|, |rhs|)`.

This is because it is the more common model around the internet, and
as such is likely to be less surprising to the users. In the future
we might want to provide the other model as well.

Closes #1746
2019-10-13 11:56:50 +02:00
Martin Hořeňovský
c8db4e77c4 Add a from_range(Container) overload to the generator helpers 2019-10-09 14:51:36 +02:00
Martin Hořeňovský
1c5749669e Merge pull request #1769 from amitherman95/amitherman-1767
Patch:Failure to pass special chars through input file
2019-10-09 14:16:50 +02:00
Martin Hořeňovský
3109add95c Add tests for the -f/--input-file command line argument 2019-10-09 12:54:13 +02:00
amitherman95
adb4789136 Patch:Failure to apply filters through external file 2019-10-09 11:43:06 +02:00
Martin Hořeňovský
75200e199e Merge pull request #1768 from RT222/master
Simplified benchmark output with --benchmark-no-analysis
2019-10-08 21:07:35 +02:00
Martin Hořeňovský
a5a22cdadb Have the random generators use the global rng instance
This means that if you nest multiple random generators inside one
test case, they will not return the same sequence of numbers.

Idea taken from #1736 by Amit Herman.

Closes #1736
Closes #1734
2019-10-07 21:53:07 +02:00
Martin Hořeňovský
535da5c513 Introduce Catch's own RNG based on the PCG family of RNGs
In the future, we will also want to introduce our own
`uniform_int_distribution` and `uniform_real_distribution` to get
repeatable test runs across different platforms.
2019-10-07 19:56:23 +02:00
RT222
2331249a8d Simplified benchmark output with --benchmark-no-analysis
Removed unused informations from benchmarks output when the --benchmark-no-analysis flag is used, making the results easier to read.
2019-10-07 15:40:00 +02:00
Martin Hořeňovský
319cb9e1da Add a generator that takes an iterator pair 2019-10-06 13:55:10 +02:00
Martin Hořeňovský
b8b765d55e Merge pull request #1765 from kevingranade/patch-1
Add Cataclysm:Dark Days Ahead to project list
2019-10-06 12:41:46 +02:00
Kevin Granade
a0ebd63806 Add Cataclysm:Dark Days Ahead to project list 2019-10-05 20:18:31 -07:00
Martin Hořeňovský
4bd2c3ad6a Fix compilation error with CATCH_CONFIG_GLOBAL_NEXTAFTER
Wrong nesting of namespaces resulted in the `Catch` namespace
being ambigous between `::Catch` and `::{anon}::Catch` namespaces.
This should fix it.

Closes #1761
2019-10-05 21:03:46 +02:00
Martin Hořeňovský
c38a5caa2e Allow full range of target ULP values for the ULPMatcher
Previously it was limited to roughly 2 billion ULPs, rather than
the roughly 2^64 possible ones.
2019-10-05 13:38:22 +02:00
Martin Hořeňovský
ebc5609484 Add test for INF == Approx(1) 2019-10-04 14:19:39 +02:00
Wim Leflere
fcda35f645 update name of Value Generators in doc to match class names 2019-10-04 13:31:37 +02:00
Martin Hořeňovský
02ee130bd0 Special case Approx(inf) to better follow user expectations 2019-10-04 13:28:43 +02:00
Martin Hořeňovský
815f99541d Do not explicitly install conan
Instead, let it be installed as a dependency of `conan-package-tools`
to avoid trouble with the fact that pip is really bad at version
resolution, and that up-to-date version of the `conan` package is not
supported by up-to-date version of the `conan-package-tools` package.
2019-10-03 00:00:17 +02:00
Martin Hořeňovský
da0062f7c1 Merge pull request #1752 from amitherman95/amitherman-1737
Escape characters bug patch(v2.9.2)
2019-09-22 10:48:08 +02:00
Martin Hořeňovský
de42f8a93e Fix escaping of quotes in coverage helper 2019-09-21 23:19:45 +02:00
Martin Hořeňovský
af84f1350e Add documentation for the table generator helper 2019-09-21 01:00:53 +02:00
Martin Hořeňovský
fc2066bf18 Add tests for escaping special characters in CLI 2019-09-21 00:50:17 +02:00
amitherman95
2bcff9dd35 Escape characters bug patch(v2.9.2) 2019-09-21 00:46:58 +02:00
Martin Hořeňovský
3beccfb429 Remove the no longer used is_unique type trait
It was used in checking that types in TEMPLATE_TEST_CASE and friends
were unique, but this was removed for v2.8.0 (#1628). Since there
are no further uses of this trait, the simplest thing to do is to
just remove it.

Fixes #1757
2019-09-20 23:28:19 +02:00
Martin Hořeňovský
af8b2538a6 Ignore leading/trailing whitespace in test/section specs
The leading/trailing whitespace is problematic because of e.g.
`WHEN` macro having preceeding whitespace for alignment, and it is
generally messy.

Credits to Phil who did lot of the original work.

Closes #1708
2019-09-09 14:28:11 +02:00
Martin Hořeňovský
a156440b19 Reinline some StringRef methods with trivial bodies 2019-09-08 21:08:37 +02:00
Martin Hořeňovský
dab0296b64 Add test for past-the-end substr on StringRef 2019-09-08 21:07:21 +02:00
Martin Hořeňovský
9f4c4777a5 Remove (mostly) unused overloads of StringRef operator + 2019-09-08 21:01:33 +02:00
Martin Hořeňovský
293012a002 Inline SourceLineInfo::empty definition 2019-09-08 18:20:49 +02:00
Martin Hořeňovský
e2b3443fe7 Do not blindly access empty StringRefs 2019-09-08 17:44:56 +02:00
Martin Hořeňovský
7b865daccc Make StringRef's operator std::string explicit
This way it is explicit when there is a `StringRef` -> `std::string`
conversion and makes it easier to look for allocations that could
be avoided.

Doing this has already removed one allocation per registered test
case, as there was a completely pointless `StringRef` -> `std::string`
conversion when parsing tags of a test case.
2019-09-08 15:58:10 +02:00
Martin Hořeňovský
14362533bb Check for empty expression properly
The old code was a left-over from the times when the
`capturedExpression` member was a `const char*`, which could always
be indexed. With the change to use `StringRef`, blindly indexing 0th
element is invalid, as it is not indexable part of a StringRef.
2019-09-08 14:35:01 +02:00
Matthias Moulin
a5bb3e3d91 Small updates to include directives (#1726)
Fixed some inconsistencies in include directives.
2019-09-08 14:25:23 +02:00
Martin Hořeňovský
923db16322 Use StringRefs through the enum registration 2019-09-08 14:14:46 +02:00
Martin Hořeňovský
fbbaadb704 Use StringRef literal for unknown enum values instead of string lit 2019-09-08 14:14:14 +02:00
Martin Hořeňovský
dd1f0f1c72 Add test for --filename-as-tags 2019-09-07 20:43:14 +02:00
Martin Hořeňovský
d27d580d0b Add test for --libidentify command line flag 2019-09-07 20:36:12 +02:00
Martin Hořeňovský
6da00c1b64 Split out the rest of string manipulation tests 2019-09-07 20:22:36 +02:00
Martin Hořeňovský
fe967b1f41 Remove the ill-considered StringRef::numberOfCharacters
It never counted characters, only codepoints. If you think these
are interchangeable, you should not touch non-ascii text.
2019-09-07 20:13:22 +02:00
Martin Hořeňovský
f2c2711bdc Add trim for StringRef 2019-09-07 11:31:00 +02:00
Martin Hořeňovský
b77ab74b72 Start adding tests for string manip functions 2019-09-06 18:50:57 +02:00
Martin Hořeňovský
4038ee6bc6 Stop compilation if registering an enum could truncate its value
We probably want to use a bigger type (e.g. `int64_t`) later on,
but the is a mess right now anyway.
2019-09-06 18:36:59 +02:00
Martin Hořeňovský
789f3591ef Do not write singular characters into stream as C-strings 2019-09-06 18:30:16 +02:00
Martin Hořeňovský
6e8d769775 Unify handling of __has_include checks 2019-09-06 13:38:58 +02:00
Martin Hořeňovský
1189a73be2 Do not assume that version placeholders contain ")" 2019-09-06 13:25:39 +02:00
Martin Hořeňovský
071bacad5e Properly linkthrough additions to the configuration docs 2019-09-06 13:24:51 +02:00
Martin Hořeňovský
addf799040 Workaround missing std::nextafter in uClibc
Luckily, the rest of C++11 features seem to be supported...

Closes #1739
2019-09-06 13:08:44 +02:00
Martin Hořeňovský
155274f0df Add disabling the use of Android's logging at compile time
This is done via the new compile time toggle,
`CATCH_CONFIG_ANDROID_LOGWRITE`.

Closes #1743
2019-09-06 12:44:06 +02:00
Benjamin Worpitz
18d597cf10 Allow to use non-copyable and non-movable types in TEMPLATE_LIST_TEST_CASE
The parameter given to `convert` may not be copyable therefore it has to be
captured by const reference. For example an `std::tuple` that contains a
non-copyable type is itself non-copyable.

The NonDefaultConstructible test-case was reduced by one example type
because it did not add any value.
2019-09-06 12:15:09 +02:00
Martin Hořeňovský
6629c11ef8 Optimize in-repo PNGs 2019-09-06 12:12:47 +02:00
Martin Hořeňovský
c6bf56b3d5 Fix Travis builds with clang 5/6
There is some weird broken dependency in their version of Trusty
(14.04 LTE), so we are using Xenial (16.04 LTE) instead.
2019-09-06 12:07:29 +02:00
Martin Hořeňovský
623e348d9e Merge pull request #1744 from ux3d/add-ux3d-to-commercial-users
add UX3D to commercial users
2019-09-06 11:37:55 +02:00
Benjamin Schmithüsen
46f767e602 add UX3D to commercial users 2019-09-06 11:27:33 +02:00
Martin Hořeňovský
ce42deb72f Add Android's log library to Catch2's CMake interface 2019-08-10 20:51:15 +02:00
Martin Hořeňovský
46a70071a7 Use __android_log_write instead of __android_log_print
`print` version of the logging functions supports `printf`-like
formatting, which we do not use and given our current debug print
internals, will never use. This should be slightly more efficient
and expresses the intent better.
2019-08-10 14:51:38 +02:00
Jesse Alas
378cc1a670 Rename template parameter names to avoid name conflict on Solaris.
Closes #1722
2019-08-10 10:55:17 +02:00
Martin Hořeňovský
e2d863b090 Actually run the random generator tests 2019-08-09 11:21:05 +02:00
Martin Hořeňovský
ebe6a07c23 Remove the new tests from approvals
They lead to stringification of file (which is ok) and file line
(not ok) to the approvals, which makes them exceedingly brittle
and not worth approval testing. Instead we just run them as part
of the base test run.
2019-08-09 11:13:28 +02:00
Martin Hořeňovský
edcfd7fc62 Add missed item to v2.9.2 release notes 2019-08-09 10:57:59 +02:00
Martin Hořeňovský
738818ae1d Add a test for the internals 2019-08-09 10:50:53 +02:00
Martin Hořeňovský
2c869e17e4 v2.9.2 2019-08-08 14:05:24 +02:00
Martin Hořeňovský
0ab11aa9b4 (Hopefully) Fix Obj-C++ compilation of matchers
Thanks to bdb for the patch, related to #1661
2019-08-07 20:35:27 +02:00
Martin Hořeňovský
7a6af7ba76 Merge pull request #1717 from ax3l/fix-storageClassFirst
static constexpr: storage class first
2019-08-07 09:23:47 +02:00
Martin Hořeňovský
fa096b26d1 Merge pull request #1715 from sfranzen/fix-compact-reporter
Fix infinite loop in compact reporter printer
2019-08-07 09:12:38 +02:00
Axel Huebl
820b1f12bf static constexpr: storage class first
Seen with PGI compiler for `static constexpr`:
```
warning: storage class is not first
```
2019-08-06 19:17:16 -05:00
Steven Franzen
6070745cab Improve reporting of unmatched filters (#1684)
This PR ultimately does 3 things
* Separately tracks matched tests per each filter part (that is, a set of filters separated by an OR (`,`)), which allows Catch2 to report each of the alternative filters that don't match any tests.
* Fixes `-w NoTests` to return non-zero in the process
* Adds tests for `-w NoTests`.
2019-08-06 20:51:19 +02:00
Steven Franzen
3d9e7db2e0 Fix infinite loop in compact reporter printer
Also simplify some variables with auto deduction.
2019-08-06 20:19:42 +02:00
Martin Hořeňovský
cf55cfd76f Tiny speedup when listing tags
Noticed that the code was originally concatenating strings just to
then append the result to another string. Now it does not create
temporaries and also preallocates the string buffer.
2019-08-05 19:12:29 +02:00
Martin Hořeňovský
3701c2e2e6 Small cleanup of self tests 2019-08-04 13:50:25 +02:00
Martin Hořeňovský
7dc7d77af2 Add a test for Catch version output 2019-08-03 20:16:46 +02:00
Martin Hořeňovský
06bc20cf37 Improve handling of newlines in release scripts
Under WSL, Python in text mode will translate `\n` into `\r\n`, even
though other tools and utilities use `\n` (because WSL is basically
Linux). This leads to the update scripts leaving the files with
Windows newlines even though git and similar expect them to have
Linux newlines.

By instead handling files in binary mode, we can keep the original
newlines. This commits switches parts of the update process to
binary mode, but not all because some of the will require a lot of
work to fix.
2019-08-03 19:59:35 +02:00
Martin Hořeňovský
7a4beed6a6 Make release script update version placeholders in docs 2019-08-03 10:44:57 +02:00
Clare Macrae
67b4ada6b0 Add 'Introduced in Catch 2.3.0.' text 2019-08-02 19:18:47 +02:00
Clare Macrae
119569a67e Add 'Introduced in Catch 2.4.0.' text 2019-08-02 19:18:47 +02:00
Clare Macrae
ab713894cc Add docs for AND_GIVEN macro - see #1360 2019-08-02 19:18:47 +02:00
Clare Macrae
69fc94d6f8 Add 'Introduced in Catch 2.4.1.' text 2019-08-02 19:18:47 +02:00
Clare Macrae
49cd7c96b4 Add 'Introduced in Catch 2.4.2.' text 2019-08-02 19:18:47 +02:00
Clare Macrae
e998d152cc Add 'Introduced in Catch 2.5.0.' text 2019-08-02 19:18:47 +02:00
Clare Macrae
42a5903188 Add 'Introduced in Catch 2.6.0.' text 2019-08-02 19:18:47 +02:00
Clare Macrae
c071f07e1a Add 'Introduced in Catch 2.7.0.' note 2019-08-02 19:18:47 +02:00
Clare Macrae
53776a90cf Add 'Introduced in Catch 2.7.1.' note 2019-08-02 19:18:47 +02:00
Clare Macrae
4511dc0c16 Add 'Introduced in Catch 2.8.0.' text 2019-08-02 19:18:47 +02:00
Clare Macrae
e7c3bdb351 Add 'Introduced in Catch 2.8.0.' text 2019-08-02 19:18:47 +02:00
Clare Macrae
9aab958667 Add section headers, so I can later say when features were introduced 2019-08-02 19:18:47 +02:00
Clare Macrae
8cd58f75ec Add missing struct Template_Fixture_2 so that the example compiles.
Code copied from projects/SelfTest/UsageTests/Class.tests.cpp
2019-08-02 19:18:47 +02:00
Clare Macrae
d5a69cd400 Add 'Introduced in Catch 2.9.0.' text 2019-08-02 19:18:47 +02:00
Clare Macrae
1d13d88833 Helper script to create "Introduced in ..." text - see #1667 2019-08-02 19:18:47 +02:00
Martin Hořeňovský
de0674c116 Add a template for creating new documentation page
Related to #1695
2019-08-02 13:17:22 +02:00
Martin Hořeňovský
3d7282c2bd Add a section on documentation to contributing.md
Related to #1695
2019-08-02 10:58:51 +02:00
Mike Cowan
e5c0e3322d Add Android implementation of writeToDebugConsole that prints to Logcat (#1710) 2019-07-31 23:12:34 +02:00
Martin Hořeňovský
dc8c8e957f Use an up to date conan package version again
Last time it was fixed to a specific version because the `conan`
and the `conan-package-tools` package that `pip install` would
gather were not compatible, let's hope it won't happen again.
2019-07-31 15:59:16 +02:00
Martin Hořeňovský
ba9193370b Add autoconfiguration for RTX
Closes #1693
2019-07-30 11:28:28 +02:00
Czapa10
7b70b11c23 Add PopHead to Open Source projects using Catch 2019-07-30 09:37:05 +02:00
Martin Hořeňovský
ab80277a86 Improve the REQUIRE_THROWS_MATCHES documentation a bit 2019-07-29 20:39:02 +02:00
Joachim Meyer
7e7ab0e28b Fix xml reporter crashing when a benchmark failed. 2019-07-29 15:30:33 +02:00
Martin Hořeňovský
425957dc63 Update vector matcher documentation
As it turns out, there were 2 undocumented vector matchers. I also
improved the documentation of them all.

Closes #1699
2019-07-27 18:41:42 +02:00
Martin Hořeňovský
d017f6d18f Document CATCH_CONFIG_CPP17_BYTE macro
Leftover from #1686
2019-07-26 21:43:46 +02:00
Martin Hořeňovský
91244d30a7 Document CATCH_CONFIG_CPP17_OPTIONAL macro 2019-07-26 21:42:54 +02:00
Martin Hořeňovský
62b3f6c3c2 Merge pull request #1698 from sfranzen/fix-#1634
Fix CTest command issue with square brackets
2019-07-22 13:15:35 +02:00
Benjamin Worpitz
e7c26f09d1 Fix non-default-constructible type lists used in TEMPLATE_LIST_TEST_CASE (#1697)
* Fix non-default-constructible type lists used in TEMPLATE_LIST_TEST_CASE

std::tuple is not default constructible when the first type is not
default-constuctible. Therefore it can not be instantiated.
to circumvent this, we have to use std::declval in the unevaluate decltype
context.
2019-07-22 12:56:33 +02:00
Martin Hořeňovský
a22b7df46c Merge pull request #1700 from claremacrae/patch-3
Fix typo in 2.7.1 release notes
2019-07-22 12:13:29 +02:00
Clare Macrae
032068b889 Fix typo in 2.7.1 release notes
GENERATE_VAR -> GENERATE_REF
2019-07-21 22:04:50 +01:00
Steven Franzen
2aed6233cf Fix CTest command issue with square brackets 2019-07-21 16:29:46 +02:00
Martin Hořeňovský
fb74bb133c Fix coverage report merging
For some time now (I'd guess almost a year 🤷), the coverage
merging on Windows has been failing, because the reports have been
generated in a different folder than expected. Our merge script did
not report failure because it was not checking the returned error
code from OpenCppCoverage, and for some reason, the `codecov` tool
happily returned 0 even though it did not find the file it was
supposed to upload...

The former is also fixed by this commit.
2019-07-20 21:12:17 +02:00
Martin Hořeňovský
0b42ada60d Coverage helper now passes-on test return value
This allows #1684 to proceed forward.
2019-07-20 21:05:31 +02:00
Martin Hořeňovský
c424ca47f9 Revert "Do not resolve symbolic path when sanitizing filepath during approvals"
This reverts commit 52f3abadbb.

Opens #1691
2019-07-19 18:16:21 +02:00
Martin Hořeňovský
52f3abadbb Do not resolve symbolic path when sanitizing filepath during approvals
Fixes #1691
2019-07-18 16:33:57 +02:00
Martin Hořeňovský
53281b471f Prevent compilation of generators that use bool in dangerous manner
Closes #1692
2019-07-18 11:54:18 +02:00
Martin Hořeňovský
03ffc1014c Add a notice that benchmarking supports needs opt-in 2019-07-14 15:49:17 +02:00
Stuart Dootson
87739ad3fe Add std::byte stringification support (#1686)
* Add `std::byte` support

1. Add byte detection in Catch config
2. Add a `std::byte`specialisation for Catch2::Detail::StringMaker
2019-07-13 14:47:56 +02:00
Clare Macrae
0c27554af5 Update Contents in docs #1667 2019-07-06 17:25:55 +02:00
Martin Hořeňovský
11488e63b6 Use _WIN32 macro for detecting MSVC Windows
Previously we used `WIN32`, which sometimes does exist, but according to
https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros?view=vs-2019
`_WIN32` is the one that is actually provided by the compiler.

Closes #1676.
2019-07-06 16:55:10 +02:00
Martin Hořeňovský
820271bf24 Remove the weird backronym from readme 2019-07-02 20:43:37 +02:00
Martin Hořeňovský
56d4510138 Default the SelfTest project to C++11
Unlike the previous approach, this will still obey
`-DCMAKE_CXX_STANDARD=X` properly.
2019-07-02 20:42:14 +02:00
Martin Hořeňovský
c0d3a2e08f Merge pull request #1672 from sommd/master
Fix ChunkGenerator with chunk-size 0
2019-07-01 18:07:37 +02:00
Martin Hořeňovský
2c3018a9d5 Merge pull request #1673 from sfranzen/fix-sections
Fix TrackerBase::close children completion check
2019-06-30 09:17:01 +02:00
Martin Hořeňovský
9a6551b22b Add integration test for the children completion check fix 2019-06-30 00:00:41 +02:00
Steven Franzen
800f1b1d3d Fix TrackerBase::close children completion check
Now verifies that all children have completed, instead of only the last.
2019-06-29 18:02:28 +02:00
David Sommerich
9cf5897a11 Fix ChunkGenerator with chunk-size 0
Fixes #1671
2019-06-29 23:48:30 +10:00
Scott Hutchinson
6f32c67ea7 Adding to documentation for --order and --rng-seed 2019-06-21 15:17:55 +02:00
Martin Hořeňovský
7eea3ab245 Actually fix the CMake platform-independence problem 2019-06-17 19:41:17 +02:00
Justin Bassett
80af9ca687 Rollback ctest labels in CatchAddTests.cmake
Parsing --list-tests is broken, as Catch automatically line wraps the
line when it gets too long, stripping any whitespace in the process.
This means that it's impossible to reproduce the exact name of the
test if the test's name is long enough to line-wrap.

Furthermore, overwriting the LABELS property with the discovered labels
breaks users who manually added custom ctest labels.

Rolling back to using --list-test-names-only for now, as it does not
wrap lines even on very long test names.

We may be able parse the output of --list-tags to produce the ctest labels.
However, the straightforward way of doing this is to use CMake's
get_property(TEST ...) and set_property(TEST ... APPEND ...), which don't
work if the test name has spaces or other special characters. We would
need to mangle the test name to a valid CMake identifier to do it that way.
2019-06-17 19:17:32 +02:00
Martin Hořeňovský
33286fdc37 Fix bug with making arch-independent CMake config file
Closes #1660
2019-06-17 19:08:16 +02:00
Martin Hořeňovský
2f631bb808 v2.9.1 2019-06-17 12:02:14 +02:00
Martin Hořeňovský
25cc09dcec Fix benchmarking in stand-alone files 2019-06-17 11:58:40 +02:00
Martin Hořeňovský
f9dce28e7d v2.9.0 2019-06-16 10:42:59 +02:00
Jayesh Badwaik
b87caafd91 Remove explicit setting of CXX_STANDARD for SelfTest target
- The current setup tries to detect USE_CPP14/USE_CPP17 and sets the
    CXX_STANDARD property for the SelfTest target. This is not ideal, since
    CMAKE_CXX_STANDARD can be provided by the toolchain file or as command line
    option and should be used by the library internally correctly.  Hence, the
    whole set of the relevant lines from `projects/CMakeLists.txt` have been
    removed.

  - The above can also cause subtle issues where the user is expecting the tests
    to compile with C++17 after setting CMAKE_CXX_STANDARD and then getting
    results of compilation with C++11 as USE_CPP17 has not been set.

  - The current build matrix used the above code to run the tests. So, even
    though the it should not required anymore to build Catch2, it was still
    required to send correct options to build matrix. In that respect,
    .travis.yml has been modified to send correct options to the build command
    in the new setup.
2019-06-15 20:33:28 +02:00
geh
bbbd5c4e08 Added null-ptr check in Colour::use() 2019-06-15 18:06:59 +02:00
Jozef Grajciar
f41051f22a test approvals for TEMPLATE_LIST_TEST_CASE 2019-06-15 15:40:39 +02:00
Jozef Grajciar
e90d5a86e4 docs for TEMPLATE_LIST_TEST_CASE 2019-06-15 15:40:39 +02:00
Jozef Grajciar
dbc1295354 tests for TEMPLATE_LIST_TEST_CASE 2019-06-15 15:40:39 +02:00
Jozef Grajciar
f2cfc2b852 TEMPLATE_LIST_TEST_CASE implementation
Closes #1627
2019-06-15 15:40:39 +02:00
Martin Hořeňovský
c365ac392b Standardize and document the parallel processing toggle 2019-06-15 12:50:36 +02:00
Martin Hořeňovský
e640c3837a Move the async-using parts of benchmarking into a .cpp file
This keeps it out of the main include path when benchmarking is
enabled, somewhat reducing the compilation-time penalty.

Also moved some other functions into the .cpp file, especially
helpers that could be given internal linkage, and concretized some
iterator-templated code that only ever used
`std::vector<double>::iterator`.
2019-06-15 11:43:25 +02:00
Martin Hořeňovský
b468d7cbff Link benchmarking docs from the doc main page 2019-06-15 09:23:00 +02:00
Martin Hořeňovský
7142d5a8c9 Show bound when stringifying the WithinULP matcher
Closes #1581
2019-06-15 07:12:27 +02:00
Martin Hořeňovský
1967feac49 Introduce stubs for throwing specific exception types
This allows us to move <stdexcept> out of the common path, and replace
it with just <exception>. The difference between these two headers is
~13k lines after preprocessing on libstdc++ (16k vs 3k) and ~17k lines
for MS's STL(33k vs 16k).

Note that this is only beneficial if no other stdlib header we use
includes <stdexcept>. AFAIK this is true for the newest MS's STL,
but I have no idea of the applicability for libstdc++ and libc++.
2019-06-14 19:13:50 +02:00
Martin Hořeňovský
f0b7b0ca11 Add a FUNDING file 2019-06-07 19:15:35 +02:00
Martin Hořeňovský
4b1252547c Merge pull request #1616 from fodinabor/integrate_nonius
Integrate nonius to provide more advanced benchmarking
2019-06-07 07:01:47 +02:00
Martin Hořeňovský
10067a47da Add an extra test for benchmarking macros
Also updated baselines
2019-06-06 21:29:25 +02:00
Martin Hořeňovský
e340ab8db6 Various improvements to the benchmarking support
* Units from <ratio> are no longer redeclared in our own namespace
* The default clock is `steady_clock`, not `high_resolution_clock`,
because, as HH says "high_resolution_clock is useless. If you want
measure the passing of time, use steady_clock. If you want user
friendly time, use system_clock".
* Benchmarking support is opt-in, not opt-out, to avoid the large
(~10%) compile time penalty.
* Benchmarking-related options in CLI are always present, to decrease
the amount of code that is only compiled conditionally and making
the whole shebang more maintainble.
2019-06-06 21:28:56 +02:00
Joachim Meyer
ce2560ca95 Integrate Nonius benchmark into Catch2
Changes done to Nonius:
* Moved things into "Catch::Benchmark" namespace
* Benchmarks were integrated with `TEST_CASE`/`SECTION`/`GENERATE` macros
* Removed Nonius's parameters for benchmarks, Generators should be used instead
* Added relevant methods to the reporter interface (default-implemented, to avoid
breaking existing 3rd party reporters)
* Async processing is guarded with `_REENTRANT` macro for GCC/Clang, used by default
on MSVC
* Added a macro `CATCH_CONFIG_DISABLE_BENCHMARKING` that removes all traces of
benchmarking from Catch
2019-06-06 19:33:37 +02:00
Martin Hořeňovský
00347f1e79 v2.8.0 2019-05-26 22:47:00 +02:00
Martin Hořeňovský
a5a2d08fbb Remove commented out code 2019-05-26 21:19:55 +02:00
Martin Hořeňovský
97602b248b Remove obsolete file with wrong advice 2019-05-25 21:20:37 +02:00
Martin Hořeňovský
e28e162795 Merge pull request #1638 from janisozaur/patch-1
Prevent building in source dir
2019-05-25 21:15:58 +02:00
Martin Hořeňovský
90378f4a59 Have conan test-build the package in a separate subdirectory 2019-05-25 19:58:49 +02:00
Jozef Grajciar
84f8e806b8 Nttp support tests approvals 2019-05-23 21:03:47 +02:00
Jozef Grajciar
732e4b06db docs for signature based parametrised test cases 2019-05-23 21:03:47 +02:00
Jozef Grajciar
0c43f98fa2 Nttp support
Closes #1531
2019-05-23 21:03:47 +02:00
Martin Hořeňovský
bd703dd74b Merge pull request #1611 from cincodenada/unscoped-disabled-prefixed
Add UNSCOPED_INFO to prefix/disabled sections
2019-05-23 14:19:22 +02:00
Martin Hořeňovský
99602787cd Fix error message when unmatched quotes are encountered by CAPTURE
Thanks to @ledvinap for noticing
2019-05-23 13:54:51 +02:00
Michał Janiszewski
bfb4ee1597 Prevent building in source dir
Fixes #1636
2019-05-21 06:38:06 +02:00
Phil Nash
31537c43d9 Rebased approvals 2019-05-21 00:05:39 +01:00
Phil Nash
96355da34e StringRef no longer repoints m_start to m_data after c_str() on a substring.
This fixes an issue where a self-assignment of a StringRef copy would point into internally (and now dangling) data.
(now self-assignment check is no longer needed)
2019-05-21 00:04:44 +01:00
Phil Nash
71fce429af Fix clang warning on self-assignment 2019-05-21 00:04:44 +01:00
Jozef Grajciar
d13e094598 Remove unique type check
Closes #1628
2019-05-20 21:13:05 +02:00
Phil Nash
d30f1dda02 Rebased approvals 2019-05-18 20:53:28 +01:00
Phil Nash
3bce8ba14b Fix StringRef self-assignment after substring
Thanks to Alex Tkachenko for spotting it.
2019-05-18 17:54:39 +01:00
Jozef Grajciar
e680c4b9fb fix SEGFAULT during construction of Session
coloured output tried to write startup exceptions
to stream which was not initialized
2019-05-15 20:14:25 +02:00
mlimber
f1e14a1168 Add missing word 2019-05-09 22:40:59 +02:00
Martin Hořeňovský
92ad9ee355 Merge pull request #1614 from mlimber/master
Allow custom precision in error reports for floating-point numbers
2019-05-03 17:46:03 +02:00
Martin Hořeňovský
e2862a8d71 Add documentation for custom precision in float stringification 2019-05-03 15:40:21 +02:00
Martin Hořeňovský
1161011dd0 Refactor custom precision in floating point stringification
Also fixup tests.
2019-05-03 15:38:06 +02:00
mlimber
53a83e855e Add support for custom precision in floating point stringification
Closes #1612
2019-05-02 21:34:47 +02:00
Petr Ledvina
9c741fe960 Allow quotes in CAPTURE arguments (#1608)
* Allow quotes in CAPTURE arguments

Fix CAPTURE to handle string and character literals properly
2019-05-01 19:12:44 +02:00
Phil nash
979bbf03bb Removed another redundant ; (from docs) 2019-04-27 18:52:38 +01:00
Phil nash
33ce3f3953 added cpp to another code block in docs 2019-04-27 18:51:26 +01:00
Phil nash
87a9424c9d Removed redundant ; 2019-04-27 18:50:05 +01:00
Phil nash
00cb0035c9 Enclosed generated StringMaker for enums in Catch namespace, rather than qualified 2019-04-26 18:24:52 +01:00
Phil nash
6267b06089 Added #include for <memory> (for unique_ptr) 2019-04-26 17:06:44 +01:00
Phil nash
9837c35df1 Rebased approvals for stringified enum tests 2019-04-26 11:30:19 +01:00
Phil nash
46066ede17 Merge branch enum stringification work 2019-04-26 11:26:45 +01:00
Phil nash
6981783178 Added some missing #includes 2019-04-25 14:19:00 +01:00
Phil nash
08c8df1e3b include StringRef, rather than fwd decl, for splitString 2019-04-25 10:32:55 +01:00
Phil nash
daeb5a87e6 Removed global qualification of specialisation 2019-04-25 10:23:58 +01:00
Phil nash
f2ee4f17ad Moved enum tests that depend on internals to IntrospectiveTests.
- also factored out makeEnumInfo, so tests don't need to touch registry
- and added usage test that involves namespace
2019-04-25 10:13:11 +01:00
Wu Yuanshou
182fc3e46e fix example's mistake in slow-compiles.md
the example lack the generation of factorial.o file which lead to an undefined reference error.
2019-04-25 09:48:22 +02:00
Joel Bradshaw
6b5b72651d Add UNSCOPED_INFO to prefix/disabled sections 2019-04-24 12:56:39 -07:00
Joel Bradshaw
f45bb00351 Add failing test for CATCH_UNSCOPED_CAPTURE
Actually fails to compile, which is good
2019-04-24 12:55:11 -07:00
Martin Hořeňovský
7c37501b07 v2.7.2 2019-04-22 23:15:59 +02:00
Martin Hostettler
4a1ca1ab55 TrackerContext: Remove misleading instance static method.
TrackerContext is not used as singleton, so just remove this misleading
method
2019-04-22 16:37:22 +02:00
Phil Nash
e02d9e788f Document CATCH_REGISTER_ENUM 2019-04-21 20:32:20 +03:00
Phil Nash
541f1ed1b3 Only provide CATCH_REGISTER_ENUM
No longer have version without the CATCH_ prefix
2019-04-21 20:26:46 +03:00
Phil Nash
346723c9b6 Renamed STRINGIFY_ENUM to REGISTER_ENUM 2019-04-21 20:15:26 +03:00
Phil Nash
5a74fcc9c9 Removed IEnumInfo (just use EnumInfo directly) 2019-04-21 20:09:58 +03:00
Phil Nash
9d5d719868 Changed splitString to splitStringRef
Now takes and returns StringRefs
2019-04-21 20:03:44 +03:00
Will Handley
91b617c462 Added a vector approximate matcher 2019-04-20 10:02:17 +02:00
Martin Hořeňovský
45e552528d Remove home-rolled algorithm replacements
Previously we had them to avoid including <algorithm> in the vector
matchers, but
* we included it anyway, even though we did not use it
* we use <algorithm> anyways in the generators
2019-04-19 17:54:21 +02:00
Martin Hořeňovský
3978e9653b Add more documentation on contributing 2019-04-18 16:18:30 +02:00
Stephen Newell
d6fce7bf34 Fix warnings generated with -Wshadow 2019-04-18 15:30:38 +02:00
Martin Hořeňovský
c3c82f539c Merge pull request #1336 from ax3l/topic-overrideVirtualRedundant
Refactor: override implies virtual
2019-04-18 14:10:24 +02:00
Martin Hořeňovský
c7653811a6 Add basic CPack support
@ThijsWithaar is responsible for giving me the idea, but his PR
had couple of things that meant it was simpler to rewrite it than
to fix and merge it.

Supersedes and closes #1599
2019-04-18 13:47:33 +02:00
JoeyGrajciar
79417b9afc Revert "draft of nttp support"
This reverts commit 0c39409da7.
2019-04-18 11:35:33 +02:00
JoeyGrajciar
11cdd72db9 Merge remote-tracking branch 'refs/remotes/origin/nttp_support' 2019-04-18 11:26:33 +02:00
Jozef Grajciar
0c39409da7 draft of nttp support
added _SIG macros
2019-04-17 21:41:19 +02:00
Martin Hořeňovský
edfac75347 Add test for omitting the 'Filters' heading when there were none 2019-04-16 23:49:22 +02:00
Martin Luelf
ac94bd0520 ParseAndAddCatchTests: Ignore cmake object libraries 2019-04-14 19:10:15 +02:00
Maciej Patro
d4eec016a9 CatchAddTests now adds tags as labels for ctest
- `ctest --print-labels` now will show list of available labels
- `ctest -L <regex>` will allow to run tests with given labels(tags)
2019-04-14 18:59:53 +02:00
Martin Hořeňovský
36fb856163 Fix JUnit reporter output so that it conforms to JUnit schema
The `properties` can only go under the `testsuite` tag, not under
the `testsuites` tag.

Fixes #1598
2019-04-11 13:04:54 +02:00
Martin Hořeňovský
4e32e0a563 Fix vendored dep because upstream is non-responsive
Eventually this needs to be fixed in the textflow project by Phil,
but he has not done so in the half a year this bug has been known
to be there, so...

Closes #1470
Closes #1455
2019-04-10 20:17:25 +02:00
Daniele E. Domenichelli
1e2270b370 ParseAndAddCatchTests: Do not change CMAKE_MINIMUM_REQUIRED_VERSION when included 2019-04-10 10:50:13 +02:00
Daniele E. Domenichelli
5096e39297 ParseAndAddCatchTests: Add scope to functions in order to avoid name collisions 2019-04-10 10:50:13 +02:00
Daniele E. Domenichelli
15ccced6da ParseAndAddCatchTests: Document AdditionalCatchParameters variable 2019-04-10 10:50:13 +02:00
Daniele E. Domenichelli
682617b5b7 ParseAndAddCatchTests: Fix tests not found
When using an optional launcher the target name is not interpreted as a
target, therefore it is not replaced automatically with its path.
2019-04-10 10:50:13 +02:00
Daniele E. Domenichelli
15150c7b46 ParseAndAddCatchTests: Set the ParseAndAddCatchTests_TESTS property
After the script, the ParseAndAddCatchTests_TESTS property for the
target, and for each source file in the target is set, and contains the
list of the tests extracted from that target, or from that file.

This is useful, for example to add further labels or properties to the
tests.
2019-04-10 10:50:13 +02:00
Torfinn Berset
5ce355a38c For macOS builds, disable isDebuggerActive() for non-AppleClang targets. Fixes #1588 2019-04-10 10:19:54 +02:00
Ryan Pavlik
edde6f4736 Fix typos identified by codespell.
Self test baselines also modified accordingly, due to
one typo found in a string in test code.
2019-04-10 09:42:11 +02:00
Martin Hořeňovský
6bc5d172ee Merge pull request #1596 from 50ty/patch-1
IndexOfHideLabel is never used
2019-04-10 09:31:00 +02:00
Stefan Rommel
3079b514d4 IndexOfHideLabel is never used 2019-04-10 08:00:08 +02:00
Martin Hořeňovský
e99f1efd28 Avoid adding a default test spec when none was provided 2019-04-09 11:50:59 +02:00
Phil nash
02f13cf95a Made onto dev build and regenerated single header 2019-04-04 16:02:58 +01:00
Phil nash
43428c6093 First commit of STRINGIFY_ENUM 2019-04-04 15:55:46 +01:00
Axel Huebl
5347ff9e5f Refactor: override implies virtual
If not used with `final`, override implies `virtual`.
Detected via CodeFactor score.

Another reference on SO:
  https://stackoverflow.com/questions/43466863/isnt-virtual-keyword-redundant-when-override-or-final-specifiers-are-used
2018-07-12 14:27:06 +02:00
188 changed files with 14274 additions and 2511 deletions

View File

@@ -47,7 +47,7 @@ class BuilderSettings(object):
@property
def reference(self):
""" Read project version from branch create Conan referece
""" Read project version from branch create Conan reference
"""
return os.getenv("CONAN_REFERENCE", "Catch2/{}".format(self._version))

1
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1 @@
patreon: horenmar

View File

@@ -12,7 +12,7 @@ at docs/contributing.md. It will tell you how to properly test your changes.
<!--
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
to decrease the number of new strings allocated, that's what. The why probably
was that you have a large set of tests and found that this speeds them up.
-->

View File

@@ -9,8 +9,8 @@ common_sources: &all_sources
- llvm-toolchain-trusty
- llvm-toolchain-trusty-3.9
- llvm-toolchain-trusty-4.0
- llvm-toolchain-trusty-5.0
- llvm-toolchain-trusty-6.0
- llvm-toolchain-xenial-5.0
- llvm-toolchain-xenial-6.0
matrix:
include:
@@ -60,6 +60,7 @@ matrix:
env: COMPILER='clang++-4.0'
- os: linux
dist: xenial
compiler: clang
addons:
apt:
@@ -68,6 +69,7 @@ matrix:
env: COMPILER='clang++-5.0'
- os: linux
dist: xenial
compiler: clang
addons:
apt:
@@ -153,6 +155,7 @@ matrix:
env: COMPILER='clang++-4.0' CPP14=1
- os: linux
dist: xenial
compiler: clang
addons:
apt:
@@ -161,6 +164,7 @@ matrix:
env: COMPILER='clang++-5.0' CPP14=1
- os: linux
dist: xenial
compiler: clang
addons:
apt:
@@ -255,6 +259,7 @@ matrix:
env: COMPILER='g++-7' EXAMPLES=1 COVERAGE=1 EXTRAS=1 CPP17=1
- os: linux
dist: xenial
compiler: clang
addons:
apt:
@@ -263,6 +268,7 @@ matrix:
env: COMPILER='clang++-6.0' CPP17=1
- os: linux
dist: xenial
compiler: clang
addons:
apt:
@@ -276,7 +282,7 @@ matrix:
- "3.7"
dist: xenial
install:
- pip install conan==1.10.2 conan-package-tools
- pip install conan-package-tools
env:
- CONAN_GCC_VERSIONS=8
- CONAN_DOCKER_IMAGE=conanio/gcc8
@@ -301,10 +307,19 @@ before_script:
# Regenerate single header file, so it is tested in the examples...
- python scripts/generateSingleHeader.py
- |
if [[ ${CPP17} -eq 1 ]]; then
export CPP_STANDARD=17
elif [[ ${CPP14} -eq 1 ]]; then
export CPP_STANDARD=14
else
export CPP_STANDARD=11
fi
# Use Debug builds for running Valgrind and building examples
- cmake -H. -BBuild-Debug -DCMAKE_BUILD_TYPE=Debug -Wdev -DUSE_CPP14=${CPP14} -DUSE_CPP17=${CPP17} -DCATCH_USE_VALGRIND=${VALGRIND} -DCATCH_BUILD_EXAMPLES=${EXAMPLES} -DCATCH_ENABLE_COVERAGE=${COVERAGE} -DCATCH_BUILD_EXTRA_TESTS=${EXTRAS}
- cmake -H. -BBuild-Debug -DCMAKE_BUILD_TYPE=Debug -Wdev -DCATCH_USE_VALGRIND=${VALGRIND} -DCATCH_BUILD_EXAMPLES=${EXAMPLES} -DCATCH_ENABLE_COVERAGE=${COVERAGE} -DCATCH_BUILD_EXTRA_TESTS=${EXTRAS} -DCMAKE_CXX_STANDARD=${CPP_STANDARD} -DCMAKE_CXX_STANDARD_REQUIRED=On -DCMAKE_CXX_EXTENSIONS=OFF
# Don't bother with release build for coverage build
- cmake -H. -BBuild-Release -DCMAKE_BUILD_TYPE=Release -Wdev -DUSE_CPP14=${CPP14} -DUSE_CPP17=${CPP17}
- cmake -H. -BBuild-Release -DCMAKE_BUILD_TYPE=Release -Wdev -DCMAKE_CXX_STANDARD=${CPP_STANDARD} -DCMAKE_CXX_STANDARD_REQUIRED=On -DCMAKE_CXX_EXTENSIONS=OFF
script:

View File

@@ -19,7 +19,7 @@ set(CMAKE_REQUIRED_QUIET ${codecov_FIND_QUIETLY})
get_property(ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES)
foreach (LANG ${ENABLED_LANGUAGES})
# Gcov evaluation is dependend on the used compiler. Check gcov support for
# Gcov evaluation is dependent on the used compiler. Check gcov support for
# each compiler that is used. If gcov binary was already found for this
# compiler, do not try to find it again.
if (NOT GCOV_${CMAKE_${LANG}_COMPILER_ID}_BIN)

View File

@@ -74,7 +74,7 @@ set(CMAKE_REQUIRED_QUIET ${codecov_FIND_QUIETLY})
get_property(ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES)
foreach (LANG ${ENABLED_LANGUAGES})
# Coverage flags are not dependend on language, but the used compiler. So
# Coverage flags are not dependent on language, but the used compiler. So
# instead of searching flags foreach language, search flags foreach compiler
# used.
set(COMPILER ${CMAKE_${LANG}_COMPILER_ID})

View File

@@ -6,7 +6,11 @@ if(NOT DEFINED PROJECT_NAME)
set(NOT_SUBPROJECT ON)
endif()
project(Catch2 LANGUAGES CXX VERSION 2.7.1)
project(Catch2 LANGUAGES CXX VERSION 2.10.0)
if (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR)
message(FATAL_ERROR "Building in-source is not supported! Create a build dir and remove ${CMAKE_SOURCE_DIR}/CMakeCache.txt")
endif()
# Provide path for scripts
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/CMake")
@@ -88,6 +92,10 @@ target_include_directories(Catch2
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)
if (ANDROID)
target_link_libraries(Catch2 INTERFACE log)
endif()
# provide a namespaced alias for clients to 'link' against if catch is included as a sub-project
add_library(Catch2::Catch2 ALIAS Catch2)
@@ -132,9 +140,11 @@ if (NOT_SUBPROJECT)
#
# CMake does not provide a direct customization point for this in
# `write_basic_package_version_file`, but it can be accomplished
# indirectly by temporarily undefining `CMAKE_SIZEOF_VOID_P`.
# indirectly by temporarily redefining `CMAKE_SIZEOF_VOID_P` to an
# empty string. Note that just undefining the variable could be
# insufficient in cases where the variable was already in CMake cache
set(CATCH2_CMAKE_SIZEOF_VOID_P ${CMAKE_SIZEOF_VOID_P})
unset(CMAKE_SIZEOF_VOID_P)
set(CMAKE_SIZEOF_VOID_P "")
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/Catch2ConfigVersion.cmake"
COMPATIBILITY
@@ -205,4 +215,15 @@ if (NOT_SUBPROJECT)
${PKGCONFIG_INSTALL_DIR}
)
# CPack/CMake started taking the package version from project version 3.12
# So we need to set the version manually for older CMake versions
if(${CMAKE_VERSION} VERSION_LESS "3.12.0")
set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION})
endif()
set(CPACK_PACKAGE_CONTACT "https://github.com/catchorg/Catch2/")
include( CPack )
endif(NOT_SUBPROJECT)

View File

@@ -5,11 +5,11 @@
[![Build Status](https://travis-ci.org/catchorg/Catch2.svg?branch=master)](https://travis-ci.org/catchorg/Catch2)
[![Build status](https://ci.appveyor.com/api/projects/status/github/catchorg/Catch2?svg=true)](https://ci.appveyor.com/project/catchorg/catch2)
[![codecov](https://codecov.io/gh/catchorg/Catch2/branch/master/graph/badge.svg)](https://codecov.io/gh/catchorg/Catch2)
[![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/ZFBZ5XbLA9F1gzKi)
[![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/00GdTUbFWaV3bNah)
[![Join the chat in Discord: https://discord.gg/4CWS9zD](https://img.shields.io/badge/Discord-Chat!-brightgreen.svg)](https://discord.gg/4CWS9zD)
<a href="https://github.com/catchorg/Catch2/releases/download/v2.7.1/catch.hpp">The latest version of the single header can be downloaded directly using this link</a>
<a href="https://github.com/catchorg/Catch2/releases/download/v2.10.0/catch.hpp">The latest version of the single header can be downloaded directly using this link</a>
## Catch2 is released!
@@ -19,9 +19,8 @@ before moving to Catch2. You might also like to read [this blog post](https://le
## What's the Catch?
Catch2 stands for C++ Automated Test Cases in a Header and is a
multi-paradigm test framework for C++. which also supports Objective-C
(and maybe C).
Catch2 is a multi-paradigm test framework for C++. which also supports
Objective-C (and maybe C).
It is primarily distributed as a single header file, although certain
extensions may require additional headers.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 20 KiB

View File

@@ -18,7 +18,7 @@ class CatchConan(ConanFile):
cmake.definitions["BUILD_TESTING"] = "OFF"
cmake.definitions["CATCH_INSTALL_DOCS"] = "OFF"
cmake.definitions["CATCH_INSTALL_HELPERS"] = "ON"
cmake.configure()
cmake.configure(build_folder='build')
cmake.install()
self.copy(pattern="LICENSE.txt", dst="licenses")

View File

@@ -51,8 +51,11 @@ string(REPLACE "\n" ";" output "${output}")
# Parse output
foreach(line ${output})
set(test ${line})
# use escape commas to handle properly test cases with commans inside the name
string(REPLACE "," "\\," test_name ${test})
# Escape characters in test case names that would be parsed by Catch2
set(test_name ${test})
foreach(char , [ ])
string(REPLACE ${char} "\\${char}" test_name ${test_name})
endforeach(char)
# ...and add to script
add_command(add_test
"${prefix}${test}${suffix}"

View File

@@ -44,9 +44,19 @@
# set(OptionalCatchTestLauncher ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${NUMPROC}) #
# just before calling this ParseAndAddCatchTests function #
# #
# The AdditionalCatchParameters optional variable can be used to pass extra argument to the test #
# command. For example, to include successful tests in the output, one can write #
# set(AdditionalCatchParameters --success) #
# #
# After the script, the ParseAndAddCatchTests_TESTS property for the target, and for each source #
# file in the target is set, and contains the list of the tests extracted from that target, or #
# from that file. This is useful, for example to add further labels or properties to the tests. #
# #
#==================================================================================================#
cmake_minimum_required(VERSION 2.8.8)
if (CMAKE_MINIMUM_REQUIRED_VERSION VERSION_LESS 2.8.8)
message(FATAL_ERROR "ParseAndAddCatchTests requires CMake 2.8.8 or newer")
endif()
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)
@@ -54,7 +64,7 @@ option(PARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAME "Add fixture class name to the
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)
function(ParseAndAddCatchTests_PrintDebugMessage)
if(PARSE_CATCH_TESTS_VERBOSE)
message(STATUS "ParseAndAddCatchTests: ${ARGV}")
endif()
@@ -65,7 +75,7 @@ endfunction()
# - full line comments (i.e. // ... )
# contents have been read into '${CppCode}'.
# !keep partial line comments
function(RemoveComments CppCode)
function(ParseAndAddCatchTests_RemoveComments CppCode)
string(ASCII 2 CMakeBeginBlockComment)
string(ASCII 3 CMakeEndBlockComment)
string(REGEX REPLACE "/\\*" "${CMakeBeginBlockComment}" ${CppCode} "${${CppCode}}")
@@ -77,24 +87,29 @@ function(RemoveComments CppCode)
endfunction()
# Worker function
function(ParseFile SourceFile TestTarget)
function(ParseAndAddCatchTests_ParseFile SourceFile TestTarget)
# If SourceFile is an object library, do not scan it (as it is not a file). Exit without giving a warning about a missing file.
if(SourceFile MATCHES "\\\$<TARGET_OBJECTS:.+>")
ParseAndAddCatchTests_PrintDebugMessage("Detected OBJECT library: ${SourceFile} this will not be scanned for tests.")
return()
endif()
# 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}")
ParseAndAddCatchTests_PrintDebugMessage("parsing ${SourceFile}")
file(STRINGS ${SourceFile} Contents NEWLINE_CONSUME)
# Remove block and fullline comments
RemoveComments(Contents)
ParseAndAddCatchTests_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")
ParseAndAddCatchTests_PrintDebugMessage("Adding ${SourceFile} to CMAKE_CONFIGURE_DEPENDS property")
set_property(
DIRECTORY
APPEND
@@ -155,7 +170,6 @@ function(ParseFile SourceFile TestTarget)
list(APPEND Labels ${Tags})
list(FIND Labels "!hide" IndexOfHideLabel)
set(HiddenTagFound OFF)
foreach(label ${Labels})
string(REGEX MATCH "^!hide|^\\." result ${label})
@@ -165,26 +179,34 @@ function(ParseFile SourceFile TestTarget)
endif(result)
endforeach(label)
if(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS AND ${HiddenTagFound} AND ${CMAKE_VERSION} VERSION_LESS "3.9")
PrintDebugMessage("Skipping test \"${CTestName}\" as it has [!hide], [.] or [.foo] label")
ParseAndAddCatchTests_PrintDebugMessage("Skipping test \"${CTestName}\" as it has [!hide], [.] or [.foo] label")
else()
PrintDebugMessage("Adding test \"${CTestName}\"")
ParseAndAddCatchTests_PrintDebugMessage("Adding test \"${CTestName}\"")
if(Labels)
PrintDebugMessage("Setting labels to ${Labels}")
ParseAndAddCatchTests_PrintDebugMessage("Setting labels to ${Labels}")
endif()
# Escape commas in the test spec
string(REPLACE "," "\\," Name ${Name})
# Add the test and set its properties
add_test(NAME "\"${CTestName}\"" COMMAND ${OptionalCatchTestLauncher} ${TestTarget} ${Name} ${AdditionalCatchParameters})
add_test(NAME "\"${CTestName}\"" COMMAND ${OptionalCatchTestLauncher} $<TARGET_FILE:${TestTarget}> ${Name} ${AdditionalCatchParameters})
# Old CMake versions do not document VERSION_GREATER_EQUAL, so we use VERSION_GREATER with 3.8 instead
if(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS AND ${HiddenTagFound} AND ${CMAKE_VERSION} VERSION_GREATER "3.8")
PrintDebugMessage("Setting DISABLED test property")
ParseAndAddCatchTests_PrintDebugMessage("Setting DISABLED test property")
set_tests_properties("\"${CTestName}\"" PROPERTIES DISABLED ON)
else()
set_tests_properties("\"${CTestName}\"" PROPERTIES FAIL_REGULAR_EXPRESSION "No tests ran"
LABELS "${Labels}")
endif()
set_property(
TARGET ${TestTarget}
APPEND
PROPERTY ParseAndAddCatchTests_TESTS "\"${CTestName}\"")
set_property(
SOURCE ${SourceFile}
APPEND
PROPERTY ParseAndAddCatchTests_TESTS "\"${CTestName}\"")
endif()
@@ -193,11 +215,11 @@ endfunction()
# entry point
function(ParseAndAddCatchTests TestTarget)
PrintDebugMessage("Started parsing ${TestTarget}")
ParseAndAddCatchTests_PrintDebugMessage("Started parsing ${TestTarget}")
get_target_property(SourceFiles ${TestTarget} SOURCES)
PrintDebugMessage("Found the following sources: ${SourceFiles}")
ParseAndAddCatchTests_PrintDebugMessage("Found the following sources: ${SourceFiles}")
foreach(SourceFile ${SourceFiles})
ParseFile(${SourceFile} ${TestTarget})
ParseAndAddCatchTests_ParseFile(${SourceFile} ${TestTarget})
endforeach()
PrintDebugMessage("Finished parsing ${TestTarget}")
ParseAndAddCatchTests_PrintDebugMessage("Finished parsing ${TestTarget}")
endfunction()

View File

@@ -14,6 +14,7 @@ Writing tests:
* [Event Listeners](event-listeners.md#top)
* [Data Generators](generators.md#top)
* [Other macros](other-macros.md#top)
* [Micro benchmarking](benchmarks.md#top)
Fine tuning:
* [Supplying your own main()](own-main.md#top)

View File

@@ -136,7 +136,7 @@ REQUIRE_THROWS_WITH( dismantleHal(), "My mind is going" );
* **REQUIRE_THROWS_MATCHES(** _expression_, _exception type_, _matcher for given exception type_ **)** and
* **CHECK_THROWS_MATCHES(** _expression_, _exception type_, _matcher for given exception type_ **)**
Expects that exception of _exception type_ is thrown and it matches provided matcher (see next section for Matchers).
Expects that exception of _exception type_ is thrown and it matches provided matcher (see the [documentation for Matchers](matchers.md#top)).
_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._

256
docs/benchmarks.md Normal file
View File

@@ -0,0 +1,256 @@
<a id="top"></a>
# Authoring benchmarks
> [Introduced](https://github.com/catchorg/Catch2/issues/1616) in Catch 2.9.0.
_Note that benchmarking support is disabled by default and to enable it,
you need to define `CATCH_CONFIG_ENABLE_BENCHMARKING`. For more details,
see the [compile-time configuration documentation](configuration.md#top)._
Writing benchmarks is not easy. Catch simplifies certain aspects but you'll
always need to take care about various aspects. Understanding a few things about
the way Catch runs your code will be very helpful when writing your benchmarks.
First off, let's go over some terminology that will be used throughout this
guide.
- *User code*: user code is the code that the user provides to be measured.
- *Run*: one run is one execution of the user code.
- *Sample*: one sample is one data point obtained by measuring the time it takes
to perform a certain number of runs. One sample can consist of more than one
run if the clock available does not have enough resolution to accurately
measure a single run. All samples for a given benchmark execution are obtained
with the same number of runs.
## Execution procedure
Now I can explain how a benchmark is executed in Catch. There are three main
steps, though the first does not need to be repeated for every benchmark.
1. *Environmental probe*: before any benchmarks can be executed, the clock's
resolution is estimated. A few other environmental artifacts are also estimated
at this point, like the cost of calling the clock function, but they almost
never have any impact in the results.
2. *Estimation*: the user code is executed a few times to obtain an estimate of
the amount of runs that should be in each sample. This also has the potential
effect of bringing relevant code and data into the caches before the actual
measurement starts.
3. *Measurement*: all the samples are collected sequentially by performing the
number of runs estimated in the previous step for each sample.
This already gives us one important rule for writing benchmarks for Catch: the
benchmarks must be repeatable. The user code will be executed several times, and
the number of times it will be executed during the estimation step cannot be
known beforehand since it depends on the time it takes to execute the code.
User code that cannot be executed repeatedly will lead to bogus results or
crashes.
## Benchmark specification
Benchmarks can be specified anywhere inside a Catch test case.
There is a simple and a slightly more advanced version of the `BENCHMARK` macro.
Let's have a look how a naive Fibonacci implementation could be benchmarked:
```c++
std::uint64_t Fibonacci(std::uint64_t number) {
return number < 2 ? 1 : Fibonacci(number - 1) + Fibonacci(number - 2);
}
```
Now the most straight forward way to benchmark this function, is just adding a `BENCHMARK` macro to our test case:
```c++
TEST_CASE("Fibonacci") {
CHECK(Fibonacci(0) == 1);
// some more asserts..
CHECK(Fibonacci(5) == 8);
// some more asserts..
// now let's benchmark:
BENCHMARK("Fibonacci 20") {
return Fibonacci(20);
};
BENCHMARK("Fibonacci 25") {
return Fibonacci(25);
};
BENCHMARK("Fibonacci 30") {
return Fibonacci(30);
};
BENCHMARK("Fibonacci 35") {
return Fibonacci(35);
};
}
```
There's a few things to note:
- As `BENCHMARK` expands to a lambda expression it is necessary to add a semicolon after
the closing brace (as opposed to the first experimental version).
- The `return` is a handy way to avoid the compiler optimizing away the benchmark code.
Running this already runs the benchmarks and outputs something similar to:
```
-------------------------------------------------------------------------------
Fibonacci
-------------------------------------------------------------------------------
C:\path\to\Catch2\Benchmark.tests.cpp(10)
...............................................................................
benchmark name samples iterations estimated
mean low mean high mean
std dev low std dev high std dev
-------------------------------------------------------------------------------
Fibonacci 20 100 416439 83.2878 ms
2 ns 2 ns 2 ns
0 ns 0 ns 0 ns
Fibonacci 25 100 400776 80.1552 ms
3 ns 3 ns 3 ns
0 ns 0 ns 0 ns
Fibonacci 30 100 396873 79.3746 ms
17 ns 17 ns 17 ns
0 ns 0 ns 0 ns
Fibonacci 35 100 145169 87.1014 ms
468 ns 464 ns 473 ns
21 ns 15 ns 34 ns
```
### Advanced benchmarking
The simplest use case shown above, takes no arguments and just runs the user code that needs to be measured.
However, if using the `BENCHMARK_ADVANCED` macro and adding a `Catch::Benchmark::Chronometer` argument after
the macro, some advanced features are available. The contents of the simple benchmarks are invoked once per run,
while the blocks of the advanced benchmarks are invoked exactly twice:
once during the estimation phase, and another time during the execution phase.
```c++
BENCHMARK("simple"){ return long_computation(); };
BENCHMARK_ADVANCED("advanced")(Catch::Benchmark::Chronometer meter) {
set_up();
meter.measure([] { return long_computation(); });
};
```
These advanced benchmarks no longer consist entirely of user code to be measured.
In these cases, the code to be measured is provided via the
`Catch::Benchmark::Chronometer::measure` member function. This allows you to set up any
kind of state that might be required for the benchmark but is not to be included
in the measurements, like making a vector of random integers to feed to a
sorting algorithm.
A single call to `Catch::Benchmark::Chronometer::measure` performs the actual measurements
by invoking the callable object passed in as many times as necessary. Anything
that needs to be done outside the measurement can be done outside the call to
`measure`.
The callable object passed in to `measure` can optionally accept an `int`
parameter.
```c++
meter.measure([](int i) { return long_computation(i); });
```
If it accepts an `int` parameter, the sequence number of each run will be passed
in, starting with 0. This is useful if you want to measure some mutating code,
for example. The number of runs can be known beforehand by calling
`Catch::Benchmark::Chronometer::runs`; with this one can set up a different instance to be
mutated by each run.
```c++
std::vector<std::string> v(meter.runs());
std::fill(v.begin(), v.end(), test_string());
meter.measure([&v](int i) { in_place_escape(v[i]); });
```
Note that it is not possible to simply use the same instance for different runs
and resetting it between each run since that would pollute the measurements with
the resetting code.
It is also possible to just provide an argument name to the simple `BENCHMARK` macro to get
the same semantics as providing a callable to `meter.measure` with `int` argument:
```c++
BENCHMARK("indexed", i){ return long_computation(i); };
```
### Constructors and destructors
All of these tools give you a lot mileage, but there are two things that still
need special handling: constructors and destructors. The problem is that if you
use automatic objects they get destroyed by the end of the scope, so you end up
measuring the time for construction and destruction together. And if you use
dynamic allocation instead, you end up including the time to allocate memory in
the measurements.
To solve this conundrum, Catch provides class templates that let you manually
construct and destroy objects without dynamic allocation and in a way that lets
you measure construction and destruction separately.
```c++
BENCHMARK_ADVANCED("construct")(Catch::Benchmark::Chronometer meter)
{
std::vector<Catch::Benchmark::storage_for<std::string>> storage(meter.runs());
meter.measure([&](int i) { storage[i].construct("thing"); });
})
BENCHMARK_ADVANCED("destroy", [](Catch::Benchmark::Chronometer meter)
{
std::vector<Catch::Benchmark::destructable_object<std::string>> storage(meter.runs());
for(auto&& o : storage)
o.construct("thing");
meter.measure([&](int i) { storage[i].destruct(); });
})
```
`Catch::Benchmark::storage_for<T>` objects are just pieces of raw storage suitable for `T`
objects. You can use the `Catch::Benchmark::storage_for::construct` member function to call a constructor and
create an object in that storage. So if you want to measure the time it takes
for a certain constructor to run, you can just measure the time it takes to run
this function.
When the lifetime of a `Catch::Benchmark::storage_for<T>` object ends, if an actual object was
constructed there it will be automatically destroyed, so nothing leaks.
If you want to measure a destructor, though, we need to use
`Catch::Benchmark::destructable_object<T>`. These objects are similar to
`Catch::Benchmark::storage_for<T>` in that construction of the `T` object is manual, but
it does not destroy anything automatically. Instead, you are required to call
the `Catch::Benchmark::destructable_object::destruct` member function, which is what you
can use to measure the destruction time.
### The optimizer
Sometimes the optimizer will optimize away the very code that you want to
measure. There are several ways to use results that will prevent the optimiser
from removing them. You can use the `volatile` keyword, or you can output the
value to standard output or to a file, both of which force the program to
actually generate the value somehow.
Catch adds a third option. The values returned by any function provided as user
code are guaranteed to be evaluated and not optimised out. This means that if
your user code consists of computing a certain value, you don't need to bother
with using `volatile` or forcing output. Just `return` it from the function.
That helps with keeping the code in a natural fashion.
Here's an example:
```c++
// may measure nothing at all by skipping the long calculation since its
// result is not used
BENCHMARK("no return"){ long_calculation(); };
// the result of long_calculation() is guaranteed to be computed somehow
BENCHMARK("with return"){ return long_calculation(); };
```
However, there's no other form of control over the optimizer whatsoever. It is
up to you to write a benchmark that actually measures what you want and doesn't
just measure the time to do a whole bunch of nothing.
To sum up, there are two simple rules: whatever you would do in handwritten code
to control optimization still works in Catch; and Catch makes return values
from user code into observable effects that can't be optimized away.
<i>Adapted from nonius' documentation.</i>

View File

@@ -20,14 +20,17 @@
[Specify a seed for the Random Number Generator](#specify-a-seed-for-the-random-number-generator)<br>
[Identify framework and version according to the libIdentify standard](#identify-framework-and-version-according-to-the-libidentify-standard)<br>
[Wait for key before continuing](#wait-for-key-before-continuing)<br>
[Specify multiples of clock resolution to run benchmarks for](#specify-multiples-of-clock-resolution-to-run-benchmarks-for)<br>
[Specify the number of benchmark samples to collect](#specify-the-number-of-benchmark-samples-to-collect)<br>
[Specify the number of resamples for bootstrapping](#specify-the-number-of-resamples-for-bootstrapping)<br>
[Specify the confidence-interval for bootstrapping](#specify-the-confidence-interval-for-bootstrapping)<br>
[Disable statistical analysis of collected benchmark samples](#disable-statistical-analysis-of-collected-benchmark-samples)<br>
[Usage](#usage)<br>
[Specify the section to run](#specify-the-section-to-run)<br>
[Filenames as tags](#filenames-as-tags)<br>
[Override output colouring](#override-output-colouring)<br>
Catch works quite nicely without any command line options at all - but for those times when you want greater control the following options are available.
Click one of the followings links to take you straight to that option - or scroll on to browse the available options.
Click one of the following links to take you straight to that option - or scroll on to browse the available options.
<a href="#specifying-which-tests-to-run"> ` <test-spec> ...`</a><br />
<a href="#usage"> ` -h, -?, --help`</a><br />
@@ -57,7 +60,10 @@ Click one of the followings links to take you straight to that option - or scrol
<a href="#rng-seed"> ` --rng-seed`</a><br />
<a href="#libidentify"> ` --libidentify`</a><br />
<a href="#wait-for-keypress"> ` --wait-for-keypress`</a><br />
<a href="#benchmark-resolution-multiple"> ` --benchmark-resolution-multiple`</a><br />
<a href="#benchmark-samples"> ` --benchmark-samples`</a><br />
<a href="#benchmark-resamples"> ` --benchmark-resamples`</a><br />
<a href="#benchmark-confidence-interval"> ` --benchmark-confidence-interval`</a><br />
<a href="#benchmark-no-analysis"> ` --benchmark-no-analysis`</a><br />
<a href="#use-colour"> ` --use-colour`</a><br />
</br>
@@ -236,7 +242,7 @@ Test cases are ordered one of three ways:
### decl
Declaration order. The order the tests were originally declared in. Note that ordering between files is not guaranteed and is implementation dependent.
Declaration order (this is the default order if no --order argument is provided). The order the tests were originally declared in. Note that ordering between files is not guaranteed and is implementation dependent.
### lex
Lexicographically sorted. Tests are sorted, alpha-numerically, by name.
@@ -250,7 +256,7 @@ Randomly sorted. Test names are sorted using ```std::random_shuffle()```. By def
Sets a seed for the random number generator using ```std::srand()```.
If a number is provided this is used directly as the seed so the random pattern is repeatable.
Alternatively if the keyword ```time``` is provided then the result of calling ```std::time(0)``` is used and so the pattern becomes unpredictable.
Alternatively if the keyword ```time``` is provided then the result of calling ```std::time(0)``` is used and so the pattern becomes unpredictable. In some cases, you might need to pass the keyword ```time``` in double quotes instead of single quotes.
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)```.
@@ -267,13 +273,48 @@ See [The LibIdentify repo for more information and examples](https://github.com/
Will cause the executable to print a message and wait until the return/ enter key is pressed before continuing -
either before running any tests, after running all tests - or both, depending on the argument.
<a id="benchmark-resolution-multiple"></a>
## Specify multiples of clock resolution to run benchmarks for
<pre>--benchmark-resolution-multiple &lt;multiplier&gt;</pre>
<a id="benchmark-samples"></a>
## Specify the number of benchmark samples to collect
<pre>--benchmark-samples &lt;# of samples&gt;</pre>
When running benchmarks the clock resolution is estimated. Benchmarks are then run for exponentially increasing
numbers of iterations until some multiple of the estimated resolution is exceed. By default that multiple is 100, but
it can be overridden here.
> [Introduced](https://github.com/catchorg/Catch2/issues/1616) in Catch 2.9.0.
When running benchmarks a number of "samples" is collected. This is the base data for later statistical analysis.
Per sample a clock resolution dependent number of iterations of the user code is run, which is independent of the number of samples. Defaults to 100.
<a id="benchmark-resamples"></a>
## Specify the number of resamples for bootstrapping
<pre>--benchmark-resamples &lt;# of resamples&gt;</pre>
> [Introduced](https://github.com/catchorg/Catch2/issues/1616) in Catch 2.9.0.
After the measurements are performed, statistical [bootstrapping] is performed
on the samples. The number of resamples for that bootstrapping is configurable
but defaults to 100000. Due to the bootstrapping it is possible to give
estimates for the mean and standard deviation. The estimates come with a lower
bound and an upper bound, and the confidence interval (which is configurable but
defaults to 95%).
[bootstrapping]: http://en.wikipedia.org/wiki/Bootstrapping_%28statistics%29
<a id="benchmark-confidence-interval"></a>
## Specify the confidence-interval for bootstrapping
<pre>--benchmark-confidence-interval &lt;confidence-interval&gt;</pre>
> [Introduced](https://github.com/catchorg/Catch2/issues/1616) in Catch 2.9.0.
The confidence-interval is used for statistical bootstrapping on the samples to
calculate the upper and lower bounds of mean and standard deviation.
Must be between 0 and 1 and defaults to 0.95.
<a id="benchmark-no-analysis"></a>
## Disable statistical analysis of collected benchmark samples
<pre>--benchmark-no-analysis</pre>
> [Introduced](https://github.com/catchorg/Catch2/issues/1616) in Catch 2.9.0.
When this flag is specified no bootstrapping or any other statistical analysis is performed.
Instead the user code is only measured and the plain mean from the samples is reported.
<a id="usage"></a>
## Usage

View File

@@ -17,3 +17,4 @@ fact then please let us know - either directly, via a PR or
- NASA
- [Inscopix Inc.](https://www.inscopix.com/)
- [Makimo](https://makimo.pl/)
- [UX3D] (https://ux3d.io)

View File

@@ -89,7 +89,7 @@ them yourself, their signatures are:
By default, when Catch's stringification machinery has to stringify
a type that does not specialize `StringMaker`, does not overload `operator<<`,
is not an enumeration and is not a range, it uses `"{?}"`. This can be
overriden by defining `CATCH_CONFIG_FALLBACK_STRINGIFIER` to name of a
overridden by defining `CATCH_CONFIG_FALLBACK_STRINGIFIER` to name of a
function that should perform the stringification instead.
All types that do not provide `StringMaker` specialization or `operator<<`
@@ -127,8 +127,12 @@ Catch's selection, by defining either `CATCH_CONFIG_CPP11_TO_STRING` or
## C++17 toggles
CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS // Use std::uncaught_exceptions instead of std::uncaught_exception
CATCH_CONFIG_CPP17_STRING_VIEW // Provide StringMaker specialization for std::string_view
CATCH_CONFIG_CPP17_VARIANT // Override C++17 detection for CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER
CATCH_CONFIG_CPP17_STRING_VIEW // Override std::string_view support detection(Catch provides a StringMaker specialization by default)
CATCH_CONFIG_CPP17_VARIANT // Override std::variant support detection (checked by CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER)
CATCH_CONFIG_CPP17_OPTIONAL // Override std::optional support detection (checked by CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER)
CATCH_CONFIG_CPP17_BYTE // Override std::byte support detection (Catch provides a StringMaker specialization by default)
> `CATCH_CONFIG_CPP17_STRING_VIEW` was [introduced](https://github.com/catchorg/Catch2/issues/1376) in Catch 2.4.1.
Catch contains basic compiler/standard detection and attempts to use
some C++17 features whenever appropriate. This automatic detection
@@ -149,6 +153,12 @@ by using `_NO_` in the macro, e.g. `CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS`.
CATCH_CONFIG_DISABLE // Disables assertions and test case registration
CATCH_CONFIG_WCHAR // Enables use of wchart_t
CATCH_CONFIG_EXPERIMENTAL_REDIRECT // Enables the new (experimental) way of capturing stdout/stderr
CATCH_CONFIG_ENABLE_BENCHMARKING // Enables the integrated benchmarking features (has a significant effect on compilation speed)
CATCH_CONFIG_USE_ASYNC // Force parallel statistical processing of samples during benchmarking
CATCH_CONFIG_ANDROID_LOGWRITE // Use android's logging system for debug output
CATCH_CONFIG_GLOBAL_NEXTAFTER // Use nextafter{,f,l} instead of std::nextafter
> [`CATCH_CONFIG_ANDROID_LOGWRITE`](https://github.com/catchorg/Catch2/issues/1743) and [`CATCH_CONFIG_GLOBAL_NEXTAFTER`](https://github.com/catchorg/Catch2/pull/1739) were introduced in Catch 2.10.0
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.
@@ -207,9 +217,14 @@ By default, Catch does not stringify some types from the standard library. This
CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER // Provide StringMaker specialization for std::optional (on C++17)
CATCH_CONFIG_ENABLE_ALL_STRINGMAKERS // Defines all of the above
> `CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER` was [introduced](https://github.com/catchorg/Catch2/issues/1380) in Catch 2.4.1.
> `CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER` was [introduced](https://github.com/catchorg/Catch2/issues/1510) in Catch 2.6.0.
## Disabling exceptions
> Introduced in Catch 2.4.0.
By default, Catch2 uses exceptions to signal errors and to abort tests
when an assertion from the `REQUIRE` family of assertions fails. We also
provide an experimental support for disabling exceptions. Catch2 should

View File

@@ -1,6 +1,13 @@
<a id="top"></a>
# Contributing to Catch
**Contents**<br>
[Branches](#branches)<br>
[Directory structure](#directory-structure)<br>
[Testing your changes](#testing-your-changes)<br>
[Documenting your code](#documenting-your-code)<br>
[Code constructs to watch out for](#code-constructs-to-watch-out-for)<br>
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.
@@ -75,8 +82,87 @@ before you do so, you need to check that the introduced changes are indeed
intentional.
## Documenting your code
If you have added new feature to Catch2, it needs documentation, so that
other people can use it as well. This section collects some technical
information that you will need for updating Catch2's documentation, and
possibly some generic advise as well.
First, the technicalities:
* We introduced version tags to the documentation, which show users in
which version a specific feature was introduced. This means that newly
written documentation should be tagged with a placeholder, that will
be replaced with the actual version upon release. There are 2 styles
of placeholders used through the documentation, you should pick one that
fits your text better (if in doubt, take a look at the existing version
tags for other features).
* `> [Introduced](link-to-issue-or-PR) in Catch X.Y.Z` - this
placeholder is usually used after a section heading
* `> X (Y and Z) was [introduced](link-to-issue-or-PR) in Catch X.Y.Z`
- this placeholder is used when you need to tag a subpart of something,
e.g. list
* Crosslinks to different pages should target the `top` anchor, like this
`[link to contributing](contributing.md#top)`.
* If you have introduced a new document, there is a simple template you
should use. It provides you with the top anchor mentioned above, and also
with a backlink to the top of the documentation:
```markdown
<a id="top"></a>
# Cool feature
Text that explains how to use the cool feature.
*this document is still in-progress...*
---
[Home](Readme.md#top)
```
* For pages with more than 4 subheadings, we provide a table of contents
(ToC) at the top of the page. Because GitHub markdown does not support
automatic generation of ToC, it has to be handled semi-manually. Thus,
if you've added a new subheading to some page, you should add it to the
ToC. This can be done either manually, or by running the
`updateDocumentToC.py` script in the `scripts/` folder.
Now, for the generic tips:
* Usage examples are good
* Don't be afraid to introduce new pages
* Try to be reasonably consistent with the surrounding documentation
## Code constructs to watch out for
This section is a (sadly incomplete) listing of various constructs that
are problematic and are not always caught by our CI infrastructure.
### Naked exceptions and exceptions-related function
If you are throwing an exception, it should be done via `CATCH_ERROR`
or `CATCH_RUNTIME_ERROR` in `catch_enforce.h`. These macros will handle
the differences between compilation with or without exceptions for you.
However, some platforms (IAR) also have problems with exceptions-related
functions, such as `std::current_exceptions`. We do not have IAR in our
CI, but luckily there should not be too many reasons to use these.
However, if you do, they should be kept behind a
`CATCH_CONFIG_DISABLE_EXCEPTIONS` macro.
### Unqualified usage of functions from C's stdlib
If you are using a function from C's stdlib, please include the header
as `<cfoo>` and call the function qualified. The common knowledge that
there is no difference is wrong, QNX and VxWorks won't compile if you
include the header as `<cfoo>` and call the function unqualified.
----
_This documentation will always be in-progress as new information comes
up, but we are trying to keep it as up to date as possible._
---

View File

@@ -39,6 +39,11 @@ apart from writing it out for `--list-tests -v high`.
Because it isn't actually used nor documented, and brings complications
to Catch2's internals, description support will be removed.
### SourceLineInfo::empty()
There should be no reason to ever have an empty `SourceLineInfo`, so the
method will be removed.
## Planned changes

View File

@@ -29,13 +29,13 @@ struct MyListener : Catch::TestEventListenerBase {
using TestEventListenerBase::TestEventListenerBase; // inherit constructor
virtual void testCaseStarting( Catch::TestCaseInfo const& testInfo ) override {
void testCaseStarting( Catch::TestCaseInfo const& testInfo ) override {
// Perform some setup before a test case is run
}
virtual void testCaseEnded( Catch::TestCaseStats const& testCaseStats ) override {
void testCaseEnded( Catch::TestCaseStats const& testCaseStats ) override {
// Tear-down after a test case is run
}
}
};
CATCH_REGISTER_LISTENER( MyListener )
```

View File

@@ -1,6 +1,8 @@
<a id="top"></a>
# Data Generators
> Introduced in Catch 2.6.0.
Data generators (also known as _data driven/parametrized test cases_)
let you reuse the same set of assertions across different input values.
In Catch2, this means that they respect the ordering and nesting
@@ -34,8 +36,8 @@ Catch2's provided generator functionality consists of three parts,
* `GENERATE` macro, that serves to integrate generator expression with
a test case,
* 2 fundamental generators
* `ValueGenerator<T>` -- contains only single element
* `ValuesGenerator<T>` -- contains multiple elements
* `SingleValueGenerator<T>` -- contains only single element
* `FixedValuesGenerator<T>` -- contains multiple elements
* 5 generic generators that modify other generators
* `FilterGenerator<T, Predicate>` -- filters out elements from a generator
for which the predicate returns "false"
@@ -44,16 +46,22 @@ a test case,
* `MapGenerator<T, U, Func>` -- returns the result of applying `Func`
on elements from a different generator
* `ChunkGenerator<T>` -- returns chunks (inside `std::vector`) of n elements from a generator
* 3 specific purpose generators
* 4 specific purpose generators
* `RandomIntegerGenerator<Integral>` -- generates random Integrals from range
* `RandomFloatGenerator<Float>` -- generates random Floats from range
* `RangeGenerator<T>` -- generates all values inside a specific range
* `IteratorGenerator<T>` -- copies and returns values from an iterator range
> `ChunkGenerator<T>`, `RandomIntegerGenerator<Integral>`, `RandomFloatGenerator<Float>` and `RangeGenerator<T>` were introduced in Catch 2.7.0.
> `IteratorGenerator<T>` was introduced in Catch 2.10.0.
The generators also have associated helper functions that infer their
type, making their usage much nicer. These are
* `value(T&&)` for `ValueGenerator<T>`
* `values(std::initializer_list<T>)` for `ValuesGenerator<T>`
* `value(T&&)` for `SingleValueGenerator<T>`
* `values(std::initializer_list<T>)` for `FixedValuesGenerator<T>`
* `table<Ts...>(std::initializer_list<std::tuple<Ts...>>)` for `FixedValuesGenerator<std::tuple<Ts...>>`
* `filter(predicate, GeneratorWrapper<T>&&)` for `FilterGenerator<T, Predicate>`
* `take(count, GeneratorWrapper<T>&&)` for `TakeGenerator<T>`
* `repeat(repeats, GeneratorWrapper<T>&&)` for `RepeatGenerator<T>`
@@ -63,7 +71,12 @@ type, making their usage much nicer. These are
* `random(IntegerOrFloat a, IntegerOrFloat b)` for `RandomIntegerGenerator` or `RandomFloatGenerator`
* `range(start, end)` for `RangeGenerator<T>` with a step size of `1`
* `range(start, end, step)` for `RangeGenerator<T>` with a custom step size
* `from_range(InputIterator from, InputIterator to)` for `IteratorGenerator<T>`
* `from_range(Container const&)` for `IteratorGenerator<T>`
> `chunk()`, `random()` and both `range()` functions were introduced in Catch 2.7.0.
> `from_range` has been introduced in Catch 2.10.0
And can be used as shown in the example below to create a generator
that returns 100 odd random number:
@@ -84,7 +97,7 @@ Apart from registering generators with Catch2, the `GENERATE` macro has
one more purpose, and that is to provide simple way of generating trivial
generators, as seen in the first example on this page, where we used it
as `auto i = GENERATE(1, 2, 3);`. This usage converted each of the three
literals into a single `ValueGenerator<int>` and then placed them all in
literals into a single `SingleValueGenerator<int>` and then placed them all in
a special generator that concatenates other generators. It can also be
used with other generators as arguments, such as `auto i = GENERATE(0, 2,
take(100, random(300, 3000)));`. This is useful e.g. if you know that
@@ -96,6 +109,8 @@ scope and thus capturing references is dangerous. If you need to use
variables inside the generator expression, make sure you thought through
the lifetime implications and use `GENERATE_COPY` or `GENERATE_REF`.**
> `GENERATE_COPY` and `GENERATE_REF` were introduced in Catch 2.7.1.
You can also override the inferred type by using `as<type>` as the first
argument to the macro. This can be useful when dealing with string literals,
if you want them to come out as `std::string`:

View File

@@ -30,6 +30,8 @@ When the last `CHECK` fails in the "Bar" test case, then only one message will b
## Logging without local scope
> [Introduced](https://github.com/catchorg/Catch2/issues/1522) in Catch 2.7.0.
`UNSCOPED_INFO` is similar to `INFO` with two key differences:
- Lifetime of an unscoped message is not tied to its own scope.
@@ -85,7 +87,7 @@ Second unscoped info
## Streaming macros
All these macros allow heterogenous sequences of values to be streaming using the insertion operator (```<<```) in the same way that std::ostream, std::cout, etc support it.
All these macros allow heterogeneous sequences of values to be streaming using the insertion operator (```<<```) in the same way that std::ostream, std::cout, etc support it.
E.g.:
```c++
@@ -104,6 +106,8 @@ This semicolon will be removed with next major version. It is highly advised to
**UNSCOPED_INFO(** _message expression_ **)**
> [Introduced](https://github.com/catchorg/Catch2/issues/1522) in Catch 2.7.0.
Similar to `INFO`, but messages are not limited to their own scope: They are removed from the buffer after each assertion, section or test case, whichever comes first.
**WARN(** _message expression_ **)**

View File

@@ -12,11 +12,11 @@ The first argument is the thing (object or value) under test. The second part is
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" ) );
REQUIRE_THAT( str, EndsWith( "as a service" ) );
```
The matcher objects can take multiple arguments, allowing more fine tuning.
@@ -24,19 +24,29 @@ The built-in string matchers, for example, take a second argument specifying whe
case sensitive or not:
```c++
REQUIRE_THAT( str, EndsWith( "as a service", Catch::CaseSensitive::No ) );
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" ) ) );
REQUIRE_THAT( str,
EndsWith( "as a service" ) ||
(StartsWith( "Big data" ) && !Contains( "web scale" ) ) );
```
## Built in matchers
Catch currently provides some matchers, they are in the `Catch::Matchers` and `Catch` namespaces.
Catch2 provides some matchers by default. They can be found in the
`Catch::Matchers::foo` namespace and are imported into the `Catch`
namespace as well.
There are two parts to each of the built-in matchers, the matcher
type itself and a helper function that provides template argument
deduction when creating templated matchers. As an example, the matcher
for checking that two instances of `std::vector` are identical is
`EqualsMatcher<T>`, but the user is expected to use the `Equals`
helper function instead.
### String matchers
The string matchers are `StartsWith`, `EndsWith`, `Contains`, `Equals` and `Matches`. The first four match a literal (sub)string against a result, while `Matches` takes and matches an ECMAScript regex. Do note that `Matches` matches the string as a whole, meaning that "abc" will not match against "abcd", but "abc.*" will.
@@ -45,13 +55,42 @@ Each of the provided `std::string` matchers also takes an optional second argume
### Vector matchers
The vector matchers are `Contains`, `VectorContains` and `Equals`. `VectorContains` looks for a single element in the matched vector, `Contains` looks for a set (vector) of elements inside the matched vector.
Catch2 currently provides 5 built-in matchers that work on `std::vector`.
These are
* `Contains` which checks whether a specified vector is present in the result
* `VectorContains` which checks whether a specified element is present in the result
* `Equals` which checks whether the result is exactly equal (order matters) to a specific vector
* `UnorderedEquals` which checks whether the result is equal to a specific vector under a permutation
* `Approx` which checks whether the result is "approx-equal" (order matters, but comparison is done via `Approx`) to a specific vector
> Approx matcher was [introduced](https://github.com/catchorg/Catch2/issues/1499) in Catch 2.7.2.
### Floating point matchers
The floating point matchers are `WithinULP` and `WithinAbs`. `WithinAbs` accepts floating point numbers that are within a certain margin of target. `WithinULP` performs an [ULP](https://en.wikipedia.org/wiki/Unit_in_the_last_place)-based comparison of two floating point numbers and accepts them if they are less than certain number of ULPs apart.
Catch2 provides 3 matchers for working with floating point numbers. These
are `WithinAbsMatcher`, `WithinUlpsMatcher` and `WithinRelMatcher`.
Do note that ULP-based checks only make sense when both compared numbers are of the same type and `WithinULP` will use type of its argument as the target type. This means that `WithinULP(1.f, 1)` will expect to compare `float`s, but `WithinULP(1., 1)` will expect to compare `double`s.
The `WithinAbsMatcher` matcher accepts floating point numbers that are
within a certain distance of target. It should be constructed with the
`WithinAbs(double target, double margin)` helper.
The `WithinUlpsMatcher` matcher accepts floating point numbers that are
within a certain number of [ULPs](https://en.wikipedia.org/wiki/Unit_in_the_last_place)
of the target. Because ULP comparisons need to be done differently for
`float`s and for `double`s, there are two overloads of the helpers for
this matcher, `WithinULP(float target, int64_t ULPs)`, and
`WithinULP(double target, int64_t ULPs)`.
The `WithinRelMatcher` matcher accepts floating point numbers that are
_approximately equal_ with the target number with some specific tolerance.
In other words, it checks that `|lhs - rhs| <= epsilon * max(|lhs|, |rhs|)`,
with special casing for `INFINITY` and `NaN`. There are _4_ overloads of
the helpers for this matcher, `WithinRel(double target, double margin)`,
`WithinRel(float target, float margin)`, `WithinRel(double target)`, and
`WithinRel(float target)`. The latter two provide a default epsilon of
machine epsilon * 100.
> `WithinRel` matcher was introduced in Catch 2.10.0
### Generic matchers
Catch also aims to provide a set of generic matchers. Currently this set
@@ -72,13 +111,29 @@ The second argument is an optional description of the predicate, and is
used only during reporting of the result.
### Exception matchers
Catch2 also provides an exception matcher that can be used to verify
that an exception's message exactly matches desired string. The matcher
is `ExceptionMessageMatcher`, and we also provide a helper function
`Message`.
The matched exception must publicly derive from `std::exception` and
the message matching is done _exactly_, including case.
> `ExceptionMessageMatcher` was introduced in Catch 2.10.0
Example use:
```cpp
REQUIRE_THROWS_MATCHES(throwsDerivedException(), DerivedException, Message("DerivedException::what"));
```
## 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:
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()`.
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
@@ -92,7 +147,7 @@ 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 {
bool match( int const& i ) const override {
return i >= m_begin && i <= m_end;
}
@@ -123,7 +178,7 @@ TEST_CASE("Integers are within a range")
```
Running this test gives the following in the console:
```
/**/TestFile.cpp:123: FAILED:
CHECK_THAT( 100, IsBetween( 1, 10 ) )

View File

@@ -23,6 +23,9 @@ C++11 implementation of Approval Tests, for quick, convenient testing of legacy
### [Azmq](https://github.com/zeromq/azmq)
Boost Asio style bindings for ZeroMQ.
### [Cataclysm: Dark Days Ahead](https://github.com/CleverRaven/Cataclysm-DDA)
Post-apocalyptic survival RPG.
### [ChakraCore](https://github.com/Microsoft/ChakraCore)
The core part of the Chakra JavaScript engine that powers Microsoft Edge.
@@ -112,6 +115,9 @@ SpECTRE is a code for multi-scale, multi-physics problems in astrophysics and gr
### [Standardese](https://github.com/foonathan/standardese)
Standardese aims to be a nextgen Doxygen.
### [PopHead](https://github.com/SPC-Some-Polish-Coders/PopHead)
A 2D, Zombie, RPG game which is being made on our own engine.
---
[Home](Readme.md#top)

View File

@@ -30,7 +30,7 @@ CHECKED_IF( a == b ) {
`CHECK_NOFAIL( expr )` is a variant of `CHECK` that does not fail the test
case if _expr_ evaluates to `false`. This can be useful for checking some
assumption, that might be violated without the test neccessarily failing.
assumption, that might be violated without the test necessarily failing.
Example output:
```
@@ -59,6 +59,8 @@ TEST_CASE( "SUCCEED showcase" ) {
* `STATIC_REQUIRE`
> [Introduced](https://github.com/catchorg/Catch2/issues/1362) in Catch 2.4.2.
`STATIC_REQUIRE( expr )` is a macro that can be used the same way as a
`static_assert`, but also registers the success with Catch2, so it is
reported as a success at runtime. The whole check can also be deferred
@@ -120,7 +122,7 @@ constructor, or before Catch2's session is created in user's own main._
`ANON_TEST_CASE` is a `TEST_CASE` replacement that will autogenerate
unique name. The advantage of this is that you do not have to think
of a name for the test case,`the disadvantage is that the name doesn't
neccessarily remain stable across different links, and thus it might be
necessarily remain stable across different links, and thus it might be
hard to run directly.
Example:
@@ -132,6 +134,8 @@ ANON_TEST_CASE() {
* `DYNAMIC_SECTION`
> Introduced in Catch 2.3.0.
`DYNAMIC_SECTION` is a `SECTION` where the user can use `operator<<` to
create the final name for that section. This can be useful with e.g.
generators, or when creating a `SECTION` dynamically, within a loop.

View File

@@ -2,6 +2,12 @@
# Release notes
**Contents**<br>
[2.10.0](#2100)<br>
[2.9.2](#292)<br>
[2.9.1](#291)<br>
[2.9.0](#290)<br>
[2.8.0](#280)<br>
[2.7.2](#272)<br>
[2.7.1](#271)<br>
[2.7.0](#270)<br>
[2.6.1](#261)<br>
@@ -22,11 +28,153 @@
[Older versions](#older-versions)<br>
[Even Older versions](#even-older-versions)<br>
## 2.10.0
### Fixes
* `TEMPLATE_LIST_TEST_CASE` now properly handles non-copyable and non-movable types (#1729)
* Fixed compilation error on Solaris caused by a system header defining macro `TT` (#1722, #1723)
* `REGISTER_ENUM` will now fail at compilation time if the registered enum is too large
* Removed use of `std::is_same_v` in C++17 mode (#1757)
* Fixed parsing of escaped special characters when reading test specs from a file (#1767, #1769)
### Improvements
* Trailing and leading whitespace in test/section specs are now ignored.
* Writing to Android debug log now uses `__android_log_write` instead of `__android_log_print`
* Android logging support can now be turned on/off at compile time (#1743)
* The toggle is `CATCH_CONFIG_ANDROID_LOGWRITE`
* Added a generator that returns elements of a range
* Use via `from_range(from, to)` or `from_range(container)`
* Added support for CRTs that do not provide `std::nextafter` (#1739)
* They must still provide global `nextafter{f,l,}`
* Enabled via `CATCH_CONFIG_GLOBAL_NEXTAFTER`
* Special cased `Approx(inf)` not to match non-infinite values
* Very strictly speaking this might be a breaking change, but it should match user expectations better
* The output of benchmarking through the Console reporter when `--benchmark-no-analysis` is set is now much simpler (#1768)
* Added a matcher that can be used for checking an exceptions message (#1649, #1728)
* The matcher helper function is called `Message`
* The exception must publicly derive from `std::exception`
* The matching is done exactly, including case and whitespace
* Added a matcher that can be used for checking relative equality of floating point numbers (#1746)
* Unlike `Approx`, it considers both sides when determining the allowed margin
* Special cases `NaN` and `INFINITY` to match user expectations
* The matcher helper function is called `WithinRel`
* The ULP matcher now allows for any possible distance between the two numbers
* The random number generators now use Catch-global instance of RNG (#1734, #1736)
* This means that nested random number generators actually generate different numbers
### Miscellaneous
* In-repo PNGs have been optimized to lower overhead of using Catch2 via git clone
* Catch2 now uses its own implementation of the URBG concept
* In the future we also plan to use our own implementation of the distributions from `<random>` to provide cross-platform repeatability of random results
## 2.9.2
### Fixes
* `ChunkGenerator` can now be used with chunks of size 0 (#1671)
* Nested subsections are now run properly when specific section is run via the `-c` argument (#1670, #1673)
* Catch2 now consistently uses `_WIN32` to detect Windows platform (#1676)
* `TEMPLATE_LIST_TEST_CASE` now support non-default constructible type lists (#1697)
* Fixed a crash in the XMLReporter when a benchmark throws exception during warmup (#1706)
* Fixed a possible infinite loop in CompactReporter (#1715)
* Fixed `-w NoTests` returning 0 even when no tests were matched (#1449, #1683, #1684)
* Fixed matcher compilation under Obj-C++ (#1661)
### Improvements
* `RepeatGenerator` and `FixedValuesGenerator` now fail to compile when used with `bool` (#1692)
* Previously they would fail at runtime.
* Catch2 now supports Android's debug logging for its debug output (#1710)
* Catch2 now detects and configures itself for the RTX platform (#1693)
* You still need to pass `--benchmark-no-analysis` if you are using benchmarking under RTX
* Removed a "storage class is not first" warning when compiling Catch2 with PGI compiler (#1717)
### Miscellaneous
* Documentation now contains indication when a specific feature was introduced (#1695)
* These start with Catch2 v2.3.0, (a bit over a year ago).
* `docs/contributing.md` has been updated to provide contributors guidance on how to add these to newly written documentation
* Various other documentation improvements
* ToC fixes
* Documented `--order` and `--rng-seed` command line options
* Benchmarking documentation now clearly states that it requires opt-in
* Documented `CATCH_CONFIG_CPP17_OPTIONAL` and `CATCH_CONFIG_CPP17_BYTE` macros
* Properly documented built-in vector matchers
* Improved `*_THROWS_MATCHES` documentation a bit
* CMake config file is now arch-independent even if `CMAKE_SIZEOF_VOID_P` is in CMake cache (#1660)
* `CatchAddTests` now properly escapes `[` and `]` in test names (#1634, #1698)
* Reverted `CatchAddTests` adding tags as CTest labels (#1658)
* The script broke when test names were too long
* Overwriting `LABELS` caused trouble for users who set them manually
* CMake does not let users append to `LABELS` if the test name has spaces
## 2.9.1
### Fixes
* Fix benchmarking compilation failure in files without `CATCH_CONFIG_EXTERNAL_INTERFACES` (or implementation)
## 2.9.0
### Improvements
* The experimental benchmarking support has been replaced by integrating Nonius code (#1616)
* This provides a much more featurefull micro-benchmarking support.
* Due to the compilation cost, it is disabled by default. See the documentation for details.
* As far as backwards compatibility is concerned, this feature is still considered experimental in that we might change the interface based on user feedback.
* `WithinULP` matcher now shows the acceptable range (#1581)
* Template test cases now support type lists (#1627)
## 2.8.0
### Improvements
* Templated test cases no longer check whether the provided types are unique (#1628)
* This allows you to e.g. test over `uint32_t`, `uint64_t`, and `size_t` without compilation failing
* The precision of floating point stringification can be modified by user (#1612, #1614)
* We now provide `REGISTER_ENUM` convenience macro for generating `StringMaker` specializations for enums
* See the "String conversion" documentation for details
* Added new set of macros for template test cases that enables the use of NTTPs (#1531, #1609)
* See "Test cases and sections" documentation for details
### Fixes
* `UNSCOPED_INFO` macro now has a prefixed/disabled/prefixed+disabled versions (#1611)
* Reporting errors at startup should no longer cause a segfault under certain circumstances (#1626)
### Miscellaneous
* CMake will now prevent you from attempting in-tree build (#1636, #1638)
* Previously it would break with an obscure error message during the build step
## 2.7.2
### Improvements
* Added an approximate vector matcher (#1499)
### Fixes
* Filters will no longer be shown if there were none
* Fixed compilation error when using Homebrew GCC on OS X (#1588, #1589)
* Fixed the console reporter not showing messages that start with a newline (#1455, #1470)
* Modified JUnit reporter's output so that rng seed and filters are reported according to the JUnit schema (#1598)
* Fixed some obscure warnings and static analysis passes
### Miscellaneous
* Various improvements to `ParseAndAddCatchTests` (#1559, #1601)
* When a target is parsed, it receives `ParseAndAddCatchTests_TESTS` property which summarizes found tests
* Fixed problem with tests not being found if the `OptionalCatchTestLauncher` variables is used
* Including the script will no longer forcefully modify `CMAKE_MINIMUM_REQUIRED_VERSION`
* CMake object libraries are ignored when parsing to avoid needless warnings
* `CatchAddTests` now adds test's tags to their CTest labels (#1600)
* Added basic CPack support to our build
## 2.7.1
### Improvements
* Reporters now print out the filters applied to test cases (#1550, #1585)
* Added `GENERATE_COPY` and `GENERATE_VAR` macros that can use variables inside the generator expression
* Added `GENERATE_COPY` and `GENERATE_REF` macros that can use variables inside the generator expression
* Because of the significant danger of lifetime issues, the default `GENERATE` macro still does not allow variables
* The `map` generator helper now deduces the mapped return type (#1576)
@@ -56,7 +204,7 @@
* Running tests will no longer open the specified output file twice (#1545)
* This would cause trouble when the file was not a file, but rather a named pipe
* Fixes the CLion/Resharper integration with Catch
* Fixed `-Wunreachable-code` occuring with (old) ccache+cmake+clang combination (#1540)
* Fixed `-Wunreachable-code` occurring with (old) ccache+cmake+clang combination (#1540)
* Fixed `-Wdefaulted-function-deleted` warning with Clang 8 (#1537)
* Catch2's type traits and helpers are now properly namespaced inside `Catch::` (#1548)
* Fixed std{out,err} redirection for failing test (#1514, #1525)
@@ -738,7 +886,7 @@ Cygwin issue with `gettimeofday` - `#define` was not early enough
* Usage of `gettimeofday` inside Catch should no longer cause compilation errors.
* Improved `-Wparentheses` suppression for gcc (#674)
* When compiled with gcc 4.8 or newer, the suppression is localized to assertions only
* Otherwise it is supressed for the whole TU
* Otherwise it is suppressed for the whole TU
* Fixed test spec parser issue (with escapes in multiple names)
##### Other
@@ -821,7 +969,7 @@ Other:
##### 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
* The use of `__COUNTER__` is suppressed 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

View File

@@ -32,7 +32,7 @@ Once a release is ready, release notes need to be written. They should summarize
### 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.
After version number is incremented, single-include header is regenerated and release notes are updated, changes should be committed and pushed to GitHub.
### Release on GitHub

View File

@@ -51,14 +51,15 @@ After compiling `tests-main.cpp` once, it is enough to link it with separately c
```
$ g++ tests-main.cpp -c
$ g++ tests-main.o tests-factorial.cpp -o tests && ./tests -r compact
$ g++ factorial.cpp -c
$ g++ tests-main.o factorial.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
$ g++ tests-main.o factorial.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.
```

View File

@@ -6,6 +6,7 @@
[Tag aliases](#tag-aliases)<br>
[BDD-style test cases](#bdd-style-test-cases)<br>
[Type parametrised test cases](#type-parametrised-test-cases)<br>
[Signature based parametrised test cases](#signature-based-parametrised-test-cases)<br>
While Catch fully supports the traditional, xUnit, style of class-based fixtures containing test case methods this is not the preferred style.
@@ -83,10 +84,13 @@ This macro maps onto ```TEST_CASE``` and works in the same way, except that the
These macros map onto ```SECTION```s except that the section names are the _something_s prefixed by "given: ", "when: " or "then: " respectively.
* **AND_GIVEN(** _something_ **)**
* **AND_WHEN(** _something_ **)**
* **AND_THEN(** _something_ **)**
Similar to ```WHEN``` and ```THEN``` except that the prefixes start with "and ". These are used to chain ```WHEN```s and ```THEN```s together.
Similar to ```GIVEN```, ```WHEN``` and ```THEN``` except that the prefixes start with "and ". These are used to chain ```GIVEN```s, ```WHEN```s and ```THEN```s together.
> `AND_GIVEN` was [introduced](https://github.com/catchorg/Catch2/issues/1360) in Catch 2.4.0.
When any of these macros are used the console reporter recognises them and formats the test case header such that the Givens, Whens and Thens are aligned to aid readability.
@@ -95,11 +99,13 @@ Other than the additional prefixes and the formatting in the console reporter th
## Type parametrised test cases
In addition to `TEST_CASE`s, Catch2 also supports test cases parametrised
by types, in the form of `TEMPLATE_TEST_CASE` and
`TEMPLATE_PRODUCT_TEST_CASE`.
by types, in the form of `TEMPLATE_TEST_CASE`,
`TEMPLATE_PRODUCT_TEST_CASE` and `TEMPLATE_LIST_TEST_CASE`.
* **TEMPLATE_TEST_CASE(** _test name_ , _tags_, _type1_, _type2_, ..., _typen_ **)**
> [Introduced](https://github.com/catchorg/Catch2/issues/1437) in Catch 2.5.0.
_test name_ and _tag_ are exactly the same as they are in `TEST_CASE`,
with the difference that the tag string must be provided (however, it
can be empty). _type1_ through _typen_ is the list of types for which
@@ -150,6 +156,8 @@ TEMPLATE_TEST_CASE( "vectors can be sized and resized", "[vector][template]", in
* **TEMPLATE_PRODUCT_TEST_CASE(** _test name_ , _tags_, (_template-type1_, _template-type2_, ..., _template-typen_), (_template-arg1_, _template-arg2_, ..., _template-argm_) **)**
> [Introduced](https://github.com/catchorg/Catch2/issues/1468) in Catch 2.6.0.
_template-type1_ through _template-typen_ is list of template template
types which should be combined with each of _template-arg1_ through
_template-argm_, resulting in _n * m_ test cases. Inside the test case,
@@ -191,6 +199,77 @@ _While there is an upper limit on the number of types you can specify
in single `TEMPLATE_TEST_CASE` or `TEMPLATE_PRODUCT_TEST_CASE`, the limit
is very high and should not be encountered in practice._
* **TEMPLATE_LIST_TEST_CASE(** _test name_, _tags_, _type list_ **)**
> [Introduced](https://github.com/catchorg/Catch2/issues/1627) in Catch 2.9.0.
_type list_ is a generic list of types on which test case should be instantiated.
List can be `std::tuple`, `boost::mpl::list`, `boost::mp11::mp_list` or anything with
`template <typename...>` signature.
This allows you to reuse the _type list_ in multiple test cases.
Example:
```cpp
using MyTypes = std::tuple<int, char, float>;
TEMPLATE_LIST_TEST_CASE("Template test case with test types specified inside std::tuple", "[template][list]", MyTypes)
{
REQUIRE(sizeof(TestType) > 0);
}
```
## Signature based parametrised test cases
> [Introduced](https://github.com/catchorg/Catch2/issues/1609) in Catch 2.8.0.
In addition to [type parametrised test cases](#type-parametrised-test-cases) Catch2 also supports
signature base parametrised test cases, in form of `TEMPLATE_TEST_CASE_SIG` and `TEMPLATE_PRODUCT_TEST_CASE_SIG`.
These test cases have similar syntax like [type parametrised test cases](#type-parametrised-test-cases), with one
additional positional argument which specifies the signature.
### Signature
Signature has some strict rules for these tests cases to work properly:
* signature with multiple template parameters e.g. `typename T, size_t S` must have this format in test case declaration
`((typename T, size_t S), T, S)`
* signature with variadic template arguments e.g. `typename T, size_t S, typename...Ts` must have this format in test case declaration
`((typename T, size_t S, typename...Ts), T, S, Ts...)`
* signature with single non type template parameter e.g. `int V` must have this format in test case declaration `((int V), V)`
* signature with single type template parameter e.g. `typename T` should not be used as it is in fact `TEMPLATE_TEST_CASE`
Currently Catch2 support up to 11 template parameters in signature
### Examples
* **TEMPLATE_TEST_CASE_SIG(** _test name_ , _tags_, _signature_, _type1_, _type2_, ..., _typen_ **)**
Inside `TEMPLATE_TEST_CASE_SIG` test case you can use the names of template parameters as defined in _signature_.
```cpp
TEMPLATE_TEST_CASE_SIG("TemplateTestSig: arrays can be created from NTTP arguments", "[vector][template][nttp]",
((typename T, int V), T, V), (int,5), (float,4), (std::string,15), ((std::tuple<int, float>), 6)) {
std::array<T, V> v;
REQUIRE(v.size() > 1);
}
```
* **TEMPLATE_PRODUCT_TEST_CASE_SIG(** _test name_ , _tags_, _signature_, (_template-type1_, _template-type2_, ..., _template-typen_), (_template-arg1_, _template-arg2_, ..., _template-argm_) **)**
```cpp
template<typename T, size_t S>
struct Bar {
size_t size() { return S; }
};
TEMPLATE_PRODUCT_TEST_CASE_SIG("A Template product test case with array signature", "[template][product][nttp]", ((typename T, size_t S), T, S), (std::array, Bar), ((int, 9), (float, 42))) {
TestType x;
REQUIRE(x.size() > 0);
}
```
---
[Home](Readme.md#top)

View File

@@ -1,6 +1,8 @@
<a id="top"></a>
# Test fixtures
## Defining test fixtures
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++
@@ -84,6 +86,58 @@ _While there is an upper limit on the number of types you can specify
in single `TEMPLATE_TEST_CASE_METHOD` or `TEMPLATE_PRODUCT_TEST_CASE_METHOD`,
the limit is very high and should not be encountered in practice._
## Signature-based parametrised test fixtures
> [Introduced](https://github.com/catchorg/Catch2/issues/1609) in Catch 2.8.0.
Catch2 also provides `TEMPLATE_TEST_CASE_METHOD_SIG` and `TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG` to support
fixtures using non-type template parameters. These test cases work similar to `TEMPLATE_TEST_CASE_METHOD` and `TEMPLATE_PRODUCT_TEST_CASE_METHOD`,
with additional positional argument for [signature](test-cases-and-sections.md#signature-based-parametrised-test-cases).
Example:
```cpp
template <int V>
struct Nttp_Fixture{
int value = V;
};
TEMPLATE_TEST_CASE_METHOD_SIG(Nttp_Fixture, "A TEMPLATE_TEST_CASE_METHOD_SIG based test run that succeeds", "[class][template][nttp]",((int V), V), 1, 3, 6) {
REQUIRE(Nttp_Fixture<V>::value > 0);
}
template<typename T>
struct Template_Fixture_2 {
Template_Fixture_2() {}
T m_a;
};
template< typename T, size_t V>
struct Template_Foo_2 {
size_t size() { return V; }
};
TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG(Template_Fixture_2, "A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds", "[class][template][product][nttp]", ((typename T, size_t S), T, S),(std::array, Template_Foo_2), ((int,2), (float,6)))
{
REQUIRE(Template_Fixture_2<TestType>{}.m_a.size() >= 2);
}
```
## Template fixtures with types specified in template type lists
Catch2 also provides `TEMPLATE_LIST_TEST_CASE_METHOD` to support template fixtures with types specified in
template type lists like `std::tuple`, `boost::mpl::list` or `boost::mp11::mp_list`. This test case works the same as `TEMPLATE_TEST_CASE_METHOD`,
only difference is the source of types. This allows you to reuse the template type list in multiple test cases.
Example:
```cpp
using MyTypes = std::tuple<int, char, double>;
TEMPLATE_LIST_TEST_CASE_METHOD(Template_Fixture, "Template test case method with test types specified inside std::tuple", "[class][template][list]", MyTypes)
{
REQUIRE( Template_Fixture<TestType>::m_a == 1 );
}
```
---
[Home](Readme.md#top)

View File

@@ -6,6 +6,9 @@
[Catch::StringMaker specialisation](#catchstringmaker-specialisation)<br>
[Catch::is_range specialisation](#catchis_range-specialisation)<br>
[Exceptions](#exceptions)<br>
[Enums](#enums)<br>
[Floating point precision](#floating-point-precision)<br>
Catch needs to be able to convert types you use in assertions and logging expressions into strings (for logging and reporting purposes).
Most built-in or std types are supported out of the box but there are two ways that you can tell Catch how to convert your own types (or other, third-party types) into strings.
@@ -14,7 +17,7 @@ Most built-in or std types are supported out of the box but there are two ways t
This is the standard way of providing string conversions in C++ - and the chances are you may already provide this for your own purposes. If you're not familiar with this idiom it involves writing a free function of the form:
```
```cpp
std::ostream& operator << ( std::ostream& os, T const& value ) {
os << convertMyTypeToString( value );
return os;
@@ -28,7 +31,7 @@ You should put this function in the same namespace as your type, or the global n
## Catch::StringMaker specialisation
If you don't want to provide an ```operator <<``` overload, or you want to convert your type differently for testing purposes, you can provide a specialization for `Catch::StringMaker<T>`:
```
```cpp
namespace Catch {
template<>
struct StringMaker<T> {
@@ -60,12 +63,70 @@ namespace Catch {
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:
```
```cpp
CATCH_TRANSLATE_EXCEPTION( MyType& ex ) {
return ex.message();
}
```
## Enums
> Introduced in Catch 2.8.0.
Enums that already have a `<<` overload for `std::ostream` will convert to strings as expected.
If you only need to convert enums to strings for test reporting purposes you can provide a `StringMaker` specialisations as any other type.
However, as a convenience, Catch provides the `REGISTER_ENUM` helper macro that will generate the `StringMaker` specialiation for you with minimal code.
Simply provide it the (qualified) enum name, followed by all the enum values, and you're done!
E.g.
```cpp
enum class Fruits { Banana, Apple, Mango };
CATCH_REGISTER_ENUM( Fruits, Fruits::Banana, Fruits::Apple, Fruits::Mango )
TEST_CASE() {
REQUIRE( Fruits::Mango == Fruits::Apple );
}
```
... or if the enum is in a namespace:
```cpp
namespace Bikeshed {
enum class Colours { Red, Green, Blue };
}
// Important!: This macro must appear at top level scope - not inside a namespace
// You can fully qualify the names, or use a using if you prefer
CATCH_REGISTER_ENUM( Bikeshed::Colours,
Bikeshed::Colours::Red,
Bikeshed::Colours::Green,
Bikeshed::Colours::Blue )
TEST_CASE() {
REQUIRE( Bikeshed::Colours::Red == Bikeshed::Colours::Blue );
}
```
## Floating point precision
> [Introduced](https://github.com/catchorg/Catch2/issues/1614) in Catch 2.8.0.
Catch provides a built-in `StringMaker` specialization for both `float`
and `double`. By default, it uses what we think is a reasonable precision,
but you can customize it by modifying the `precision` static variable
inside the `StringMaker` specialization, like so:
```cpp
Catch::StringMaker<float>::precision = 15;
const float testFloat1 = 1.12345678901234567899f;
const float testFloat2 = 1.12345678991234567899f;
REQUIRE(testFloat1 == testFloat2);
```
This assertion will fail and print out the `testFloat1` and `testFloat2`
to 15 decimal places.
---
[Home](Readme.md#top)

View File

@@ -305,7 +305,7 @@ struct MyListener : Catch::TestEventListenerBase {
~MyListener();
// The whole test run starting
virtual void testRunStarting( Catch::TestRunInfo const& testRunInfo ) override {
void testRunStarting( Catch::TestRunInfo const& testRunInfo ) override {
std::cout
<< std::boolalpha
<< "\nEvent: testRunStarting:\n";
@@ -313,7 +313,7 @@ struct MyListener : Catch::TestEventListenerBase {
}
// The whole test run ending
virtual void testRunEnded( Catch::TestRunStats const& testRunStats ) override {
void testRunEnded( Catch::TestRunStats const& testRunStats ) override {
std::cout
<< dashed_line
<< "\nEvent: testRunEnded:\n";
@@ -321,7 +321,7 @@ struct MyListener : Catch::TestEventListenerBase {
}
// A test is being skipped (because it is "hidden")
virtual void skipTest( Catch::TestCaseInfo const& testInfo ) override {
void skipTest( Catch::TestCaseInfo const& testInfo ) override {
std::cout
<< dashed_line
<< "\nEvent: skipTest:\n";
@@ -329,7 +329,7 @@ struct MyListener : Catch::TestEventListenerBase {
}
// Test cases starting
virtual void testCaseStarting( Catch::TestCaseInfo const& testInfo ) override {
void testCaseStarting( Catch::TestCaseInfo const& testInfo ) override {
std::cout
<< dashed_line
<< "\nEvent: testCaseStarting:\n";
@@ -337,30 +337,30 @@ struct MyListener : Catch::TestEventListenerBase {
}
// Test cases ending
virtual void testCaseEnded( Catch::TestCaseStats const& testCaseStats ) override {
void testCaseEnded( Catch::TestCaseStats const& testCaseStats ) override {
std::cout << "\nEvent: testCaseEnded:\n";
print( std::cout, 1, "testCaseStats", testCaseStats );
}
// Sections starting
virtual void sectionStarting( Catch::SectionInfo const& sectionInfo ) override {
void sectionStarting( Catch::SectionInfo const& sectionInfo ) override {
std::cout << "\nEvent: sectionStarting:\n";
print( std::cout, 1, "- sectionInfo", sectionInfo );
}
// Sections ending
virtual void sectionEnded( Catch::SectionStats const& sectionStats ) override {
void sectionEnded( Catch::SectionStats const& sectionStats ) override {
std::cout << "\nEvent: sectionEnded:\n";
print( std::cout, 1, "- sectionStats", sectionStats );
}
// Assertions before/ after
virtual void assertionStarting( Catch::AssertionInfo const& assertionInfo ) override {
void assertionStarting( Catch::AssertionInfo const& assertionInfo ) override {
std::cout << "\nEvent: assertionStarting:\n";
print( std::cout, 1, "- assertionInfo", assertionInfo );
}
virtual bool assertionEnded( Catch::AssertionStats const& assertionStats ) override {
bool assertionEnded( Catch::AssertionStats const& assertionStats ) override {
std::cout << "\nEvent: assertionEnded:\n";
print( std::cout, 1, "- assertionStats", assertionStats );
return true;

View File

@@ -10,8 +10,8 @@
#define TWOBLUECUBES_CATCH_HPP_INCLUDED
#define CATCH_VERSION_MAJOR 2
#define CATCH_VERSION_MINOR 7
#define CATCH_VERSION_PATCH 1
#define CATCH_VERSION_MINOR 10
#define CATCH_VERSION_PATCH 0
#ifdef __clang__
# pragma clang system_header
@@ -53,7 +53,6 @@
#include "internal/catch_test_registry.h"
#include "internal/catch_capture.hpp"
#include "internal/catch_section.h"
#include "internal/catch_benchmark.h"
#include "internal/catch_interfaces_exception.h"
#include "internal/catch_approx.h"
#include "internal/catch_compiler_capabilities.h"
@@ -75,10 +74,15 @@
#include "internal/catch_objc.hpp"
#endif
#ifdef CATCH_CONFIG_EXTERNAL_INTERFACES
// Benchmarking needs the externally-facing parts of reporters to work
#if defined(CATCH_CONFIG_EXTERNAL_INTERFACES) || defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
#include "internal/catch_external_interfaces.h"
#endif
#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
#include "internal/benchmark/catch_benchmark.hpp"
#endif
#endif // ! CATCH_CONFIG_IMPL_ONLY
#ifdef CATCH_IMPL
@@ -89,6 +93,7 @@
#include "internal/catch_default_main.hpp"
#endif
#if !defined(CATCH_CONFIG_IMPL_ONLY)
#ifdef CLARA_CONFIG_MAIN_NOT_DEFINED
@@ -132,6 +137,7 @@
#endif // CATCH_CONFIG_DISABLE_MATCHERS
#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg )
#define CATCH_UNSCOPED_INFO( msg ) INTERNAL_CATCH_UNSCOPED_INFO( "CATCH_UNSCOPED_INFO", msg )
#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( "CATCH_WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
#define CATCH_CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CATCH_CAPTURE",__VA_ARGS__ )
@@ -149,14 +155,22 @@
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
#define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ )
#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
#define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ )
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ )
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ )
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ )
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ )
#else
#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) )
#define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ ) )
#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
#define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) )
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) )
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ ) )
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) )
#endif
@@ -179,6 +193,13 @@
#define CATCH_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc )
#define CATCH_AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc )
#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
#define CATCH_BENCHMARK(...) \
INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____B_E_N_C_H____), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,))
#define CATCH_BENCHMARK_ADVANCED(name) \
INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____B_E_N_C_H____), name)
#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required
#else
@@ -232,14 +253,26 @@
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
#define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ )
#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
#define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ )
#define TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ )
#define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ )
#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ )
#define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ )
#define TEMPLATE_LIST_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE(__VA_ARGS__)
#define TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, __VA_ARGS__ )
#else
#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) )
#define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ ) )
#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
#define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) )
#define TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) )
#define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ ) )
#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
#define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) )
#define TEMPLATE_LIST_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE( __VA_ARGS__ ) )
#define TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
#endif
@@ -266,6 +299,13 @@
#define THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc )
#define AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc )
#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
#define BENCHMARK(...) \
INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____B_E_N_C_H____), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,))
#define BENCHMARK_ADVANCED(name) \
INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____B_E_N_C_H____), name)
#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
using Catch::Detail::Approx;
#else // CATCH_CONFIG_DISABLE
@@ -305,9 +345,10 @@ using Catch::Detail::Approx;
#define CATCH_REQUIRE_THAT( arg, matcher ) (void)(0)
#endif // CATCH_CONFIG_DISABLE_MATCHERS
#define CATCH_INFO( msg ) (void)(0)
#define CATCH_WARN( msg ) (void)(0)
#define CATCH_CAPTURE( msg ) (void)(0)
#define CATCH_INFO( msg ) (void)(0)
#define CATCH_UNSCOPED_INFO( msg ) (void)(0)
#define CATCH_WARN( msg ) (void)(0)
#define CATCH_CAPTURE( msg ) (void)(0)
#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
@@ -322,15 +363,23 @@ using Catch::Detail::Approx;
#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) )
#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), className )
#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__)
#define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__)
#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__)
#define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ )
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
#else
#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) ) )
#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), className ) )
#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__) )
#define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__) )
#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__ ) )
#define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ ) )
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
#endif
// "BDD-style" convenience wrappers
@@ -382,6 +431,7 @@ using Catch::Detail::Approx;
#endif // CATCH_CONFIG_DISABLE_MATCHERS
#define INFO( msg ) (void)(0)
#define UNSCOPED_INFO( msg ) (void)(0)
#define WARN( msg ) (void)(0)
#define CAPTURE( msg ) (void)(0)
@@ -397,15 +447,23 @@ using Catch::Detail::Approx;
#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) )
#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), className )
#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__)
#define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__)
#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__)
#define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ )
#define TEMPLATE_PRODUCT_TEST_CASE( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ )
#define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ )
#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
#define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
#else
#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) ) )
#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), className ) )
#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__) )
#define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__) )
#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__ ) )
#define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ ) )
#define TEMPLATE_PRODUCT_TEST_CASE( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ )
#define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ )
#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
#define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
#endif
#define STATIC_REQUIRE( ... ) (void)(0)

View File

@@ -111,6 +111,9 @@ public:
m_suffix = false;
auto width = m_column.m_width - indent();
m_end = m_pos;
if (line()[m_pos] == '\n') {
++m_end;
}
while (m_end < line().size() && line()[m_end] != '\n')
++m_end;

View File

@@ -0,0 +1,122 @@
/*
* Created by Joachim on 16/04/2019.
* Adapted from donated nonius code.
*
* 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)
*/
// Benchmark
#ifndef TWOBLUECUBES_CATCH_BENCHMARK_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_BENCHMARK_HPP_INCLUDED
#include "../catch_config.hpp"
#include "../catch_context.h"
#include "../catch_interfaces_reporter.h"
#include "../catch_test_registry.h"
#include "catch_chronometer.hpp"
#include "catch_clock.hpp"
#include "catch_environment.hpp"
#include "catch_execution_plan.hpp"
#include "detail/catch_estimate_clock.hpp"
#include "detail/catch_complete_invoke.hpp"
#include "detail/catch_analyse.hpp"
#include "detail/catch_benchmark_function.hpp"
#include "detail/catch_run_for_at_least.hpp"
#include <algorithm>
#include <functional>
#include <string>
#include <vector>
#include <cmath>
namespace Catch {
namespace Benchmark {
struct Benchmark {
Benchmark(std::string &&name)
: name(std::move(name)) {}
template <class FUN>
Benchmark(std::string &&name, FUN &&func)
: fun(std::move(func)), name(std::move(name)) {}
template <typename Clock>
ExecutionPlan<FloatDuration<Clock>> prepare(const IConfig &cfg, Environment<FloatDuration<Clock>> env) const {
auto min_time = env.clock_resolution.mean * Detail::minimum_ticks;
auto run_time = std::max(min_time, std::chrono::duration_cast<decltype(min_time)>(Detail::warmup_time));
auto&& test = Detail::run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(run_time), 1, fun);
int new_iters = static_cast<int>(std::ceil(min_time * test.iterations / test.elapsed));
return { new_iters, test.elapsed / test.iterations * new_iters * cfg.benchmarkSamples(), fun, std::chrono::duration_cast<FloatDuration<Clock>>(Detail::warmup_time), Detail::warmup_iterations };
}
template <typename Clock = default_clock>
void run() {
IConfigPtr cfg = getCurrentContext().getConfig();
auto env = Detail::measure_environment<Clock>();
getResultCapture().benchmarkPreparing(name);
CATCH_TRY{
auto plan = user_code([&] {
return prepare<Clock>(*cfg, env);
});
BenchmarkInfo info {
name,
plan.estimated_duration.count(),
plan.iterations_per_sample,
cfg->benchmarkSamples(),
cfg->benchmarkResamples(),
env.clock_resolution.mean.count(),
env.clock_cost.mean.count()
};
getResultCapture().benchmarkStarting(info);
auto samples = user_code([&] {
return plan.template run<Clock>(*cfg, env);
});
auto analysis = Detail::analyse(*cfg, env, samples.begin(), samples.end());
BenchmarkStats<std::chrono::duration<double, std::nano>> stats{ info, analysis.samples, analysis.mean, analysis.standard_deviation, analysis.outliers, analysis.outlier_variance };
getResultCapture().benchmarkEnded(stats);
} CATCH_CATCH_ALL{
if (translateActiveException() != Detail::benchmarkErrorMsg) // benchmark errors have been reported, otherwise rethrow.
std::rethrow_exception(std::current_exception());
}
}
// sets lambda to be used in fun *and* executes benchmark!
template <typename Fun,
typename std::enable_if<!Detail::is_related<Fun, Benchmark>::value, int>::type = 0>
Benchmark & operator=(Fun func) {
fun = Detail::BenchmarkFunction(func);
run();
return *this;
}
explicit operator bool() {
return true;
}
private:
Detail::BenchmarkFunction fun;
std::string name;
};
}
} // namespace Catch
#define INTERNAL_CATCH_GET_1_ARG(arg1, arg2, ...) arg1
#define INTERNAL_CATCH_GET_2_ARG(arg1, arg2, ...) arg2
#define INTERNAL_CATCH_BENCHMARK(BenchmarkName, name, benchmarkIndex)\
if( Catch::Benchmark::Benchmark BenchmarkName{name} ) \
BenchmarkName = [&](int benchmarkIndex)
#define INTERNAL_CATCH_BENCHMARK_ADVANCED(BenchmarkName, name)\
if( Catch::Benchmark::Benchmark BenchmarkName{name} ) \
BenchmarkName = [&]
#endif // TWOBLUECUBES_CATCH_BENCHMARK_HPP_INCLUDED

View File

@@ -0,0 +1,71 @@
/*
* Created by Joachim on 16/04/2019.
* Adapted from donated nonius code.
*
* 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)
*/
// User-facing chronometer
#ifndef TWOBLUECUBES_CATCH_CHRONOMETER_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_CHRONOMETER_HPP_INCLUDED
#include "catch_clock.hpp"
#include "catch_optimizer.hpp"
#include "detail/catch_complete_invoke.hpp"
#include "../catch_meta.hpp"
namespace Catch {
namespace Benchmark {
namespace Detail {
struct ChronometerConcept {
virtual void start() = 0;
virtual void finish() = 0;
virtual ~ChronometerConcept() = default;
};
template <typename Clock>
struct ChronometerModel final : public ChronometerConcept {
void start() override { started = Clock::now(); }
void finish() override { finished = Clock::now(); }
ClockDuration<Clock> elapsed() const { return finished - started; }
TimePoint<Clock> started;
TimePoint<Clock> finished;
};
} // namespace Detail
struct Chronometer {
public:
template <typename Fun>
void measure(Fun&& fun) { measure(std::forward<Fun>(fun), is_callable<Fun(int)>()); }
int runs() const { return k; }
Chronometer(Detail::ChronometerConcept& meter, int k)
: impl(&meter)
, k(k) {}
private:
template <typename Fun>
void measure(Fun&& fun, std::false_type) {
measure([&fun](int) { return fun(); }, std::true_type());
}
template <typename Fun>
void measure(Fun&& fun, std::true_type) {
Detail::optimizer_barrier();
impl->start();
for (int i = 0; i < k; ++i) invoke_deoptimized(fun, i);
impl->finish();
Detail::optimizer_barrier();
}
Detail::ChronometerConcept* impl;
int k;
};
} // namespace Benchmark
} // namespace Catch
#endif // TWOBLUECUBES_CATCH_CHRONOMETER_HPP_INCLUDED

View File

@@ -0,0 +1,40 @@
/*
* Created by Joachim on 16/04/2019.
* Adapted from donated nonius code.
*
* 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)
*/
// Clocks
#ifndef TWOBLUECUBES_CATCH_CLOCK_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_CLOCK_HPP_INCLUDED
#include <chrono>
#include <ratio>
namespace Catch {
namespace Benchmark {
template <typename Clock>
using ClockDuration = typename Clock::duration;
template <typename Clock>
using FloatDuration = std::chrono::duration<double, typename Clock::period>;
template <typename Clock>
using TimePoint = typename Clock::time_point;
using default_clock = std::chrono::steady_clock;
template <typename Clock>
struct now {
TimePoint<Clock> operator()() const {
return Clock::now();
}
};
using fp_seconds = std::chrono::duration<double, std::ratio<1>>;
} // namespace Benchmark
} // namespace Catch
#endif // TWOBLUECUBES_CATCH_CLOCK_HPP_INCLUDED

View File

@@ -0,0 +1,73 @@
/*
* Created by Joachim on 16/04/2019.
* Adapted from donated nonius code.
*
* 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)
*/
// Constructor and destructor helpers
#ifndef TWOBLUECUBES_CATCH_CONSTRUCTOR_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_CONSTRUCTOR_HPP_INCLUDED
#include <type_traits>
namespace Catch {
namespace Detail {
template <typename T, bool Destruct>
struct ObjectStorage
{
using TStorage = typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type;
ObjectStorage() : data() {}
ObjectStorage(const ObjectStorage& other)
{
new(&data) T(other.stored_object());
}
ObjectStorage(ObjectStorage&& other)
{
new(&data) T(std::move(other.stored_object()));
}
~ObjectStorage() { destruct_on_exit<T>(); }
template <typename... Args>
void construct(Args&&... args)
{
new (&data) T(std::forward<Args>(args)...);
}
template <bool AllowManualDestruction = !Destruct>
typename std::enable_if<AllowManualDestruction>::type destruct()
{
stored_object().~T();
}
private:
// If this is a constructor benchmark, destruct the underlying object
template <typename U>
void destruct_on_exit(typename std::enable_if<Destruct, U>::type* = 0) { destruct<true>(); }
// Otherwise, don't
template <typename U>
void destruct_on_exit(typename std::enable_if<!Destruct, U>::type* = 0) { }
T& stored_object()
{
return *static_cast<T*>(static_cast<void*>(&data));
}
TStorage data;
};
}
template <typename T>
using storage_for = Detail::ObjectStorage<T, true>;
template <typename T>
using destructable_object = Detail::ObjectStorage<T, false>;
}
#endif // TWOBLUECUBES_CATCH_CONSTRUCTOR_HPP_INCLUDED

View File

@@ -0,0 +1,38 @@
/*
* Created by Joachim on 16/04/2019.
* Adapted from donated nonius code.
*
* 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)
*/
// Environment information
#ifndef TWOBLUECUBES_CATCH_ENVIRONMENT_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_ENVIRONMENT_HPP_INCLUDED
#include "catch_clock.hpp"
#include "catch_outlier_classification.hpp"
namespace Catch {
namespace Benchmark {
template <typename Duration>
struct EnvironmentEstimate {
Duration mean;
OutlierClassification outliers;
template <typename Duration2>
operator EnvironmentEstimate<Duration2>() const {
return { mean, outliers };
}
};
template <typename Clock>
struct Environment {
using clock_type = Clock;
EnvironmentEstimate<FloatDuration<Clock>> clock_resolution;
EnvironmentEstimate<FloatDuration<Clock>> clock_cost;
};
} // namespace Benchmark
} // namespace Catch
#endif // TWOBLUECUBES_CATCH_ENVIRONMENT_HPP_INCLUDED

View File

@@ -0,0 +1,31 @@
/*
* Created by Joachim on 16/04/2019.
* Adapted from donated nonius code.
*
* 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)
*/
// Statistics estimates
#ifndef TWOBLUECUBES_CATCH_ESTIMATE_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_ESTIMATE_HPP_INCLUDED
namespace Catch {
namespace Benchmark {
template <typename Duration>
struct Estimate {
Duration point;
Duration lower_bound;
Duration upper_bound;
double confidence_interval;
template <typename Duration2>
operator Estimate<Duration2>() const {
return { point, lower_bound, upper_bound, confidence_interval };
}
};
} // namespace Benchmark
} // namespace Catch
#endif // TWOBLUECUBES_CATCH_ESTIMATE_HPP_INCLUDED

View File

@@ -0,0 +1,58 @@
/*
* Created by Joachim on 16/04/2019.
* Adapted from donated nonius code.
*
* 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)
*/
// Execution plan
#ifndef TWOBLUECUBES_CATCH_EXECUTION_PLAN_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_EXECUTION_PLAN_HPP_INCLUDED
#include "../catch_config.hpp"
#include "catch_clock.hpp"
#include "catch_environment.hpp"
#include "detail/catch_benchmark_function.hpp"
#include "detail/catch_repeat.hpp"
#include "detail/catch_run_for_at_least.hpp"
#include <algorithm>
namespace Catch {
namespace Benchmark {
template <typename Duration>
struct ExecutionPlan {
int iterations_per_sample;
Duration estimated_duration;
Detail::BenchmarkFunction benchmark;
Duration warmup_time;
int warmup_iterations;
template <typename Duration2>
operator ExecutionPlan<Duration2>() const {
return { iterations_per_sample, estimated_duration, benchmark, warmup_time, warmup_iterations };
}
template <typename Clock>
std::vector<FloatDuration<Clock>> run(const IConfig &cfg, Environment<FloatDuration<Clock>> env) const {
// warmup a bit
Detail::run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(warmup_time), warmup_iterations, Detail::repeat(now<Clock>{}));
std::vector<FloatDuration<Clock>> times;
times.reserve(cfg.benchmarkSamples());
std::generate_n(std::back_inserter(times), cfg.benchmarkSamples(), [this, env] {
Detail::ChronometerModel<Clock> model;
this->benchmark(Chronometer(model, iterations_per_sample));
auto sample_time = model.elapsed() - env.clock_cost.mean;
if (sample_time < FloatDuration<Clock>::zero()) sample_time = FloatDuration<Clock>::zero();
return sample_time / iterations_per_sample;
});
return times;
}
};
} // namespace Benchmark
} // namespace Catch
#endif // TWOBLUECUBES_CATCH_EXECUTION_PLAN_HPP_INCLUDED

View File

@@ -0,0 +1,68 @@
/*
* Created by Joachim on 16/04/2019.
* Adapted from donated nonius code.
*
* 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)
*/
// Hinting the optimizer
#ifndef TWOBLUECUBES_CATCH_OPTIMIZER_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_OPTIMIZER_HPP_INCLUDED
#if defined(_MSC_VER)
# include <atomic> // atomic_thread_fence
#endif
namespace Catch {
namespace Benchmark {
#if defined(__GNUC__) || defined(__clang__)
template <typename T>
inline void keep_memory(T* p) {
asm volatile("" : : "g"(p) : "memory");
}
inline void keep_memory() {
asm volatile("" : : : "memory");
}
namespace Detail {
inline void optimizer_barrier() { keep_memory(); }
} // namespace Detail
#elif defined(_MSC_VER)
#pragma optimize("", off)
template <typename T>
inline void keep_memory(T* p) {
// thanks @milleniumbug
*reinterpret_cast<char volatile*>(p) = *reinterpret_cast<char const volatile*>(p);
}
// TODO equivalent keep_memory()
#pragma optimize("", on)
namespace Detail {
inline void optimizer_barrier() {
std::atomic_thread_fence(std::memory_order_seq_cst);
}
} // namespace Detail
#endif
template <typename T>
inline void deoptimize_value(T&& x) {
keep_memory(&x);
}
template <typename Fn, typename... Args>
inline auto invoke_deoptimized(Fn&& fn, Args&&... args) -> typename std::enable_if<!std::is_same<void, decltype(fn(args...))>::value>::type {
deoptimize_value(std::forward<Fn>(fn) (std::forward<Args...>(args...)));
}
template <typename Fn, typename... Args>
inline auto invoke_deoptimized(Fn&& fn, Args&&... args) -> typename std::enable_if<std::is_same<void, decltype(fn(args...))>::value>::type {
std::forward<Fn>(fn) (std::forward<Args...>(args...));
}
} // namespace Benchmark
} // namespace Catch
#endif // TWOBLUECUBES_CATCH_OPTIMIZER_HPP_INCLUDED

View File

@@ -0,0 +1,29 @@
/*
* Created by Joachim on 16/04/2019.
* Adapted from donated nonius code.
*
* 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)
*/
// Outlier information
#ifndef TWOBLUECUBES_CATCH_OUTLIERS_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_OUTLIERS_HPP_INCLUDED
namespace Catch {
namespace Benchmark {
struct OutlierClassification {
int samples_seen = 0;
int low_severe = 0; // more than 3 times IQR below Q1
int low_mild = 0; // 1.5 to 3 times IQR below Q1
int high_mild = 0; // 1.5 to 3 times IQR above Q3
int high_severe = 0; // more than 3 times IQR above Q3
int total() const {
return low_severe + low_mild + high_mild + high_severe;
}
};
} // namespace Benchmark
} // namespace Catch
#endif // TWOBLUECUBES_CATCH_OUTLIERS_HPP_INCLUDED

View File

@@ -0,0 +1,50 @@
/*
* Created by Joachim on 16/04/2019.
* Adapted from donated nonius code.
*
* 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)
*/
// Benchmark results
#ifndef TWOBLUECUBES_CATCH_BENCHMARK_RESULTS_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_BENCHMARK_RESULTS_HPP_INCLUDED
#include "catch_clock.hpp"
#include "catch_estimate.hpp"
#include "catch_outlier_classification.hpp"
#include <algorithm>
#include <vector>
#include <string>
#include <iterator>
namespace Catch {
namespace Benchmark {
template <typename Duration>
struct SampleAnalysis {
std::vector<Duration> samples;
Estimate<Duration> mean;
Estimate<Duration> standard_deviation;
OutlierClassification outliers;
double outlier_variance;
template <typename Duration2>
operator SampleAnalysis<Duration2>() const {
std::vector<Duration2> samples2;
samples2.reserve(samples.size());
std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](Duration d) { return Duration2(d); });
return {
std::move(samples2),
mean,
standard_deviation,
outliers,
outlier_variance,
};
}
};
} // namespace Benchmark
} // namespace Catch
#endif // TWOBLUECUBES_CATCH_BENCHMARK_RESULTS_HPP_INCLUDED

View File

@@ -0,0 +1,78 @@
/*
* Created by Joachim on 16/04/2019.
* Adapted from donated nonius code.
*
* 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)
*/
// Run and analyse one benchmark
#ifndef TWOBLUECUBES_CATCH_DETAIL_ANALYSE_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_DETAIL_ANALYSE_HPP_INCLUDED
#include "../catch_clock.hpp"
#include "../catch_sample_analysis.hpp"
#include "catch_stats.hpp"
#include <algorithm>
#include <iterator>
#include <vector>
namespace Catch {
namespace Benchmark {
namespace Detail {
template <typename Duration, typename Iterator>
SampleAnalysis<Duration> analyse(const IConfig &cfg, Environment<Duration>, Iterator first, Iterator last) {
if (!cfg.benchmarkNoAnalysis()) {
std::vector<double> samples;
samples.reserve(last - first);
std::transform(first, last, std::back_inserter(samples), [](Duration d) { return d.count(); });
auto analysis = Catch::Benchmark::Detail::analyse_samples(cfg.benchmarkConfidenceInterval(), cfg.benchmarkResamples(), samples.begin(), samples.end());
auto outliers = Catch::Benchmark::Detail::classify_outliers(samples.begin(), samples.end());
auto wrap_estimate = [](Estimate<double> e) {
return Estimate<Duration> {
Duration(e.point),
Duration(e.lower_bound),
Duration(e.upper_bound),
e.confidence_interval,
};
};
std::vector<Duration> samples2;
samples2.reserve(samples.size());
std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](double d) { return Duration(d); });
return {
std::move(samples2),
wrap_estimate(analysis.mean),
wrap_estimate(analysis.standard_deviation),
outliers,
analysis.outlier_variance,
};
} else {
std::vector<Duration> samples;
samples.reserve(last - first);
Duration mean = Duration(0);
int i = 0;
for (auto it = first; it < last; ++it, ++i) {
samples.push_back(Duration(*it));
mean += Duration(*it);
}
mean /= i;
return {
std::move(samples),
Estimate<Duration>{mean, mean, mean, 0.0},
Estimate<Duration>{Duration(0), Duration(0), Duration(0), 0.0},
OutlierClassification{},
0.0
};
}
}
} // namespace Detail
} // namespace Benchmark
} // namespace Catch
#endif // TWOBLUECUBES_CATCH_DETAIL_ANALYSE_HPP_INCLUDED

View File

@@ -0,0 +1,105 @@
/*
* Created by Joachim on 16/04/2019.
* Adapted from donated nonius code.
*
* 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)
*/
// Dumb std::function implementation for consistent call overhead
#ifndef TWOBLUECUBES_CATCH_DETAIL_BENCHMARK_FUNCTION_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_DETAIL_BENCHMARK_FUNCTION_HPP_INCLUDED
#include "../catch_chronometer.hpp"
#include "catch_complete_invoke.hpp"
#include "../../catch_meta.hpp"
#include <cassert>
#include <type_traits>
#include <utility>
#include <memory>
namespace Catch {
namespace Benchmark {
namespace Detail {
template <typename T>
using Decay = typename std::decay<T>::type;
template <typename T, typename U>
struct is_related
: std::is_same<Decay<T>, Decay<U>> {};
/// We need to reinvent std::function because every piece of code that might add overhead
/// in a measurement context needs to have consistent performance characteristics so that we
/// can account for it in the measurement.
/// Implementations of std::function with optimizations that aren't always applicable, like
/// small buffer optimizations, are not uncommon.
/// This is effectively an implementation of std::function without any such optimizations;
/// it may be slow, but it is consistently slow.
struct BenchmarkFunction {
private:
struct callable {
virtual void call(Chronometer meter) const = 0;
virtual callable* clone() const = 0;
virtual ~callable() = default;
};
template <typename Fun>
struct model : public callable {
model(Fun&& fun) : fun(std::move(fun)) {}
model(Fun const& fun) : fun(fun) {}
model<Fun>* clone() const override { return new model<Fun>(*this); }
void call(Chronometer meter) const override {
call(meter, is_callable<Fun(Chronometer)>());
}
void call(Chronometer meter, std::true_type) const {
fun(meter);
}
void call(Chronometer meter, std::false_type) const {
meter.measure(fun);
}
Fun fun;
};
struct do_nothing { void operator()() const {} };
template <typename T>
BenchmarkFunction(model<T>* c) : f(c) {}
public:
BenchmarkFunction()
: f(new model<do_nothing>{ {} }) {}
template <typename Fun,
typename std::enable_if<!is_related<Fun, BenchmarkFunction>::value, int>::type = 0>
BenchmarkFunction(Fun&& fun)
: f(new model<typename std::decay<Fun>::type>(std::forward<Fun>(fun))) {}
BenchmarkFunction(BenchmarkFunction&& that)
: f(std::move(that.f)) {}
BenchmarkFunction(BenchmarkFunction const& that)
: f(that.f->clone()) {}
BenchmarkFunction& operator=(BenchmarkFunction&& that) {
f = std::move(that.f);
return *this;
}
BenchmarkFunction& operator=(BenchmarkFunction const& that) {
f.reset(that.f->clone());
return *this;
}
void operator()(Chronometer meter) const { f->call(meter); }
private:
std::unique_ptr<callable> f;
};
} // namespace Detail
} // namespace Benchmark
} // namespace Catch
#endif // TWOBLUECUBES_CATCH_DETAIL_BENCHMARK_FUNCTION_HPP_INCLUDED

View File

@@ -0,0 +1,69 @@
/*
* Created by Joachim on 16/04/2019.
* Adapted from donated nonius code.
*
* 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)
*/
// Invoke with a special case for void
#ifndef TWOBLUECUBES_CATCH_DETAIL_COMPLETE_INVOKE_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_DETAIL_COMPLETE_INVOKE_HPP_INCLUDED
#include "../../catch_enforce.h"
#include <type_traits>
#include <utility>
namespace Catch {
namespace Benchmark {
namespace Detail {
template <typename T>
struct CompleteType { using type = T; };
template <>
struct CompleteType<void> { struct type {}; };
template <typename T>
using CompleteType_t = typename CompleteType<T>::type;
template <typename Result>
struct CompleteInvoker {
template <typename Fun, typename... Args>
static Result invoke(Fun&& fun, Args&&... args) {
return std::forward<Fun>(fun)(std::forward<Args>(args)...);
}
};
template <>
struct CompleteInvoker<void> {
template <typename Fun, typename... Args>
static CompleteType_t<void> invoke(Fun&& fun, Args&&... args) {
std::forward<Fun>(fun)(std::forward<Args>(args)...);
return {};
}
};
template <typename Sig>
using ResultOf_t = typename std::result_of<Sig>::type;
// invoke and not return void :(
template <typename Fun, typename... Args>
CompleteType_t<ResultOf_t<Fun(Args...)>> complete_invoke(Fun&& fun, Args&&... args) {
return CompleteInvoker<ResultOf_t<Fun(Args...)>>::invoke(std::forward<Fun>(fun), std::forward<Args>(args)...);
}
const std::string benchmarkErrorMsg = "a benchmark failed to run successfully";
} // namespace Detail
template <typename Fun>
Detail::CompleteType_t<Detail::ResultOf_t<Fun()>> user_code(Fun&& fun) {
CATCH_TRY{
return Detail::complete_invoke(std::forward<Fun>(fun));
} CATCH_CATCH_ALL{
getResultCapture().benchmarkFailed(translateActiveException());
CATCH_RUNTIME_ERROR(Detail::benchmarkErrorMsg);
}
}
} // namespace Benchmark
} // namespace Catch
#endif // TWOBLUECUBES_CATCH_DETAIL_COMPLETE_INVOKE_HPP_INCLUDED

View File

@@ -0,0 +1,113 @@
/*
* Created by Joachim on 16/04/2019.
* Adapted from donated nonius code.
*
* 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)
*/
// Environment measurement
#ifndef TWOBLUECUBES_CATCH_DETAIL_ESTIMATE_CLOCK_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_DETAIL_ESTIMATE_CLOCK_HPP_INCLUDED
#include "../catch_clock.hpp"
#include "../catch_environment.hpp"
#include "catch_stats.hpp"
#include "catch_measure.hpp"
#include "catch_run_for_at_least.hpp"
#include "../catch_clock.hpp"
#include <algorithm>
#include <iterator>
#include <tuple>
#include <vector>
#include <cmath>
namespace Catch {
namespace Benchmark {
namespace Detail {
template <typename Clock>
std::vector<double> resolution(int k) {
std::vector<TimePoint<Clock>> times;
times.reserve(k + 1);
std::generate_n(std::back_inserter(times), k + 1, now<Clock>{});
std::vector<double> deltas;
deltas.reserve(k);
std::transform(std::next(times.begin()), times.end(), times.begin(),
std::back_inserter(deltas),
[](TimePoint<Clock> a, TimePoint<Clock> b) { return static_cast<double>((a - b).count()); });
return deltas;
}
const auto warmup_iterations = 10000;
const auto warmup_time = std::chrono::milliseconds(100);
const auto minimum_ticks = 1000;
const auto warmup_seed = 10000;
const auto clock_resolution_estimation_time = std::chrono::milliseconds(500);
const auto clock_cost_estimation_time_limit = std::chrono::seconds(1);
const auto clock_cost_estimation_tick_limit = 100000;
const auto clock_cost_estimation_time = std::chrono::milliseconds(10);
const auto clock_cost_estimation_iterations = 10000;
template <typename Clock>
int warmup() {
return run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(warmup_time), warmup_seed, &resolution<Clock>)
.iterations;
}
template <typename Clock>
EnvironmentEstimate<FloatDuration<Clock>> estimate_clock_resolution(int iterations) {
auto r = run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(clock_resolution_estimation_time), iterations, &resolution<Clock>)
.result;
return {
FloatDuration<Clock>(mean(r.begin(), r.end())),
classify_outliers(r.begin(), r.end()),
};
}
template <typename Clock>
EnvironmentEstimate<FloatDuration<Clock>> estimate_clock_cost(FloatDuration<Clock> resolution) {
auto time_limit = std::min(resolution * clock_cost_estimation_tick_limit, FloatDuration<Clock>(clock_cost_estimation_time_limit));
auto time_clock = [](int k) {
return Detail::measure<Clock>([k] {
for (int i = 0; i < k; ++i) {
volatile auto ignored = Clock::now();
(void)ignored;
}
}).elapsed;
};
time_clock(1);
int iters = clock_cost_estimation_iterations;
auto&& r = run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(clock_cost_estimation_time), iters, time_clock);
std::vector<double> times;
int nsamples = static_cast<int>(std::ceil(time_limit / r.elapsed));
times.reserve(nsamples);
std::generate_n(std::back_inserter(times), nsamples, [time_clock, &r] {
return static_cast<double>((time_clock(r.iterations) / r.iterations).count());
});
return {
FloatDuration<Clock>(mean(times.begin(), times.end())),
classify_outliers(times.begin(), times.end()),
};
}
template <typename Clock>
Environment<FloatDuration<Clock>> measure_environment() {
static Environment<FloatDuration<Clock>>* env = nullptr;
if (env) {
return *env;
}
auto iters = Detail::warmup<Clock>();
auto resolution = Detail::estimate_clock_resolution<Clock>(iters);
auto cost = Detail::estimate_clock_cost<Clock>(resolution.mean);
env = new Environment<FloatDuration<Clock>>{ resolution, cost };
return *env;
}
} // namespace Detail
} // namespace Benchmark
} // namespace Catch
#endif // TWOBLUECUBES_CATCH_DETAIL_ESTIMATE_CLOCK_HPP_INCLUDED

View File

@@ -0,0 +1,35 @@
/*
* Created by Joachim on 16/04/2019.
* Adapted from donated nonius code.
*
* 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)
*/
// Measure
#ifndef TWOBLUECUBES_CATCH_DETAIL_MEASURE_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_DETAIL_MEASURE_HPP_INCLUDED
#include "../catch_clock.hpp"
#include "catch_complete_invoke.hpp"
#include "catch_timing.hpp"
#include <utility>
namespace Catch {
namespace Benchmark {
namespace Detail {
template <typename Clock, typename Fun, typename... Args>
TimingOf<Clock, Fun(Args...)> measure(Fun&& fun, Args&&... args) {
auto start = Clock::now();
auto&& r = Detail::complete_invoke(fun, std::forward<Args>(args)...);
auto end = Clock::now();
auto delta = end - start;
return { delta, std::forward<decltype(r)>(r), 1 };
}
} // namespace Detail
} // namespace Benchmark
} // namespace Catch
#endif // TWOBLUECUBES_CATCH_DETAIL_MEASURE_HPP_INCLUDED

View File

@@ -0,0 +1,37 @@
/*
* Created by Joachim on 16/04/2019.
* Adapted from donated nonius code.
*
* 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)
*/
// repeat algorithm
#ifndef TWOBLUECUBES_CATCH_DETAIL_REPEAT_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_DETAIL_REPEAT_HPP_INCLUDED
#include <type_traits>
#include <utility>
namespace Catch {
namespace Benchmark {
namespace Detail {
template <typename Fun>
struct repeater {
void operator()(int k) const {
for (int i = 0; i < k; ++i) {
fun();
}
}
Fun fun;
};
template <typename Fun>
repeater<typename std::decay<Fun>::type> repeat(Fun&& fun) {
return { std::forward<Fun>(fun) };
}
} // namespace Detail
} // namespace Benchmark
} // namespace Catch
#endif // TWOBLUECUBES_CATCH_DETAIL_REPEAT_HPP_INCLUDED

View File

@@ -0,0 +1,65 @@
/*
* Created by Joachim on 16/04/2019.
* Adapted from donated nonius code.
*
* 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)
*/
// Run a function for a minimum amount of time
#ifndef TWOBLUECUBES_CATCH_RUN_FOR_AT_LEAST_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_RUN_FOR_AT_LEAST_HPP_INCLUDED
#include "../catch_clock.hpp"
#include "../catch_chronometer.hpp"
#include "catch_measure.hpp"
#include "catch_complete_invoke.hpp"
#include "catch_timing.hpp"
#include "../../catch_meta.hpp"
#include <utility>
#include <type_traits>
namespace Catch {
namespace Benchmark {
namespace Detail {
template <typename Clock, typename Fun>
TimingOf<Clock, Fun(int)> measure_one(Fun&& fun, int iters, std::false_type) {
return Detail::measure<Clock>(fun, iters);
}
template <typename Clock, typename Fun>
TimingOf<Clock, Fun(Chronometer)> measure_one(Fun&& fun, int iters, std::true_type) {
Detail::ChronometerModel<Clock> meter;
auto&& result = Detail::complete_invoke(fun, Chronometer(meter, iters));
return { meter.elapsed(), std::move(result), iters };
}
template <typename Clock, typename Fun>
using run_for_at_least_argument_t = typename std::conditional<is_callable<Fun(Chronometer)>::value, Chronometer, int>::type;
struct optimized_away_error : std::exception {
const char* what() const noexcept override {
return "could not measure benchmark, maybe it was optimized away";
}
};
template <typename Clock, typename Fun>
TimingOf<Clock, Fun(run_for_at_least_argument_t<Clock, Fun>)> run_for_at_least(ClockDuration<Clock> how_long, int seed, Fun&& fun) {
auto iters = seed;
while (iters < (1 << 30)) {
auto&& Timing = measure_one<Clock>(fun, iters, is_callable<Fun(Chronometer)>());
if (Timing.elapsed >= how_long) {
return { Timing.elapsed, std::move(Timing.result), iters };
}
iters *= 2;
}
throw optimized_away_error{};
}
} // namespace Detail
} // namespace Benchmark
} // namespace Catch
#endif // TWOBLUECUBES_CATCH_RUN_FOR_AT_LEAST_HPP_INCLUDED

View File

@@ -0,0 +1,223 @@
/*
* Created by Martin on 15/06/2019.
* Adapted from donated nonius code.
*
* 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)
*/
// Statistical analysis tools
#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
#include "catch_stats.hpp"
#include "../../catch_compiler_capabilities.h"
#include <cassert>
#include <random>
#if defined(CATCH_CONFIG_USE_ASYNC)
#include <future>
#endif
namespace {
double erf_inv(double x) {
// Code accompanying the article "Approximating the erfinv function" in GPU Computing Gems, Volume 2
double w, p;
w = -log((1.0 - x) * (1.0 + x));
if (w < 6.250000) {
w = w - 3.125000;
p = -3.6444120640178196996e-21;
p = -1.685059138182016589e-19 + p * w;
p = 1.2858480715256400167e-18 + p * w;
p = 1.115787767802518096e-17 + p * w;
p = -1.333171662854620906e-16 + p * w;
p = 2.0972767875968561637e-17 + p * w;
p = 6.6376381343583238325e-15 + p * w;
p = -4.0545662729752068639e-14 + p * w;
p = -8.1519341976054721522e-14 + p * w;
p = 2.6335093153082322977e-12 + p * w;
p = -1.2975133253453532498e-11 + p * w;
p = -5.4154120542946279317e-11 + p * w;
p = 1.051212273321532285e-09 + p * w;
p = -4.1126339803469836976e-09 + p * w;
p = -2.9070369957882005086e-08 + p * w;
p = 4.2347877827932403518e-07 + p * w;
p = -1.3654692000834678645e-06 + p * w;
p = -1.3882523362786468719e-05 + p * w;
p = 0.0001867342080340571352 + p * w;
p = -0.00074070253416626697512 + p * w;
p = -0.0060336708714301490533 + p * w;
p = 0.24015818242558961693 + p * w;
p = 1.6536545626831027356 + p * w;
} else if (w < 16.000000) {
w = sqrt(w) - 3.250000;
p = 2.2137376921775787049e-09;
p = 9.0756561938885390979e-08 + p * w;
p = -2.7517406297064545428e-07 + p * w;
p = 1.8239629214389227755e-08 + p * w;
p = 1.5027403968909827627e-06 + p * w;
p = -4.013867526981545969e-06 + p * w;
p = 2.9234449089955446044e-06 + p * w;
p = 1.2475304481671778723e-05 + p * w;
p = -4.7318229009055733981e-05 + p * w;
p = 6.8284851459573175448e-05 + p * w;
p = 2.4031110387097893999e-05 + p * w;
p = -0.0003550375203628474796 + p * w;
p = 0.00095328937973738049703 + p * w;
p = -0.0016882755560235047313 + p * w;
p = 0.0024914420961078508066 + p * w;
p = -0.0037512085075692412107 + p * w;
p = 0.005370914553590063617 + p * w;
p = 1.0052589676941592334 + p * w;
p = 3.0838856104922207635 + p * w;
} else {
w = sqrt(w) - 5.000000;
p = -2.7109920616438573243e-11;
p = -2.5556418169965252055e-10 + p * w;
p = 1.5076572693500548083e-09 + p * w;
p = -3.7894654401267369937e-09 + p * w;
p = 7.6157012080783393804e-09 + p * w;
p = -1.4960026627149240478e-08 + p * w;
p = 2.9147953450901080826e-08 + p * w;
p = -6.7711997758452339498e-08 + p * w;
p = 2.2900482228026654717e-07 + p * w;
p = -9.9298272942317002539e-07 + p * w;
p = 4.5260625972231537039e-06 + p * w;
p = -1.9681778105531670567e-05 + p * w;
p = 7.5995277030017761139e-05 + p * w;
p = -0.00021503011930044477347 + p * w;
p = -0.00013871931833623122026 + p * w;
p = 1.0103004648645343977 + p * w;
p = 4.8499064014085844221 + p * w;
}
return p * x;
}
double standard_deviation(std::vector<double>::iterator first, std::vector<double>::iterator last) {
auto m = Catch::Benchmark::Detail::mean(first, last);
double variance = std::accumulate(first, last, 0., [m](double a, double b) {
double diff = b - m;
return a + diff * diff;
}) / (last - first);
return std::sqrt(variance);
}
}
namespace Catch {
namespace Benchmark {
namespace Detail {
double weighted_average_quantile(int k, int q, std::vector<double>::iterator first, std::vector<double>::iterator last) {
auto count = last - first;
double idx = (count - 1) * k / static_cast<double>(q);
int j = static_cast<int>(idx);
double g = idx - j;
std::nth_element(first, first + j, last);
auto xj = first[j];
if (g == 0) return xj;
auto xj1 = *std::min_element(first + (j + 1), last);
return xj + g * (xj1 - xj);
}
double erfc_inv(double x) {
return erf_inv(1.0 - x);
}
double normal_quantile(double p) {
static const double ROOT_TWO = std::sqrt(2.0);
double result = 0.0;
assert(p >= 0 && p <= 1);
if (p < 0 || p > 1) {
return result;
}
result = -erfc_inv(2.0 * p);
// result *= normal distribution standard deviation (1.0) * sqrt(2)
result *= /*sd * */ ROOT_TWO;
// result += normal disttribution mean (0)
return result;
}
double outlier_variance(Estimate<double> mean, Estimate<double> stddev, int n) {
double sb = stddev.point;
double mn = mean.point / n;
double mg_min = mn / 2.;
double sg = std::min(mg_min / 4., sb / std::sqrt(n));
double sg2 = sg * sg;
double sb2 = sb * sb;
auto c_max = [n, mn, sb2, sg2](double x) -> double {
double k = mn - x;
double d = k * k;
double nd = n * d;
double k0 = -n * nd;
double k1 = sb2 - n * sg2 + nd;
double det = k1 * k1 - 4 * sg2 * k0;
return (int)(-2. * k0 / (k1 + std::sqrt(det)));
};
auto var_out = [n, sb2, sg2](double c) {
double nc = n - c;
return (nc / n) * (sb2 - nc * sg2);
};
return std::min(var_out(1), var_out(std::min(c_max(0.), c_max(mg_min)))) / sb2;
}
bootstrap_analysis analyse_samples(double confidence_level, int n_resamples, std::vector<double>::iterator first, std::vector<double>::iterator last) {
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
static std::random_device entropy;
CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
auto n = static_cast<int>(last - first); // seriously, one can't use integral types without hell in C++
auto mean = &Detail::mean<std::vector<double>::iterator>;
auto stddev = &standard_deviation;
#if defined(CATCH_CONFIG_USE_ASYNC)
auto Estimate = [=](double(*f)(std::vector<double>::iterator, std::vector<double>::iterator)) {
auto seed = entropy();
return std::async(std::launch::async, [=] {
std::mt19937 rng(seed);
auto resampled = resample(rng, n_resamples, first, last, f);
return bootstrap(confidence_level, first, last, resampled, f);
});
};
auto mean_future = Estimate(mean);
auto stddev_future = Estimate(stddev);
auto mean_estimate = mean_future.get();
auto stddev_estimate = stddev_future.get();
#else
auto Estimate = [=](double(*f)(std::vector<double>::iterator, std::vector<double>::iterator)) {
auto seed = entropy();
std::mt19937 rng(seed);
auto resampled = resample(rng, n_resamples, first, last, f);
return bootstrap(confidence_level, first, last, resampled, f);
};
auto mean_estimate = Estimate(mean);
auto stddev_estimate = Estimate(stddev);
#endif // CATCH_USE_ASYNC
double outlier_variance = Detail::outlier_variance(mean_estimate, stddev_estimate, n);
return { mean_estimate, stddev_estimate, outlier_variance };
}
} // namespace Detail
} // namespace Benchmark
} // namespace Catch
#endif // CATCH_CONFIG_ENABLE_BENCHMARKING

View File

@@ -0,0 +1,158 @@
/*
* Created by Joachim on 16/04/2019.
* Adapted from donated nonius code.
*
* 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)
*/
// Statistical analysis tools
#ifndef TWOBLUECUBES_CATCH_DETAIL_ANALYSIS_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_DETAIL_ANALYSIS_HPP_INCLUDED
#include "../catch_clock.hpp"
#include "../catch_estimate.hpp"
#include "../catch_outlier_classification.hpp"
#include <algorithm>
#include <functional>
#include <vector>
#include <numeric>
#include <tuple>
#include <cmath>
#include <utility>
#include <cstddef>
namespace Catch {
namespace Benchmark {
namespace Detail {
using sample = std::vector<double>;
double weighted_average_quantile(int k, int q, std::vector<double>::iterator first, std::vector<double>::iterator last);
template <typename Iterator>
OutlierClassification classify_outliers(Iterator first, Iterator last) {
std::vector<double> copy(first, last);
auto q1 = weighted_average_quantile(1, 4, copy.begin(), copy.end());
auto q3 = weighted_average_quantile(3, 4, copy.begin(), copy.end());
auto iqr = q3 - q1;
auto los = q1 - (iqr * 3.);
auto lom = q1 - (iqr * 1.5);
auto him = q3 + (iqr * 1.5);
auto his = q3 + (iqr * 3.);
OutlierClassification o;
for (; first != last; ++first) {
auto&& t = *first;
if (t < los) ++o.low_severe;
else if (t < lom) ++o.low_mild;
else if (t > his) ++o.high_severe;
else if (t > him) ++o.high_mild;
++o.samples_seen;
}
return o;
}
template <typename Iterator>
double mean(Iterator first, Iterator last) {
auto count = last - first;
double sum = std::accumulate(first, last, 0.);
return sum / count;
}
template <typename URng, typename Iterator, typename Estimator>
sample resample(URng& rng, int resamples, Iterator first, Iterator last, Estimator& estimator) {
auto n = last - first;
std::uniform_int_distribution<decltype(n)> dist(0, n - 1);
sample out;
out.reserve(resamples);
std::generate_n(std::back_inserter(out), resamples, [n, first, &estimator, &dist, &rng] {
std::vector<double> resampled;
resampled.reserve(n);
std::generate_n(std::back_inserter(resampled), n, [first, &dist, &rng] { return first[dist(rng)]; });
return estimator(resampled.begin(), resampled.end());
});
std::sort(out.begin(), out.end());
return out;
}
template <typename Estimator, typename Iterator>
sample jackknife(Estimator&& estimator, Iterator first, Iterator last) {
auto n = last - first;
auto second = std::next(first);
sample results;
results.reserve(n);
for (auto it = first; it != last; ++it) {
std::iter_swap(it, first);
results.push_back(estimator(second, last));
}
return results;
}
inline double normal_cdf(double x) {
return std::erfc(-x / std::sqrt(2.0)) / 2.0;
}
double erfc_inv(double x);
double normal_quantile(double p);
template <typename Iterator, typename Estimator>
Estimate<double> bootstrap(double confidence_level, Iterator first, Iterator last, sample const& resample, Estimator&& estimator) {
auto n_samples = last - first;
double point = estimator(first, last);
// Degenerate case with a single sample
if (n_samples == 1) return { point, point, point, confidence_level };
sample jack = jackknife(estimator, first, last);
double jack_mean = mean(jack.begin(), jack.end());
double sum_squares, sum_cubes;
std::tie(sum_squares, sum_cubes) = std::accumulate(jack.begin(), jack.end(), std::make_pair(0., 0.), [jack_mean](std::pair<double, double> sqcb, double x) -> std::pair<double, double> {
auto d = jack_mean - x;
auto d2 = d * d;
auto d3 = d2 * d;
return { sqcb.first + d2, sqcb.second + d3 };
});
double accel = sum_cubes / (6 * std::pow(sum_squares, 1.5));
int n = static_cast<int>(resample.size());
double prob_n = std::count_if(resample.begin(), resample.end(), [point](double x) { return x < point; }) / (double)n;
// degenerate case with uniform samples
if (prob_n == 0) return { point, point, point, confidence_level };
double bias = normal_quantile(prob_n);
double z1 = normal_quantile((1. - confidence_level) / 2.);
auto cumn = [n](double x) -> int {
return std::lround(normal_cdf(x) * n); };
auto a = [bias, accel](double b) { return bias + b / (1. - accel * b); };
double b1 = bias + z1;
double b2 = bias - z1;
double a1 = a(b1);
double a2 = a(b2);
auto lo = std::max(cumn(a1), 0);
auto hi = std::min(cumn(a2), n - 1);
return { point, resample[lo], resample[hi], confidence_level };
}
double outlier_variance(Estimate<double> mean, Estimate<double> stddev, int n);
struct bootstrap_analysis {
Estimate<double> mean;
Estimate<double> standard_deviation;
double outlier_variance;
};
bootstrap_analysis analyse_samples(double confidence_level, int n_resamples, std::vector<double>::iterator first, std::vector<double>::iterator last);
} // namespace Detail
} // namespace Benchmark
} // namespace Catch
#endif // TWOBLUECUBES_CATCH_DETAIL_ANALYSIS_HPP_INCLUDED

View File

@@ -0,0 +1,33 @@
/*
* Created by Joachim on 16/04/2019.
* Adapted from donated nonius code.
*
* 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)
*/
// Timing
#ifndef TWOBLUECUBES_CATCH_DETAIL_TIMING_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_DETAIL_TIMING_HPP_INCLUDED
#include "../catch_clock.hpp"
#include "catch_complete_invoke.hpp"
#include <tuple>
#include <type_traits>
namespace Catch {
namespace Benchmark {
template <typename Duration, typename Result>
struct Timing {
Duration elapsed;
Result result;
int iterations;
};
template <typename Clock, typename Sig>
using TimingOf = Timing<ClockDuration<Clock>, Detail::CompleteType_t<Detail::ResultOf_t<Sig>>>;
} // namespace Benchmark
} // namespace Catch
#endif // TWOBLUECUBES_CATCH_DETAIL_TIMING_HPP_INCLUDED

View File

@@ -52,21 +52,22 @@ namespace Detail {
bool Approx::equalityComparisonImpl(const double other) const {
// First try with fixed margin, then compute margin based on epsilon, scale and Approx's value
// Thanks to Richard Harris for his help refining the scaled margin value
return marginComparison(m_value, other, m_margin) || marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(m_value)));
return marginComparison(m_value, other, m_margin)
|| marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(std::isinf(m_value)? 0 : m_value)));
}
void Approx::setMargin(double margin) {
CATCH_ENFORCE(margin >= 0,
"Invalid Approx::margin: " << margin << '.'
void Approx::setMargin(double newMargin) {
CATCH_ENFORCE(newMargin >= 0,
"Invalid Approx::margin: " << newMargin << '.'
<< " Approx::Margin has to be non-negative.");
m_margin = margin;
m_margin = newMargin;
}
void Approx::setEpsilon(double epsilon) {
CATCH_ENFORCE(epsilon >= 0 && epsilon <= 1.0,
"Invalid Approx::epsilon: " << epsilon << '.'
void Approx::setEpsilon(double newEpsilon) {
CATCH_ENFORCE(newEpsilon >= 0 && newEpsilon <= 1.0,
"Invalid Approx::epsilon: " << newEpsilon << '.'
<< " Approx::epsilon has to be in [0, 1]");
m_epsilon = epsilon;
m_epsilon = newEpsilon;
}
} // end namespace Detail

View File

@@ -45,7 +45,7 @@ namespace Catch {
}
bool AssertionResult::hasExpression() const {
return m_info.capturedExpression[0] != 0;
return !m_info.capturedExpression.empty();
}
bool AssertionResult::hasMessage() const {
@@ -53,16 +53,22 @@ namespace Catch {
}
std::string AssertionResult::getExpression() const {
if( isFalseTest( m_info.resultDisposition ) )
return "!(" + m_info.capturedExpression + ")";
else
return m_info.capturedExpression;
// Possibly overallocating by 3 characters should be basically free
std::string expr; expr.reserve(m_info.capturedExpression.size() + 3);
if (isFalseTest(m_info.resultDisposition)) {
expr += "!(";
}
expr += m_info.capturedExpression;
if (isFalseTest(m_info.resultDisposition)) {
expr += ')';
}
return expr;
}
std::string AssertionResult::getExpressionInMacro() const {
std::string expr;
if( m_info.macroName[0] == 0 )
expr = m_info.capturedExpression;
if( m_info.macroName.empty() )
expr = static_cast<std::string>(m_info.capturedExpression);
else {
expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 );
expr += m_info.macroName;

View File

@@ -1,36 +0,0 @@
/*
* Created by Phil on 04/07/2017.
* Copyright 2017 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#include "catch_benchmark.h"
#include "catch_capture.hpp"
#include "catch_interfaces_reporter.h"
#include "catch_context.h"
namespace Catch {
auto BenchmarkLooper::getResolution() -> uint64_t {
return getEstimatedClockResolution() * getCurrentContext().getConfig()->benchmarkResolutionMultiple();
}
void BenchmarkLooper::reportStart() {
getResultCapture().benchmarkStarting( { m_name } );
}
auto BenchmarkLooper::needsMoreIterations() -> bool {
auto elapsed = m_timer.getElapsedNanoseconds();
// Exponentially increasing iterations until we're confident in our timer resolution
if( elapsed < m_resolution ) {
m_iterationsToRun *= 10;
return true;
}
getResultCapture().benchmarkEnded( { { m_name }, m_count, elapsed } );
return false;
}
} // end namespace Catch

View File

@@ -1,57 +0,0 @@
/*
* Created by Phil on 04/07/2017.
* Copyright 2017 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef TWOBLUECUBES_CATCH_BENCHMARK_H_INCLUDED
#define TWOBLUECUBES_CATCH_BENCHMARK_H_INCLUDED
#include "catch_stringref.h"
#include "catch_timer.h"
#include <cstdint>
#include <string>
namespace Catch {
class BenchmarkLooper {
std::string m_name;
std::size_t m_count = 0;
std::size_t m_iterationsToRun = 1;
uint64_t m_resolution;
Timer m_timer;
static auto getResolution() -> uint64_t;
public:
// Keep most of this inline as it's on the code path that is being timed
BenchmarkLooper( StringRef name )
: m_name( name ),
m_resolution( getResolution() )
{
reportStart();
m_timer.start();
}
explicit operator bool() {
if( m_count < m_iterationsToRun )
return true;
return needsMoreIterations();
}
void increment() {
++m_count;
}
void reportStart();
auto needsMoreIterations() -> bool;
};
} // end namespace Catch
#define BENCHMARK( name ) \
for( Catch::BenchmarkLooper looper( name ); looper; looper.increment() )
#endif // TWOBLUECUBES_CATCH_BENCHMARK_H_INCLUDED

View File

@@ -10,6 +10,7 @@
#include "catch_capture.hpp"
#include "catch_matchers.h"
#include "catch_matchers_exception.hpp"
#include "catch_matchers_floating.h"
#include "catch_matchers_generic.hpp"
#include "catch_matchers_string.h"

View File

@@ -196,11 +196,19 @@ namespace Catch {
| Opt( setWaitForKeypress, "start|exit|both" )
["--wait-for-keypress"]
( "waits for a keypress before exiting" )
| Opt( config.benchmarkResolutionMultiple, "multiplier" )
["--benchmark-resolution-multiple"]
( "multiple of clock resolution to run benchmarks" )
| Arg( config.testsOrTags, "test name|pattern|tags" )
| Opt( config.benchmarkSamples, "samples" )
["--benchmark-samples"]
( "number of samples to collect (default: 100)" )
| Opt( config.benchmarkResamples, "resamples" )
["--benchmark-resamples"]
( "number of resamples for the bootstrap (default: 100000)" )
| Opt( config.benchmarkConfidenceInterval, "confidence interval" )
["--benchmark-confidence-interval"]
( "confidence interval for the bootstrap (between 0 and 1, default: 0.95)" )
| Opt( config.benchmarkNoAnalysis )
["--benchmark-no-analysis"]
( "perform only measurements; do not perform any analysis" )
| Arg( config.testsOrTags, "test name|pattern|tags" )
( "which test or tests to use" );
return cli;

View File

@@ -15,9 +15,6 @@
namespace Catch {
bool SourceLineInfo::empty() const noexcept {
return file[0] == '\0';
}
bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const noexcept {
return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0);
}

View File

@@ -57,7 +57,7 @@ namespace Catch {
SourceLineInfo( SourceLineInfo&& ) noexcept = default;
SourceLineInfo& operator = ( SourceLineInfo&& ) noexcept = default;
bool empty() const noexcept;
bool empty() const noexcept { return file[0] == '\0'; }
bool operator == ( SourceLineInfo const& other ) const noexcept;
bool operator < ( SourceLineInfo const& other ) const noexcept;

View File

@@ -64,6 +64,12 @@
# define CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS \
_Pragma( "clang diagnostic pop" )
# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
_Pragma( "clang diagnostic push" ) \
_Pragma( "clang diagnostic ignored \"-Wgnu-zero-variadic-macro-arguments\"" )
# define CATCH_INTERNAL_UNSUPPRESS_ZERO_VARIADIC_WARNINGS \
_Pragma( "clang diagnostic pop" )
#endif // __clang__
@@ -88,6 +94,7 @@
// Android somehow still does not support std::to_string
#if defined(__ANDROID__)
# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING
# define CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE
#endif
////////////////////////////////////////////////////////////////////////////////
@@ -109,12 +116,12 @@
// 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
// some versions of cygwin (most) do not support std::to_string. Use the libstd check.
// some versions of cygwin (most) do not support std::to_string. Use the libstd check.
// https://gcc.gnu.org/onlinedocs/gcc-4.8.2/libstdc++/api/a01053_source.html line 2812-2813
# if !((__cplusplus >= 201103L) && defined(_GLIBCXX_USE_C99) \
&& !defined(_GLIBCXX_HAVE_BROKEN_VSWPRINTF))
&& !defined(_GLIBCXX_HAVE_BROKEN_VSWPRINTF))
# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING
# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING
# endif
#endif // __CYGWIN__
@@ -142,7 +149,11 @@
# if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL)
# define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
# endif
#endif // _MSC_VER
#if defined(_REENTRANT) || defined(_MSC_VER)
// Enable async processing, as -pthread is specified or no additional linking is required
# define CATCH_INTERNAL_CONFIG_USE_ASYNC
#endif // _MSC_VER
////////////////////////////////////////////////////////////////////////////////
@@ -174,41 +185,55 @@
#define CATCH_INTERNAL_CONFIG_COUNTER
#endif
////////////////////////////////////////////////////////////////////////////////
// Check if string_view is available and usable
// The check is split apart to work around v140 (VS2015) preprocessor issue...
#if defined(__has_include)
#if __has_include(<string_view>) && defined(CATCH_CPP17_OR_GREATER)
# define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW
#endif
#endif
////////////////////////////////////////////////////////////////////////////////
// Check if optional is available and usable
#if defined(__has_include)
# if __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER)
# define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL
# endif // __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER)
#endif // __has_include
////////////////////////////////////////////////////////////////////////////////
// Check if variant is available and usable
// RTX is a special version of Windows that is real time.
// This means that it is detected as Windows, but does not provide
// the same set of capabilities as real Windows does.
#if defined(UNDER_RTSS) || defined(RTX64_BUILD)
#define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH
#define CATCH_INTERNAL_CONFIG_NO_ASYNC
#define CATCH_CONFIG_COLOUR_NONE
#endif
#if defined(__UCLIBC__)
#define CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER
#endif
// Various stdlib support checks that require __has_include
#if defined(__has_include)
# if __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER)
# if defined(__clang__) && (__clang_major__ < 8)
// work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852
// fix should be in clang 8, workaround in libstdc++ 8.2
# include <ciso646>
# if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9)
# define CATCH_CONFIG_NO_CPP17_VARIANT
# else
# define CATCH_INTERNAL_CONFIG_CPP17_VARIANT
# endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9)
# else
# define CATCH_INTERNAL_CONFIG_CPP17_VARIANT
# endif // defined(__clang__) && (__clang_major__ < 8)
# endif // __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER)
#endif // __has_include
// Check if string_view is available and usable
#if __has_include(<string_view>) && defined(CATCH_CPP17_OR_GREATER)
# define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW
#endif
// Check if optional is available and usable
# if __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER)
# define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL
# endif // __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER)
// Check if byte is available and usable
# if __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER)
# define CATCH_INTERNAL_CONFIG_CPP17_BYTE
# endif // __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER)
// Check if variant is available and usable
# if __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER)
# if defined(__clang__) && (__clang_major__ < 8)
// work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852
// fix should be in clang 8, workaround in libstdc++ 8.2
# include <ciso646>
# if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9)
# define CATCH_CONFIG_NO_CPP17_VARIANT
# else
# define CATCH_INTERNAL_CONFIG_CPP17_VARIANT
# endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9)
# else
# define CATCH_INTERNAL_CONFIG_CPP17_VARIANT
# endif // defined(__clang__) && (__clang_major__ < 8)
# endif // __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER)
#endif // defined(__has_include)
#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER)
@@ -246,6 +271,11 @@
# define CATCH_CONFIG_CPP17_VARIANT
#endif
#if defined(CATCH_INTERNAL_CONFIG_CPP17_BYTE) && !defined(CATCH_CONFIG_NO_CPP17_BYTE) && !defined(CATCH_CONFIG_CPP17_BYTE)
# define CATCH_CONFIG_CPP17_BYTE
#endif
#if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT)
# define CATCH_INTERNAL_CONFIG_NEW_CAPTURE
#endif
@@ -262,6 +292,18 @@
# define CATCH_CONFIG_POLYFILL_ISNAN
#endif
#if defined(CATCH_INTERNAL_CONFIG_USE_ASYNC) && !defined(CATCH_INTERNAL_CONFIG_NO_ASYNC) && !defined(CATCH_CONFIG_NO_USE_ASYNC) && !defined(CATCH_CONFIG_USE_ASYNC)
# define CATCH_CONFIG_USE_ASYNC
#endif
#if defined(CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_NO_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_ANDROID_LOGWRITE)
# define CATCH_CONFIG_ANDROID_LOGWRITE
#endif
#if defined(CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_NO_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_GLOBAL_NEXTAFTER)
# define CATCH_CONFIG_GLOBAL_NEXTAFTER
#endif
#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS)
# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS
# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS
@@ -274,6 +316,10 @@
# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS
# define CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS
#endif
#if !defined(CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS)
# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS
# define CATCH_INTERNAL_UNSUPPRESS_ZERO_VARIADIC_WARNINGS
#endif
#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
#define CATCH_TRY if ((true))

View File

@@ -15,14 +15,23 @@ namespace Catch {
: m_data( data ),
m_stream( openStream() )
{
TestSpecParser parser(ITagAliasRegistry::get());
if (data.testsOrTags.empty()) {
parser.parse("~[.]"); // All not hidden tests
// We need to trim filter specs to avoid trouble with superfluous
// whitespace (esp. important for bdd macros, as those are manually
// aligned with whitespace).
for (auto& elem : m_data.testsOrTags) {
elem = trim(elem);
}
else {
for (auto& elem : m_data.sectionsToRun) {
elem = trim(elem);
}
TestSpecParser parser(ITagAliasRegistry::get());
if (!m_data.testsOrTags.empty()) {
m_hasTestFilters = true;
for( auto const& testOrTags : data.testsOrTags )
parser.parse( testOrTags );
for (auto const& testOrTags : m_data.testsOrTags) {
parser.parse(testOrTags);
}
}
m_testSpec = parser.testSpec();
}
@@ -57,13 +66,17 @@ namespace Catch {
ShowDurations::OrNot Config::showDurations() const { return m_data.showDurations; }
RunTests::InWhatOrder Config::runOrder() const { return m_data.runOrder; }
unsigned int Config::rngSeed() const { return m_data.rngSeed; }
int Config::benchmarkResolutionMultiple() const { return m_data.benchmarkResolutionMultiple; }
UseColour::YesOrNo Config::useColour() const { return m_data.useColour; }
bool Config::shouldDebugBreak() const { return m_data.shouldDebugBreak; }
int Config::abortAfter() const { return m_data.abortAfter; }
bool Config::showInvisibles() const { return m_data.showInvisibles; }
Verbosity Config::verbosity() const { return m_data.verbosity; }
bool Config::benchmarkNoAnalysis() const { return m_data.benchmarkNoAnalysis; }
int Config::benchmarkSamples() const { return m_data.benchmarkSamples; }
double Config::benchmarkConfidenceInterval() const { return m_data.benchmarkConfidenceInterval; }
unsigned int Config::benchmarkResamples() const { return m_data.benchmarkResamples; }
IStream const* Config::openStream() {
return Catch::makeStream(m_data.outputFilename);
}

View File

@@ -42,7 +42,11 @@ namespace Catch {
int abortAfter = -1;
unsigned int rngSeed = 0;
int benchmarkResolutionMultiple = 100;
bool benchmarkNoAnalysis = false;
unsigned int benchmarkSamples = 100;
double benchmarkConfidenceInterval = 0.95;
unsigned int benchmarkResamples = 100000;
Verbosity verbosity = Verbosity::Normal;
WarnAbout::What warnings = WarnAbout::Nothing;
@@ -85,7 +89,7 @@ namespace Catch {
std::vector<std::string> const& getTestsOrTags() const override;
std::vector<std::string> const& getSectionsToRun() const override;
virtual TestSpec const& testSpec() const override;
TestSpec const& testSpec() const override;
bool hasTestFilters() const override;
bool showHelp() const;
@@ -100,12 +104,15 @@ namespace Catch {
ShowDurations::OrNot showDurations() const override;
RunTests::InWhatOrder runOrder() const override;
unsigned int rngSeed() const override;
int benchmarkResolutionMultiple() const override;
UseColour::YesOrNo useColour() const override;
bool shouldDebugBreak() const override;
int abortAfter() const override;
bool showInvisibles() const override;
Verbosity verbosity() const override;
bool benchmarkNoAnalysis() const override;
int benchmarkSamples() const override;
double benchmarkConfidenceInterval() const override;
unsigned int benchmarkResamples() const override;
private:

View File

@@ -69,7 +69,7 @@ namespace {
originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY );
}
virtual void use( Colour::Code _colourCode ) override {
void use( Colour::Code _colourCode ) override {
switch( _colourCode ) {
case Colour::None: return setTextAttribute( originalForegroundAttributes );
case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
@@ -132,7 +132,7 @@ namespace {
// https://github.com/philsquared/Catch/pull/131
class PosixColourImpl : public IColourImpl {
public:
virtual void use( Colour::Code _colourCode ) override {
void use( Colour::Code _colourCode ) override {
switch( _colourCode ) {
case Colour::None:
case Colour::White: return setColour( "[0m" );
@@ -222,7 +222,13 @@ namespace Catch {
void Colour::use( Code _colourCode ) {
static IColourImpl* impl = platformColourInstance();
impl->use( _colourCode );
// Strictly speaking, this cannot possibly happen.
// However, under some conditions it does happen (see #1626),
// and this change is small enough that we can let practicality
// triumph over purity in this case.
if (impl != NULL) {
impl->use( _colourCode );
}
}
std::ostream& operator << ( std::ostream& os, Colour const& ) {

View File

@@ -7,33 +7,34 @@
*/
#include "catch_context.h"
#include "catch_common.h"
#include "catch_random_number_generator.h"
namespace Catch {
class Context : public IMutableContext, NonCopyable {
public: // IContext
virtual IResultCapture* getResultCapture() override {
IResultCapture* getResultCapture() override {
return m_resultCapture;
}
virtual IRunner* getRunner() override {
IRunner* getRunner() override {
return m_runner;
}
virtual IConfigPtr const& getConfig() const override {
IConfigPtr const& getConfig() const override {
return m_config;
}
virtual ~Context() override;
~Context() override;
public: // IMutableContext
virtual void setResultCapture( IResultCapture* resultCapture ) override {
void setResultCapture( IResultCapture* resultCapture ) override {
m_resultCapture = resultCapture;
}
virtual void setRunner( IRunner* runner ) override {
void setRunner( IRunner* runner ) override {
m_runner = runner;
}
virtual void setConfig( IConfigPtr const& config ) override {
void setConfig( IConfigPtr const& config ) override {
m_config = config;
}
@@ -59,4 +60,11 @@ namespace Catch {
IContext::~IContext() = default;
IMutableContext::~IMutableContext() = default;
Context::~Context() = default;
SimplePcg32& rng() {
static SimplePcg32 s_rng;
return s_rng;
}
}

View File

@@ -55,6 +55,9 @@ namespace Catch {
}
void cleanUpContext();
class SimplePcg32;
SimplePcg32& rng();
}
#endif // TWOBLUECUBES_CATCH_CONTEXT_H_INCLUDED

View File

@@ -7,11 +7,21 @@
*/
#include "catch_debug_console.h"
#include "catch_compiler_capabilities.h"
#include "catch_stream.h"
#include "catch_platform.h"
#include "catch_windows_h_proxy.h"
#ifdef CATCH_PLATFORM_WINDOWS
#if defined(CATCH_CONFIG_ANDROID_LOGWRITE)
#include <android/log.h>
namespace Catch {
void writeToDebugConsole( std::string const& text ) {
__android_log_write( ANDROID_LOG_DEBUG, "Catch", text.c_str() );
}
}
#elif defined(CATCH_PLATFORM_WINDOWS)
namespace Catch {
void writeToDebugConsole( std::string const& text ) {

View File

@@ -18,19 +18,23 @@
# include <stdbool.h>
# include <sys/types.h>
# include <unistd.h>
# include <sys/sysctl.h>
# include <cstddef>
# include <ostream>
namespace Catch {
#ifdef __apple_build_version__
// These headers will only compile with AppleClang (XCode)
// For other compilers (Clang, GCC, ... ) we need to exclude them
# include <sys/sysctl.h>
#endif
namespace Catch {
#ifdef __apple_build_version__
// The following function is taken directly from the following technical note:
// http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html
// https://developer.apple.com/library/archive/qa/qa1361/_index.html
// Returns true if the current process is being debugged (either
// running under the debugger or has a debugger attached post facto).
bool isDebuggerActive(){
int mib[4];
struct kinfo_proc info;
std::size_t size;
@@ -60,6 +64,12 @@ namespace Catch {
return ( (info.kp_proc.p_flag & P_TRACED) != 0 );
}
#else
bool isDebuggerActive() {
// We need to find another way to determine this for non-appleclang compilers on macOS
return false;
}
#endif
} // namespace Catch
#elif defined(CATCH_PLATFORM_LINUX)

View File

@@ -7,6 +7,9 @@
#include "catch_enforce.h"
#include <stdexcept>
namespace Catch {
#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS_CUSTOM_HANDLER)
[[noreturn]]
@@ -16,4 +19,22 @@ namespace Catch {
std::terminate();
}
#endif
[[noreturn]]
void throw_logic_error(std::string const& msg) {
throw_exception(std::logic_error(msg));
}
[[noreturn]]
void throw_domain_error(std::string const& msg) {
throw_exception(std::domain_error(msg));
}
[[noreturn]]
void throw_runtime_error(std::string const& msg) {
throw_exception(std::runtime_error(msg));
}
} // namespace Catch;

View File

@@ -11,8 +11,7 @@
#include "catch_compiler_capabilities.h"
#include "catch_stream.h"
#include <stdexcept>
#include <exception>
namespace Catch {
#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
@@ -25,18 +24,30 @@ namespace Catch {
[[noreturn]]
void throw_exception(std::exception const& e);
#endif
[[noreturn]]
void throw_logic_error(std::string const& msg);
[[noreturn]]
void throw_domain_error(std::string const& msg);
[[noreturn]]
void throw_runtime_error(std::string const& msg);
} // namespace Catch;
#define CATCH_PREPARE_EXCEPTION( type, msg ) \
type( ( Catch::ReusableStringStream() << msg ).str() )
#define CATCH_INTERNAL_ERROR( msg ) \
Catch::throw_exception(CATCH_PREPARE_EXCEPTION( std::logic_error, CATCH_INTERNAL_LINEINFO << ": Internal Catch error: " << msg))
#define CATCH_ERROR( msg ) \
Catch::throw_exception(CATCH_PREPARE_EXCEPTION( std::domain_error, msg ))
#define CATCH_RUNTIME_ERROR( msg ) \
Catch::throw_exception(CATCH_PREPARE_EXCEPTION( std::runtime_error, msg ))
#define CATCH_ENFORCE( condition, msg ) \
do{ if( !(condition) ) CATCH_ERROR( msg ); } while(false)
#define CATCH_MAKE_MSG(...) \
(Catch::ReusableStringStream() << __VA_ARGS__).str()
#define CATCH_INTERNAL_ERROR(...) \
Catch::throw_logic_error(CATCH_MAKE_MSG( CATCH_INTERNAL_LINEINFO << ": Internal Catch2 error: " << __VA_ARGS__))
#define CATCH_ERROR(...) \
Catch::throw_domain_error(CATCH_MAKE_MSG( __VA_ARGS__ ))
#define CATCH_RUNTIME_ERROR(...) \
Catch::throw_runtime_error(CATCH_MAKE_MSG( __VA_ARGS__ ))
#define CATCH_ENFORCE( condition, ... ) \
do{ if( !(condition) ) CATCH_ERROR( __VA_ARGS__ ); } while(false)
#endif // TWOBLUECUBES_CATCH_ENFORCE_H_INCLUDED

View File

@@ -0,0 +1,75 @@
/*
* Created by Phil on 4/4/2019.
* Copyright 2019 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_enum_values_registry.h"
#include "catch_string_manip.h"
#include "catch_stream.h"
#include <map>
#include <cassert>
namespace Catch {
IMutableEnumValuesRegistry::~IMutableEnumValuesRegistry() {}
namespace Detail {
namespace {
// Extracts the actual name part of an enum instance
// In other words, it returns the Blue part of Bikeshed::Colour::Blue
StringRef extractInstanceName(StringRef enumInstance) {
// Find last occurence of ":"
size_t name_start = enumInstance.size();
while (name_start > 0 && enumInstance[name_start - 1] != ':') {
--name_start;
}
return enumInstance.substr(name_start, enumInstance.size() - name_start);
}
}
std::vector<StringRef> parseEnums( StringRef enums ) {
auto enumValues = splitStringRef( enums, ',' );
std::vector<StringRef> parsed;
parsed.reserve( enumValues.size() );
for( auto const& enumValue : enumValues ) {
parsed.push_back(trim(extractInstanceName(enumValue)));
}
return parsed;
}
EnumInfo::~EnumInfo() {}
StringRef EnumInfo::lookup( int value ) const {
for( auto const& valueToName : m_values ) {
if( valueToName.first == value )
return valueToName.second;
}
return "{** unexpected enum value **}"_sr;
}
std::unique_ptr<EnumInfo> makeEnumInfo( StringRef enumName, StringRef allValueNames, std::vector<int> const& values ) {
std::unique_ptr<EnumInfo> enumInfo( new EnumInfo );
enumInfo->m_name = enumName;
enumInfo->m_values.reserve( values.size() );
const auto valueNames = Catch::Detail::parseEnums( allValueNames );
assert( valueNames.size() == values.size() );
std::size_t i = 0;
for( auto value : values )
enumInfo->m_values.push_back({ value, valueNames[i++] });
return enumInfo;
}
EnumInfo const& EnumValuesRegistry::registerEnum( StringRef enumName, StringRef allValueNames, std::vector<int> const& values ) {
m_enumInfos.push_back(makeEnumInfo(enumName, allValueNames, values));
return *m_enumInfos.back();
}
} // Detail
} // Catch

View File

@@ -0,0 +1,35 @@
/*
* Created by Phil on 4/4/2019.
* Copyright 2019 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_ENUMVALUESREGISTRY_H_INCLUDED
#define TWOBLUECUBES_CATCH_ENUMVALUESREGISTRY_H_INCLUDED
#include "catch_interfaces_enum_values_registry.h"
#include <vector>
#include <memory>
namespace Catch {
namespace Detail {
std::unique_ptr<EnumInfo> makeEnumInfo( StringRef enumName, StringRef allValueNames, std::vector<int> const& values );
class EnumValuesRegistry : public IMutableEnumValuesRegistry {
std::vector<std::unique_ptr<EnumInfo>> m_enumInfos;
EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::vector<int> const& values) override;
};
std::vector<StringRef> parseEnums( StringRef enums );
} // Detail
} // Catch
#endif //TWOBLUECUBES_CATCH_ENUMVALUESREGISTRY_H_INCLUDED

View File

@@ -19,7 +19,7 @@ namespace Catch {
public:
~ExceptionTranslatorRegistry();
virtual void registerTranslator( const IExceptionTranslator* translator );
virtual std::string translateActiveException() const override;
std::string translateActiveException() const override;
std::string tryTranslators() const;
private:

View File

@@ -97,7 +97,7 @@ namespace Catch {
// 32kb for the alternate stack seems to be sufficient. However, this value
// is experimentally determined, so that's not guaranteed.
constexpr static std::size_t sigStackSize = 32768 >= MINSIGSTKSZ ? 32768 : MINSIGSTKSZ;
static constexpr std::size_t sigStackSize = 32768 >= MINSIGSTKSZ ? 32768 : MINSIGSTKSZ;
static SignalDefs signalDefs[] = {
{ SIGINT, "SIGINT - Terminal interrupt signal" },

View File

@@ -70,6 +70,9 @@ namespace Generators {
template<typename T>
class FixedValuesGenerator final : public IGenerator<T> {
static_assert(!std::is_same<T, bool>::value,
"FixedValuesGenerator does not support bools because of std::vector<bool>"
"specialization, use SingleValue Generator instead.");
std::vector<T> m_values;
size_t m_idx = 0;
public:

View File

@@ -91,6 +91,9 @@ namespace Generators {
template <typename T>
class RepeatGenerator : public IGenerator<T> {
static_assert(!std::is_same<T, bool>::value,
"RepeatGenerator currently does not support bools"
"because of std::vector<bool> specialization");
GeneratorWrapper<T> m_generator;
mutable std::vector<T> m_returned;
size_t m_target_repeats;
@@ -205,12 +208,14 @@ namespace Generators {
m_chunk_size(size), m_generator(std::move(generator))
{
m_chunk.reserve(m_chunk_size);
m_chunk.push_back(m_generator.get());
for (size_t i = 1; i < m_chunk_size; ++i) {
if (!m_generator.next()) {
Catch::throw_exception(GeneratorException("Not enough values to initialize the first chunk"));
}
if (m_chunk_size != 0) {
m_chunk.push_back(m_generator.get());
for (size_t i = 1; i < m_chunk_size; ++i) {
if (!m_generator.next()) {
Catch::throw_exception(GeneratorException("Not enough values to initialize the first chunk"));
}
m_chunk.push_back(m_generator.get());
}
}
}
std::vector<T> const& get() const override {

View File

@@ -10,6 +10,7 @@
#include "catch_context.h"
#include "catch_generators.hpp"
#include "catch_interfaces_config.h"
#include "catch_random_number_generator.h"
#include <random>
@@ -18,14 +19,13 @@ namespace Generators {
template <typename Float>
class RandomFloatingGenerator final : public IGenerator<Float> {
// FIXME: What is the right seed?
std::minstd_rand m_rand;
Catch::SimplePcg32& m_rng;
std::uniform_real_distribution<Float> m_dist;
Float m_current_number;
public:
RandomFloatingGenerator(Float a, Float b):
m_rand(getCurrentContext().getConfig()->rngSeed()),
m_rng(rng()),
m_dist(a, b) {
static_cast<void>(next());
}
@@ -34,20 +34,20 @@ public:
return m_current_number;
}
bool next() override {
m_current_number = m_dist(m_rand);
m_current_number = m_dist(m_rng);
return true;
}
};
template <typename Integer>
class RandomIntegerGenerator final : public IGenerator<Integer> {
std::minstd_rand m_rand;
Catch::SimplePcg32& m_rng;
std::uniform_int_distribution<Integer> m_dist;
Integer m_current_number;
public:
RandomIntegerGenerator(Integer a, Integer b):
m_rand(getCurrentContext().getConfig()->rngSeed()),
m_rng(rng()),
m_dist(a, b) {
static_cast<void>(next());
}
@@ -56,7 +56,7 @@ public:
return m_current_number;
}
bool next() override {
m_current_number = m_dist(m_rand);
m_current_number = m_dist(m_rng);
return true;
}
};
@@ -128,6 +128,46 @@ GeneratorWrapper<T> range(T const& start, T const& end) {
}
template <typename T>
class IteratorGenerator final : public IGenerator<T> {
static_assert(!std::is_same<T, bool>::value,
"IteratorGenerator currently does not support bools"
"because of std::vector<bool> specialization");
std::vector<T> m_elems;
size_t m_current = 0;
public:
template <typename InputIterator, typename InputSentinel>
IteratorGenerator(InputIterator first, InputSentinel last):m_elems(first, last) {
if (m_elems.empty()) {
Catch::throw_exception(GeneratorException("IteratorGenerator received no valid values"));
}
}
T const& get() const override {
return m_elems[m_current];
}
bool next() override {
++m_current;
return m_current != m_elems.size();
}
};
template <typename InputIterator,
typename InputSentinel,
typename ResultType = typename std::iterator_traits<InputIterator>::value_type>
GeneratorWrapper<ResultType> from_range(InputIterator from, InputSentinel to) {
return GeneratorWrapper<ResultType>(pf::make_unique<IteratorGenerator<ResultType>>(from, to));
}
template <typename Container,
typename ResultType = typename Container::value_type>
GeneratorWrapper<ResultType> from_range(Container const& cnt) {
return GeneratorWrapper<ResultType>(pf::make_unique<IteratorGenerator<ResultType>>(cnt.begin(), cnt.end()));
}
} // namespace Generators
} // namespace Catch

View File

@@ -9,6 +9,7 @@
#define TWOBLUECUBES_CATCH_INTERFACES_CAPTURE_H_INCLUDED
#include <string>
#include <chrono>
#include "catch_stringref.h"
#include "catch_result_type.h"
@@ -22,14 +23,18 @@ namespace Catch {
struct MessageInfo;
struct MessageBuilder;
struct Counts;
struct BenchmarkInfo;
struct BenchmarkStats;
struct AssertionReaction;
struct SourceLineInfo;
struct ITransientExpression;
struct IGeneratorTracker;
#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
struct BenchmarkInfo;
template <typename Duration = std::chrono::duration<double, std::nano>>
struct BenchmarkStats;
#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
struct IResultCapture {
virtual ~IResultCapture();
@@ -41,8 +46,12 @@ namespace Catch {
virtual auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& = 0;
#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
virtual void benchmarkPreparing( std::string const& name ) = 0;
virtual void benchmarkStarting( BenchmarkInfo const& info ) = 0;
virtual void benchmarkEnded( BenchmarkStats const& stats ) = 0;
virtual void benchmarkEnded( BenchmarkStats<> const& stats ) = 0;
virtual void benchmarkFailed( std::string const& error ) = 0;
#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
virtual void pushScopedMessage( MessageInfo const& message ) = 0;
virtual void popScopedMessage( MessageInfo const& message ) = 0;

View File

@@ -1,4 +1,4 @@
#include "internal/catch_interfaces_config.h"
#include "catch_interfaces_config.h"
namespace Catch {
IConfig::~IConfig() = default;

View File

@@ -9,6 +9,7 @@
#define TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED
#include "catch_common.h"
#include "catch_option.hpp"
#include <iosfwd>
#include <string>
@@ -50,7 +51,7 @@ namespace Catch {
BeforeExit = 2,
BeforeStartAndExit = BeforeStart | BeforeExit
}; };
class TestSpec;
struct IConfig : NonCopyable {
@@ -72,10 +73,14 @@ namespace Catch {
virtual std::vector<std::string> const& getTestsOrTags() const = 0;
virtual RunTests::InWhatOrder runOrder() const = 0;
virtual unsigned int rngSeed() const = 0;
virtual int benchmarkResolutionMultiple() const = 0;
virtual UseColour::YesOrNo useColour() const = 0;
virtual std::vector<std::string> const& getSectionsToRun() const = 0;
virtual Verbosity verbosity() const = 0;
virtual bool benchmarkNoAnalysis() const = 0;
virtual int benchmarkSamples() const = 0;
virtual double benchmarkConfidenceInterval() const = 0;
virtual unsigned int benchmarkResamples() const = 0;
};
using IConfigPtr = std::shared_ptr<IConfig const>;

View File

@@ -0,0 +1,46 @@
/*
* Created by Phil on 4/4/2019.
* Copyright 2019 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_INTERFACESENUMVALUESREGISTRY_H_INCLUDED
#define TWOBLUECUBES_CATCH_INTERFACESENUMVALUESREGISTRY_H_INCLUDED
#include "catch_stringref.h"
#include <vector>
namespace Catch {
namespace Detail {
struct EnumInfo {
StringRef m_name;
std::vector<std::pair<int, StringRef>> m_values;
~EnumInfo();
StringRef lookup( int value ) const;
};
} // namespace Detail
struct IMutableEnumValuesRegistry {
virtual ~IMutableEnumValuesRegistry();
virtual Detail::EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::vector<int> const& values ) = 0;
template<typename E>
Detail::EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::initializer_list<E> values ) {
static_assert(sizeof(int) >= sizeof(E), "Cannot serialize enum to int");
std::vector<int> intValues;
intValues.reserve( values.size() );
for( auto enumValue : values )
intValues.push_back( static_cast<int>( enumValue ) );
return registerEnum( enumName, allEnums, intValues );
}
};
} // Catch
#endif //TWOBLUECUBES_CATCH_INTERFACESENUMVALUESREGISTRY_H_INCLUDED

View File

@@ -1,4 +1,4 @@
#include "internal/catch_interfaces_exception.h"
#include "catch_interfaces_exception.h"
namespace Catch {
IExceptionTranslator::~IExceptionTranslator() = default;

View File

@@ -1,4 +1,4 @@
#include "internal/catch_interfaces_registry_hub.h"
#include "catch_interfaces_registry_hub.h"
namespace Catch {
IRegistryHub::~IRegistryHub() = default;

View File

@@ -22,6 +22,8 @@ namespace Catch {
struct IReporterRegistry;
struct IReporterFactory;
struct ITagAliasRegistry;
struct IMutableEnumValuesRegistry;
class StartupExceptionRegistry;
using IReporterFactoryPtr = std::shared_ptr<IReporterFactory>;
@@ -32,7 +34,6 @@ namespace Catch {
virtual IReporterRegistry const& getReporterRegistry() const = 0;
virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0;
virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0;
virtual IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const = 0;
@@ -47,6 +48,7 @@ namespace Catch {
virtual void registerTranslator( const IExceptionTranslator* translator ) = 0;
virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) = 0;
virtual void registerStartupException() noexcept = 0;
virtual IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() = 0;
};
IRegistryHub const& getRegistryHub();

View File

@@ -18,12 +18,18 @@
#include "catch_option.hpp"
#include "catch_stringref.h"
#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
#include "benchmark/catch_estimate.hpp"
#include "benchmark/catch_outlier_classification.hpp"
#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
#include <string>
#include <iosfwd>
#include <map>
#include <set>
#include <memory>
#include <algorithm>
namespace Catch {
@@ -159,14 +165,43 @@ namespace Catch {
bool aborting;
};
#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
struct BenchmarkInfo {
std::string name;
double estimatedDuration;
int iterations;
int samples;
unsigned int resamples;
double clockResolution;
double clockCost;
};
template <class Duration>
struct BenchmarkStats {
BenchmarkInfo info;
std::size_t iterations;
uint64_t elapsedTimeInNanoseconds;
std::vector<Duration> samples;
Benchmark::Estimate<Duration> mean;
Benchmark::Estimate<Duration> standardDeviation;
Benchmark::OutlierClassification outliers;
double outlierVariance;
template <typename Duration2>
operator BenchmarkStats<Duration2>() const {
std::vector<Duration2> samples2;
samples2.reserve(samples.size());
std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](Duration d) { return Duration2(d); });
return {
info,
std::move(samples2),
mean,
standardDeviation,
outliers,
outlierVariance,
};
}
};
#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
struct IStreamingReporter {
virtual ~IStreamingReporter() = default;
@@ -185,17 +220,18 @@ namespace Catch {
virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0;
virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0;
// *** experimental ***
#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
virtual void benchmarkPreparing( std::string const& ) {}
virtual void benchmarkStarting( BenchmarkInfo const& ) {}
virtual void benchmarkEnded( BenchmarkStats<> const& ) {}
virtual void benchmarkFailed( std::string const& ) {}
#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0;
// The return value indicates if the messages buffer should be cleared:
virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0;
// *** experimental ***
virtual void benchmarkEnded( BenchmarkStats const& ) {}
virtual void sectionEnded( SectionStats const& sectionStats ) = 0;
virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0;
virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0;

View File

@@ -1,4 +1,4 @@
#include "internal/catch_interfaces_runner.h"
#include "catch_interfaces_runner.h"
namespace Catch {
IRunner::~IRunner() = default;

View File

@@ -1,4 +1,4 @@
#include "internal/catch_interfaces_testcase.h"
#include "catch_interfaces_testcase.h"
namespace Catch {
ITestInvoker::~ITestInvoker() = default;

View File

@@ -28,6 +28,7 @@ namespace Catch {
virtual std::vector<TestCase> const& getAllTestsSorted( IConfig const& config ) const = 0;
};
bool isThrowSafe( TestCase const& testCase, IConfig const& config );
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 );

View File

@@ -84,9 +84,18 @@ namespace Catch {
}
std::string TagInfo::all() const {
std::string out;
for( auto const& spelling : spellings )
out += "[" + spelling + "]";
size_t size = 0;
for (auto const& spelling : spellings) {
// Add 2 for the brackes
size += spelling.size() + 2;
}
std::string out; out.reserve(size);
for (auto const& spelling : spellings) {
out += '[';
out += spelling;
out += ']';
}
return out;
}

View File

@@ -44,6 +44,15 @@ namespace Matchers {
virtual bool match( ObjectT const& arg ) const = 0;
};
#if defined(__OBJC__)
// Hack to fix Catch GH issue #1661. Could use id for generic Object support.
// use of const for Object pointers is very uncommon and under ARC it causes some kind of signature mismatch that breaks compilation
template<>
struct MatcherMethod<NSString*> {
virtual bool match( NSString* arg ) const = 0;
};
#endif
#ifdef __clang__
# pragma clang diagnostic pop
#endif

View File

@@ -0,0 +1,30 @@
/*
* Created by Martin Hořeňovský on 13/10/2019.
*
* 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_exception.hpp"
namespace Catch {
namespace Matchers {
namespace Exception {
bool ExceptionMessageMatcher::match(std::exception const& ex) const {
return ex.what() == m_message;
}
std::string ExceptionMessageMatcher::describe() const {
return "exception message matches \"" + m_message + "\"";
}
}
Exception::ExceptionMessageMatcher Message(std::string const& message) {
return Exception::ExceptionMessageMatcher(message);
}
// namespace Exception
} // namespace Matchers
} // namespace Catch

View File

@@ -0,0 +1,36 @@
/*
* Created by Martin Hořeňovský on 13/10/2019.
*
* 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_EXCEPTION_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_MATCHERS_EXCEPTION_HPP_INCLUDED
#include "catch_matchers.h"
namespace Catch {
namespace Matchers {
namespace Exception {
class ExceptionMessageMatcher : public MatcherBase<std::exception> {
std::string m_message;
public:
ExceptionMessageMatcher(std::string const& message):
m_message(message)
{}
bool match(std::exception const& ex) const override;
std::string describe() const override;
};
} // namespace Exception
Exception::ExceptionMessageMatcher Message(std::string const& message);
} // namespace Matchers
} // namespace Catch
#endif // TWOBLUECUBES_CATCH_MATCHERS_EXCEPTION_HPP_INCLUDED

View File

@@ -11,75 +11,117 @@
#include "catch_to_string.hpp"
#include "catch_tostring.h"
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <cstdint>
#include <cstring>
#include <sstream>
#include <type_traits>
#include <iomanip>
#include <limits>
namespace Catch {
namespace Matchers {
namespace Floating {
enum class FloatingPointKind : uint8_t {
Float,
Double
};
}
}
namespace {
int32_t convert(float f) {
static_assert(sizeof(float) == sizeof(int32_t), "Important ULP matcher assumption violated");
int32_t i;
std::memcpy(&i, &f, sizeof(f));
return i;
}
int64_t convert(double d) {
static_assert(sizeof(double) == sizeof(int64_t), "Important ULP matcher assumption violated");
int64_t i;
std::memcpy(&i, &d, sizeof(d));
return i;
}
template <typename FP>
bool almostEqualUlps(FP lhs, FP rhs, uint64_t maxUlpDiff) {
// Comparison with NaN should always be false.
// This way we can rule it out before getting into the ugly details
if (Catch::isnan(lhs) || Catch::isnan(rhs)) {
return false;
}
auto lc = convert(lhs);
auto rc = convert(rhs);
if ((lc < 0) != (rc < 0)) {
// Potentially we can have +0 and -0
return lhs == rhs;
}
auto ulpDiff = std::abs(lc - rc);
return static_cast<uint64_t>(ulpDiff) <= maxUlpDiff;
}
} //end anonymous namespace
#if defined(CATCH_CONFIG_GLOBAL_NEXTAFTER)
#if defined(__clang__)
#pragma clang diagnostic push
// The long double overload is currently unused
#pragma clang diagnostic ignored "-Wunused-function"
#endif
float nextafter(float x, float y) {
return ::nextafterf(x, y);
}
double nextafter(double x, double y) {
return ::nextafter(x, y);
}
long double nextafter(long double x, long double y) {
return ::nextafterl(x, y);
}
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
#endif // ^^^ CATCH_CONFIG_GLOBAL_NEXTAFTER ^^^
namespace {
template <typename FP>
FP step(FP start, FP direction, uint64_t steps) {
for (uint64_t i = 0; i < steps; ++i) {
#if defined(CATCH_CONFIG_GLOBAL_NEXTAFTER)
start = Catch::nextafter(start, direction);
#else
start = std::nextafter(start, direction);
#endif
}
return start;
}
namespace {
template <typename T>
struct Converter;
template <>
struct Converter<float> {
static_assert(sizeof(float) == sizeof(int32_t), "Important ULP matcher assumption violated");
Converter(float f) {
std::memcpy(&i, &f, sizeof(f));
// Performs equivalent check of std::fabs(lhs - rhs) <= margin
// But without the subtraction to allow for INFINITY in comparison
bool marginComparison(double lhs, double rhs, double margin) {
return (lhs + margin >= rhs) && (rhs + margin >= lhs);
}
int32_t i;
};
template <>
struct Converter<double> {
static_assert(sizeof(double) == sizeof(int64_t), "Important ULP matcher assumption violated");
Converter(double d) {
std::memcpy(&i, &d, sizeof(d));
}
int64_t i;
};
template <typename T>
auto convert(T t) -> Converter<T> {
return Converter<T>(t);
}
template <typename FP>
bool almostEqualUlps(FP lhs, FP rhs, int maxUlpDiff) {
// Comparison with NaN should always be false.
// This way we can rule it out before getting into the ugly details
if (Catch::isnan(lhs) || Catch::isnan(rhs)) {
return false;
}
auto lc = convert(lhs);
auto rc = convert(rhs);
if ((lc.i < 0) != (rc.i < 0)) {
// Potentially we can have +0 and -0
return lhs == rhs;
}
auto ulpDiff = std::abs(lc.i - rc.i);
return ulpDiff <= maxUlpDiff;
}
}
} // end anonymous namespace
namespace Catch {
namespace Matchers {
namespace Floating {
enum class FloatingPointKind : uint8_t {
Float,
Double
};
WithinAbsMatcher::WithinAbsMatcher(double target, double margin)
:m_target{ target }, m_margin{ margin } {
CATCH_ENFORCE(margin >= 0, "Invalid margin: " << margin << '.'
@@ -97,10 +139,11 @@ namespace Floating {
}
WithinUlpsMatcher::WithinUlpsMatcher(double target, int ulps, FloatingPointKind baseType)
WithinUlpsMatcher::WithinUlpsMatcher(double target, uint64_t ulps, FloatingPointKind baseType)
:m_target{ target }, m_ulps{ ulps }, m_type{ baseType } {
CATCH_ENFORCE(ulps >= 0, "Invalid ULP setting: " << ulps << '.'
<< " ULPs have to be non-negative.");
CATCH_ENFORCE(m_type == FloatingPointKind::Double
|| m_ulps < std::numeric_limits<uint32_t>::max(),
"Provided ULP is impossibly large for a float comparison.");
}
#if defined(__clang__)
@@ -125,18 +168,59 @@ namespace Floating {
#endif
std::string WithinUlpsMatcher::describe() const {
return "is within " + Catch::to_string(m_ulps) + " ULPs of " + ::Catch::Detail::stringify(m_target) + ((m_type == FloatingPointKind::Float)? "f" : "");
std::stringstream ret;
ret << "is within " << m_ulps << " ULPs of " << ::Catch::Detail::stringify(m_target);
if (m_type == FloatingPointKind::Float) {
ret << 'f';
}
ret << " ([";
ret << std::fixed << std::setprecision(std::numeric_limits<double>::max_digits10);
if (m_type == FloatingPointKind::Double) {
ret << step(m_target, static_cast<double>(-INFINITY), m_ulps)
<< ", "
<< step(m_target, static_cast<double>(INFINITY), m_ulps);
} else {
ret << step<float>(static_cast<float>(m_target), -INFINITY, m_ulps)
<< ", "
<< step<float>(static_cast<float>(m_target), INFINITY, m_ulps);
}
ret << "])";
return ret.str();
//return "is within " + Catch::to_string(m_ulps) + " ULPs of " + ::Catch::Detail::stringify(m_target) + ((m_type == FloatingPointKind::Float)? "f" : "");
}
WithinRelMatcher::WithinRelMatcher(double target, double epsilon):
m_target(target),
m_epsilon(epsilon){
CATCH_ENFORCE(m_epsilon >= 0., "Relative comparison with epsilon < 0 does not make sense.");
CATCH_ENFORCE(m_epsilon < 1., "Relative comparison with epsilon >= 1 does not make sense.");
}
bool WithinRelMatcher::match(double const& matchee) const {
const auto relMargin = m_epsilon * std::max(std::fabs(matchee), std::fabs(m_target));
return marginComparison(matchee, m_target,
std::isinf(relMargin)? 0 : relMargin);
}
std::string WithinRelMatcher::describe() const {
Catch::ReusableStringStream sstr;
sstr << "and " << m_target << " are within " << m_epsilon * 100. << "% of each other";
return sstr.str();
}
}// namespace Floating
Floating::WithinUlpsMatcher WithinULP(double target, int maxUlpDiff) {
Floating::WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff) {
return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Double);
}
Floating::WithinUlpsMatcher WithinULP(float target, int maxUlpDiff) {
Floating::WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff) {
return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Float);
}
@@ -144,6 +228,23 @@ Floating::WithinAbsMatcher WithinAbs(double target, double margin) {
return Floating::WithinAbsMatcher(target, margin);
}
Floating::WithinRelMatcher WithinRel(double target, double eps) {
return Floating::WithinRelMatcher(target, eps);
}
Floating::WithinRelMatcher WithinRel(double target) {
return Floating::WithinRelMatcher(target, std::numeric_limits<double>::epsilon() * 100);
}
Floating::WithinRelMatcher WithinRel(float target, float eps) {
return Floating::WithinRelMatcher(target, eps);
}
Floating::WithinRelMatcher WithinRel(float target) {
return Floating::WithinRelMatcher(target, std::numeric_limits<float>::epsilon() * 100);
}
} // namespace Matchers
} // namespace Catch

View File

@@ -9,9 +9,6 @@
#include "catch_matchers.h"
#include <type_traits>
#include <cmath>
namespace Catch {
namespace Matchers {
@@ -29,23 +26,43 @@ namespace Matchers {
};
struct WithinUlpsMatcher : MatcherBase<double> {
WithinUlpsMatcher(double target, int ulps, FloatingPointKind baseType);
WithinUlpsMatcher(double target, uint64_t ulps, FloatingPointKind baseType);
bool match(double const& matchee) const override;
std::string describe() const override;
private:
double m_target;
int m_ulps;
uint64_t m_ulps;
FloatingPointKind m_type;
};
// Given IEEE-754 format for floats and doubles, we can assume
// that float -> double promotion is lossless. Given this, we can
// assume that if we do the standard relative comparison of
// |lhs - rhs| <= epsilon * max(fabs(lhs), fabs(rhs)), then we get
// the same result if we do this for floats, as if we do this for
// doubles that were promoted from floats.
struct WithinRelMatcher : MatcherBase<double> {
WithinRelMatcher(double target, double epsilon);
bool match(double const& matchee) const override;
std::string describe() const override;
private:
double m_target;
double m_epsilon;
};
} // namespace Floating
// The following functions create the actual matcher objects.
// This allows the types to be inferred
Floating::WithinUlpsMatcher WithinULP(double target, int maxUlpDiff);
Floating::WithinUlpsMatcher WithinULP(float target, int maxUlpDiff);
Floating::WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff);
Floating::WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff);
Floating::WithinAbsMatcher WithinAbs(double target, double margin);
Floating::WithinRelMatcher WithinRel(double target, double eps);
// defaults epsilon to 100*numeric_limits<double>::epsilon()
Floating::WithinRelMatcher WithinRel(double target);
Floating::WithinRelMatcher WithinRel(float target, float eps);
// defaults epsilon to 100*numeric_limits<float>::epsilon()
Floating::WithinRelMatcher WithinRel(float target);
} // namespace Matchers
} // namespace Catch

View File

@@ -45,7 +45,7 @@ public:
// The following functions create the actual matcher objects.
// The user has to explicitly specify type to the function, because
// infering std::function<bool(T const&)> is hard (but possible) and
// inferring std::function<bool(T const&)> is hard (but possible) and
// requires a lot of TMP.
template<typename T>
Generic::PredicateMatcher<T> Predicate(std::function<bool(T const&)> const& predicate, std::string const& description = "") {

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