Compare commits

..

78 Commits

Author SHA1 Message Date
Martin Hořeňovský
03d122a35c v2.4.2 2018-10-26 21:14:16 +02:00
Martin Hořeňovský
1d9b506e39 Add documentation for some miscellaneous and less important macros
Fixes #1367
2018-10-26 20:50:32 +02:00
Martin Hořeňovský
779e83bc20 Update Clara to v1.1.5 to fix TextFlow bugs 2018-10-26 18:48:28 +02:00
Stephane Del Pino
544c7d7cbf Add the optional variable OptionalCatchTestLauncher
This variable is set to allow the use of the nice ParseAndAddCatchTests script
in the case where a launcher is needed to execute  the script.

This is introduced to allow to launch unit tests using mpi. In this case one can
write for instance
  set(OptionalCatchTestLauncher ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${NUMPROC})
before calling the ParseAndAddCatchTests function.
2018-10-25 15:51:15 +02:00
Maciej Patro
8b3c09c137 Catch's CLI now checks whether requested reporter exists
Fixes #1351
2018-10-25 15:43:30 +02:00
Maciej Patro
b7f41237b1 Remove unused parameter from listReporters() 2018-10-25 15:43:30 +02:00
MaciejPatro
1faccd601d Improve path normalization for approvalTests.py
This fixes 3 problems:

* Relative paths on Windows are now supported
* Out-of-tree (paths starting with ../) builds are now supported
* Path separator normalization no longer affects non-path components of input (problem with Compact reporter)


Fixes #1379 
Fixes #1222 
Fixes #1200 
Fixes #1194
2018-10-19 12:46:06 +02:00
Jozef Grajciar
ab98afe68b Catch::LeakDetector: added cleanup call to destructor
simple code with provided main function which just returns 0
leaks memory due to fact that singletons are not cleaned up

running valgrind on such simple application reports that 752 bytes
are still available in 11 blocks

this commit adds destructor to Catch::LeakDetector which calls
Catch::cleanUp()
2018-10-18 11:47:21 +02:00
Martin Hořeňovský
054d356332 Add STATIC_REQUIRE assertion
By default, it expands into a `static_assert` + `SUCCEED` pair, but
it can also be deferred to runtime by defining
`CATCH_CONFIG_RUNTIME_STATIC_REQUIRE`, which causes it to expand
into plain old `REQUIRE`.

Closes #1362
Closes #1356
2018-10-16 16:16:00 +02:00
Maciej Patro
0144ae9ad2 Fix catch_discover_tests() - now should correctly find tests with commas | Related to #1327 2018-10-16 16:06:31 +02:00
JoeyGrajciar
e1307016f0 Session::applyCommandLine overload on wchar_t (#1401)
* Session::applyCommandLine overload on wchar_t

This allows users on Windows to use Catch::Session::applyCommandLine
with wchar_t * arguments of application.

With this change Session::run became templated so both char and wchar_t
version have the same implementation.
2018-10-13 19:29:53 +02:00
Martin Hořeňovský
6b9ca0888a Add tests for #1404 2018-10-13 16:53:44 +02:00
Jozef Grajciar
9f8b848fe5 XmlReporter: add information about rng-seed
Xml result of reported will now contain value of rng-seed in case it
is not zero.
The value will be stored in element Randomness and it's attribute seed.

Relates to #1402
2018-10-13 16:53:44 +02:00
Martin Hořeňovský
aaaac35d92 Add tests for #1403 2018-10-13 16:53:30 +02:00
Eddie
6cede0101a Fix different operator<< overload sets used for SFINAE and insertion 2018-10-13 16:53:30 +02:00
Miguel Gaio
f1faaa9c10 Fix convert from char on ARM build
Some platforms set the signedness of char to unsigned (eg. ARM).
Convert from char should not assume the signedness of char.

Fix build issue with -Werror,-Wtautological-unsigned-zero-compare flags.

Signed-off-by: Miguel Gaio <mgaio35@gmail.com>
2018-10-13 12:56:05 +02:00
Martin Hořeňovský
9e1bdca466 v2.4.1 2018-09-28 15:52:51 +02:00
Martin Hořeňovský
be49a539e4 Fix a bug in UnorderedEqualsMatcher
Previously a mismatched prefix would be skipped before the actual
comparison would be performed. Obviously, it is supposed to be
_matching_ prefix that is skipped.
2018-09-28 15:30:02 +02:00
Martin Moene
558bbe7d24 Add example for TeamCity reporter and refer to it
Prevent warnings
- gnu: -Wcomment: multi-line comment
- clang: -Wweak-vtables 'class' has no out-of-line virtual method definitions; its vtable will be emitted in every translation unit
- clang: -Winconsistent-missing-override: 'method' overrides a member function but is not marked 'override'
- MSVC: C4702: unreachable code
2018-09-27 23:20:02 +02:00
wimo7083
f4881f172a prevent cygwin to_string compiler error 2018-09-27 20:56:27 +02:00
Mike Cowan
de06340e7d Abort when total assertions failed is greater than or equal to configured value 2018-09-22 22:39:08 +02:00
Martin Hořeňovský
4dd6e81d0f Update "Known limitations" section of documentation
This fixes some wording that implies C++98 standard, updates
the recommended solution to looped SECTION macros and mentioned
the "last section failed, test needs to be rerun" problem.

Related to #1367
Related to #1384
Related to #1389
2018-09-21 21:03:14 +02:00
Martin Hořeňovský
9e6d7bbf00 Add documentation for installing Catch from the repository
This might prove helpful when the package managers either doesn't
have Catch at all, or provides it in obsolete version (Ubuntu 16.04,
I am looking at you).

Closes #1383
2018-09-21 20:48:18 +02:00
Martin Hořeňovský
dfb025cf08 Change wording of Approx documentation to be less misleading
The "percentage" suggests that the expected epsilon can be in
[0, 100], but the expected values are in [0, 1]. The new wording
uses "coefficient", to make it clearer that we are talking about
values in [0, 1].

Closes #1388
2018-09-21 20:04:56 +02:00
melak47
c638c57209 Add StringMaker for std::variant, std::monostate (#1380)
The StringMaker is off by default and can be enabled by a new macro `CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER`, to avoid increasing the footprint of stringification machinery by default.
2018-09-20 14:13:35 +02:00
melak47
a575536abe Add StringMaker for std::(w)string_view
Fixes #1375
2018-09-10 11:37:26 +02:00
Martin Hořeňovský
1eb42eed97 Add C++17 builds to Travis 2018-09-10 09:30:09 +02:00
Martin Hořeňovský
46e99e258f Fixup TOC script sluggification and documentation 2018-09-09 17:09:57 +02:00
Martin Hořeňovský
a212fb440b Merge branch 'dev-appveyor-fixup-coverage-scripts' 2018-09-09 11:37:17 +02:00
Martin Hořeňovský
1e98c820bb Simplify the Appveyor configuration batch script 2018-09-09 10:18:30 +02:00
Martin Hořeňovský
bcfa9b1775 Properly exit appveyor batch scripts on error 2018-09-09 10:18:29 +02:00
Martin Hořeňovský
a3876adba6 Fix CTest regex error
The desired behaviour was to match a literal "[.]", so the regex
has to be escaped as "\\[\\.\\]" -- double backslashes, because
it has to be escaped from CMake as well as from the regex engine.
2018-09-09 10:17:08 +02:00
Martin Hořeňovský
2a4725b40e Enable some more generator tests in standard test run 2018-09-08 18:23:38 +02:00
Martin Moene
a81c01d4f9 Updated documentation TOCs 2018-09-08 11:05:52 +02:00
Martin Hořeňovský
60b05b2041 v2.4.0 2018-09-04 11:59:15 +02:00
Martin Hořeňovský
232ea3c456 Add documentation for no-exception support
Closes #703
Closes #1358
2018-09-04 10:06:31 +02:00
Martin Hořeňovský
a5c900d077 Add ExtraTest for CATCH_CONFIG_DISABLE 2018-09-04 10:06:30 +02:00
Martin Hořeňovský
8b01883854 Add support for -fno-exceptions (or equivalent)
This means

* Adding new configuration toggle `CATCH_CONFIG_DISABLE_EXCEPTIONS`
and a best-guess configuration auto-checking for it.
* Adding new set of internal macros, `CATCH_TRY`, `CATCH_CATCH_ALL`
and `CATCH_CATCH_ANON` that can be used in place of regular `try`,
`catch(...)` and `catch(T const&)` respectively, while disappearing
when `CATCH_CONFIG_DISABLE_EXCEPTIONS` is enabled.
* Replacing all uses of `throw` with calls to `Catch::throw_exception`
customization point.
* Providing a default implementation for the above customization point
when `CATCH_CONFIG_DISABLE_EXCEPTIONS` is set.
* Letting users override this implementation with their own.
* Some minor changes and ifdefs all around to support the above
2018-09-03 21:08:27 +02:00
Martin Hořeňovský
86da2846af Replace most naked throws with macros from catch_enforce.h
This is a first step towards support a no-exceptions mode
2018-09-03 18:07:34 +02:00
Martin Hořeňovský
ef9150fe6f Directly set Approx's members in operator()
This avoids instantiating the member-setting function template
and checking the invariants in cases where we know the invariant
already holds.
2018-09-03 10:20:58 +02:00
Martin Hořeňovský
84fa76e985 Move Approx's validity checks out of line into cpp file
This avoids having to include <stdexcept> in the main include path
and speeds up the compilation if Approx is used with multiple
different types.
2018-09-03 10:15:51 +02:00
Martin Hořeňovský
fcd91c7d6b Only look for Python binary when building tests
Fixes #1374
2018-09-02 18:55:17 +02:00
Martin Hořeňovský
efbf50fc7d Add test for AND_GIVEN and update the baselines 2018-09-02 16:53:57 +02:00
Matthew Parnell
64fd5b8058 Add BDD AND_GIVEN based macros
issue #1360

It is possible to have multple  given contexts in a single BDD scenario;
if you have to type 'and' in the GIVEN description; it's very likely you
need an AND.

A generic AND  is not possible, thus a AND_GIVEN  is added to complement
the AND_WHEN and AND_THEN.

Can be used without needing to increase indent:

	SCENARIO("...") {
		GIVEN("...")
		AND_GIVEN("...") {
			WHEN("...") {
				THEN("...") {
					// ...
				}
			}
		}
	}

would correctly output, when requested/needed:

    Given: ...
And given: ...
     When: ...
     Then: ...

The padding had to be increased by a character in the output message, to
continue to be uniform.
2018-09-02 16:53:57 +02:00
Martin Hořeňovský
ee73989f9b Suppress Wunreachable-code in floating matchers and exception tests
Closes #1350
2018-09-01 22:34:29 +02:00
Martin Hořeňovský
646e1f608d Make Catch2ConfigVersion.cmake be generated as arch-independent
As it turns out, there is a fairly reasonable workaround available.

Closes #1368
2018-09-01 21:51:49 +02:00
Martin Hořeňovský
6f75acbfb5 Add tests for CATCH_CONFIG_DISABLE 2018-09-01 17:28:06 +02:00
Martin Hořeňovský
9c3cc4a076 Add test for CATCH_CONFIG_PREFIX_ALL 2018-09-01 15:01:51 +02:00
Martin Hořeňovský
f3972f0695 Add test for CATCH_CONFIG_DISABLE_STRINGIFICATION 2018-08-31 21:27:35 +02:00
Martin Hořeňovský
38e1731f69 Build ExtraTests when building Examples on AppVeyor 2018-08-31 18:32:23 +02:00
Martin Hořeňovský
0947752a44 Avoid running C++17 tests as part of approvals on VS 2017 2018-08-31 18:25:42 +02:00
Martin Hořeňovský
0646e0283c Disable installation step when Catch is used as a subproject
This is because otherwise the installations paths provided via
GNUInstallDirs become messed up and parts of the installation
package will end up in the wrong place.

Also it doesn't make much sense to force dependees to also install
our header alongside them.

Closes #1373
2018-08-31 11:43:09 +02:00
Axel Huebl
90663b2e75 Tests: Spaces & TABs
Fix TABs and none-PEP8 spaces in approval test.
Does not yet fix overlong lines for full `flake8` compliance.
2018-08-29 18:28:27 +02:00
Axel Huebl
7667a7d89c Docs: TABs to Spaces
Replace TABs with four (4) spaces in code docs.
2018-08-29 18:05:22 +02:00
Axel Huebl
9773d89ab4 Code: TABs to Spaces
Replace TABs with four (4) spaces in source files.
2018-08-29 14:59:11 +02:00
George Fotopoulos
2067c8d3bd Update opensource-users.md
Add "thor"
Update "forest" description
2018-08-29 14:51:17 +02:00
Martin Hořeňovský
1742ab76a2 No longer allow failures for VS2017 on AppVeyor 2018-08-29 13:39:24 +02:00
Martin Hořeňovský
898d111f72 Fix generateSingleHeader.py to properly copy utf-8 2018-08-29 12:52:29 +02:00
Martin Hořeňovský
5202993555 Fix VS2017 approvals on AppVeyor
Because of a change in VS toolset, missing option <UseFullPaths>
is no longer interpreted as "don't pass /FC to the compiler", but
rather as "pass /FC to the compiler". This is problematic, because
/FC not only changes how much of the path is reporter by the compiler
(e.g. in `__FILE__` macro), but it also lower cases the path.

This lower-casing of the path broke our approval tests for VS2017
about 5 months ago.

Using CMake 3.13 (not yet released) would also let us fix it, but
for now we use a vcxproj.user file that is merged with the main project
and explicitly disables `/FC`.
2018-08-28 12:58:08 +02:00
Martin Hořeňovský
f061dabbad Add ExtraTests infrastructure
This means
* a new cmake option, `CATCH_BUILD_EXTRA_TESTS`, that conditionally
includes the ExtraTests subfolder
* building and running them on some of the Travis build images
* An example configuration test

In the future these should be extended to cover most of the
configuration options in Catch2, but this is a start.
2018-08-28 12:57:20 +02:00
Martin Hořeňovský
1a501fcb48 Fix examples compilation for some combinations of Clang and libstdc++ 2018-08-28 10:12:53 +02:00
Martin Hořeňovský
94121a5f6d Add a basic documentation for generators 2018-08-24 13:34:27 +02:00
Martin Hořeňovský
92e25049cf Move all<int> to .cpp file to remove <limits> from common path 2018-08-24 13:34:03 +02:00
Martin Hořeňovský
fdcd46420e Update baselines 2018-08-24 13:31:51 +02:00
Phil Nash
7c25dae9ea First attempt at data generator support
The support is to be considered experimental, that is, the interfaces,
the first party generators and helper functions can change or be removed
at any point in time.

Related to #850
2018-08-24 13:31:51 +02:00
David Seifert
7f18282d17 Allow overriding of Python interpreter
* Calling `python` does not allow overriding
  downstream when running tests.
2018-08-20 14:52:54 +02:00
Phil Nash
1cdaa48a0b CAPTURE is now variadic 2018-08-19 22:40:20 +02:00
Phil Nash
1a63fad8d6 Seed the RNG in approval tests 2018-08-19 22:34:14 +02:00
Phil Nash
d6f2fd486c Moved ReusableStringStream impl to generic singleton 2018-08-19 11:28:46 +02:00
Phil Nash
5884ec1e28 Moved registry hub to generic singleton 2018-08-19 11:13:19 +02:00
Phil Nash
eb783fc20e Added generic singletons facility
<sigh> yes, I know - but we have them - may as well make them consistent and safer
2018-08-19 10:34:44 +02:00
Igor Murashkin
38248f3f2c Add pragma ignore for -Wnon-virtual-dtor in Catch matchers 2018-08-17 17:14:56 +02:00
Martin Hořeňovský
c9de7dd12d Optimize SourceLineInfo::operator< with short-circuiting
In case of 2 instances of SourceLineInfo constructed in the same
file, they will have the same `file` pointer (even at O0). Thus, we
can check if they are equal before calling potentially pointless
`strcmp`.
2018-07-23 20:46:42 +02:00
Martin Hořeňovský
52cbb507ab Avoid copying StringRef
In theory the copy is cheap (couple of pointers change), but tests
are usually compiled in Debug mode/with minimal optimizations, which
means that most users will still have to pay the cost for those
function calls.
2018-07-23 14:04:43 +02:00
Martin Hořeňovský
83bfae1a50 Construct StringRef from constant strings in macros directly using UDL
This avoids having to call `strlen` to get the constant string's length
and thus should improve performance.
2018-07-23 14:00:45 +02:00
Martin Hořeňovský
f7f592dfc9 Introduce "C-namespaced" UDL for StringRef 2018-07-23 14:00:45 +02:00
Martin Hořeňovský
78804ea304 Replace std::string with StringRef in MessageInfo for macro capture
Because the macro name is compile-time constant, we do not have to
worry about lifetimes and will avoid allocation in case of missing
SSO or long macro name.
2018-07-23 14:00:44 +02:00
Martin Hořeňovský
b93284716e Update gitattributes 2018-07-23 10:15:52 +02:00
114 changed files with 7669 additions and 1424 deletions

2
.gitattributes vendored
View File

@@ -17,6 +17,6 @@
# Keep the single include header with LFs to make sure it is uploaded,
# hashed etc with LF
single_include/*.hpp eol=lf
single_include/**/*.hpp eol=lf
# Also keep the LICENCE file with LFs for the same reason
LICENCE.txt eol=lf

View File

@@ -219,7 +219,7 @@ matrix:
apt:
sources: *all_sources
packages: ['lcov', 'g++-7']
env: COMPILER='g++-7' CPP14=1 EXAMPLES=1 COVERAGE=1
env: COMPILER='g++-7' CPP14=1 EXAMPLES=1 COVERAGE=1 EXTRAS=1
- os: linux
compiler: clang
@@ -229,7 +229,7 @@ matrix:
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty
env: COMPILER='clang++-3.8' EXAMPLES=1 COVERAGE=1
env: COMPILER='clang++-3.8' EXAMPLES=1 COVERAGE=1 EXTRAS=1
- os: linux
compiler: gcc
@@ -237,19 +237,46 @@ matrix:
apt:
sources: *all_sources
packages: ['valgrind', 'lcov', 'g++-7']
env: COMPILER='g++-7' CPP14=1 VALGRIND=1
env: COMPILER='g++-7' CPP14=1 VALGRIND=1
- os: osx
osx_image: xcode9.1
compiler: clang
env: COMPILER='clang++' CPP14=1 EXAMPLES=1 COVERAGE=1
env: COMPILER='clang++' CPP14=1 EXAMPLES=1 COVERAGE=1 EXTRAS=1
# 7/ C++17 builds
- os: linux
compiler: gcc
addons: *gcc7
env: COMPILER='g++-7' CPP17=1
- os: linux
compiler: gcc
addons: *gcc7
env: COMPILER='g++-7' EXAMPLES=1 COVERAGE=1 EXTRAS=1 CPP17=1
- os: linux
compiler: clang
addons:
apt:
sources: *all_sources
packages: ['clang-6.0', 'libstdc++-8-dev']
env: COMPILER='clang++-6.0' CPP17=1
- os: linux
compiler: clang
addons:
apt:
sources: *all_sources
packages: ['clang-6.0', 'libstdc++-8-dev']
env: COMPILER='clang++-6.0' CPP17=1 EXAMPLES=1 COVERAGE=1 EXTRAS=1
install:
- DEPS_DIR="${TRAVIS_BUILD_DIR}/deps"
- mkdir -p ${DEPS_DIR} && cd ${DEPS_DIR}
- |
if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then
CMAKE_URL="http://www.cmake.org/files/v3.5/cmake-3.5.2-Linux-x86_64.tar.gz"
CMAKE_URL="http://cmake.org/files/v3.8/cmake-3.8.2-Linux-x86_64.tar.gz"
mkdir cmake && travis_retry wget --no-check-certificate --quiet -O - ${CMAKE_URL} | tar --strip-components=1 -xz -C cmake
export PATH=${DEPS_DIR}/cmake/bin:${PATH}
elif [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then
@@ -263,7 +290,7 @@ before_script:
- python scripts/generateSingleHeader.py
# Use Debug builds for running Valgrind and building examples
- cmake -H. -BBuild-Debug -DCMAKE_BUILD_TYPE=Debug -Wdev -DUSE_CPP14=${CPP14} -DCATCH_USE_VALGRIND=${VALGRIND} -DCATCH_BUILD_EXAMPLES=${EXAMPLES} -DCATCH_ENABLE_COVERAGE=${COVERAGE}
- 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}
# Don't bother with release build for coverage build
- cmake -H. -BBuild-Release -DCMAKE_BUILD_TYPE=Release -Wdev -DUSE_CPP14=${CPP14}

View File

@@ -6,7 +6,7 @@ if(NOT DEFINED PROJECT_NAME)
set(NOT_SUBPROJECT ON)
endif()
project(Catch2 LANGUAGES CXX VERSION 2.3.0)
project(Catch2 LANGUAGES CXX VERSION 2.4.2)
# Provide path for scripts
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/CMake")
@@ -18,6 +18,7 @@ include(CTest)
option(CATCH_USE_VALGRIND "Perform SelfTests with Valgrind" OFF)
option(CATCH_BUILD_TESTING "Build SelfTest project" ON)
option(CATCH_BUILD_EXAMPLES "Build documentation examples" OFF)
option(CATCH_BUILD_EXTRA_TESTS "Build extra tests" OFF)
option(CATCH_ENABLE_COVERAGE "Generate coverage for codecov.io" OFF)
option(CATCH_ENABLE_WERROR "Enable all warnings as errors" ON)
option(CATCH_INSTALL_DOCS "Install documentation alongside library" ON)
@@ -37,6 +38,10 @@ if(USE_WMAIN)
endif()
if (BUILD_TESTING AND CATCH_BUILD_TESTING AND NOT_SUBPROJECT)
find_package(PythonInterp)
if (NOT PYTHONINTERP_FOUND)
message(FATAL_ERROR "Python not found, but required for tests")
endif()
add_subdirectory(projects)
endif()
@@ -44,6 +49,9 @@ if(CATCH_BUILD_EXAMPLES)
add_subdirectory(examples)
endif()
if(CATCH_BUILD_EXTRA_TESTS)
add_subdirectory(projects/ExtraTests)
endif()
# add catch as a 'linkable' target
add_library(Catch2 INTERFACE)
@@ -83,102 +91,118 @@ target_include_directories(Catch2
# provide a namespaced alias for clients to 'link' against if catch is included as a sub-project
add_library(Catch2::Catch2 ALIAS Catch2)
set(CATCH_CMAKE_CONFIG_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/Catch2")
# Only perform the installation steps when Catch is not being used as
# a subproject via `add_subdirectory`, or the destinations will break,
# see https://github.com/catchorg/Catch2/issues/1373
if (NOT_SUBPROJECT)
set(CATCH_CMAKE_CONFIG_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/Catch2")
include(CMakePackageConfigHelpers)
configure_package_config_file(
${CMAKE_CURRENT_LIST_DIR}/CMake/Catch2Config.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/Catch2Config.cmake
INSTALL_DESTINATION
${CATCH_CMAKE_CONFIG_DESTINATION}
)
configure_package_config_file(
${CMAKE_CURRENT_LIST_DIR}/CMake/Catch2Config.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/Catch2Config.cmake
INSTALL_DESTINATION
${CATCH_CMAKE_CONFIG_DESTINATION}
)
# create and install an export set for catch target as Catch2::Catch
install(
TARGETS
Catch2
EXPORT
Catch2Targets
DESTINATION
${CMAKE_INSTALL_LIBDIR}
)
# create and install an export set for catch target as Catch2::Catch
install(
TARGETS
Catch2
EXPORT
Catch2Targets
DESTINATION
${CMAKE_INSTALL_LIBDIR}
)
install(
EXPORT
Catch2Targets
NAMESPACE
Catch2::
DESTINATION
${CATCH_CMAKE_CONFIG_DESTINATION}
)
install(
EXPORT
Catch2Targets
NAMESPACE
Catch2::
DESTINATION
${CATCH_CMAKE_CONFIG_DESTINATION}
)
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/Catch2ConfigVersion.cmake"
COMPATIBILITY
SameMajorVersion
)
# By default, FooConfigVersion is tied to architecture that it was
# generated on. Because Catch2 is header-only, it is arch-independent
# and thus Catch2ConfigVersion should not be tied to the architecture
# it was generated on.
#
# 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`.
set(CATCH2_CMAKE_SIZEOF_VOID_P ${CMAKE_SIZEOF_VOID_P})
unset(CMAKE_SIZEOF_VOID_P)
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/Catch2ConfigVersion.cmake"
COMPATIBILITY
SameMajorVersion
)
set(CMAKE_SIZEOF_VOID_P ${CATCH2_CMAKE_SIZEOF_VOID_P})
install(
DIRECTORY
"single_include/"
DESTINATION
"${CMAKE_INSTALL_INCLUDEDIR}"
)
install(
FILES
"${CMAKE_CURRENT_BINARY_DIR}/Catch2Config.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/Catch2ConfigVersion.cmake"
DESTINATION
${CATCH_CMAKE_CONFIG_DESTINATION}
)
install(
DIRECTORY
"single_include/"
DESTINATION
"${CMAKE_INSTALL_INCLUDEDIR}"
)
# Install documentation
if(CATCH_INSTALL_DOCS)
install(
DIRECTORY
docs/
DESTINATION
"${CMAKE_INSTALL_DOCDIR}"
)
endif()
install(
FILES
"${CMAKE_CURRENT_BINARY_DIR}/Catch2Config.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/Catch2ConfigVersion.cmake"
DESTINATION
${CATCH_CMAKE_CONFIG_DESTINATION}
)
if(CATCH_INSTALL_HELPERS)
# Install CMake scripts
install(
FILES
"contrib/ParseAndAddCatchTests.cmake"
"contrib/Catch.cmake"
"contrib/CatchAddTests.cmake"
DESTINATION
${CATCH_CMAKE_CONFIG_DESTINATION}
)
# Install documentation
if(CATCH_INSTALL_DOCS)
install(
DIRECTORY
docs/
DESTINATION
"${CMAKE_INSTALL_DOCDIR}"
)
endif()
# Install debugger helpers
install(
FILES
"contrib/gdbinit"
"contrib/lldbinit"
DESTINATION
${CMAKE_INSTALL_DATAROOTDIR}/Catch2
)
endif()
if(CATCH_INSTALL_HELPERS)
# Install CMake scripts
install(
FILES
"contrib/ParseAndAddCatchTests.cmake"
"contrib/Catch.cmake"
"contrib/CatchAddTests.cmake"
DESTINATION
${CATCH_CMAKE_CONFIG_DESTINATION}
)
## Provide some pkg-config integration
set(PKGCONFIG_INSTALL_DIR
"${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig"
CACHE PATH "Path where catch2.pc is installed"
)
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/CMake/catch2.pc.in
${CMAKE_CURRENT_BINARY_DIR}/catch2.pc
@ONLY
)
install(
FILES
"${CMAKE_CURRENT_BINARY_DIR}/catch2.pc"
DESTINATION
${PKGCONFIG_INSTALL_DIR}
)
# Install debugger helpers
install(
FILES
"contrib/gdbinit"
"contrib/lldbinit"
DESTINATION
${CMAKE_INSTALL_DATAROOTDIR}/Catch2
)
endif()
## Provide some pkg-config integration
set(PKGCONFIG_INSTALL_DIR
"${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig"
CACHE PATH "Path where catch2.pc is installed"
)
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/CMake/catch2.pc.in
${CMAKE_CURRENT_BINARY_DIR}/catch2.pc
@ONLY
)
install(
FILES
"${CMAKE_CURRENT_BINARY_DIR}/catch2.pc"
DESTINATION
${PKGCONFIG_INSTALL_DIR}
)
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/Gcuv2Xx3wmWIPNzy)
[![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/rbkudthN4hBNJznk)
[![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.3.0/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.4.2/catch.hpp">The latest version of the single header can be downloaded directly using this link</a>
## Catch2 is released!

View File

@@ -33,8 +33,6 @@ environment:
matrix:
allow_failures:
- os: Visual Studio 2017
exclude:
- os: Visual Studio 2015
additional_flags: "/permissive- /std:c++latest"

View File

@@ -4,7 +4,7 @@ from conans import ConanFile, CMake
class CatchConan(ConanFile):
name = "Catch"
version = "2.3.0"
version = "2.4.2"
description = "A modern, C++-native, header-only, framework for unit-tests, TDD and BDD"
author = "philsquared"
generators = "cmake"

View File

@@ -51,12 +51,14 @@ 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})
# ...and add to script
add_command(add_test
"${prefix}${test}${suffix}"
${TEST_EXECUTOR}
"${TEST_EXECUTABLE}"
"${test}"
"${test_name}"
${extra_args}
)
add_command(set_tests_properties

View File

@@ -39,6 +39,11 @@
# PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS (Default OFF) #
# -- causes CMake to rerun when file with tests changes so that new tests will be discovered #
# #
# One can also set (locally) the optional variable OptionalCatchTestLauncher to precise the way #
# a test should be run. For instance to use test MPI, one can write #
# set(OptionalCatchTestLauncher ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${NUMPROC}) #
# just before calling this ParseAndAddCatchTests function #
# #
#==================================================================================================#
cmake_minimum_required(VERSION 2.8.8)
@@ -168,7 +173,7 @@ function(ParseFile SourceFile TestTarget)
endif()
# Add the test and set its properties
add_test(NAME "\"${CTestName}\"" COMMAND ${TestTarget} ${Name} ${AdditionalCatchParameters})
add_test(NAME "\"${CTestName}\"" COMMAND ${OptionalCatchTestLauncher} ${TestTarget} ${Name} ${AdditionalCatchParameters})
set_tests_properties("\"${CTestName}\"" PROPERTIES FAIL_REGULAR_EXPRESSION "No tests ran"
LABELS "${Labels}")
endif()

View File

@@ -12,6 +12,8 @@ Writing tests:
* [Test fixtures](test-fixtures.md#top)
* [Reporters](reporters.md#top)
* [Event Listeners](event-listeners.md#top)
* [Data Generators](generators.md#top)
* [Other macros](other-macros.md#top)
Fine tuning:
* [Supplying your own main()](own-main.md#top)

View File

@@ -71,7 +71,7 @@ REQUIRE( performComputation() == 2.1_a );
`Approx` is constructed with defaults that should cover most simple cases.
For the more complex cases, `Approx` provides 3 customization points:
* __epsilon__ - epsilon serves to set the percentage by which a result
* __epsilon__ - epsilon serves to set the coefficient by which a result
can differ from `Approx`'s value before it is rejected.
_By default set to `std::numeric_limits<float>::epsilon()*100`._
* __margin__ - margin serves to set the the absolute value by which

View File

@@ -1,6 +1,12 @@
<a id="top"></a>
# CI and other odd pieces
**Contents**<br>
[Continuous Integration systems](#continuous-integration-systems)<br>
[Other reporters](#other-reporters)<br>
[Low-level tools](#low-level-tools)<br>
[CMake](#cmake)<br>
This page talks about how Catch integrates with Continuous Integration
Build Systems may refer to low-level tools, like CMake, or larger systems that run on servers, like Jenkins or TeamCity. This page will talk about both.

View File

@@ -1,6 +1,12 @@
<a id="top"></a>
# CMake integration
**Contents**<br>
[CMake target](#cmake-target)<br>
[Automatic test registration](#automatic-test-registration)<br>
[CMake project options](#cmake-project-options)<br>
[Installing Catch2 from git repository](#installing-catch2-from-git-repository)<br>
Because we use CMake to build Catch2, we also provide a couple of
integration points for our users.
@@ -47,7 +53,7 @@ to your CMake module path.
`Catch.cmake` provides function `catch_discover_tests` to get tests from
a target. This function works by running the resulting executable with
`--list-test-names-only` flag, and then parsing the output to find all
existing tests.
existing tests.
#### Usage
```cmake
@@ -166,6 +172,16 @@ step will be re-ran when the test files change, letting new tests be
automatically discovered. Defaults to `OFF`.
Optionally, one can specify a launching command to run tests by setting the
variable `OptionalCatchTestLauncher` before calling `ParseAndAddCatchTests`. For
instance to run some tests using `MPI` and other sequentially, one can write
```cmake
set(OptionalCatchTestLauncher ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${NUMPROC})
ParseAndAddCatchTests(mpi_foo)
unset(OptionalCatchTestLauncher)
ParseAndAddCatchTests(bar)
```
## CMake project options
Catch2's CMake project also provides some options for other projects
@@ -184,6 +200,27 @@ included in the installation. Defaults to `ON`.
* `BUILD_TESTING` -- When `ON` and the project is not used as a subproject,
Catch2's test binary will be built. Defaults to `ON`.
## Installing Catch2 from git repository
If you cannot install Catch2 from a package manager (e.g. Ubuntu 16.04
provides catch only in version 1.2.0) you might want to install it from
the repository instead. Assuming you have enough rights, you can just
install it to the default location, like so:
```
$ git clone https://github.com/catchorg/Catch2.git
$ cd Catch2
$ cmake -Bbuild -H. -DBUILD_TESTING=OFF
$ sudo cmake --build build/ --target install
```
If you do not have superuser rights, you will also need to specify
[CMAKE_INSTALL_PREFIX](https://cmake.org/cmake/help/latest/variable/CMAKE_INSTALL_PREFIX.html)
when configuring the build, and then modify your calls to
[find_package](https://cmake.org/cmake/help/latest/command/find_package.html)
accordingly.
---
[Home](Readme.md#top)

View File

@@ -24,7 +24,7 @@
[Usage](#usage)<br>
[Specify the section to run](#specify-the-section-to-run)<br>
[Filenames as tags](#filenames-as-tags)<br>
[Override output colouring](#use-colour)<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.

View File

@@ -3,15 +3,19 @@
**Contents**<br>
[main()/ implementation](#main-implementation)<br>
[Reporter / Listener interfaces](#reporter--listener-interfaces)<br>
[Prefixing Catch macros](#prefixing-catch-macros)<br>
[Terminal colour](#terminal-colour)<br>
[Console width](#console-width)<br>
[stdout](#stdout)<br>
[Fallback stringifier](#fallback-stringifier)<br>
[Default reporter](#default-reporter)<br>
[C++11 toggles](#c11-toggles)<br>
[C++17 toggles](#c17-toggles)<br>
[Other toggles](#other-toggles)<br>
[Windows header clutter](#windows-header-clutter)<br>
[Enabling stringification](#enabling-stringification)<br>
[Disabling exceptions](#disabling-exceptions)<br>
Catch is designed to "just work" as much as possible. For most people the only configuration needed is telling Catch which source file should host all the implementation code (```CATCH_CONFIG_MAIN```).
@@ -19,12 +23,12 @@ Nonetheless there are still some occasions where finer control is needed. For th
## main()/ implementation
CATCH_CONFIG_MAIN // Designates this as implementation file and defines main()
CATCH_CONFIG_RUNNER // Designates this as implementation file
CATCH_CONFIG_MAIN // Designates this as implementation file and defines main()
CATCH_CONFIG_RUNNER // Designates this as implementation file
Although Catch is header only it still, internally, maintains a distinction between interface headers and headers that contain implementation. Only one source file in your test project should compile the implementation headers and this is controlled through the use of one of these macros - one of these identifiers should be defined before including Catch in *exactly one implementation file in your project*.
# Reporter / Listener interfaces
## Reporter / Listener interfaces
CATCH_CONFIG_EXTERNAL_INTERFACES // Brings in necessary headers for Reporter/Listener implementation
@@ -34,16 +38,16 @@ Implied by both `CATCH_CONFIG_MAIN` and `CATCH_CONFIG_RUNNER`.
## Prefixing Catch macros
CATCH_CONFIG_PREFIX_ALL
CATCH_CONFIG_PREFIX_ALL
To keep test code clean and uncluttered Catch uses short macro names (e.g. ```TEST_CASE``` and ```REQUIRE```). Occasionally these may conflict with identifiers from platform headers or the system under test. In this case the above identifier can be defined. This will cause all the Catch user macros to be prefixed with ```CATCH_``` (e.g. ```CATCH_TEST_CASE``` and ```CATCH_REQUIRE```).
## Terminal colour
CATCH_CONFIG_COLOUR_NONE // completely disables all text colouring
CATCH_CONFIG_COLOUR_WINDOWS // forces the Win32 console API to be used
CATCH_CONFIG_COLOUR_ANSI // forces ANSI colour codes to be used
CATCH_CONFIG_COLOUR_NONE // completely disables all text colouring
CATCH_CONFIG_COLOUR_WINDOWS // forces the Win32 console API to be used
CATCH_CONFIG_COLOUR_ANSI // forces ANSI colour codes to be used
Yes, I am English, so I will continue to spell "colour" with a 'u'.
@@ -57,14 +61,14 @@ Typically you should place the ```#define``` before #including "catch.hpp" in yo
## Console width
CATCH_CONFIG_CONSOLE_WIDTH = x // where x is a number
CATCH_CONFIG_CONSOLE_WIDTH = x // where x is a number
Catch formats output intended for the console to fit within a fixed number of characters. This is especially important as indentation is used extensively and uncontrolled line wraps break this.
By default a console width of 80 is assumed but this can be controlled by defining the above identifier to be a different value.
## stdout
CATCH_CONFIG_NOSTDOUT
CATCH_CONFIG_NOSTDOUT
To support platforms that do not provide `std::cout`, `std::cerr` and
`std::clog`, Catch does not usem the directly, but rather calls
@@ -123,6 +127,8 @@ 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 contains basic compiler/standard detection and attempts to use
some C++17 features whenever appropriate. This automatic detection
@@ -197,9 +203,44 @@ By default, Catch does not stringify some types from the standard library. This
CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER // Provide StringMaker specialization for std::pair
CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER // Provide StringMaker specialization for std::tuple
CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER // Provide StringMaker specialization for std::chrono::duration, std::chrono::timepoint
CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER // Provide StringMaker specialization for std::variant, std::monostate (on C++17)
CATCH_CONFIG_ENABLE_ALL_STRINGMAKERS // Defines all of the above
## Disabling exceptions
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
automatically detect when it is compiled with exceptions disabled, but
it can be forced to compile without exceptions by defining
CATCH_CONFIG_DISABLE_EXCEPTIONS
Note that when using Catch2 without exceptions, there are 2 major
limitations:
1) If there is an error that would normally be signalled by an exception,
the exception's message will instead be written to `Catch::cerr` and
`std::terminate` will be called.
2) If an assertion from the `REQUIRE` family of macros fails,
`std::terminate` will be called after the active reporter returns.
There is also a customization point for the exact behaviour of what
happens instead of exception being thrown. To use it, define
CATCH_CONFIG_DISABLE_EXCEPTIONS_CUSTOM_HANDLER
and provide a definition for this function:
```cpp
namespace Catch {
[[noreturn]]
void throw_exception(std::exception const&);
}
```
---
[Home](Readme.md#top)

50
docs/generators.md Normal file
View File

@@ -0,0 +1,50 @@
<a id="top"></a>
# Data Generators
_Generators are currently considered an experimental feature and their
API can change between versions freely._
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
of the `TEST_CASE` and `SECTION` macros.
How does combining generators and test cases work might be better
explained by an example:
```cpp
TEST_CASE("Generators") {
auto i = GENERATE( range(1, 11) );
SECTION( "Some section" ) {
auto j = GENERATE( range( 11, 21 ) );
REQUIRE(i < j);
}
}
```
the assertion will be checked 100 times, because there are 10 possible
values for `i` (1, 2, ..., 10) and for each of them, there are 10 possible
values for `j` (11, 12, ..., 20).
You can also combine multiple generators by concatenation:
```cpp
static int square(int x) { return x * x; }
TEST_CASE("Generators 2") {
auto i = GENERATE(0, 1, -1, range(-20, -10), range(10, 20));
CAPTURE(i);
REQUIRE(square(i) >= 0);
}
```
This will call `square` with arguments `0`, `1`, `-1`, `-20`, ..., `-11`,
`10`, ..., `19`.
----------
Because of the experimental nature of the current Generator implementation,
we won't list all of the first-party generators in Catch2. Instead you
should look at our current usage tests in
[projects/SelfTest/UsageTests/Generators.tests.cpp](/projects/SelfTest/UsageTests/Generators.tests.cpp).
For implementing your own generators, you can look at their implementation in
[include/internal/catch_generators.hpp](/include/internal/catch_generators.hpp).

View File

@@ -1,12 +1,19 @@
<a id="top"></a>
# Known limitations
Catch has some known limitations, that we are not planning to change. Some of these are caused by our desire to support C++98 compilers, some of these are caused by our desire to keep Catch crossplatform, some exist because their priority is seen as low compared to the development effort they would need and some other yet are compiler/runtime bugs.
Over time, some limitations of Catch2 emerged. Some of these are due
to implementation details that cannot be easily changed, some of these
are due to lack of development resources on our part, and some of these
are due to plain old 3rd party bugs.
## Implementation limits
### Sections nested in loops
If you are using `SECTION`s inside loops, you have to create them with different name per loop's iteration. The recommended way to do so is to incorporate the loop's counter into section's name, like so
If you are using `SECTION`s inside loops, you have to create them with
different name per loop's iteration. The recommended way to do so is to
incorporate the loop's counter into section's name, like so:
```cpp
TEST_CASE( "Looped section" ) {
for (char i = '0'; i < '5'; ++i) {
@@ -17,6 +24,27 @@ TEST_CASE( "Looped section" ) {
}
```
or with a `DYNAMIC_SECTION` macro (that was made for exactly this purpose):
```cpp
TEST_CASE( "Looped section" ) {
for (char i = '0'; i < '5'; ++i) {
DYNAMIC_SECTION( "Looped section " << i) {
SUCCEED( "Everything is OK" );
}
}
}
```
### Tests might be run again if last section fails
If the last section in a test fails, it might be run again. This is because
Catch2 discovers `SECTION`s dynamically, as they are about to run, and
if the last section in test case is aborted during execution (e.g. via
the `REQUIRE` family of macros), Catch2 does not know that there are no
more sections in that test case and must run the test case again.
## Features
This section outlines some missing features, what is their status and their possible workarounds.
@@ -137,3 +165,14 @@ If you are seeing a problem like this, i.e. a weird test paths that trigger only
This is a bug in `libstdc++-4.8`, where all matching methods from `<regex>` return false. Since `Matches` uses `<regex>` internally, if the underlying implementation does not work, it doesn't work either.
Workaround: Use newer version of `libstdc++`.
### libstdc++, `_GLIBCXX_DEBUG` macro and random ordering of tests
Running a Catch2 binary compiled against libstdc++ with `_GLIBCXX_DEBUG`
macro defined with `--order rand` will cause a debug check to trigger and
abort the run due to self-assignment.
[This is a known bug inside libstdc++](https://stackoverflow.com/questions/22915325/avoiding-self-assignment-in-stdshuffle/23691322)
Workaround: Don't use `--order rand` when compiling against debug-enabled
libstdc++.

View File

@@ -3,12 +3,15 @@
## Already available
- Catch main: [Catch-provided main](../examples/000-CatchMain.cpp)
- Test Case: [Single-file](../examples/010-TestCase.cpp)
- Test Case: [Multiple-file 1](../examples/020-TestCase-1.cpp), [2](../examples/020-TestCase-2.cpp)
- Assertion: [REQUIRE, CHECK](../examples/030-Asn-Require-Check.cpp)
- Fixture: [Sections](../examples/100-Fix-Section.cpp)
- Fixture: [Class-based fixtures](../examples/110-Fix-ClassFixture.cpp)
- BDD: [SCENARIO, GIVEN, WHEN, THEN](../examples/120-Bdd-ScenarioGivenWhenThen.cpp)
- Report: [Catch-provided main](../examples/200-Rpt-CatchMain.cpp)
- Report: [TeamCity reporter](../examples/207-Rpt-TeamCityReporter.cpp)
- Listener: [Listeners](../examples/210-Evt-EventListeners.cpp)
- Configuration: [Provide your own output streams](../examples/231-Cfg-OutputStreams.cpp)
@@ -27,7 +30,10 @@
- Logging: [FAIL, FAIL_CHECK - Issue message and force failure/continue](../examples/170-Log-Fail.cpp)
- Logging: [SUCCEED - Issue message and continue](../examples/180-Log-Succeed.cpp)
- Report: [User-defined type](../examples/190-Rpt-ReportUserDefinedType.cpp)
- Report: [Reporter](../examples/200-Rpt-UserDefinedReporter.cpp)
- Report: [User-defined reporter](../examples/202-Rpt-UserDefinedReporter.cpp)
- Report: [Automake reporter](../examples/205-Rpt-AutomakeReporter.cpp)
- Report: [TAP reporter](../examples/206-Rpt-TapReporter.cpp)
- Report: [Multiple reporter](../examples/208-Rpt-MultipleReporters.cpp)
- Configuration: [Provide your own main()](../examples/220-Cfg-OwnMain.cpp)
- Configuration: [Compile-time configuration](../examples/230-Cfg-CompileTimeConfiguration.cpp)
- Configuration: [Run-time configuration](../examples/240-Cfg-RunTimeConfiguration.cpp)

View File

@@ -36,7 +36,7 @@ The next-generation core storage and query engine for Couchbase Lite
A High-performance Cluster Computing Engine
### [forest](https://github.com/xorz57/forest)
Forest is an open-source, template library of tree data structures written in C++11.
Template Library of Tree Data Structures
### [Fuxedo](https://github.com/fuxedo/fuxedo)
Open source Oracle Tuxedo-like XATMI middleware for C and C++.
@@ -71,6 +71,9 @@ A C++ client library for Consul. Consul is a distributed tool for discovering an
### [Reactive-Extensions/ RxCpp](https://github.com/Reactive-Extensions/RxCpp)
A library of algorithms for values-distributed-in-time
### [thor](https://github.com/xorz57/thor)
Wrapper Library for CUDA
### [TextFlowCpp](https://github.com/philsquared/textflowcpp)
A small, single-header-only, library for wrapping and composing columns of text

150
docs/other-macros.md Normal file
View File

@@ -0,0 +1,150 @@
<a id="top"></a>
# Other macros
This page serves as a reference for macros that are not documented
elsewhere. For now, these macros are separated into 2 rough categories,
"assertion related macros" and "test case related macros".
## Assertion related macros
* `CHECKED_IF` and `CHECKED_ELSE`
`CHECKED_IF( expr )` is an `if` replacement, that also applies Catch2's
stringification machinery to the _expr_ and records the result. As with
`if`, the block after a `CHECKED_IF` is entered only if the expression
evaluates to `true`. `CHECKED_ELSE( expr )` work similarly, but the block
is entered only if the _expr_ evaluated to `false`.
Example:
```cpp
int a = ...;
int b = ...;
CHECKED_IF( a == b ) {
// This block is entered when a == b
} CHECKED_ELSE ( a == b ) {
// This block is entered when a != b
}
```
* `CHECK_NOFAIL`
`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.
Example output:
```
main.cpp:6:
FAILED - but was ok:
CHECK_NOFAIL( 1 == 2 )
main.cpp:7:
PASSED:
CHECK( 2 == 2 )
```
* `SUCCEED`
`SUCCEED( msg )` is mostly equivalent with `INFO( msg ); REQUIRE( true );`.
In other words, `SUCCEED` is for cases where just reaching a certain line
means that the test has been a success.
Example usage:
```cpp
TEST_CASE( "SUCCEED showcase" ) {
int I = 1;
SUCCEED( "I is " << I );
}
```
* `STATIC_REQUIRE`
`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
to the runtime, by defining `CATCH_CONFIG_RUNTIME_STATIC_REQUIRE` before
including the Catch2 header.
Example:
```cpp
TEST_CASE("STATIC_REQUIRE showcase", "[traits]") {
STATIC_REQUIRE( std::is_void<void>::value );
STATIC_REQUIRE_FALSE( std::is_void<int>::value );
}
```
## Test case related macros
* `METHOD_AS_TEST_CASE`
`METHOD_AS_TEST_CASE( member-function-pointer, description )` lets you
register a member function of a class as a Catch2 test case. The class
will be separately instantiated for each method registered in this way.
```cpp
class TestClass {
std::string s;
public:
TestClass()
:s( "hello" )
{}
void testCase() {
REQUIRE( s == "hello" );
}
};
METHOD_AS_TEST_CASE( TestClass::testCase, "Use class's method as a test case", "[class]" )
```
* `REGISTER_TEST_CASE`
`REGISTER_TEST_CASE( function, description )` let's you register
a `function` as a test case. The function has to have `void()` signature,
the description can contain both name and tags.
Example:
```cpp
REGISTER_TEST_CASE( someFunction, "ManuallyRegistered", "[tags]" );
```
_Note that the registration still has to happen before Catch2's session
is initiated. This means that it either needs to be done in a global
constructor, or before Catch2's session is created in user's own main._
* `ANON_TEST_CASE`
`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
hard to run directly.
Example:
```cpp
ANON_TEST_CASE() {
SUCCEED("Hello from anonymous test case");
}
```
* `DYNAMIC_SECTION`
`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.
Example:
```cpp
TEST_CASE( "looped SECTION tests" ) {
int a = 1;
for( int b = 0; b < 10; ++b ) {
DYNAMIC_SECTION( "b is currently: " << b ) {
CHECK( b > a );
}
}
}
```

View File

@@ -1,6 +1,12 @@
<a id="top"></a>
# Supplying main() yourself
**Contents**<br>
[Let Catch take full control of args and config](#let-catch-take-full-control-of-args-and-config)<br>
[Amending the config](#amending-the-config)<br>
[Adding your own command line options](#adding-your-own-command-line-options)<br>
[Version detection](#version-detection)<br>
The easiest way to use Catch is to let it supply ```main()``` for you and handle configuring itself from the command line.
This is achieved by writing ```#define CATCH_CONFIG_MAIN``` before the ```#include "catch.hpp"``` in *exactly one* source file.
@@ -45,7 +51,7 @@ int main( int argc, char* argv[] )
int returnCode = session.applyCommandLine( argc, argv );
if( returnCode != 0 ) // Indicates a command line error
return returnCode;
return returnCode;
// writing to session.configData() or session.Config() here
// overrides command line args
@@ -94,7 +100,7 @@ int main( int argc, char* argv[] )
// Let Catch (using Clara) parse the command line
int returnCode = session.applyCommandLine( argc, argv );
if( returnCode != 0 ) // Indicates a command line error
return returnCode;
return returnCode;
// if set on the command line then 'height' is now set at this point
if( height > 0 )

View File

@@ -1,6 +1,91 @@
<a id="top"></a>
# 2.3.0
# Release notes
**Contents**<br>
[2.4.2](#242)<br>
[2.4.1](#241)<br>
[2.4.0](#240)<br>
[2.3.0](#230)<br>
[2.2.3](#223)<br>
[2.2.2](#222)<br>
[2.2.1](#221)<br>
[2.2.0](#220)<br>
[2.1.2](#212)<br>
[2.1.1](#211)<br>
[2.1.0](#210)<br>
[2.0.1](#201)<br>
[Older versions](#older-versions)<br>
[Even Older versions](#even-older-versions)<br>
## 2.4.2
### Improvements
* XmlReporter now also outputs the RNG seed that was used in a run (#1404)
* `Catch::Session::applyCommandLine` now also accepts `wchar_t` arguments.
* However, Catch2 still does not support unicode.
* Added `STATIC_REQUIRE` macro (#1356, #1362)
* Catch2's singleton's are now cleaned up even if tests are run (#1411)
* This is mostly useful as a FP prevention for users who define their own main.
* Specifying an invalid reporter via `-r` is now reported sooner (#1351, #1422)
### Fixes
* Stringification no longer assumes that `char` is signed (#1399, #1407)
* This caused a `Wtautological-compare` warning.
* SFINAE for `operator<<` no longer sees different overload set than the actual insertion (#1403)
### Contrib
* `catch_discover_tests` correctly adds tests with comma in name (#1327, #1409)
* Added a new customization point in how the tests are launched to `catch_discover_tests`
## 2.4.1
### Improvements
* Added a StringMaker for `std::(w)string_view` (#1375, #1376)
* Added a StringMaker for `std::variant` (#1380)
* This one is disabled by default to avoid increased compile-time drag
* Added detection for cygwin environment without `std::to_string` (#1396, #1397)
### Fixes
* `UnorderedEqualsMatcher` will no longer accept erroneously accept
vectors that share suffix, but are not permutation of the desired vector
* Abort after (`-x N`) can no longer be overshot by nested `REQUIRES` and
subsequently ignored (#1391, #1392)
## 2.4.0
**This release brings two new experimental features, generator support
and a `-fno-exceptions` support. Being experimental means that they
will not be subject to the usual stability guarantees provided by semver.**
### Improvements
* Various small runtime performance improvements
* `CAPTURE` macro is now variadic
* Added `AND_GIVEN` macro (#1360)
* Added experimental support for data generators
* See [their documentation](generators.md) for details
* Added support for compiling and running Catch without exceptions
* Doing so limits the functionality somewhat
* Look [into the documentation](configuration.md#disablingexceptions) for details
### Fixes
* Suppressed `-Wnon-virtual-dtor` warnings in Matchers (#1357)
* Suppressed `-Wunreachable-code` warnings in floating point matchers (#1350)
### CMake
* It is now possible to override which Python is used to run Catch's tests (#1365)
* Catch now provides infrastructure for adding tests that check compile-time configuration
* Catch no longer tries to install itself when used as a subproject (#1373)
* Catch2ConfigVersion.cmake is now generated as arch-independent (#1368)
* This means that installing Catch from 32-bit machine and copying it to 64-bit one works
* This fixes conan installation of Catch
## 2.3.0
**This release changes the include paths provided by our CMake and
pkg-config integration. The proper include path for the single-header
@@ -11,7 +96,7 @@ than `single_include/catch.hpp`.**
## Fixes
### Fixes
* Fixed Objective-C++ build
* `-Wunused-variable` suppression no longer leaks from Catch's header under Clang
* Implementation of the experimental new output capture can now be disabled (#1335)
@@ -19,7 +104,7 @@ than `single_include/catch.hpp`.**
* The JUnit and XML reporters will no longer skip over successful tests when running without `-s` (#1264, #1267, #1310)
* See improvements for more details
## Improvements
### Improvements
* pkg-config and CMake integration has been rewritten
* If you use them, the new include path is `#include <catch2/catch.hpp>`
* CMake installation now also installs scripts from `contrib/`
@@ -31,12 +116,12 @@ than `single_include/catch.hpp`.**
* This means that you can do `DYNAMIC_SECTION("For X := " << x)`.
# 2.2.3
## 2.2.3
**To fix some of the bugs, some behavior had to change in potentially breaking manner.**
**This means that even though this is a patch release, it might not be a drop-in replacement.**
## Fixes
### Fixes
* Listeners are now called before reporter
* This was always documented to be the case, now it actually works that way
* Catch's commandline will no longer accept multiple reporters
@@ -55,23 +140,23 @@ than `single_include/catch.hpp`.**
* **This has potential to be a breaking change**
* Fixed compilation error when a type has an `operator<<` with templated lhs (#1285, #1306)
## Improvements
### Improvements
* Added a new, experimental, output capture (#1243)
* This capture can also redirect output written via C apis, e.g. `printf`
* To opt-in, define `CATCH_CONFIG_EXPERIMENTAL_REDIRECT` in the implementation file
* Added a new fallback stringifier for classes derived from `std::exception`
* Both `StringMaker` specialization and `operator<<` overload are given priority
## Miscellaneous
### Miscellaneous
* `contrib/` now contains dbg scripts that skip over Catch's internals (#904, #1283)
* `gdbinit` for gdb `lldbinit` for lldb
* `CatchAddTests.cmake` no longer strips whitespace from tests (#1265, #1281)
* Online documentation now describes `--use-colour` option (#1263)
# 2.2.2
## 2.2.2
## Fixes
### Fixes
* Fixed bug in `WithinAbs::match()` failing spuriously (#1228)
* Fixed clang-tidy diagnostic about virtual call in destructor (#1226)
* Reduced the number of GCC warnings suppression leaking out of the header (#1090, #1091)
@@ -80,7 +165,7 @@ than `single_include/catch.hpp`.**
* On platforms where `std::chrono::high_resolution_clock`'s resolution is low, the calibration would appear stuck
* Fixed compilation error when stringifying static arrays of `unsigned char`s (#1238)
## Improvements
### Improvements
* XML encoder now hex-encodes invalid UTF-8 sequences (#1207)
* This affects xml and junit reporters
* Some invalid UTF-8 parts are left as is, e.g. surrogate pairs. This is because certain extensions of UTF-8 allow them, such as WTF-8.
@@ -89,29 +174,29 @@ than `single_include/catch.hpp`.**
* Added `PredicateMatcher`, a matcher that takes an arbitrary predicate function (#1236)
* See [documentation for details](https://github.com/catchorg/Catch2/blob/master/docs/matchers.md)
## Others
### Others
* Modified CMake-installed pkg-config to allow `#include <catch.hpp>`(#1239)
* The plans to standardize on `#include <catch2/catch.hpp>` are still in effect
# 2.2.1
## 2.2.1
## Fixes
### Fixes
* Fixed compilation error when compiling Catch2 with `std=c++17` against libc++ (#1214)
* Clara (Catch2's CLI parsing library) used `std::optional` without including it explicitly
* Fixed Catch2 return code always being 0 (#1215)
* In the words of STL, "We feel superbad about letting this in"
# 2.2.0
## 2.2.0
## Fixes
### Fixes
* Hidden tests are not listed by default when listing tests (#1175)
* This makes `catch_discover_tests` CMake script work better
* Fixed regression that meant `<windows.h>` could potentially not be included properly (#1197)
* Fixed installing `Catch2ConfigVersion.cmake` when Catch2 is a subproject.
## Improvements
### Improvements
* Added an option to warn (+ exit with error) when no tests were ran (#1158)
* Use as `-w NoTests`
* Added provisional support for Emscripten (#1114)
@@ -123,38 +208,38 @@ than `single_include/catch.hpp`.**
* Added support for DJGPP DOS crosscompiler (#1206)
# 2.1.2
## 2.1.2
## Fixes
### Fixes
* Fixed compilation error with `-fno-rtti` (#1165)
* Fixed NoAssertion warnings
* `operator<<` is used before range-based stringification (#1172)
* Fixed `-Wpedantic` warnings (extra semicolons and binary literals) (#1173)
## Improvements
### Improvements
* Added `CATCH_VERSION_{MAJOR,MINOR,PATCH}` macros (#1131)
* Added `BrightYellow` colour for use in reporters (#979)
* It is also used by ConsoleReporter for reconstructed expressions
## Other changes
### Other changes
* Catch is now exported as a CMake package and linkable target (#1170)
# 2.1.1
## 2.1.1
## Improvements
### Improvements
* Static arrays are now properly stringified like ranges across MSVC/GCC/Clang
* Embedded newer version of Clara -- v1.1.1
* This should fix some warnings dragged in from Clara
* MSVC's CLR exceptions are supported
## Fixes
### Fixes
* Fixed compilation when comparison operators do not return bool (#1147)
* Fixed CLR exceptions blowing up the executable during translation (#1138)
## Other changes
### Other changes
* Many CMake changes
* `NO_SELFTEST` option is deprecated, use `BUILD_TESTING` instead.
* Catch specific CMake options were prefixed with `CATCH_` for namespacing purposes
@@ -162,9 +247,9 @@ than `single_include/catch.hpp`.**
# 2.1.0
## 2.1.0
## Improvements
### Improvements
* Various performance improvements
* On top of the performance regression fixes
* Experimental support for PCH was added (#1061)
@@ -174,7 +259,7 @@ than `single_include/catch.hpp`.**
* Bugs in g++ 4.x and 5.x mean that some of them have to be left in
## Fixes
### Fixes
* Fixed performance regression from Catch classic
* One of the performance improvement patches for Catch classic was not applied to Catch2
* Fixed platform detection for iOS (#1084)
@@ -187,7 +272,7 @@ than `single_include/catch.hpp`.**
* Fixed `std::uncaught_exception` deprecation warning (#1124)
## New features
### New features
* New Matchers
* Regex matcher for strings, `Matches`.
* Set-equal matcher for vectors, `UnorderedEquals`
@@ -196,15 +281,15 @@ than `single_include/catch.hpp`.**
* Containers are objects that respond to ADL `begin(T)` and `end(T)`.
## Other changes
### Other changes
* Reporters will now be versioned in the `single_include` folder to ensure their compatibility with the last released version
# 2.0.1
## 2.0.1
## Breaking changes
### Breaking changes
* Removed C++98 support
* Removed legacy reporter support
* Removed legacy generator support
@@ -234,7 +319,7 @@ than `single_include/catch.hpp`.**
* `INFINITY == Approx(INFINITY)` returns true
## Improvements
### Improvements
* Reporters and Listeners can be defined in files different from the main file
* The file has to define `CATCH_CONFIG_EXTERNAL_INTERFACES` before including catch.hpp.
* Errors that happen during set up before main are now caught and properly reported once main is entered
@@ -268,7 +353,7 @@ than `single_include/catch.hpp`.**
* Add `pkg-config` support to CMake install command
## Fixes
### Fixes
* Don't use console colour if running in XCode
* Explicit constructor in reporter base class
* Swept out `-Wweak-vtables`, `-Wexit-time-destructors`, `-Wglobal-constructors` warnings
@@ -280,7 +365,7 @@ than `single_include/catch.hpp`.**
* Suppressed C4061 warning under MSVC
## Internal changes
### Internal changes
* The development version now uses .cpp files instead of header files containing implementation.
* This makes partial rebuilds much faster during development
* The expression decomposition layer has been rewritten
@@ -288,13 +373,33 @@ than `single_include/catch.hpp`.**
* New library (TextFlow) is used for formatting text to output
# Older versions
## Older versions
## 1.11.x
### 1.12.x
### 1.11.0
#### 1.12.2
##### Fixes
* Fixed missing <cassert> include
#### Fixes
#### 1.12.1
##### Fixes
* Fixed deprecation warning in `ScopedMessage::~ScopedMessage`
* All uses of `min` or `max` identifiers are now wrapped in parentheses
* This avoids problems when Windows headers define `min` and `max` macros
#### 1.12.0
##### Fixes
* Fixed compilation for strict C++98 mode (ie not gnu++98) and older compilers (#1103)
* `INFO` messages are included in the `xml` reporter output even without `-s` specified.
### 1.11.x
#### 1.11.0
##### Fixes
* The original expression in `REQUIRE_FALSE( expr )` is now reporter properly as `!( expr )` (#1051)
* Previously the parentheses were missing and `x != y` would be expanded as `!x != x`
* `Approx::Margin` is now inclusive (#952)
@@ -302,7 +407,7 @@ than `single_include/catch.hpp`.**
* This means that `REQUIRE( 0.25f == Approx( 0.0f ).margin( 0.25f ) )` passes, instead of fails
* `RandomNumberGenerator::result_type` is now unsigned (#1050)
#### Improvements
##### Improvements
* `__JETBRAINS_IDE__` macro handling is now CLion version specific (#1017)
* When CLion 2017.3 or newer is detected, `__COUNTER__` is used instead of
* TeamCity reporter now explicitly flushes output stream after each report (#1057)
@@ -310,35 +415,35 @@ than `single_include/catch.hpp`.**
* `ParseAndAddCatchTests` now can add test files as dependency to CMake configuration
* This means you do not have to manually rerun CMake configuration step to detect new tests
## 1.10.x
### 1.10.x
### 1.10.0
#### 1.10.0
#### Fixes
##### Fixes
* Evaluation layer has been rewritten (backported from Catch 2)
* The new layer is much simpler and fixes some issues (#981)
* Implemented workaround for VS 2017 raw string literal stringification bug (#995)
* Fixed interaction between `[!shouldfail]` and `[!mayfail]` tags and sections
* Previously sections with failing assertions would be marked as failed, not failed-but-ok
#### Improvements
##### Improvements
* Added [libidentify](https://github.com/janwilmans/LibIdentify) support
* Added "wait-for-keypress" option
## 1.9.x
### 1.9.x
### 1.9.6
#### 1.9.6
#### Improvements
##### Improvements
* Catch's runtime overhead has been significantly decreased (#937, #939)
* Added `--list-extra-info` cli option (#934).
* It lists all tests together with extra information, ie filename, line number and description.
### 1.9.5
#### 1.9.5
#### Fixes
##### Fixes
* Truthy expressions are now reconstructed properly, not as booleans (#914)
* Various warnings are no longer erroneously suppressed in test files (files that include `catch.hpp`, but do not define `CATCH_CONFIG_MAIN` or `CATCH_CONFIG_RUNNER`) (#871)
* Catch no longer fails to link when main is compiled as C++, but linked against Objective-C (#855)
@@ -346,35 +451,35 @@ than `single_include/catch.hpp`.**
* Previously any GCC with minor version less than 3 would be incorrectly classified as not supporting `__COUNTER__`.
* Suppressed C4996 warning caused by upcoming updated to MSVC 2017, marking `std::uncaught_exception` as deprecated. (#927)
#### Improvements
##### Improvements
* CMake integration script now incorporates debug messages and registers tests in an improved way (#911)
* Various documentation improvements
### 1.9.4
#### 1.9.4
#### Fixes
##### Fixes
* `CATCH_FAIL` macro no longer causes compilation error without variadic macro support
* `INFO` messages are no longer cleared after being reported once
#### Improvements and minor changes
##### Improvements and minor changes
* Catch now uses `wmain` when compiled under Windows and `UNICODE` is defined.
* Note that Catch still officially supports only ASCII
### 1.9.3
#### 1.9.3
#### Fixes
##### Fixes
* Completed the fix for (lack of) uint64_t in earlier Visual Studios
### 1.9.2
#### 1.9.2
#### Improvements and minor changes
##### Improvements and minor changes
* All of `Approx`'s member functions now accept strong typedefs in C++11 mode (#888)
* Previously `Approx::scale`, `Approx::epsilon`, `Approx::margin` and `Approx::operator()` didn't.
#### Fixes
##### Fixes
* POSIX signals are now disabled by default under QNX (#889)
* QNX does not support current enough (2001) POSIX specification
* JUnit no longer counts exceptions as failures if given test case is marked as ok to fail.
@@ -382,22 +487,22 @@ than `single_include/catch.hpp`.**
* Catch no longer attempts to define `uint64_t` on windows (#862)
* This was causing trouble when compiled under Cygwin
#### Other
##### Other
* Catch is now compiled under MSVC 2017 using `std:c++latest` (C++17 mode) in CI
* We now provide cmake script that autoregisters Catch tests into ctest.
* See `contrib` folder.
### 1.9.1
#### 1.9.1
#### Fixes
##### Fixes
* Unexpected exceptions are no longer ignored by default (#885, #887)
### 1.9.0
#### 1.9.0
#### Improvements and minor changes
##### Improvements and minor changes
* Catch no longer attempts to ensure the exception type passed by user in `REQUIRE_THROWS_AS` is a constant reference.
* It was causing trouble when `REQUIRE_THROWS_AS` was used inside templated functions
* This actually reverts changes made in v1.7.2
@@ -411,7 +516,7 @@ than `single_include/catch.hpp`.**
* When Catch is compiled using C++11, `Approx` is now constructible with anything that can be explicitly converted to `double`.
* Captured messages are now printed on unexpected exceptions
#### Fixes:
##### Fixes:
* Clang's `-Wexit-time-destructors` should be suppressed for Catch's internals
* GCC's `-Wparentheses` is now suppressed for all TU's that include `catch.hpp`.
* This is functionally a revert of changes made in 1.8.0, where we tried using `_Pragma` based suppression. This should have kept the suppression local to Catch's assertions, but bugs in GCC's handling of `_Pragma`s in C++ mode meant that it did not always work.
@@ -420,18 +525,18 @@ than `single_include/catch.hpp`.**
* [Details can be found in documentation](configuration.md#catch_config_cpp11_stream_insertable_check)
#### Other notes:
##### Other notes:
* We have added VS 2017 to our CI
* Work on Catch 2 should start soon
## 1.8.x
### 1.8.x
### 1.8.2
#### 1.8.2
#### Improvements and minor changes
##### Improvements and minor changes
* TAP reporter now behaves as if `-s` was always set
* This should be more consistent with the protocol desired behaviour.
* Compact reporter now obeys `-d yes` argument (#780)
@@ -445,7 +550,7 @@ than `single_include/catch.hpp`.**
* Listeners provide a way to hook into events generated by running your tests, including start and end of run, every test case, every section and every assertion.
#### Fixes:
##### Fixes:
* Catch no longer attempts to reconstruct expression that led to a fatal error (#810)
* This fixes possible signal/SEH loop when processing expressions, where the signal was triggered by expression decomposition.
* Fixed (C4265) missing virtual destructor warning in Matchers (#844)
@@ -462,21 +567,21 @@ than `single_include/catch.hpp`.**
* Regression in Objective-C bindings (Matchers) fixed (#854)
#### Other notes:
##### Other notes:
* We have added VS 2013 and 2015 to our CI
* Catch Classic (1.x.x) now contains its own, forked, version of Clara (the argument parser).
### 1.8.1
#### 1.8.1
#### Fixes
##### Fixes
Cygwin issue with `gettimeofday` - `#define` was not early enough
### 1.8.0
#### 1.8.0
#### New features/ minor changes
##### New features/ minor changes
* Matchers have new, simpler (and documented) interface.
* Catch provides string and vector matchers.
@@ -496,7 +601,7 @@ Cygwin issue with `gettimeofday` - `#define` was not early enough
* `Approx` now supports an optional margin of absolute error
* It has also received [new documentation](assertions.md#top).
#### Fixes
##### Fixes
* Silenced C4312 ("conversion from int to 'ClassName *") warnings in the evaluate layer.
* Fixed C4512 ("assignment operator could not be generated") warnings under VS2013.
* Cygwin compatibility fixes
@@ -507,15 +612,15 @@ Cygwin issue with `gettimeofday` - `#define` was not early enough
* Otherwise it is supressed for the whole TU
* Fixed test spec parser issue (with escapes in multiple names)
#### Other
##### Other
* Various documentation fixes and improvements
## 1.7.x
### 1.7.x
### 1.7.2
#### 1.7.2
#### Fixes and minor improvements
##### Fixes and minor improvements
Xml:
(technically the first two are breaking changes but are also fixes and arguably break few if any people)
@@ -534,9 +639,9 @@ Other:
* Silenced a few more warnings in different circumstances
* Travis improvements
### 1.7.1
#### 1.7.1
#### Fixes:
##### Fixes:
* Fixed inconsistency in defining `NOMINMAX` and `WIN32_LEAN_AND_MEAN` inside `catch.hpp`.
* Fixed SEH-related compilation error under older MinGW compilers, by making Windows SEH handling opt-in for compilers other than MSVC.
* For specifics, look into the [documentation](configuration.md#top).
@@ -546,9 +651,9 @@ Other:
* Fixed possible infinite recursion in Windows SEH.
* Fixed possible compilation error caused by Catch's operator overloads being ambiguous in regards to user-defined templated operators.
### 1.7.0
#### 1.7.0
#### Features/ Changes:
##### Features/ Changes:
* Catch now runs significantly faster for passing tests
* Microbenchmark focused on Catch's overhead went from ~3.4s to ~0.7s.
* Real world test using [JSON for Modern C++](https://github.com/nlohmann/json)'s test suite went from ~6m 25s to ~4m 14s.
@@ -562,30 +667,30 @@ Other:
* Certain characters (space, tab, etc) are now pretty printed.
* This means that a `char c = ' '; REQUIRE(c == '\t');` would be printed as `' ' == '\t'`, instead of ` == 9`.
#### Fixes:
##### Fixes:
* Text formatting no longer attempts to access out-of-bounds characters under certain conditions.
* THROW family of assertions no longer trigger `-Wunused-value` on expressions containing explicit cast.
* Breaking into debugger under OS X works again and no longer required `DEBUG` to be defined.
* Compilation no longer breaks under certain compiler if a lambda is used inside assertion macro.
#### Other:
##### Other:
* Catch's CMakeLists now defines install command.
* Catch's CMakeLists now generates projects with warnings enabled.
## 1.6.x
### 1.6.x
### 1.6.1
#### 1.6.1
#### Features/ Changes:
##### Features/ Changes:
* Catch now supports breaking into debugger on Linux
#### Fixes:
##### Fixes:
* Generators no longer leak memory (generators are still unsupported in general)
* JUnit reporter now reports UTC timestamps, instead of "tbd"
* `CHECK_THAT` macro is now properly defined as `CATCH_CHECK_THAT` when using `CATCH_` prefixed macros
#### Other:
##### Other:
* Types with overloaded `&&` operator are no longer evaluated twice when used in an assertion macro.
* The use of `__COUNTER__` is supressed when Catch is parsed by CLion
* This change is not active when compiling a binary
@@ -595,28 +700,28 @@ Other:
* This can be disabled if needed, see [documentation](configuration.md#top) for details.
### 1.6.0
#### 1.6.0
#### Cmake/ projects:
##### Cmake/ projects:
* Moved CMakeLists.txt to root, made it friendlier for CLion and generating XCode and VS projects, and removed the manually maintained XCode and VS projects.
#### Features/ Changes:
##### Features/ Changes:
* Approx now supports `>=` and `<=`
* Can now use `\` to escape chars in test names on command line
* Standardize C++11 feature toggles
#### Fixes:
##### Fixes:
* Blue shell colour
* Missing argument to `CATCH_CHECK_THROWS`
* Don't encode extended ASCII in XML
* use `std::shuffle` on more compilers (fixes deprecation warning/error)
* Use `__COUNTER__` more consistently (where available)
#### Other:
##### Other:
* Tweaks and changes to scripts - particularly for Approval test - to make them more portable
# Even Older versions
## Even Older versions
Release notes were not maintained prior to v1.6.0, but you should be able to work them out from the Git history
---

View File

@@ -25,8 +25,8 @@ Because of the way the junit format is structured the run must complete before a
There are a few additional reporters, for specific build systems, in the Catch repository (in `include\reporters`) which you can `#include` in your project if you would like to make use of them.
Do this in one source file - the same one you have `CATCH_CONFIG_MAIN` or `CATCH_CONFIG_RUNNER`.
* `teamcity` writes the native, streaming, format that [TeamCity](https://www.jetbrains.com/teamcity/) understands.
Use this when building as part of a TeamCity build to see results as they happen.
* `teamcity` writes the native, streaming, format that [TeamCity](https://www.jetbrains.com/teamcity/) understands.
Use this when building as part of a TeamCity build to see results as they happen ([code example](../examples/207-Rpt-TeamCityReporter.cpp)).
* `tap` writes in the TAP ([Test Anything Protocol](https://en.wikipedia.org/wiki/Test_Anything_Protocol)) format.
* `automake` writes in a format that correspond to [automake .trs](https://www.gnu.org/software/automake/manual/html_node/Log-files-generation-and-test-results-recording.html) files

View File

@@ -20,10 +20,10 @@ Tags allow an arbitrary number of additional strings to be associated with a tes
As an example - given the following test cases:
TEST_CASE( "A", "[widget]" ) { /* ... */ }
TEST_CASE( "B", "[widget]" ) { /* ... */ }
TEST_CASE( "C", "[gadget]" ) { /* ... */ }
TEST_CASE( "D", "[widget][gadget]" ) { /* ... */ }
TEST_CASE( "A", "[widget]" ) { /* ... */ }
TEST_CASE( "B", "[widget]" ) { /* ... */ }
TEST_CASE( "C", "[gadget]" ) { /* ... */ }
TEST_CASE( "D", "[widget][gadget]" ) { /* ... */ }
The tag expression, ```"[widget]"``` selects A, B & D. ```"[gadget]"``` selects C & D. ```"[widget][gadget]"``` selects just D and ```"[widget],[gadget]"``` selects all four test cases.
@@ -37,7 +37,7 @@ All tag names beginning with non-alphanumeric characters are reserved by Catch.
* `[!hide]` or `[.]` - causes test cases to be skipped from the default list (i.e. when no test cases have been explicitly selected through tag expressions or name wildcards). The hide tag is often combined with another, user, tag (for example `[.][integration]` - so all integration tests are excluded from the default run but can be run by passing `[integration]` on the command line). As a short-cut you can combine these by simply prefixing your user tag with a `.` - e.g. `[.integration]`. Because the hide tag has evolved to have several forms, all forms are added as tags if you use one of them.
* `[!throws]` - lets Catch know that this test is likely to throw an exception even if successful. This causes the test to be excluded when running with `-e` or `--nothrow`.
* `[!throws]` - lets Catch know that this test is likely to throw an exception even if successful. This causes the test to be excluded when running with `-e` or `--nothrow`.
* `[!mayfail]` - doesn't fail the test if any given assertion fails (but still reports it). This can be useful to flag a work-in-progress, or a known issue that you don't want to immediately fix but still want to track in your tests.
@@ -55,11 +55,11 @@ All tag names beginning with non-alphanumeric characters are reserved by Catch.
Between tag expressions and wildcarded test names (as well as combinations of the two) quite complex patterns can be constructed to direct which test cases are run. If a complex pattern is used often it is convenient to be able to create an alias for the expression. This can be done, in code, using the following form:
CATCH_REGISTER_TAG_ALIAS( <alias string>, <tag expression> )
CATCH_REGISTER_TAG_ALIAS( <alias string>, <tag expression> )
Aliases must begin with the `@` character. An example of a tag alias is:
CATCH_REGISTER_TAG_ALIAS( "[@nhf]", "[failing]~[.]" )
CATCH_REGISTER_TAG_ALIAS( "[@nhf]", "[failing]~[.]" )
Now when `[@nhf]` is used on the command line this matches all tests that are tagged `[failing]`, but which are not also hidden.

View File

@@ -1,6 +1,12 @@
<a id="top"></a>
# String conversions
**Contents**<br>
[operator << overload for std::ostream](#operator--overload-for-stdostream)<br>
[Catch::StringMaker specialisation](#catchstringmaker-specialisation)<br>
[Catch::is_range specialisation](#catchis_range-specialisation)<br>
[Exceptions](#exceptions)<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.
@@ -10,8 +16,8 @@ This is the standard way of providing string conversions in C++ - and the chance
```
std::ostream& operator << ( std::ostream& os, T const& value ) {
os << convertMyTypeToString( value );
return os;
os << convertMyTypeToString( value );
return os;
}
```
@@ -19,21 +25,21 @@ std::ostream& operator << ( std::ostream& os, T const& value ) {
You should put this function in the same namespace as your type and have it declared before including Catch's header.
## Catch::StringMaker<T> specialisation
## 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>`:
```
namespace Catch {
template<>
template<>
struct StringMaker<T> {
static std::string convert( T const& value ) {
return convertMyTypeToString( value );
static std::string convert( T const& value ) {
return convertMyTypeToString( value );
}
};
}
```
## Catch::is_range<T> specialisation
## Catch::is_range specialisation
As a fallback, Catch attempts to detect if the type can be iterated
(`begin(T)` and `end(T)` are valid) and if it can be, it is stringified
as a range. For certain types this can lead to infinite recursion, so
@@ -56,7 +62,7 @@ By default all exceptions deriving from `std::exception` will be translated to s
```
CATCH_TRANSLATE_EXCEPTION( MyType& ex ) {
return ex.message();
return ex.message();
}
```

View File

@@ -15,7 +15,7 @@
The simplest way to get Catch2 is to download the latest [single header version](https://raw.githubusercontent.com/catchorg/Catch2/master/single_include/catch2/catch.hpp). The single header is generated by merging a set of individual headers but it is still just normal source code in a header file.
Alternative ways of getting Catch2 include using your system package
manager, or installing it using its CMake package.
manager, or installing it using [its CMake package](cmake-integration.md#installing-catch2-from-git-repository).
The full source for Catch2, including test projects, documentation, and other things, is hosted on GitHub. [http://catch-lib.net](http://catch-lib.net) will redirect you there.

View File

@@ -0,0 +1,27 @@
// 200-Rpt-CatchMain.cpp
// In a Catch project with multiple files, dedicate one file to compile the
// source code of Catch itself and reuse the resulting object file for linking.
// Let Catch provide main():
#define CATCH_CONFIG_MAIN
#include <catch2/catch.hpp>
#ifdef CATCH_EXAMPLE_RPT_1
#include CATCH_EXAMPLE_RPT_1
#endif
#ifdef CATCH_EXAMPLE_RPT_2
#include CATCH_EXAMPLE_RPT_2
#endif
#ifdef CATCH_EXAMPLE_RPT_3
#include CATCH_EXAMPLE_RPT_3
#endif
// That's it
// Compile implementation of Catch for use with files that do contain tests:
// - g++ -std=c++11 -Wall -I$(CATCH_ROOT) -DCATCH_EXAMPLE_RPT_1=\"include/reporters/catch_reporter_teamcity.hpp\" -o 200-Rpt-CatchMainTeamCity.o -c 200-Rpt-CatchMain.cpp
// cl -EHsc -I%CATCH_ROOT% -DCATCH_EXAMPLE_RPT_1=\"include/reporters/catch_reporter_teamcity.hpp\" -Fo200-Rpt-CatchMainTeamCity.obj -c 200-Rpt-CatchMain.cpp

View File

@@ -0,0 +1,171 @@
// 207-Rpt-TeamCityReporter.cpp
// Catch has built-in and external reporters:
// Built-in:
// - compact
// - console
// - junit
// - xml
// External:
// - automake
// - tap
// - teamcity (this example)
// main() and reporter code provided in 200-Rpt-CatchMain.cpp
#include <catch2/catch.hpp>
#ifdef _MSC_VER
# pragma warning (disable : 4702) // Disable warning: unreachable code
#endif
TEST_CASE( "TeamCity passes unconditionally succeeding assertion", "[teamcity]" ) {
SUCCEED();
}
TEST_CASE( "TeamCity reports unconditionally failing assertion", "[teamcity]" ) {
FAIL();
}
TEST_CASE( "TeamCity reports failing check", "[teamcity]" ) {
REQUIRE( 3 == 7 );
}
TEST_CASE( "TeamCity reports failing check-false", "[teamcity]" ) {
REQUIRE_FALSE( 3 == 3 );
}
TEST_CASE( "TeamCity reports failing check-that", "[teamcity]" ) {
using namespace Catch;
REQUIRE_THAT( "hello", Contains( "world" ) );
}
TEST_CASE( "TeamCity reports unexpected exception", "[teamcity]" ) {
REQUIRE( (throw std::runtime_error("surprise!"), true) );
}
TEST_CASE( "TeamCity reports undesired exception", "[teamcity]" ) {
REQUIRE_NOTHROW( (throw std::runtime_error("surprise!"), true) );
}
TEST_CASE( "TeamCity reports missing expected exception", "[teamcity]" ) {
REQUIRE_THROWS( true );
}
TEST_CASE( "TeamCity reports missing specific expected exception", "[teamcity]" ) {
REQUIRE_THROWS_AS( throw std::bad_alloc(), std::runtime_error );
}
TEST_CASE( "TeamCity reports unexpected message in expected exception", "[teamcity]" ) {
using namespace Catch;
CHECK_THROWS_WITH( throw std::runtime_error("hello"), "world" );
CHECK_THROWS_WITH( throw std::runtime_error("hello"), Contains("world") );
}
struct MyException: public std::runtime_error
{
MyException( char const * text )
: std::runtime_error( text ) {}
~MyException() override;
};
// prevent -Wweak-vtables:
MyException::~MyException() = default;
struct MyExceptionMatcher : Catch::MatcherBase< std::runtime_error >
{
std::string m_text;
MyExceptionMatcher( char const * text )
: m_text( text )
{}
~MyExceptionMatcher() override;
bool match( std::runtime_error const & arg ) const override
{
return m_text == arg.what() ;
}
std::string describe() const override
{
return "it's me";
}
};
// prevent -Wweak-vtables:
MyExceptionMatcher::~MyExceptionMatcher() = default;
TEST_CASE( "TeamCity failing check-throws-matches", "[teamcity]" ) {
CHECK_THROWS_MATCHES( throw MyException("hello"), MyException, MyExceptionMatcher("world") );
}
// [!throws] - lets Catch know that this test is likely to throw an exception even if successful.
// This causes the test to be excluded when running with -e or --nothrow.
// No special effects for the reporter.
TEST_CASE( "TeamCity throwing exception with tag [!throws]", "[teamcity][!throws]" ) {
REQUIRE_THROWS( throw std::runtime_error("unsurprisingly") );
}
// [!mayfail] - doesn't fail the test if any given assertion fails (but still reports it). This can be useful to flag a work-in-progress, or a known issue that you don't want to immediately fix but still want to track in your tests.
TEST_CASE( "TeamCity failing assertion with tag [!mayfail]", "[teamcity][!mayfail] " ) {
REQUIRE( 3 == 7 ); // doesn't fail test case this time, reports: testIgnored
REQUIRE( 3 == 3 );
}
// [!shouldfail] - like [!mayfail] but fails the test if it passes.
// This can be useful if you want to be notified of accidental, or third-party, fixes.
TEST_CASE( "TeamCity succeeding assertion with tag [!shouldfail]", "[teamcity][!shouldfail]" ) {
SUCCEED( "Marked [!shouldfail]" );
}
// Compile & run:
// - g++ -std=c++11 -Wall -I$(CATCH_ROOT) -DCATCH_EXAMPLE_RPT_1=\"include/reporters/catch_reporter_teamcity.hpp\" -o 200-Rpt-CatchMainTeamCity.o -c 200-Rpt-CatchMain.cpp
// - g++ -std=c++11 -Wall -I$(CATCH_ROOT) -o 207-Rpt-TeamCityReporter 207-Rpt-TeamCityReporter.cpp 200-Rpt-CatchMainTeamCity.o && 207-Rpt-TeamCityReporter --list-reporters
//
// - cl -EHsc -I%CATCH_ROOT% -DCATCH_EXAMPLE_RPT_1=\"include/reporters/catch_reporter_teamcity.hpp\" -Fo200-Rpt-CatchMainTeamCity.obj -c 200-Rpt-CatchMain.cpp
// - cl -EHsc -I%CATCH_ROOT% 207-Rpt-TeamCityReporter.cpp 200-Rpt-CatchMainTeamCity.o && 207-Rpt-TeamCityReporter --list-reporters
// Compilation output (--list-reporters):
// Available reporters:
// compact: Reports test results on a single line, suitable for IDEs
// console: Reports test results as plain lines of text
// junit: Reports test results in an XML format that looks like Ant's
// junitreport target
// teamcity: Reports test results as TeamCity service messages
// xml: Reports test results as an XML document
// Expected output (abbreviated and broken into shorter lines):
//
// prompt> 207-Rpt-TeamCityReporter.exe --reporter teamcity
// ##teamcity[testSuiteStarted name='207-Rpt-TeamCityReporter.exe']
// ##teamcity[testStarted name='TeamCity passes unconditionally succeeding assertion']
// ##teamcity[testFinished name='TeamCity passes unconditionally succeeding assertion' duration='1']
// ##teamcity[testStarted name='TeamCity reports unconditionally failing assertion']
// ##teamcity[testFailed name='TeamCity reports unconditionally failing assertion' /
// message='.../examples/207-Rpt-TeamCityReporter.cpp:23|n/
// ...............................................................................|n|n/
// .../examples/207-Rpt-TeamCityReporter.cpp:25|nexplicit failure']
// ##teamcity[testFinished name='TeamCity reports unconditionally failing assertion' duration='3']
// ...

View File

@@ -8,10 +8,13 @@ cmake_minimum_required( VERSION 3.0 )
project( CatchExamples CXX )
message( STATUS "Examples included" )
# define folders used:
set( EXAMPLES_DIR ${CATCH_DIR}/examples )
set( HEADER_DIR ${CATCH_DIR}/single_include )
set( REPORTER_HEADER_DIR ${CATCH_DIR}/include/reporters )
# single-file sources:
@@ -43,6 +46,26 @@ set( SOURCES_IDIOMATIC_TESTS
210-Evt-EventListeners.cpp
)
# main-s for reporter-specific test sources:
set( SOURCES_REPORTERS_MAIN
200-Rpt-CatchMain.cpp
)
string( REPLACE ".cpp" "" BASENAMES_REPORTERS_MAIN 200-Rpt-CatchMain.cpp )
set( NAMES_REPORTERS TeamCity )
foreach( reporter ${NAMES_REPORTERS} )
list( APPEND SOURCES_SPECIFIC_REPORTERS_MAIN ${BASENAMES_REPORTERS_MAIN}${reporter}.cpp )
endforeach()
# sources to combine with 200-Rpt-CatchMain{Reporter}.cpp:
set( SOURCES_REPORTERS_TESTS
207-Rpt-TeamCityReporter.cpp
)
# check if all sources are listed, warn if not:
set( SOURCES_ALL
@@ -50,6 +73,8 @@ set( SOURCES_ALL
${SOURCES_SINGLE_FILE}
${SOURCES_IDIOMATIC_MAIN}
${SOURCES_IDIOMATIC_TESTS}
${SOURCES_REPORTERS_MAIN}
${SOURCES_REPORTERS_TESTS}
)
foreach( name ${SOURCES_ALL} )
@@ -62,16 +87,31 @@ CheckFileList( SOURCES_ALL_PATH ${EXAMPLES_DIR} )
string( REPLACE ".cpp" "" BASENAMES_SINGLE_FILE "${SOURCES_SINGLE_FILE}" )
string( REPLACE ".cpp" "" BASENAMES_IDIOMATIC_TESTS "${SOURCES_IDIOMATIC_TESTS}" )
string( REPLACE ".cpp" "" BASENAMES_REPORTERS_TESTS "${SOURCES_REPORTERS_TESTS}" )
string( REPLACE ".cpp" "" BASENAMES_REPORTERS_MAIN "${SOURCES_REPORTERS_MAIN}" )
set( TARGETS_SINGLE_FILE ${BASENAMES_SINGLE_FILE} )
set( TARGETS_IDIOMATIC_TESTS ${BASENAMES_IDIOMATIC_TESTS} )
set( TARGETS_ALL ${TARGETS_SINGLE_FILE} ${TARGETS_IDIOMATIC_TESTS} 020-TestCase CatchMain )
set( TARGETS_REPORTERS_TESTS ${BASENAMES_REPORTERS_TESTS} )
set( TARGETS_REPORTERS_MAIN ${BASENAMES_REPORTERS_MAIN} )
set( TARGETS_ALL
${TARGETS_SINGLE_FILE}
020-TestCase
${TARGETS_IDIOMATIC_TESTS} CatchMain
${TARGETS_REPORTERS_TESTS} CatchMainTeamCity
)
# define program targets:
add_library( CatchMain OBJECT ${EXAMPLES_DIR}/${SOURCES_IDIOMATIC_MAIN} ${HEADER_DIR}/catch2/catch.hpp )
add_library( CatchMain OBJECT ${EXAMPLES_DIR}/${SOURCES_IDIOMATIC_MAIN} ${HEADER_DIR}/catch2/catch.hpp )
#add_library( CatchMainAutomake OBJECT ${EXAMPLES_DIR}/200-Rpt-CatchMain.cpp ${HEADER_DIR}/catch2/catch.hpp )
#add_library( CatchMainTap OBJECT ${EXAMPLES_DIR}/200-Rpt-CatchMain.cpp ${HEADER_DIR}/catch2/catch.hpp )
add_library( CatchMainTeamCity OBJECT ${EXAMPLES_DIR}/200-Rpt-CatchMain.cpp ${HEADER_DIR}/catch2/catch.hpp )
add_executable( 020-TestCase ${EXAMPLES_DIR}/020-TestCase-1.cpp ${EXAMPLES_DIR}/020-TestCase-2.cpp ${HEADER_DIR}/catch2/catch.hpp )
#target_compile_definitions( CatchMainAutomake PRIVATE CATCH_EXAMPLE_RPT_1=\"include/reporters/catch_reporter_automake.hpp\" )
#target_compile_definitions( CatchMainTap PRIVATE CATCH_EXAMPLE_RPT_1=\"include/reporters/catch_reporter_tap.hpp\" )
target_compile_definitions( CatchMainTeamCity PRIVATE CATCH_EXAMPLE_RPT_1=\"include/reporters/catch_reporter_teamcity.hpp\" )
foreach( name ${TARGETS_SINGLE_FILE} )
add_executable( ${name} ${EXAMPLES_DIR}/${name}.cpp ${HEADER_DIR}/catch2/catch.hpp )
@@ -81,10 +121,21 @@ foreach( name ${TARGETS_IDIOMATIC_TESTS} )
add_executable( ${name} ${EXAMPLES_DIR}/${name}.cpp $<TARGET_OBJECTS:CatchMain> ${HEADER_DIR}/catch2/catch.hpp )
endforeach()
add_executable( 020-TestCase ${EXAMPLES_DIR}/020-TestCase-1.cpp ${EXAMPLES_DIR}/020-TestCase-2.cpp ${HEADER_DIR}/catch2/catch.hpp )
#add_executable( 207-Rpt-AutomakeReporter ${EXAMPLES_DIR}/207-Rpt-AutomakeReporter.cpp $<TARGET_OBJECTS:CatchMainAutomake> ${HEADER_DIR}/catch2/catch.hpp )
#add_executable( 207-Rpt-TapReporter ${EXAMPLES_DIR}/207-Rpt-TapReporter.cpp $<TARGET_OBJECTS:CatchMainTap> ${HEADER_DIR}/catch2/catch.hpp )
add_executable( 207-Rpt-TeamCityReporter ${EXAMPLES_DIR}/207-Rpt-TeamCityReporter.cpp $<TARGET_OBJECTS:CatchMainTeamCity> ${HEADER_DIR}/catch2/catch.hpp )
#foreach( name ${TARGETS_REPORTERS_TESTS} )
# add_executable( ${name} ${EXAMPLES_DIR}/${name}.cpp $<TARGET_OBJECTS:CatchMain> ${HEADER_DIR}/catch2/catch.hpp )
#endforeach()
foreach( name ${TARGETS_ALL} )
target_include_directories( ${name} PRIVATE ${HEADER_DIR} )
target_include_directories( ${name} PRIVATE ${HEADER_DIR} ${CATCH_DIR} )
set_property(TARGET ${name} PROPERTY CXX_STANDARD 11)
set_property(TARGET ${name} PROPERTY CXX_EXTENSIONS OFF)
# Add desired warnings
if ( CMAKE_CXX_COMPILER_ID MATCHES "Clang|AppleClang|GNU" )
@@ -99,3 +150,4 @@ foreach( name ${TARGETS_ALL} )
target_compile_options( ${name} PRIVATE /W4 /w44265 /WX )
endif()
endforeach()

View File

@@ -10,8 +10,8 @@
#define TWOBLUECUBES_CATCH_HPP_INCLUDED
#define CATCH_VERSION_MAJOR 2
#define CATCH_VERSION_MINOR 3
#define CATCH_VERSION_PATCH 0
#define CATCH_VERSION_MINOR 4
#define CATCH_VERSION_PATCH 2
#ifdef __clang__
# pragma clang system_header
@@ -62,6 +62,7 @@
#ifndef CATCH_CONFIG_DISABLE_MATCHERS
#include "internal/catch_capture_matchers.h"
#endif
#include "internal/catch_generators.hpp"
// These files are included here so the single_include script doesn't put them
// in the conditionally compiled sections
@@ -130,7 +131,7 @@
#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg )
#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( "CATCH_WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
#define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( "CATCH_CAPTURE", #msg " := " << ::Catch::Detail::stringify(msg) )
#define CATCH_CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CATCH_CAPTURE",__VA_ARGS__ )
#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
@@ -144,14 +145,24 @@
#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE()
#if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE)
#define CATCH_STATIC_REQUIRE( ... ) static_assert( __VA_ARGS__ , #__VA_ARGS__ ); CATCH_SUCCEED( #__VA_ARGS__ )
#define CATCH_STATIC_REQUIRE_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); CATCH_SUCCEED( #__VA_ARGS__ )
#else
#define CATCH_STATIC_REQUIRE( ... ) CATCH_REQUIRE( __VA_ARGS__ )
#define CATCH_STATIC_REQUIRE_FALSE( ... ) CATCH_REQUIRE_FALSE( __VA_ARGS__ )
#endif
// "BDD-style" convenience wrappers
#define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ )
#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ )
#define CATCH_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Given: " << desc )
#define CATCH_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " When: " << desc )
#define CATCH_AND_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And when: " << desc )
#define CATCH_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc )
#define CATCH_AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc )
#define CATCH_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Given: " << desc )
#define CATCH_AND_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And given: " << desc )
#define CATCH_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " When: " << desc )
#define CATCH_AND_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And when: " << desc )
#define CATCH_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc )
#define CATCH_AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc )
// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required
#else
@@ -190,7 +201,7 @@
#define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg )
#define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
#define CAPTURE( msg ) INTERNAL_CATCH_INFO( "CAPTURE", #msg " := " << ::Catch::Detail::stringify(msg) )
#define CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CAPTURE",__VA_ARGS__ )
#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
@@ -203,6 +214,14 @@
#define SUCCEED( ... ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE()
#if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE)
#define STATIC_REQUIRE( ... ) static_assert( __VA_ARGS__, #__VA_ARGS__ ); SUCCEED( #__VA_ARGS__ )
#define STATIC_REQUIRE_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); SUCCEED( "!(" #__VA_ARGS__ ")" )
#else
#define STATIC_REQUIRE( ... ) REQUIRE( __VA_ARGS__ )
#define STATIC_REQUIRE_FALSE( ... ) REQUIRE_FALSE( __VA_ARGS__ )
#endif
#endif
#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature )
@@ -211,11 +230,12 @@
#define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ )
#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ )
#define GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Given: " << desc )
#define WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " When: " << desc )
#define AND_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And when: " << desc )
#define THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc )
#define AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc )
#define GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Given: " << desc )
#define AND_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And given: " << desc )
#define WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " When: " << desc )
#define AND_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And when: " << desc )
#define THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc )
#define AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc )
using Catch::Detail::Approx;
@@ -276,11 +296,15 @@ using Catch::Detail::Approx;
#define CATCH_SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className )
#define CATCH_GIVEN( desc )
#define CATCH_AND_GIVEN( desc )
#define CATCH_WHEN( desc )
#define CATCH_AND_WHEN( desc )
#define CATCH_THEN( desc )
#define CATCH_AND_THEN( desc )
#define CATCH_STATIC_REQUIRE( ... ) (void)(0)
#define CATCH_STATIC_REQUIRE_FALSE( ... ) (void)(0)
// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required
#else
@@ -331,6 +355,10 @@ using Catch::Detail::Approx;
#define SUCCEED( ... ) (void)(0)
#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
#define STATIC_REQUIRE( ... ) (void)(0)
#define STATIC_REQUIRE_FALSE( ... ) (void)(0)
#endif
#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature )
@@ -340,6 +368,7 @@ using Catch::Detail::Approx;
#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className )
#define GIVEN( desc )
#define AND_GIVEN( desc )
#define WHEN( desc )
#define AND_WHEN( desc )
#define THEN( desc )

View File

@@ -5,7 +5,7 @@
//
// See https://github.com/philsquared/Clara for more details
// Clara v1.1.4
// Clara v1.1.5
#ifndef CATCH_CLARA_HPP_INCLUDED
#define CATCH_CLARA_HPP_INCLUDED
@@ -34,8 +34,8 @@
//
// A single-header library for wrapping and laying out basic text, by Phil Nash
//
// This work is licensed under the BSD 2-Clause license.
// See the accompanying LICENSE file, or the one at https://opensource.org/licenses/BSD-2-Clause
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// This project is hosted at https://github.com/philsquared/textflowcpp
@@ -52,317 +52,326 @@
#endif
namespace Catch { namespace clara { namespace TextFlow {
namespace Catch {
namespace clara {
namespace TextFlow {
inline auto isWhitespace( char c ) -> bool {
static std::string chars = " \t\n\r";
return chars.find( c ) != std::string::npos;
}
inline auto isBreakableBefore( char c ) -> bool {
static std::string chars = "[({<|";
return chars.find( c ) != std::string::npos;
}
inline auto isBreakableAfter( char c ) -> bool {
static std::string chars = "])}>.,:;*+-=&/\\";
return chars.find( c ) != std::string::npos;
}
inline auto isWhitespace(char c) -> bool {
static std::string chars = " \t\n\r";
return chars.find(c) != std::string::npos;
}
inline auto isBreakableBefore(char c) -> bool {
static std::string chars = "[({<|";
return chars.find(c) != std::string::npos;
}
inline auto isBreakableAfter(char c) -> bool {
static std::string chars = "])}>.,:;*+-=&/\\";
return chars.find(c) != std::string::npos;
}
class Columns;
class Columns;
class Column {
std::vector<std::string> m_strings;
size_t m_width = CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH;
size_t m_indent = 0;
size_t m_initialIndent = std::string::npos;
class Column {
std::vector<std::string> m_strings;
size_t m_width = CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH;
size_t m_indent = 0;
size_t m_initialIndent = std::string::npos;
public:
class iterator {
friend Column;
public:
class iterator {
friend Column;
Column const& m_column;
size_t m_stringIndex = 0;
size_t m_pos = 0;
Column const& m_column;
size_t m_stringIndex = 0;
size_t m_pos = 0;
size_t m_len = 0;
size_t m_end = 0;
bool m_suffix = false;
size_t m_len = 0;
size_t m_end = 0;
bool m_suffix = false;
iterator( Column const& column, size_t stringIndex )
: m_column( column ),
m_stringIndex( stringIndex )
{}
iterator(Column const& column, size_t stringIndex)
: m_column(column),
m_stringIndex(stringIndex) {}
auto line() const -> std::string const& { return m_column.m_strings[m_stringIndex]; }
auto line() const -> std::string const& { return m_column.m_strings[m_stringIndex]; }
auto isBoundary( size_t at ) const -> bool {
assert( at > 0 );
assert( at <= line().size() );
auto isBoundary(size_t at) const -> bool {
assert(at > 0);
assert(at <= line().size());
return at == line().size() ||
( isWhitespace( line()[at] ) && !isWhitespace( line()[at-1] ) ) ||
isBreakableBefore( line()[at] ) ||
isBreakableAfter( line()[at-1] );
}
return at == line().size() ||
(isWhitespace(line()[at]) && !isWhitespace(line()[at - 1])) ||
isBreakableBefore(line()[at]) ||
isBreakableAfter(line()[at - 1]);
}
void calcLength() {
assert( m_stringIndex < m_column.m_strings.size() );
void calcLength() {
assert(m_stringIndex < m_column.m_strings.size());
m_suffix = false;
auto width = m_column.m_width-indent();
m_end = m_pos;
while( m_end < line().size() && line()[m_end] != '\n' )
++m_end;
m_suffix = false;
auto width = m_column.m_width - indent();
m_end = m_pos;
while (m_end < line().size() && line()[m_end] != '\n')
++m_end;
if( m_end < m_pos + width ) {
m_len = m_end - m_pos;
}
else {
size_t len = width;
while (len > 0 && !isBoundary(m_pos + len))
--len;
while (len > 0 && isWhitespace( line()[m_pos + len - 1] ))
--len;
if (m_end < m_pos + width) {
m_len = m_end - m_pos;
} else {
size_t len = width;
while (len > 0 && !isBoundary(m_pos + len))
--len;
while (len > 0 && isWhitespace(line()[m_pos + len - 1]))
--len;
if (len > 0) {
m_len = len;
} else {
m_suffix = true;
m_len = width - 1;
}
}
}
if (len > 0) {
m_len = len;
} else {
m_suffix = true;
m_len = width - 1;
}
}
}
auto indent() const -> size_t {
auto initial = m_pos == 0 && m_stringIndex == 0 ? m_column.m_initialIndent : std::string::npos;
return initial == std::string::npos ? m_column.m_indent : initial;
}
auto indent() const -> size_t {
auto initial = m_pos == 0 && m_stringIndex == 0 ? m_column.m_initialIndent : std::string::npos;
return initial == std::string::npos ? m_column.m_indent : initial;
}
auto addIndentAndSuffix(std::string const &plain) const -> std::string {
return std::string( indent(), ' ' ) + (m_suffix ? plain + "-" : plain);
}
auto addIndentAndSuffix(std::string const &plain) const -> std::string {
return std::string(indent(), ' ') + (m_suffix ? plain + "-" : plain);
}
public:
explicit iterator( Column const& column ) : m_column( column ) {
assert( m_column.m_width > m_column.m_indent );
assert( m_column.m_initialIndent == std::string::npos || m_column.m_width > m_column.m_initialIndent );
calcLength();
if( m_len == 0 )
m_stringIndex++; // Empty string
}
public:
using difference_type = std::ptrdiff_t;
using value_type = std::string;
using pointer = value_type * ;
using reference = value_type & ;
using iterator_category = std::forward_iterator_tag;
auto operator *() const -> std::string {
assert( m_stringIndex < m_column.m_strings.size() );
assert( m_pos <= m_end );
if( m_pos + m_column.m_width < m_end )
return addIndentAndSuffix(line().substr(m_pos, m_len));
else
return addIndentAndSuffix(line().substr(m_pos, m_end - m_pos));
}
explicit iterator(Column const& column) : m_column(column) {
assert(m_column.m_width > m_column.m_indent);
assert(m_column.m_initialIndent == std::string::npos || m_column.m_width > m_column.m_initialIndent);
calcLength();
if (m_len == 0)
m_stringIndex++; // Empty string
}
auto operator ++() -> iterator& {
m_pos += m_len;
if( m_pos < line().size() && line()[m_pos] == '\n' )
m_pos += 1;
else
while( m_pos < line().size() && isWhitespace( line()[m_pos] ) )
++m_pos;
auto operator *() const -> std::string {
assert(m_stringIndex < m_column.m_strings.size());
assert(m_pos <= m_end);
return addIndentAndSuffix(line().substr(m_pos, m_len));
}
if( m_pos == line().size() ) {
m_pos = 0;
++m_stringIndex;
}
if( m_stringIndex < m_column.m_strings.size() )
calcLength();
return *this;
}
auto operator ++(int) -> iterator {
iterator prev( *this );
operator++();
return prev;
}
auto operator ++() -> iterator& {
m_pos += m_len;
if (m_pos < line().size() && line()[m_pos] == '\n')
m_pos += 1;
else
while (m_pos < line().size() && isWhitespace(line()[m_pos]))
++m_pos;
auto operator ==( iterator const& other ) const -> bool {
return
m_pos == other.m_pos &&
m_stringIndex == other.m_stringIndex &&
&m_column == &other.m_column;
}
auto operator !=( iterator const& other ) const -> bool {
return !operator==( other );
}
};
using const_iterator = iterator;
if (m_pos == line().size()) {
m_pos = 0;
++m_stringIndex;
}
if (m_stringIndex < m_column.m_strings.size())
calcLength();
return *this;
}
auto operator ++(int) -> iterator {
iterator prev(*this);
operator++();
return prev;
}
explicit Column( std::string const& text ) { m_strings.push_back( text ); }
auto operator ==(iterator const& other) const -> bool {
return
m_pos == other.m_pos &&
m_stringIndex == other.m_stringIndex &&
&m_column == &other.m_column;
}
auto operator !=(iterator const& other) const -> bool {
return !operator==(other);
}
};
using const_iterator = iterator;
auto width( size_t newWidth ) -> Column& {
assert( newWidth > 0 );
m_width = newWidth;
return *this;
}
auto indent( size_t newIndent ) -> Column& {
m_indent = newIndent;
return *this;
}
auto initialIndent( size_t newIndent ) -> Column& {
m_initialIndent = newIndent;
return *this;
}
explicit Column(std::string const& text) { m_strings.push_back(text); }
auto width() const -> size_t { return m_width; }
auto begin() const -> iterator { return iterator( *this ); }
auto end() const -> iterator { return { *this, m_strings.size() }; }
auto width(size_t newWidth) -> Column& {
assert(newWidth > 0);
m_width = newWidth;
return *this;
}
auto indent(size_t newIndent) -> Column& {
m_indent = newIndent;
return *this;
}
auto initialIndent(size_t newIndent) -> Column& {
m_initialIndent = newIndent;
return *this;
}
inline friend std::ostream& operator << ( std::ostream& os, Column const& col ) {
bool first = true;
for( auto line : col ) {
if( first )
first = false;
else
os << "\n";
os << line;
}
return os;
}
auto width() const -> size_t { return m_width; }
auto begin() const -> iterator { return iterator(*this); }
auto end() const -> iterator { return { *this, m_strings.size() }; }
auto operator + ( Column const& other ) -> Columns;
inline friend std::ostream& operator << (std::ostream& os, Column const& col) {
bool first = true;
for (auto line : col) {
if (first)
first = false;
else
os << "\n";
os << line;
}
return os;
}
auto toString() const -> std::string {
std::ostringstream oss;
oss << *this;
return oss.str();
}
};
auto operator + (Column const& other)->Columns;
class Spacer : public Column {
auto toString() const -> std::string {
std::ostringstream oss;
oss << *this;
return oss.str();
}
};
public:
explicit Spacer( size_t spaceWidth ) : Column( "" ) {
width( spaceWidth );
}
};
class Spacer : public Column {
class Columns {
std::vector<Column> m_columns;
public:
explicit Spacer(size_t spaceWidth) : Column("") {
width(spaceWidth);
}
};
public:
class Columns {
std::vector<Column> m_columns;
class iterator {
friend Columns;
struct EndTag {};
public:
std::vector<Column> const& m_columns;
std::vector<Column::iterator> m_iterators;
size_t m_activeIterators;
class iterator {
friend Columns;
struct EndTag {};
iterator( Columns const& columns, EndTag )
: m_columns( columns.m_columns ),
m_activeIterators( 0 )
{
m_iterators.reserve( m_columns.size() );
std::vector<Column> const& m_columns;
std::vector<Column::iterator> m_iterators;
size_t m_activeIterators;
for( auto const& col : m_columns )
m_iterators.push_back( col.end() );
}
iterator(Columns const& columns, EndTag)
: m_columns(columns.m_columns),
m_activeIterators(0) {
m_iterators.reserve(m_columns.size());
public:
explicit iterator( Columns const& columns )
: m_columns( columns.m_columns ),
m_activeIterators( m_columns.size() )
{
m_iterators.reserve( m_columns.size() );
for (auto const& col : m_columns)
m_iterators.push_back(col.end());
}
for( auto const& col : m_columns )
m_iterators.push_back( col.begin() );
}
public:
using difference_type = std::ptrdiff_t;
using value_type = std::string;
using pointer = value_type * ;
using reference = value_type & ;
using iterator_category = std::forward_iterator_tag;
auto operator ==( iterator const& other ) const -> bool {
return m_iterators == other.m_iterators;
}
auto operator !=( iterator const& other ) const -> bool {
return m_iterators != other.m_iterators;
}
auto operator *() const -> std::string {
std::string row, padding;
explicit iterator(Columns const& columns)
: m_columns(columns.m_columns),
m_activeIterators(m_columns.size()) {
m_iterators.reserve(m_columns.size());
for( size_t i = 0; i < m_columns.size(); ++i ) {
auto width = m_columns[i].width();
if( m_iterators[i] != m_columns[i].end() ) {
std::string col = *m_iterators[i];
row += padding + col;
if( col.size() < width )
padding = std::string( width - col.size(), ' ' );
else
padding = "";
}
else {
padding += std::string( width, ' ' );
}
}
return row;
}
auto operator ++() -> iterator& {
for( size_t i = 0; i < m_columns.size(); ++i ) {
if (m_iterators[i] != m_columns[i].end())
++m_iterators[i];
}
return *this;
}
auto operator ++(int) -> iterator {
iterator prev( *this );
operator++();
return prev;
}
};
using const_iterator = iterator;
for (auto const& col : m_columns)
m_iterators.push_back(col.begin());
}
auto begin() const -> iterator { return iterator( *this ); }
auto end() const -> iterator { return { *this, iterator::EndTag() }; }
auto operator ==(iterator const& other) const -> bool {
return m_iterators == other.m_iterators;
}
auto operator !=(iterator const& other) const -> bool {
return m_iterators != other.m_iterators;
}
auto operator *() const -> std::string {
std::string row, padding;
auto operator += ( Column const& col ) -> Columns& {
m_columns.push_back( col );
return *this;
}
auto operator + ( Column const& col ) -> Columns {
Columns combined = *this;
combined += col;
return combined;
}
for (size_t i = 0; i < m_columns.size(); ++i) {
auto width = m_columns[i].width();
if (m_iterators[i] != m_columns[i].end()) {
std::string col = *m_iterators[i];
row += padding + col;
if (col.size() < width)
padding = std::string(width - col.size(), ' ');
else
padding = "";
} else {
padding += std::string(width, ' ');
}
}
return row;
}
auto operator ++() -> iterator& {
for (size_t i = 0; i < m_columns.size(); ++i) {
if (m_iterators[i] != m_columns[i].end())
++m_iterators[i];
}
return *this;
}
auto operator ++(int) -> iterator {
iterator prev(*this);
operator++();
return prev;
}
};
using const_iterator = iterator;
inline friend std::ostream& operator << ( std::ostream& os, Columns const& cols ) {
auto begin() const -> iterator { return iterator(*this); }
auto end() const -> iterator { return { *this, iterator::EndTag() }; }
bool first = true;
for( auto line : cols ) {
if( first )
first = false;
else
os << "\n";
os << line;
}
return os;
}
auto operator += (Column const& col) -> Columns& {
m_columns.push_back(col);
return *this;
}
auto operator + (Column const& col) -> Columns {
Columns combined = *this;
combined += col;
return combined;
}
auto toString() const -> std::string {
std::ostringstream oss;
oss << *this;
return oss.str();
}
};
inline friend std::ostream& operator << (std::ostream& os, Columns const& cols) {
inline auto Column::operator + ( Column const& other ) -> Columns {
Columns cols;
cols += *this;
cols += other;
return cols;
}
}}} // namespace Catch::clara::TextFlow
bool first = true;
for (auto line : cols) {
if (first)
first = false;
else
os << "\n";
os << line;
}
return os;
}
auto toString() const -> std::string {
std::ostringstream oss;
oss << *this;
return oss.str();
}
};
inline auto Column::operator + (Column const& other) -> Columns {
Columns cols;
cols += *this;
cols += other;
return cols;
}
}
}
}
#endif // CATCH_CLARA_TEXTFLOW_HPP_INCLUDED
// ----------- end of #include from clara_textflow.hpp -----------
// ........... back in clara.hpp
#include <string>
#include <memory>
#include <set>
#include <algorithm>

View File

@@ -7,6 +7,7 @@
*/
#include "catch_approx.h"
#include "catch_enforce.h"
#include <cmath>
#include <limits>
@@ -54,6 +55,20 @@ namespace Detail {
return marginComparison(m_value, other, m_margin) || marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(m_value)));
}
void Approx::setMargin(double margin) {
CATCH_ENFORCE(margin >= 0,
"Invalid Approx::margin: " << margin << '.'
<< " Approx::Margin has to be non-negative.");
m_margin = margin;
}
void Approx::setEpsilon(double epsilon) {
CATCH_ENFORCE(epsilon >= 0 && epsilon <= 1.0,
"Invalid Approx::epsilon: " << epsilon << '.'
<< " Approx::epsilon has to be in [0, 1]");
m_epsilon = epsilon;
}
} // end namespace Detail
namespace literals {

View File

@@ -11,7 +11,6 @@
#include "catch_tostring.h"
#include <type_traits>
#include <stdexcept>
namespace Catch {
namespace Detail {
@@ -19,6 +18,12 @@ namespace Detail {
class Approx {
private:
bool equalityComparisonImpl(double other) const;
// Validates the new margin (margin >= 0)
// out-of-line to avoid including stdexcept in the header
void setMargin(double margin);
// Validates the new epsilon (0 < epsilon < 1)
// out-of-line to avoid including stdexcept in the header
void setEpsilon(double epsilon);
public:
explicit Approx ( double value );
@@ -30,9 +35,9 @@ namespace Detail {
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
Approx operator()( T const& value ) {
Approx approx( static_cast<double>(value) );
approx.epsilon( m_epsilon );
approx.margin( m_margin );
approx.scale( m_scale );
approx.m_epsilon = m_epsilon;
approx.m_margin = m_margin;
approx.m_scale = m_scale;
return approx;
}
@@ -85,27 +90,14 @@ namespace Detail {
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
Approx& epsilon( T const& newEpsilon ) {
double epsilonAsDouble = static_cast<double>(newEpsilon);
if( epsilonAsDouble < 0 || epsilonAsDouble > 1.0 ) {
throw std::domain_error
( "Invalid Approx::epsilon: " +
Catch::Detail::stringify( epsilonAsDouble ) +
", Approx::epsilon has to be between 0 and 1" );
}
m_epsilon = epsilonAsDouble;
setEpsilon(epsilonAsDouble);
return *this;
}
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
Approx& margin( T const& newMargin ) {
double marginAsDouble = static_cast<double>(newMargin);
if( marginAsDouble < 0 ) {
throw std::domain_error
( "Invalid Approx::margin: " +
Catch::Detail::stringify( marginAsDouble ) +
", Approx::Margin has to be non-negative." );
}
m_margin = marginAsDouble;
setMargin(marginAsDouble);
return *this;
}
@@ -124,7 +116,7 @@ namespace Detail {
double m_value;
};
} // end namespace Detail
namespace literals {
Detail::Approx operator "" _a(long double val);
Detail::Approx operator "" _a(unsigned long long val);

View File

@@ -52,7 +52,7 @@ namespace Catch {
}
AssertionHandler::AssertionHandler
( StringRef macroName,
( StringRef const& macroName,
SourceLineInfo const& lineInfo,
StringRef capturedExpression,
ResultDisposition::Flags resultDisposition )
@@ -81,8 +81,13 @@ namespace Catch {
// (To go back to the test and change execution, jump over the throw, next)
CATCH_BREAK_INTO_DEBUGGER();
}
if( m_reaction.shouldThrow )
if (m_reaction.shouldThrow) {
#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
throw Catch::TestFailureException();
#else
CATCH_ERROR( "Test failure requires aborting test!" );
#endif
}
}
void AssertionHandler::setCompleted() {
m_completed = true;
@@ -109,7 +114,7 @@ namespace Catch {
// This is the overload that takes a string and infers the Equals matcher from it
// The more general overload, that takes any string matcher, is in catch_capture_matchers.cpp
void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef matcherString ) {
void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef const& matcherString ) {
handleExceptionMatchExpr( handler, Matchers::Equals( str ), matcherString );
}

View File

@@ -49,7 +49,7 @@ namespace Catch {
public:
AssertionHandler
( StringRef macroName,
( StringRef const& macroName,
SourceLineInfo const& lineInfo,
StringRef capturedExpression,
ResultDisposition::Flags resultDisposition );
@@ -81,7 +81,7 @@ namespace Catch {
auto allowThrows() const -> bool;
};
void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef matcherString );
void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef const& matcherString );
} // namespace Catch

View File

@@ -9,8 +9,9 @@
#define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED
#include "catch_assertionhandler.h"
#include "catch_message.h"
#include "catch_interfaces_capture.h"
#include "catch_message.h"
#include "catch_stringref.h"
#if !defined(CATCH_CONFIG_DISABLE)
@@ -20,7 +21,7 @@
#define CATCH_INTERNAL_STRINGIFY(...) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION"
#endif
#if defined(CATCH_CONFIG_FAST_COMPILE)
#if defined(CATCH_CONFIG_FAST_COMPILE) || defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
///////////////////////////////////////////////////////////////////////////////
// Another way to speed-up compilation is to omit local try-catch for REQUIRE*
@@ -40,7 +41,7 @@
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \
do { \
Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \
Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \
INTERNAL_CATCH_TRY { \
CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
catchAssertionHandler.handleExpr( Catch::Decomposer() <= __VA_ARGS__ ); \
@@ -63,7 +64,7 @@
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, ... ) \
do { \
Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \
Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \
try { \
static_cast<void>(__VA_ARGS__); \
catchAssertionHandler.handleExceptionNotThrownAsExpected(); \
@@ -77,7 +78,7 @@
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_THROWS( macroName, resultDisposition, ... ) \
do { \
Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition); \
Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition); \
if( catchAssertionHandler.allowThrows() ) \
try { \
static_cast<void>(__VA_ARGS__); \
@@ -94,7 +95,7 @@
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \
do { \
Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr) ", " CATCH_INTERNAL_STRINGIFY(exceptionType), resultDisposition ); \
Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr) ", " CATCH_INTERNAL_STRINGIFY(exceptionType), resultDisposition ); \
if( catchAssertionHandler.allowThrows() ) \
try { \
static_cast<void>(expr); \
@@ -115,27 +116,32 @@
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \
do { \
Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, Catch::StringRef(), resultDisposition ); \
Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::StringRef(), resultDisposition ); \
catchAssertionHandler.handleMessage( messageType, ( Catch::MessageStream() << __VA_ARGS__ + ::Catch::StreamEndStop() ).m_stream.str() ); \
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
} while( false )
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_CAPTURE( varName, macroName, ... ) \
auto varName = Catch::Capturer( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info, #__VA_ARGS__ ); \
varName.captureValues( 0, __VA_ARGS__ )
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_INFO( macroName, log ) \
Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage )( Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log );
Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage )( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log );
///////////////////////////////////////////////////////////////////////////////
// Although this is matcher-based, it can be used with just a string
#define INTERNAL_CATCH_THROWS_STR_MATCHES( macroName, resultDisposition, matcher, ... ) \
do { \
Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
if( catchAssertionHandler.allowThrows() ) \
try { \
static_cast<void>(__VA_ARGS__); \
catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \
} \
catch( ... ) { \
Catch::handleExceptionMatchExpr( catchAssertionHandler, matcher, #matcher ); \
Catch::handleExceptionMatchExpr( catchAssertionHandler, matcher, #matcher##_catch_sr ); \
} \
else \
catchAssertionHandler.handleThrowingCallSkipped(); \

View File

@@ -15,7 +15,7 @@ namespace Catch {
// This is the general overload that takes a any string matcher
// There is another overload, in catch_assertionhandler.h/.cpp, that only takes a string and infers
// the Equals matcher (so the header does not mention matchers)
void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef matcherString ) {
void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef const& matcherString ) {
std::string exceptionMessage = Catch::translateActiveException();
MatchExpr<std::string, StringMatcher const&> expr( exceptionMessage, matcher, matcherString );
handler.handleExpr( expr );

View File

@@ -14,6 +14,7 @@
#include "catch_matchers_generic.hpp"
#include "catch_matchers_string.h"
#include "catch_matchers_vector.h"
#include "catch_stringref.h"
namespace Catch {
@@ -23,7 +24,7 @@ namespace Catch {
MatcherT m_matcher;
StringRef m_matcherString;
public:
MatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef matcherString )
MatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef const& matcherString )
: ITransientExpression{ true, matcher.match( arg ) },
m_arg( arg ),
m_matcher( matcher ),
@@ -42,10 +43,10 @@ namespace Catch {
using StringMatcher = Matchers::Impl::MatcherBase<std::string>;
void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef matcherString );
void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef const& matcherString );
template<typename ArgT, typename MatcherT>
auto makeMatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef matcherString ) -> MatchExpr<ArgT, MatcherT> {
auto makeMatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef const& matcherString ) -> MatchExpr<ArgT, MatcherT> {
return MatchExpr<ArgT, MatcherT>( arg, matcher, matcherString );
}
@@ -55,9 +56,9 @@ namespace Catch {
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \
do { \
Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
INTERNAL_CATCH_TRY { \
catchAssertionHandler.handleExpr( Catch::makeMatchExpr( arg, matcher, #matcher ) ); \
catchAssertionHandler.handleExpr( Catch::makeMatchExpr( arg, matcher, #matcher##_catch_sr ) ); \
} INTERNAL_CATCH_CATCH( catchAssertionHandler ) \
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
} while( false )
@@ -66,14 +67,14 @@ namespace Catch {
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_THROWS_MATCHES( macroName, exceptionType, resultDisposition, matcher, ... ) \
do { \
Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(exceptionType) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(exceptionType) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
if( catchAssertionHandler.allowThrows() ) \
try { \
static_cast<void>(__VA_ARGS__ ); \
catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \
} \
catch( exceptionType const& ex ) { \
catchAssertionHandler.handleExpr( Catch::makeMatchExpr( ex, matcher, #matcher ) ); \
catchAssertionHandler.handleExpr( Catch::makeMatchExpr( ex, matcher, #matcher##_catch_sr ) ); \
} \
catch( ... ) { \
catchAssertionHandler.handleUnexpectedInflightException(); \

View File

@@ -10,6 +10,9 @@
#include "catch_string_manip.h"
#include "catch_interfaces_registry_hub.h"
#include "catch_interfaces_reporter.h"
#include <fstream>
#include <ctime>
@@ -105,6 +108,18 @@ namespace Catch {
return ParserResult::runtimeError( "Unrecognised verbosity, '" + verbosity + "'" );
return ParserResult::ok( ParseResultType::Matched );
};
auto const setReporter = [&]( std::string const& reporter ) {
IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories();
auto lcReporter = toLower( reporter );
auto result = factories.find( lcReporter );
if( factories.end() != result )
config.reporterName = lcReporter;
else
return ParserResult::runtimeError( "Unrecognized reporter, '" + reporter + "'. Check available with --list-reporters" );
return ParserResult::ok( ParseResultType::Matched );
};
auto cli
= ExeName( config.processName )
@@ -130,7 +145,7 @@ namespace Catch {
| Opt( config.outputFilename, "filename" )
["-o"]["--out"]
( "output filename" )
| Opt( config.reporterName, "name" )
| Opt( setReporter, "name" )
["-r"]["--reporter"]
( "reporter to use (defaults to console)" )
| Opt( config.name, "name" )

View File

@@ -22,7 +22,9 @@ namespace Catch {
return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0);
}
bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const noexcept {
return line < other.line || ( line == other.line && (std::strcmp(file, other.file) < 0));
// We can assume that the same file will usually have the same pointer.
// Thus, if the pointers are the same, there is no point in calling the strcmp
return line < other.line || ( line == other.line && file != other.file && (std::strcmp(file, other.file) < 0));
}
std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) {

View File

@@ -22,6 +22,10 @@
#include <string>
#include <cstdint>
// We need a dummy global operator<< so we can bring it into Catch namespace later
struct Catch_global_namespace_dummy {};
std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy);
namespace Catch {
struct CaseSensitive { enum Choice {
@@ -63,6 +67,11 @@ namespace Catch {
std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info );
// Bring in operator<< from global namespace into Catch namespace
// This is necessary because the overload of operator<< above makes
// lookup stop at namespace Catch
using ::operator<<;
// Use this in variadic streaming macros to allow
// >> +StreamEndStop
// as well as

View File

@@ -14,6 +14,7 @@
// CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported?
// CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported?
// CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported?
// CATCH_CONFIG_DISABLE_EXCEPTIONS : Are exceptions enabled?
// ****************
// Note to maintainers: if new toggles are added please document them
// in configuration.md, too
@@ -28,11 +29,11 @@
#ifdef __cplusplus
# if __cplusplus >= 201402L
# if (__cplusplus >= 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L)
# define CATCH_CPP14_OR_GREATER
# endif
# if __cplusplus >= 201703L
# if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
# define CATCH_CPP17_OR_GREATER
# endif
@@ -108,7 +109,14 @@
// 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.
// 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))
# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING
# endif
#endif // __CYGWIN__
////////////////////////////////////////////////////////////////////////////////
@@ -131,7 +139,12 @@
#endif // _MSC_VER
////////////////////////////////////////////////////////////////////////////////
// Check if we are compiled with -fno-exceptions or equivalent
#if defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND)
# define CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED
#endif
////////////////////////////////////////////////////////////////////////////////
// DJGPP
#ifdef __DJGPP__
# define CATCH_INTERNAL_CONFIG_NO_WCHAR
@@ -148,6 +161,33 @@
#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 variant is available and usable
#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)
# endif // defined(__clang__) && (__clang_major__ < 8)
# endif // __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER)
#endif // __has_include
#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER)
# define CATCH_CONFIG_COUNTER
#endif
@@ -171,6 +211,14 @@
# define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
#endif
#if defined(CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_NO_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_CPP17_STRING_VIEW)
# define CATCH_CONFIG_CPP17_STRING_VIEW
#endif
#if defined(CATCH_INTERNAL_CONFIG_CPP17_VARIANT) && !defined(CATCH_CONFIG_NO_CPP17_VARIANT) && !defined(CATCH_CONFIG_CPP17_VARIANT)
# define CATCH_CONFIG_CPP17_VARIANT
#endif
#if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT)
# define CATCH_INTERNAL_CONFIG_NEW_CAPTURE
#endif
@@ -179,6 +227,10 @@
# define CATCH_CONFIG_NEW_CAPTURE
#endif
#if !defined(CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
# define CATCH_CONFIG_DISABLE_EXCEPTIONS
#endif
#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS)
# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS
# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS
@@ -192,6 +244,16 @@
# define CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS
#endif
#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
#define CATCH_TRY if ((true))
#define CATCH_CATCH_ALL if ((false))
#define CATCH_CATCH_ANON(type) if ((false))
#else
#define CATCH_TRY try
#define CATCH_CATCH_ALL catch (...)
#define CATCH_CATCH_ANON(type) catch (type)
#endif
#endif // TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED

View File

@@ -0,0 +1,19 @@
/*
* Created by Martin on 03/09/2018.
*
* 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_enforce.h"
namespace Catch {
#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS_CUSTOM_HANDLER)
[[noreturn]]
void throw_exception(std::exception const& e) {
Catch::cerr() << "Catch will terminate because it needed to throw an exception.\n"
<< "The message was: " << e.what() << '\n';
std::terminate();
}
#endif
} // namespace Catch;

View File

@@ -8,17 +8,35 @@
#define TWOBLUECUBES_CATCH_ENFORCE_H_INCLUDED
#include "catch_common.h"
#include "catch_compiler_capabilities.h"
#include "catch_stream.h"
#include <stdexcept>
namespace Catch {
#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
template <typename Ex>
[[noreturn]]
void throw_exception(Ex const& e) {
throw e;
}
#else // ^^ Exceptions are enabled // Exceptions are disabled vv
[[noreturn]]
void throw_exception(std::exception const& e);
#endif
} // namespace Catch;
#define CATCH_PREPARE_EXCEPTION( type, msg ) \
type( ( Catch::ReusableStringStream() << msg ).str() )
#define CATCH_INTERNAL_ERROR( msg ) \
throw CATCH_PREPARE_EXCEPTION( std::logic_error, CATCH_INTERNAL_LINEINFO << ": Internal Catch error: " << msg);
Catch::throw_exception(CATCH_PREPARE_EXCEPTION( std::logic_error, CATCH_INTERNAL_LINEINFO << ": Internal Catch error: " << msg))
#define CATCH_ERROR( msg ) \
throw CATCH_PREPARE_EXCEPTION( std::domain_error, msg )
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)
#endif // TWOBLUECUBES_CATCH_ENFORCE_H_INCLUDED

View File

@@ -6,8 +6,10 @@
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#include "catch_assertionhandler.h"
#include "catch_exception_translator_registry.h"
#include "catch_assertionhandler.h"
#include "catch_compiler_capabilities.h"
#include "catch_enforce.h"
#ifdef __OBJC__
#import "Foundation/Foundation.h"
@@ -22,6 +24,7 @@ namespace Catch {
m_translators.push_back( std::unique_ptr<const IExceptionTranslator>( translator ) );
}
#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
std::string ExceptionTranslatorRegistry::translateActiveException() const {
try {
#ifdef __OBJC__
@@ -64,6 +67,13 @@ namespace Catch {
}
}
#else // ^^ Exceptions are enabled // Exceptions are disabled vv
std::string ExceptionTranslatorRegistry::translateActiveException() const {
CATCH_INTERNAL_ERROR("Attempted to translate active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!");
}
#endif
std::string ExceptionTranslatorRegistry::tryTranslators() const {
if( m_translators.empty() )
std::rethrow_exception(std::current_exception());

View File

@@ -0,0 +1,50 @@
/*
* Created by Phil Nash on 15/6/2018.
*
* 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_generators.hpp"
#include "catch_random_number_generator.h"
#include "catch_interfaces_capture.h"
#include <limits>
#include <set>
namespace Catch {
IGeneratorTracker::~IGeneratorTracker() {}
namespace Generators {
GeneratorBase::~GeneratorBase() {}
std::vector<size_t> randomiseIndices( size_t selectionSize, size_t sourceSize ) {
assert( selectionSize <= sourceSize );
std::vector<size_t> indices;
indices.reserve( selectionSize );
std::uniform_int_distribution<size_t> uid( 0, sourceSize-1 );
std::set<size_t> seen;
// !TBD: improve this algorithm
while( indices.size() < selectionSize ) {
auto index = uid( rng() );
if( seen.insert( index ).second )
indices.push_back( index );
}
return indices;
}
auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& {
return getResultCapture().acquireGeneratorTracker( lineInfo );
}
template<>
auto all<int>() -> Generator<int> {
return range( std::numeric_limits<int>::min(), std::numeric_limits<int>::max() );
}
} // namespace Generators
} // namespace Catch

View File

@@ -0,0 +1,253 @@
/*
* Created by Phil Nash on 15/6/2018.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED
#include "catch_interfaces_generatortracker.h"
#include "catch_common.h"
#include "catch_enforce.h"
#include <memory>
#include <vector>
#include <cassert>
#include <utility>
namespace Catch {
namespace Generators {
// !TBD move this into its own location?
namespace pf{
template<typename T, typename... Args>
std::unique_ptr<T> make_unique( Args&&... args ) {
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
}
template<typename T>
struct IGenerator {
virtual ~IGenerator() {}
virtual auto get( size_t index ) const -> T = 0;
};
template<typename T>
class SingleValueGenerator : public IGenerator<T> {
T m_value;
public:
SingleValueGenerator( T const& value ) : m_value( value ) {}
auto get( size_t ) const -> T override {
return m_value;
}
};
template<typename T>
class FixedValuesGenerator : public IGenerator<T> {
std::vector<T> m_values;
public:
FixedValuesGenerator( std::initializer_list<T> values ) : m_values( values ) {}
auto get( size_t index ) const -> T override {
return m_values[index];
}
};
template<typename T>
class RangeGenerator : public IGenerator<T> {
T const m_first;
T const m_last;
public:
RangeGenerator( T const& first, T const& last ) : m_first( first ), m_last( last ) {
assert( m_last > m_first );
}
auto get( size_t index ) const -> T override {
// ToDo:: introduce a safe cast to catch potential overflows
return static_cast<T>(m_first+index);
}
};
template<typename T>
struct NullGenerator : IGenerator<T> {
auto get( size_t ) const -> T override {
CATCH_INTERNAL_ERROR("A Null Generator is always empty");
}
};
template<typename T>
class Generator {
std::unique_ptr<IGenerator<T>> m_generator;
size_t m_size;
public:
Generator( size_t size, std::unique_ptr<IGenerator<T>> generator )
: m_generator( std::move( generator ) ),
m_size( size )
{}
auto size() const -> size_t { return m_size; }
auto operator[]( size_t index ) const -> T {
assert( index < m_size );
return m_generator->get( index );
}
};
std::vector<size_t> randomiseIndices( size_t selectionSize, size_t sourceSize );
template<typename T>
class GeneratorRandomiser : public IGenerator<T> {
Generator<T> m_baseGenerator;
std::vector<size_t> m_indices;
public:
GeneratorRandomiser( Generator<T>&& baseGenerator, size_t numberOfItems )
: m_baseGenerator( std::move( baseGenerator ) ),
m_indices( randomiseIndices( numberOfItems, m_baseGenerator.size() ) )
{}
auto get( size_t index ) const -> T override {
return m_baseGenerator[m_indices[index]];
}
};
template<typename T>
struct RequiresASpecialisationFor;
template<typename T>
auto all() -> Generator<T> { return RequiresASpecialisationFor<T>(); }
template<>
auto all<int>() -> Generator<int>;
template<typename T>
auto range( T const& first, T const& last ) -> Generator<T> {
return Generator<T>( (last-first), pf::make_unique<RangeGenerator<T>>( first, last ) );
}
template<typename T>
auto random( T const& first, T const& last ) -> Generator<T> {
auto gen = range( first, last );
auto size = gen.size();
return Generator<T>( size, pf::make_unique<GeneratorRandomiser<T>>( std::move( gen ), size ) );
}
template<typename T>
auto random( size_t size ) -> Generator<T> {
return Generator<T>( size, pf::make_unique<GeneratorRandomiser<T>>( all<T>(), size ) );
}
template<typename T>
auto values( std::initializer_list<T> values ) -> Generator<T> {
return Generator<T>( values.size(), pf::make_unique<FixedValuesGenerator<T>>( values ) );
}
template<typename T>
auto value( T const& val ) -> Generator<T> {
return Generator<T>( 1, pf::make_unique<SingleValueGenerator<T>>( val ) );
}
template<typename T>
auto as() -> Generator<T> {
return Generator<T>( 0, pf::make_unique<NullGenerator<T>>() );
}
template<typename... Ts>
auto table( std::initializer_list<std::tuple<Ts...>>&& tuples ) -> Generator<std::tuple<Ts...>> {
return values<std::tuple<Ts...>>( std::forward<std::initializer_list<std::tuple<Ts...>>>( tuples ) );
}
template<typename T>
struct Generators : GeneratorBase {
std::vector<Generator<T>> m_generators;
using type = T;
Generators() : GeneratorBase( 0 ) {}
void populate( T&& val ) {
m_size += 1;
m_generators.emplace_back( value( std::move( val ) ) );
}
template<typename U>
void populate( U&& val ) {
populate( T( std::move( val ) ) );
}
void populate( Generator<T>&& generator ) {
m_size += generator.size();
m_generators.emplace_back( std::move( generator ) );
}
template<typename U, typename... Gs>
void populate( U&& valueOrGenerator, Gs... moreGenerators ) {
populate( std::forward<U>( valueOrGenerator ) );
populate( std::forward<Gs>( moreGenerators )... );
}
auto operator[]( size_t index ) const -> T {
size_t sizes = 0;
for( auto const& gen : m_generators ) {
auto localIndex = index-sizes;
sizes += gen.size();
if( index < sizes )
return gen[localIndex];
}
CATCH_INTERNAL_ERROR("Index '" << index << "' is out of range (" << sizes << ')');
}
};
template<typename T, typename... Gs>
auto makeGenerators( Generator<T>&& generator, Gs... moreGenerators ) -> Generators<T> {
Generators<T> generators;
generators.m_generators.reserve( 1+sizeof...(Gs) );
generators.populate( std::move( generator ), std::forward<Gs>( moreGenerators )... );
return generators;
}
template<typename T>
auto makeGenerators( Generator<T>&& generator ) -> Generators<T> {
Generators<T> generators;
generators.populate( std::move( generator ) );
return generators;
}
template<typename T, typename... Gs>
auto makeGenerators( T&& val, Gs... moreGenerators ) -> Generators<T> {
return makeGenerators( value( std::forward<T>( val ) ), std::forward<Gs>( moreGenerators )... );
}
template<typename T, typename U, typename... Gs>
auto makeGenerators( U&& val, Gs... moreGenerators ) -> Generators<T> {
return makeGenerators( value( T( std::forward<U>( val ) ) ), std::forward<Gs>( moreGenerators )... );
}
auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker&;
template<typename L>
// Note: The type after -> is weird, because VS2015 cannot parse
// the expression used in the typedef inside, when it is in
// return type. Yeah, ¯\_(ツ)_/¯
auto generate( SourceLineInfo const& lineInfo, L const& generatorExpression ) -> decltype(std::declval<decltype(generatorExpression())>()[0]) {
using UnderlyingType = typename decltype(generatorExpression())::type;
IGeneratorTracker& tracker = acquireGeneratorTracker( lineInfo );
if( !tracker.hasGenerator() )
tracker.setGenerator( pf::make_unique<Generators<UnderlyingType>>( generatorExpression() ) );
auto const& generator = static_cast<Generators<UnderlyingType> const&>( *tracker.getGenerator() );
return generator[tracker.getIndex()];
}
} // namespace Generators
} // namespace Catch
#define GENERATE( ... ) \
Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, []{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } )
#endif // TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED

View File

@@ -24,8 +24,10 @@ namespace Catch {
struct BenchmarkInfo;
struct BenchmarkStats;
struct AssertionReaction;
struct SourceLineInfo;
struct ITransientExpression;
struct IGeneratorTracker;
struct IResultCapture {
@@ -36,6 +38,8 @@ namespace Catch {
virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0;
virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0;
virtual auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& = 0;
virtual void benchmarkStarting( BenchmarkInfo const& info ) = 0;
virtual void benchmarkEnded( BenchmarkStats const& stats ) = 0;

View File

@@ -0,0 +1,39 @@
/*
* Created by Phil Nash on 26/6/2018.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef TWOBLUECUBES_CATCH_INTERFACES_GENERATORTRACKER_INCLUDED
#define TWOBLUECUBES_CATCH_INTERFACES_GENERATORTRACKER_INCLUDED
#include <memory>
namespace Catch {
namespace Generators {
class GeneratorBase {
protected:
size_t m_size = 0;
public:
GeneratorBase( size_t size ) : m_size( size ) {}
virtual ~GeneratorBase();
auto size() const -> size_t { return m_size; }
};
using GeneratorBasePtr = std::unique_ptr<GeneratorBase>;
} // namespace Generators
struct IGeneratorTracker {
virtual ~IGeneratorTracker();
virtual auto hasGenerator() const -> bool = 0;
virtual auto getGenerator() const -> Generators::GeneratorBasePtr const& = 0;
virtual void setGenerator( Generators::GeneratorBasePtr&& generator ) = 0;
virtual auto getIndex() const -> std::size_t = 0;
};
} // namespace Catch
#endif //TWOBLUECUBES_CATCH_INTERFACES_GENERATORTRACKER_INCLUDED

View File

@@ -33,7 +33,7 @@ namespace Catch {
virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0;
virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0;
virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0;
virtual IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const = 0;
virtual StartupExceptionRegistry const& getStartupExceptionRegistry() const = 0;
@@ -49,7 +49,7 @@ namespace Catch {
virtual void registerStartupException() noexcept = 0;
};
IRegistryHub& getRegistryHub();
IRegistryHub const& getRegistryHub();
IMutableRegistryHub& getMutableRegistryHub();
void cleanUp();
std::string translateActiveException();

View File

@@ -6,6 +6,7 @@
*/
#include "catch_leak_detector.h"
#include "catch_interfaces_registry_hub.h"
#ifdef CATCH_CONFIG_WINDOWS_CRTDBG
@@ -13,16 +14,16 @@
namespace Catch {
LeakDetector::LeakDetector() {
int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
flag |= _CRTDBG_LEAK_CHECK_DF;
flag |= _CRTDBG_ALLOC_MEM_DF;
_CrtSetDbgFlag(flag);
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
_CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
// Change this to leaking allocation's number to break there
_CrtSetBreakAlloc(-1);
}
LeakDetector::LeakDetector() {
int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
flag |= _CRTDBG_LEAK_CHECK_DF;
flag |= _CRTDBG_ALLOC_MEM_DF;
_CrtSetDbgFlag(flag);
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
_CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
// Change this to leaking allocation's number to break there
_CrtSetBreakAlloc(-1);
}
}
#else
@@ -30,3 +31,7 @@ namespace Catch {
Catch::LeakDetector::LeakDetector() {}
#endif
Catch::LeakDetector::~LeakDetector() {
Catch::cleanUp();
}

View File

@@ -11,6 +11,7 @@ namespace Catch {
struct LeakDetector {
LeakDetector();
~LeakDetector();
};
}

View File

@@ -124,7 +124,7 @@ namespace Catch {
return tagCounts.size();
}
std::size_t listReporters( Config const& /*config*/ ) {
std::size_t listReporters() {
Catch::cout() << "Available reporters:\n";
IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories();
std::size_t maxNameLen = 0;
@@ -155,7 +155,7 @@ namespace Catch {
if( config.listTags() )
listedCount = listedCount.valueOr(0) + listTags( config );
if( config.listReporters() )
listedCount = listedCount.valueOr(0) + listReporters( config );
listedCount = listedCount.valueOr(0) + listReporters();
return listedCount;
}

View File

@@ -29,7 +29,7 @@ namespace Catch {
std::size_t listTags( Config const& config );
std::size_t listReporters( Config const& /*config*/ );
std::size_t listReporters();
Option<std::size_t> list( Config const& config );

View File

@@ -34,6 +34,11 @@ namespace Matchers {
mutable std::string m_cachedToString;
};
#ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wnon-virtual-dtor"
#endif
template<typename ObjectT>
struct MatcherMethod {
virtual bool match( ObjectT const& arg ) const = 0;
@@ -43,6 +48,10 @@ namespace Matchers {
virtual bool match( PtrT* arg ) const = 0;
};
#ifdef __clang__
# pragma clang diagnostic pop
#endif
template<typename T>
struct MatcherBase : MatcherUntypedBase, MatcherMethod<T> {

View File

@@ -6,13 +6,13 @@
*/
#include "catch_matchers_floating.h"
#include "catch_enforce.h"
#include "catch_to_string.hpp"
#include "catch_tostring.h"
#include <cstdlib>
#include <cstdint>
#include <cstring>
#include <stdexcept>
namespace Catch {
namespace Matchers {
@@ -81,9 +81,8 @@ namespace Matchers {
namespace Floating {
WithinAbsMatcher::WithinAbsMatcher(double target, double margin)
:m_target{ target }, m_margin{ margin } {
if (m_margin < 0) {
throw std::domain_error("Allowed margin difference has to be >= 0");
}
CATCH_ENFORCE(margin >= 0, "Invalid margin: " << margin << '.'
<< " Margin has to be non-negative.");
}
// Performs equivalent check of std::fabs(lhs - rhs) <= margin
@@ -99,11 +98,16 @@ namespace Floating {
WithinUlpsMatcher::WithinUlpsMatcher(double target, int ulps, FloatingPointKind baseType)
:m_target{ target }, m_ulps{ ulps }, m_type{ baseType } {
if (m_ulps < 0) {
throw std::domain_error("Allowed ulp difference has to be >= 0");
}
CATCH_ENFORCE(ulps >= 0, "Invalid ULP setting: " << ulps << '.'
<< " ULPs have to be non-negative.");
}
#if defined(__clang__)
#pragma clang diagnostic push
// Clang <3.5 reports on the default branch in the switch below
#pragma clang diagnostic ignored "-Wunreachable-code"
#endif
bool WithinUlpsMatcher::match(double const& matchee) const {
switch (m_type) {
case FloatingPointKind::Float:
@@ -111,10 +115,14 @@ namespace Floating {
case FloatingPointKind::Double:
return almostEqualUlps<double>(matchee, m_target, m_ulps);
default:
throw std::domain_error("Unknown FloatingPointKind value");
CATCH_INTERNAL_ERROR( "Unknown FloatingPointKind value" );
}
}
#if defined(__clang__)
#pragma clang diagnostic pop
#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" : "");
}

View File

@@ -124,7 +124,7 @@ namespace Matchers {
auto lfirst = m_target.begin(), llast = m_target.end();
auto rfirst = vec.begin(), rlast = vec.end();
// Cut common prefix to optimize checking of permuted parts
while (lfirst != llast && *lfirst != *rfirst) {
while (lfirst != llast && *lfirst == *rfirst) {
++lfirst; ++rfirst;
}
if (lfirst == llast) {

View File

@@ -10,9 +10,11 @@
#include "catch_interfaces_capture.h"
#include "catch_uncaught_exceptions.h"
#include <cassert>
namespace Catch {
MessageInfo::MessageInfo( std::string const& _macroName,
MessageInfo::MessageInfo( StringRef const& _macroName,
SourceLineInfo const& _lineInfo,
ResultWas::OfType _type )
: macroName( _macroName ),
@@ -35,7 +37,7 @@ namespace Catch {
////////////////////////////////////////////////////////////////////////////
Catch::MessageBuilder::MessageBuilder( std::string const& macroName,
Catch::MessageBuilder::MessageBuilder( StringRef const& macroName,
SourceLineInfo const& lineInfo,
ResultWas::OfType type )
:m_info(macroName, lineInfo, type) {}
@@ -55,4 +57,36 @@ namespace Catch {
getResultCapture().popScopedMessage(m_info);
}
}
Capturer::Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names ) {
auto start = std::string::npos;
for( size_t pos = 0; pos <= names.size(); ++pos ) {
char c = names[pos];
if( pos == names.size() || c == ' ' || c == '\t' || c == ',' || c == ']' ) {
if( start != std::string::npos ) {
m_messages.push_back( MessageInfo( macroName, lineInfo, resultType ) );
m_messages.back().message = names.substr( start, pos-start) + " := ";
start = std::string::npos;
}
}
else if( c != '[' && c != ']' && start == std::string::npos )
start = pos;
}
}
Capturer::~Capturer() {
if ( !uncaught_exceptions() ){
assert( m_captured == m_messages.size() );
for( size_t i = 0; i < m_captured; ++i )
m_resultCapture.popScopedMessage( m_messages[i] );
}
}
void Capturer::captureValue( size_t index, StringRef value ) {
assert( index < m_messages.size() );
m_messages[index].message += value;
m_resultCapture.pushScopedMessage( m_messages[index] );
m_captured++;
}
} // end namespace Catch

View File

@@ -8,19 +8,23 @@
#ifndef TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED
#define TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED
#include <string>
#include "catch_result_type.h"
#include "catch_common.h"
#include "catch_stream.h"
#include "catch_interfaces_capture.h"
#include "catch_tostring.h"
#include <string>
#include <vector>
namespace Catch {
struct MessageInfo {
MessageInfo( std::string const& _macroName,
MessageInfo( StringRef const& _macroName,
SourceLineInfo const& _lineInfo,
ResultWas::OfType _type );
std::string macroName;
StringRef macroName;
std::string message;
SourceLineInfo lineInfo;
ResultWas::OfType type;
@@ -44,7 +48,7 @@ namespace Catch {
};
struct MessageBuilder : MessageStream {
MessageBuilder( std::string const& macroName,
MessageBuilder( StringRef const& macroName,
SourceLineInfo const& lineInfo,
ResultWas::OfType type );
@@ -65,6 +69,28 @@ namespace Catch {
MessageInfo m_info;
};
class Capturer {
std::vector<MessageInfo> m_messages;
IResultCapture& m_resultCapture = getResultCapture();
size_t m_captured = 0;
public:
Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names );
~Capturer();
void captureValue( size_t index, StringRef value );
template<typename T>
void captureValues( size_t index, T&& value ) {
captureValue( index, Catch::Detail::stringify( value ) );
}
template<typename T, typename... Ts>
void captureValues( size_t index, T&& value, Ts&&... values ) {
captureValues( index, value );
captureValues( index+1, values... );
}
};
} // end namespace Catch
#endif // TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED

View File

@@ -6,8 +6,7 @@
*/
#include "catch_output_redirect.h"
#include "catch_enforce.h"
#include <cstdio>
#include <cstring>
@@ -56,21 +55,21 @@ namespace Catch {
#if defined(_MSC_VER)
TempFile::TempFile() {
if (tmpnam_s(m_buffer)) {
throw std::runtime_error("Could not get a temp filename");
CATCH_RUNTIME_ERROR("Could not get a temp filename");
}
if (fopen_s(&m_file, m_buffer, "w")) {
char buffer[100];
if (strerror_s(buffer, errno)) {
throw std::runtime_error("Could not translate errno to string");
CATCH_RUNTIME_ERROR("Could not translate errno to a string");
}
throw std::runtime_error("Could not open the temp file: " + std::string(m_buffer) + buffer);
CATCH_RUNTIME_ERROR("Coul dnot open the temp file: '" << m_buffer << "' because: " << buffer);
}
}
#else
TempFile::TempFile() {
m_file = std::tmpfile();
if (!m_file) {
throw std::runtime_error("Could not create a temp file.");
CATCH_RUNTIME_ERROR("Could not create a temp file.");
}
}

View File

@@ -14,6 +14,7 @@
#include "catch_exception_translator_registry.h"
#include "catch_tag_alias_registry.h"
#include "catch_startup_exception_registry.h"
#include "catch_singletons.hpp"
namespace Catch {
@@ -30,7 +31,7 @@ namespace Catch {
ITestCaseRegistry const& getTestCaseRegistry() const override {
return m_testCaseRegistry;
}
IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() override {
IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const override {
return m_exceptionTranslatorRegistry;
}
ITagAliasRegistry const& getTagAliasRegistry() const override {
@@ -67,27 +68,19 @@ namespace Catch {
TagAliasRegistry m_tagAliasRegistry;
StartupExceptionRegistry m_exceptionRegistry;
};
// Single, global, instance
RegistryHub*& getTheRegistryHub() {
static RegistryHub* theRegistryHub = nullptr;
if( !theRegistryHub )
theRegistryHub = new RegistryHub();
return theRegistryHub;
}
}
IRegistryHub& getRegistryHub() {
return *getTheRegistryHub();
using RegistryHubSingleton = Singleton<RegistryHub, IRegistryHub, IMutableRegistryHub>;
IRegistryHub const& getRegistryHub() {
return RegistryHubSingleton::get();
}
IMutableRegistryHub& getMutableRegistryHub() {
return *getTheRegistryHub();
return RegistryHubSingleton::getMutable();
}
void cleanUp() {
delete getTheRegistryHub();
getTheRegistryHub() = nullptr;
cleanupSingletons();
cleanUpContext();
ReusableStringStream::cleanup();
}
std::string translateActiveException() {
return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException();

View File

@@ -1,4 +1,5 @@
#include "catch_run_context.h"
#include "catch_compiler_capabilities.h"
#include "catch_context.h"
#include "catch_enforce.h"
#include "catch_random_number_generator.h"
@@ -11,6 +12,70 @@
namespace Catch {
namespace Generators {
struct GeneratorTracker : TestCaseTracking::TrackerBase, IGeneratorTracker {
size_t m_index = static_cast<size_t>( -1 );
GeneratorBasePtr m_generator;
GeneratorTracker( TestCaseTracking::NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
: TrackerBase( nameAndLocation, ctx, parent )
{}
~GeneratorTracker();
static GeneratorTracker& acquire( TrackerContext& ctx, TestCaseTracking::NameAndLocation const& nameAndLocation ) {
std::shared_ptr<GeneratorTracker> tracker;
ITracker& currentTracker = ctx.currentTracker();
if( TestCaseTracking::ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) {
assert( childTracker );
assert( childTracker->isIndexTracker() );
tracker = std::static_pointer_cast<GeneratorTracker>( childTracker );
}
else {
tracker = std::make_shared<GeneratorTracker>( nameAndLocation, ctx, &currentTracker );
currentTracker.addChild( tracker );
}
if( !ctx.completedCycle() && !tracker->isComplete() ) {
if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun )
tracker->moveNext();
tracker->open();
}
return *tracker;
}
void moveNext() {
m_index++;
m_children.clear();
}
// TrackerBase interface
bool isIndexTracker() const override { return true; }
auto hasGenerator() const -> bool override {
return !!m_generator;
}
void close() override {
TrackerBase::close();
if( m_runState == CompletedSuccessfully && m_index < m_generator->size()-1 )
m_runState = Executing;
}
// IGeneratorTracker interface
auto getGenerator() const -> GeneratorBasePtr const& override {
return m_generator;
}
void setGenerator( GeneratorBasePtr&& generator ) override {
m_generator = std::move( generator );
}
auto getIndex() const -> size_t override {
return m_index;
}
};
GeneratorTracker::~GeneratorTracker() {}
}
RunContext::RunContext(IConfigPtr const& _config, IStreamingReporterPtr&& reporter)
: m_runInfo(_config->name()),
m_context(getCurrentMutableContext()),
@@ -128,6 +193,13 @@ namespace Catch {
return true;
}
auto RunContext::acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& {
using namespace Generators;
GeneratorTracker& tracker = GeneratorTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( "generator", lineInfo ) );
assert( tracker.isOpen() );
m_lastAssertionInfo.lineInfo = lineInfo;
return tracker;
}
bool RunContext::testForMissingAssertions(Counts& assertions) {
if (assertions.total() != 0)
@@ -241,7 +313,7 @@ namespace Catch {
}
bool RunContext::aborting() const {
return m_totals.assertions.failed == static_cast<std::size_t>(m_config->abortAfter());
return m_totals.assertions.failed >= static_cast<std::size_t>(m_config->abortAfter());
}
void RunContext::runCurrentTest(std::string & redirectedCout, std::string & redirectedCerr) {
@@ -256,7 +328,7 @@ namespace Catch {
seedRng(*m_config);
Timer timer;
try {
CATCH_TRY {
if (m_reporter->getPreferences().shouldRedirectStdOut) {
#if !defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT)
RedirectedStdOut redirectedStdOut;
@@ -276,9 +348,9 @@ namespace Catch {
invokeActiveTestCase();
}
duration = timer.getElapsedSeconds();
} catch (TestFailureException&) {
} CATCH_CATCH_ANON (TestFailureException&) {
// This just means the test was aborted due to failure
} catch (...) {
} CATCH_CATCH_ALL {
// Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions
// are reported without translation at the point of origin.
if( m_shouldReportUnexpected ) {

View File

@@ -8,6 +8,7 @@
#ifndef TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED
#include "catch_interfaces_generatortracker.h"
#include "catch_interfaces_runner.h"
#include "catch_interfaces_reporter.h"
#include "catch_interfaces_exception.h"
@@ -79,6 +80,8 @@ namespace Catch {
void sectionEnded( SectionEndInfo const& endInfo ) override;
void sectionEndedEarly( SectionEndInfo const& endInfo ) override;
auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& override;
void benchmarkStarting( BenchmarkInfo const& info ) override;
void benchmarkEnded( BenchmarkStats const& stats ) override;

View File

@@ -119,10 +119,12 @@ namespace Catch {
Session::Session() {
static bool alreadyInstantiated = false;
if( alreadyInstantiated ) {
try { CATCH_INTERNAL_ERROR( "Only one instance of Catch::Session can ever be used" ); }
catch(...) { getMutableRegistryHub().registerStartupException(); }
CATCH_TRY { CATCH_INTERNAL_ERROR( "Only one instance of Catch::Session can ever be used" ); }
CATCH_CATCH_ALL { getMutableRegistryHub().registerStartupException(); }
}
// There cannot be exceptions at startup in no-exception mode.
#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
const auto& exceptions = getRegistryHub().getStartupExceptionRegistry().getExceptions();
if ( !exceptions.empty() ) {
m_startupExceptions = true;
@@ -137,6 +139,7 @@ namespace Catch {
}
}
}
#endif
alreadyInstantiated = true;
m_cli = makeCommandLineParser( m_configData );
@@ -182,22 +185,8 @@ namespace Catch {
return 0;
}
void Session::useConfigData( ConfigData const& configData ) {
m_configData = configData;
m_config.reset();
}
int Session::run( int argc, char* argv[] ) {
if( m_startupExceptions )
return 1;
int returnCode = applyCommandLine( argc, argv );
if( returnCode == 0 )
returnCode = run();
return returnCode;
}
#if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE)
int Session::run( int argc, wchar_t* const argv[] ) {
int Session::applyCommandLine( int argc, wchar_t const * const * argv ) {
char **utf8Argv = new char *[ argc ];
@@ -209,7 +198,7 @@ namespace Catch {
WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, NULL, NULL );
}
int returnCode = run( argc, utf8Argv );
int returnCode = applyCommandLine( argc, utf8Argv );
for ( int i = 0; i < argc; ++i )
delete [] utf8Argv[ i ];
@@ -219,6 +208,12 @@ namespace Catch {
return returnCode;
}
#endif
void Session::useConfigData( ConfigData const& configData ) {
m_configData = configData;
m_config.reset();
}
int Session::run() {
if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeStart ) != 0 ) {
Catch::cout() << "...waiting for enter/ return before starting" << std::endl;
@@ -251,11 +246,11 @@ namespace Catch {
if( m_startupExceptions )
return 1;
if( m_configData.showHelp || m_configData.libIdentify )
if (m_configData.showHelp || m_configData.libIdentify) {
return 0;
}
try
{
CATCH_TRY {
config(); // Force config to be constructed
seedRng( *m_config );
@@ -273,10 +268,12 @@ namespace Catch {
// of 256 tests has failed
return (std::min) (MaxExitCode, (std::max) (totals.error, static_cast<int>(totals.assertions.failed)));
}
#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
catch( std::exception& ex ) {
Catch::cerr() << ex.what() << std::endl;
return MaxExitCode;
}
#endif
}
} // end namespace Catch

View File

@@ -26,13 +26,22 @@ namespace Catch {
void libIdentify();
int applyCommandLine( int argc, char const * const * argv );
#if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE)
int applyCommandLine( int argc, wchar_t const * const * argv );
#endif
void useConfigData( ConfigData const& configData );
int run( int argc, char* argv[] );
#if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE)
int run( int argc, wchar_t* const argv[] );
#endif
template<typename CharT>
int run(int argc, CharT const * const argv[]) {
if (m_startupExceptions)
return 1;
int returnCode = applyCommandLine(argc, argv);
if (returnCode == 0)
returnCode = run();
return returnCode;
}
int run();
clara::Parser const& cli() const;

View File

@@ -0,0 +1,36 @@
/*
* Created by Phil Nash on 15/6/2018.
*
* 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_singletons.hpp"
#include <vector>
namespace Catch {
namespace {
static auto getSingletons() -> std::vector<ISingleton*>*& {
static std::vector<ISingleton*>* g_singletons = nullptr;
if( !g_singletons )
g_singletons = new std::vector<ISingleton*>();
return g_singletons;
}
}
ISingleton::~ISingleton() {}
void addSingleton(ISingleton* singleton ) {
getSingletons()->push_back( singleton );
}
void cleanupSingletons() {
auto& singletons = getSingletons();
for( auto singleton : *singletons )
delete singleton;
delete singletons;
singletons = nullptr;
}
} // namespace Catch

View File

@@ -0,0 +1,44 @@
/*
* Created by Phil Nash on 15/6/2018.
*
* 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_SINGLETONS_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_SINGLETONS_HPP_INCLUDED
namespace Catch {
struct ISingleton {
virtual ~ISingleton();
};
void addSingleton( ISingleton* singleton );
void cleanupSingletons();
template<typename SingletonImplT, typename InterfaceT = SingletonImplT, typename MutableInterfaceT = InterfaceT>
class Singleton : SingletonImplT, public ISingleton {
static auto getInternal() -> Singleton* {
static Singleton* s_instance = nullptr;
if( !s_instance ) {
s_instance = new Singleton;
addSingleton( s_instance );
}
return s_instance;
}
public:
static auto get() -> InterfaceT const& {
return *getInternal();
}
static auto getMutable() -> MutableInterfaceT& {
return *getInternal();
}
};
} // namespace Catch
#endif // TWOBLUECUBES_CATCH_SINGLETONS_HPP_INCLUDED

View File

@@ -7,13 +7,13 @@
*/
#include "catch_startup_exception_registry.h"
#include "catch_compiler_capabilities.h"
namespace Catch {
void StartupExceptionRegistry::add( std::exception_ptr const& exception ) noexcept {
try {
void StartupExceptionRegistry::add( std::exception_ptr const& exception ) noexcept {
CATCH_TRY {
m_exceptions.push_back(exception);
}
catch(...) {
} CATCH_CATCH_ALL {
// If we run out of memory during start-up there's really not a lot more we can do about it
std::terminate();
}

View File

@@ -12,6 +12,7 @@
#include "catch_stream.h"
#include "catch_debug_console.h"
#include "catch_stringref.h"
#include "catch_singletons.hpp"
#include <cstdio>
#include <iostream>
@@ -20,11 +21,6 @@
#include <vector>
#include <memory>
#if defined(__clang__)
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wexit-time-destructors"
#endif
namespace Catch {
Catch::IStream::~IStream() = default;
@@ -145,7 +141,6 @@ namespace Catch {
std::vector<std::unique_ptr<std::ostringstream>> m_streams;
std::vector<std::size_t> m_unused;
std::ostringstream m_referenceStream; // Used for copy state/ flags from
static StringStreams* s_instance;
auto add() -> std::size_t {
if( m_unused.empty() ) {
@@ -163,34 +158,17 @@ namespace Catch {
m_streams[index]->copyfmt( m_referenceStream ); // Restore initial flags and other state
m_unused.push_back(index);
}
// !TBD: put in TLS
static auto instance() -> StringStreams& {
if( !s_instance )
s_instance = new StringStreams();
return *s_instance;
}
static void cleanup() {
delete s_instance;
s_instance = nullptr;
}
};
StringStreams* StringStreams::s_instance = nullptr;
void ReusableStringStream::cleanup() {
StringStreams::cleanup();
}
ReusableStringStream::ReusableStringStream()
: m_index( StringStreams::instance().add() ),
m_oss( StringStreams::instance().m_streams[m_index].get() )
: m_index( Singleton<StringStreams>::getMutable().add() ),
m_oss( Singleton<StringStreams>::getMutable().m_streams[m_index].get() )
{}
ReusableStringStream::~ReusableStringStream() {
static_cast<std::ostringstream*>( m_oss )->str("");
m_oss->clear();
StringStreams::instance().release( m_index );
Singleton<StringStreams>::getMutable().release( m_index );
}
auto ReusableStringStream::str() const -> std::string {
@@ -207,7 +185,3 @@ namespace Catch {
std::ostream& clog() { return std::clog; }
#endif
}
#if defined(__clang__)
# pragma clang diagnostic pop
#endif

View File

@@ -43,8 +43,6 @@ namespace Catch {
return *this;
}
auto get() -> std::ostream& { return *m_oss; }
static void cleanup();
};
}

View File

@@ -127,4 +127,8 @@ namespace Catch {
} // namespace Catch
inline auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef {
return Catch::StringRef( rawChars, size );
}
#endif // CATCH_STRINGREF_H_INCLUDED

View File

@@ -1,12 +1,13 @@
#include "catch_tag_alias_autoregistrar.h"
#include "catch_compiler_capabilities.h"
#include "catch_interfaces_registry_hub.h"
namespace Catch {
RegistrarForTagAliases::RegistrarForTagAliases(char const* alias, char const* tag, SourceLineInfo const& lineInfo) {
try {
CATCH_TRY {
getMutableRegistryHub().registerTagAlias(alias, tag, lineInfo);
} catch (...) {
} CATCH_CATCH_ALL {
// Do not throw when constructing global objects, instead register the exception to be processed later
getMutableRegistryHub().registerStartupException();
}

View File

@@ -69,14 +69,6 @@ namespace TestCaseTracking {
}
TrackerBase::TrackerHasName::TrackerHasName( NameAndLocation const& nameAndLocation ) : m_nameAndLocation( nameAndLocation ) {}
bool TrackerBase::TrackerHasName::operator ()( ITrackerPtr const& tracker ) const {
return
tracker->nameAndLocation().location == m_nameAndLocation.location &&
tracker->nameAndLocation().name == m_nameAndLocation.name;
}
TrackerBase::TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
: m_nameAndLocation( nameAndLocation ),
m_ctx( ctx ),
@@ -105,7 +97,12 @@ namespace TestCaseTracking {
}
ITrackerPtr TrackerBase::findChild( NameAndLocation const& nameAndLocation ) {
auto it = std::find_if( m_children.begin(), m_children.end(), TrackerHasName( nameAndLocation ) );
auto it = std::find_if( m_children.begin(), m_children.end(),
[&nameAndLocation]( ITrackerPtr const& tracker ){
return
tracker->nameAndLocation().location == nameAndLocation.location &&
tracker->nameAndLocation().name == nameAndLocation.name;
} );
return( it != m_children.end() )
? *it
: nullptr;

View File

@@ -95,13 +95,6 @@ namespace TestCaseTracking {
Failed
};
class TrackerHasName {
NameAndLocation m_nameAndLocation;
public:
TrackerHasName( NameAndLocation const& nameAndLocation );
bool operator ()( ITrackerPtr const& tracker ) const;
};
using Children = std::vector<ITrackerPtr>;
NameAndLocation m_nameAndLocation;
TrackerContext& m_ctx;

View File

@@ -6,6 +6,7 @@
*/
#include "catch_test_registry.h"
#include "catch_compiler_capabilities.h"
#include "catch_test_case_registry_impl.h"
#include "catch_interfaces_registry_hub.h"
@@ -18,7 +19,7 @@ namespace Catch {
NameAndTags::NameAndTags( StringRef const& name_ , StringRef const& tags_ ) noexcept : name( name_ ), tags( tags_ ) {}
AutoReg::AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef const& classOrMethod, NameAndTags const& nameAndTags ) noexcept {
try {
CATCH_TRY {
getMutableRegistryHub()
.registerTest(
makeTestCase(
@@ -26,7 +27,7 @@ namespace Catch {
extractClassName( classOrMethod ),
nameAndTags,
lineInfo));
} catch (...) {
} CATCH_CATCH_ALL {
// Do not throw when constructing global objects, instead register the exception to be processed later
getMutableRegistryHub().registerStartupException();
}

View File

@@ -116,14 +116,9 @@ std::string StringMaker<std::string>::convert(const std::string& str) {
return s;
}
#ifdef CATCH_CONFIG_WCHAR
std::string StringMaker<std::wstring>::convert(const std::wstring& wstr) {
std::string s;
s.reserve(wstr.size());
for (auto c : wstr) {
s += (c <= 0xff) ? static_cast<char>(c) : '?';
}
return ::Catch::Detail::stringify(s);
#ifdef CATCH_CONFIG_CPP17_STRING_VIEW
std::string StringMaker<std::string_view>::convert(std::string_view str) {
return ::Catch::Detail::stringify(std::string{ str });
}
#endif
@@ -141,7 +136,23 @@ std::string StringMaker<char*>::convert(char* str) {
return{ "{null string}" };
}
}
#ifdef CATCH_CONFIG_WCHAR
std::string StringMaker<std::wstring>::convert(const std::wstring& wstr) {
std::string s;
s.reserve(wstr.size());
for (auto c : wstr) {
s += (c <= 0xff) ? static_cast<char>(c) : '?';
}
return ::Catch::Detail::stringify(s);
}
# ifdef CATCH_CONFIG_CPP17_STRING_VIEW
std::string StringMaker<std::wstring_view>::convert(std::wstring_view str) {
return StringMaker<std::wstring>::convert(std::wstring(str));
}
# endif
std::string StringMaker<wchar_t const*>::convert(wchar_t const * str) {
if (str) {
return ::Catch::Detail::stringify(std::wstring{ str });
@@ -194,7 +205,7 @@ std::string StringMaker<bool>::convert(bool b) {
return b ? "true" : "false";
}
std::string StringMaker<char>::convert(char value) {
std::string StringMaker<signed char>::convert(signed char value) {
if (value == '\r') {
return "'\\r'";
} else if (value == '\f') {
@@ -211,8 +222,8 @@ std::string StringMaker<char>::convert(char value) {
return chstr;
}
}
std::string StringMaker<signed char>::convert(signed char c) {
return ::Catch::Detail::stringify(static_cast<char>(c));
std::string StringMaker<char>::convert(char c) {
return ::Catch::Detail::stringify(static_cast<signed char>(c));
}
std::string StringMaker<unsigned char>::convert(unsigned char c) {
return ::Catch::Detail::stringify(static_cast<char>(c));

View File

@@ -16,6 +16,10 @@
#include "catch_compiler_capabilities.h"
#include "catch_stream.h"
#ifdef CATCH_CONFIG_CPP17_STRING_VIEW
#include <string_view>
#endif
#ifdef __OBJC__
#include "catch_objc_arc.hpp"
#endif
@@ -25,15 +29,7 @@
#pragma warning(disable:4180) // We attempt to stream a function (address) by const&, which MSVC complains about but is harmless
#endif
// We need a dummy global operator<< so we can bring it into Catch namespace later
struct Catch_global_namespace_dummy {};
std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy);
namespace Catch {
// Bring in operator<< from global namespace into Catch namespace
using ::operator<<;
namespace Detail {
extern const std::string unprintableString;
@@ -152,10 +148,11 @@ namespace Catch {
struct StringMaker<std::string> {
static std::string convert(const std::string& str);
};
#ifdef CATCH_CONFIG_WCHAR
#ifdef CATCH_CONFIG_CPP17_STRING_VIEW
template<>
struct StringMaker<std::wstring> {
static std::string convert(const std::wstring& wstr);
struct StringMaker<std::string_view> {
static std::string convert(std::string_view str);
};
#endif
@@ -169,6 +166,18 @@ namespace Catch {
};
#ifdef CATCH_CONFIG_WCHAR
template<>
struct StringMaker<std::wstring> {
static std::string convert(const std::wstring& wstr);
};
# ifdef CATCH_CONFIG_CPP17_STRING_VIEW
template<>
struct StringMaker<std::wstring_view> {
static std::string convert(std::wstring_view str);
};
# endif
template<>
struct StringMaker<wchar_t const *> {
static std::string convert(wchar_t const * str);
@@ -337,6 +346,7 @@ namespace Catch {
#if defined(CATCH_CONFIG_ENABLE_ALL_STRINGMAKERS)
# define CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER
# define CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER
# define CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER
# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER
#endif
@@ -401,6 +411,34 @@ namespace Catch {
}
#endif // CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER
#if defined(CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER) && defined(CATCH_CONFIG_CPP17_VARIANT)
#include <variant>
namespace Catch {
template<>
struct StringMaker<std::monostate> {
static std::string convert(const std::monostate&) {
return "{ }";
}
};
template<typename... Elements>
struct StringMaker<std::variant<Elements...>> {
static std::string convert(const std::variant<Elements...>& variant) {
if (variant.valueless_by_exception()) {
return "{valueless variant}";
} else {
return std::visit(
[](const auto& value) {
return ::Catch::Detail::stringify(value);
},
variant
);
}
}
};
}
#endif // CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER
namespace Catch {
struct not_this_one {}; // Tag type for detecting which begin/ end are being selected

View File

@@ -37,7 +37,7 @@ namespace Catch {
}
Version const& libraryVersion() {
static Version version( 2, 3, 0, "", 0 );
static Version version( 2, 4, 2, "", 0 );
return version;
}

View File

@@ -8,6 +8,7 @@
#ifndef TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED
#include "../internal/catch_enforce.h"
#include "../internal/catch_interfaces_reporter.h"
#include <algorithm>
@@ -33,7 +34,7 @@ namespace Catch {
{
m_reporterPrefs.shouldRedirectStdOut = false;
if( !DerivedT::getSupportedVerbosities().count( m_config->verbosity() ) )
throw std::domain_error( "Verbosity level not supported by this reporter" );
CATCH_ERROR( "Verbosity level not supported by this reporter" );
}
ReporterPreferences getPreferences() const override {
@@ -148,7 +149,7 @@ namespace Catch {
{
m_reporterPrefs.shouldRedirectStdOut = false;
if( !DerivedT::getSupportedVerbosities().count( m_config->verbosity() ) )
throw std::domain_error( "Verbosity level not supported by this reporter" );
CATCH_ERROR( "Verbosity level not supported by this reporter" );
}
~CumulativeReporterBase() override = default;

View File

@@ -97,12 +97,12 @@ namespace Catch {
case ResultWas::Ok:
case ResultWas::Info:
case ResultWas::Warning:
throw std::domain_error( "Internal error in TeamCity reporter" );
CATCH_ERROR( "Internal error in TeamCity reporter" );
// These cases are here to prevent compiler warnings
case ResultWas::Unknown:
case ResultWas::FailureBit:
case ResultWas::Exception:
throw std::domain_error( "Not implemented" );
CATCH_ERROR( "Not implemented" );
}
if( assertionStats.infoMessages.size() == 1 )
msg << " with message:";

View File

@@ -55,6 +55,9 @@ namespace Catch {
m_xml.startElement( "Catch" );
if( !m_config->name().empty() )
m_xml.writeAttribute( "name", m_config->name() );
if( m_config->rngSeed() != 0 )
m_xml.scopedElement( "Randomness" )
.writeAttribute( "seed", m_config->rngSeed() );
}
void XmlReporter::testGroupStarting( GroupInfo const& groupInfo ) {

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<UseFullPaths>false</UseFullPaths>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<UseFullPaths>false</UseFullPaths>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<UseFullPaths>false</UseFullPaths>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<UseFullPaths>false</UseFullPaths>
</ClCompile>
</ItemDefinitionGroup>
</Project>

View File

@@ -1,3 +1,4 @@
SETLOCAL EnableDelayedExpansion
@REM # Possibilities:
@REM # Debug build + coverage
@@ -7,21 +8,15 @@
if "%CONFIGURATION%"=="Debug" (
if "%coverage%"=="1" (
@REM # coverage needs to build the special helper as well as the main
cmake -Hmisc -Bbuild-misc -A%PLATFORM%
cmake --build build-misc
cmake -H. -BBuild -A%PLATFORM% -DUSE_WMAIN=%wmain% -DMEMORYCHECK_COMMAND=build-misc\Debug\CoverageHelper.exe -DMEMORYCHECK_COMMAND_OPTIONS=--sep-- -DMEMORYCHECK_TYPE=Valgrind
cmake -Hmisc -Bbuild-misc -A%PLATFORM% || exit /b !ERRORLEVEL!
cmake --build build-misc || exit /b !ERRORLEVEL!
cmake -H. -BBuild -A%PLATFORM% -DUSE_WMAIN=%wmain% -DMEMORYCHECK_COMMAND=build-misc\Debug\CoverageHelper.exe -DMEMORYCHECK_COMMAND_OPTIONS=--sep-- -DMEMORYCHECK_TYPE=Valgrind || exit /b !ERRORLEVEL! || exit /b !ERRORLEVEL!
) else (
@REM # We know that coverage is 0
if "%examples%"=="1" (
@REM # Examples live off the single header, so it needs to be regenerated
python scripts\generateSingleHeader.py
cmake -H. -BBuild -A%PLATFORM% -DUSE_WMAIN=%wmain% -DCATCH_BUILD_EXAMPLES=ON
) else (
@REM # This is just a plain debug build
cmake -H. -BBuild -A%PLATFORM% -DUSE_WMAIN=%wmain%
)
python scripts\generateSingleHeader.py || exit /b !ERRORLEVEL!
cmake -H. -BBuild -A%PLATFORM% -DUSE_WMAIN=%wmain% -DCATCH_BUILD_EXAMPLES=%examples% -DCATCH_BUILD_EXTRA_TESTS=%examples% || exit /b !ERRORLEVEL!
)
)
if "%CONFIGURATION%"=="Release" (
cmake -H. -BBuild -A%PLATFORM% -DUSE_WMAIN=%wmain%
cmake -H. -BBuild -A%PLATFORM% -DUSE_WMAIN=%wmain% || exit /b !ERRORLEVEL!
)

View File

@@ -1,13 +1,15 @@
SETLOCAL EnableDelayedExpansion
cd Build
if "%CONFIGURATION%"=="Debug" (
if "%coverage%"=="1" (
ctest -j 2 -C %CONFIGURATION% -D ExperimentalMemCheck
python ..\misc\appveyorMergeCoverageScript.py
codecov --root .. --no-color --disable gcov -f cobertura.xml -t %CODECOV_TOKEN%
ctest -j 2 -C %CONFIGURATION% -D ExperimentalMemCheck || exit /b !ERRORLEVEL!
python ..\misc\appveyorMergeCoverageScript.py || exit /b !ERRORLEVEL!
codecov --root .. --no-color --disable gcov -f cobertura.xml -t %CODECOV_TOKEN% || exit /b !ERRORLEVEL!
) else (
ctest -j 2 -C %CONFIGURATION%
ctest -j 2 -C %CONFIGURATION% || exit /b !ERRORLEVEL!
)
)
if "%CONFIGURATION%"=="Release" (
ctest -j 2 -C %CONFIGURATION%
ctest -j 2 -C %CONFIGURATION% || exit /b !ERRORLEVEL!
)

View File

@@ -1,10 +1,23 @@
include(MiscFunctions)
####
# Temporary workaround for VS toolset changes in 2017
# We need to disable <UseFullPaths> property, but CMake doesn't support it
# until 3.13 (not yet released)
####
if (MSVC)
configure_file(${CATCH_DIR}/misc/SelfTest.vcxproj.user
${CMAKE_BINARY_DIR}/projects
COPYONLY)
endif(MSVC) #Temporary workaround
# define the sources of the self test
# Please keep these ordered alphabetically
set(TEST_SOURCES
${SELF_TEST_DIR}/TestMain.cpp
${SELF_TEST_DIR}/IntrospectiveTests/CmdLine.tests.cpp
${SELF_TEST_DIR}/IntrospectiveTests/GeneratorsImpl.tests.cpp
${SELF_TEST_DIR}/IntrospectiveTests/PartTracker.tests.cpp
${SELF_TEST_DIR}/IntrospectiveTests/TagAlias.tests.cpp
${SELF_TEST_DIR}/IntrospectiveTests/String.tests.cpp
@@ -18,12 +31,14 @@ set(TEST_SOURCES
${SELF_TEST_DIR}/UsageTests/Decomposition.tests.cpp
${SELF_TEST_DIR}/UsageTests/EnumToString.tests.cpp
${SELF_TEST_DIR}/UsageTests/Exception.tests.cpp
${SELF_TEST_DIR}/UsageTests/Generators.tests.cpp
${SELF_TEST_DIR}/UsageTests/Message.tests.cpp
${SELF_TEST_DIR}/UsageTests/Misc.tests.cpp
${SELF_TEST_DIR}/UsageTests/ToStringChrono.tests.cpp
${SELF_TEST_DIR}/UsageTests/ToStringGeneral.tests.cpp
${SELF_TEST_DIR}/UsageTests/ToStringPair.tests.cpp
${SELF_TEST_DIR}/UsageTests/ToStringTuple.tests.cpp
${SELF_TEST_DIR}/UsageTests/ToStringVariant.tests.cpp
${SELF_TEST_DIR}/UsageTests/ToStringVector.tests.cpp
${SELF_TEST_DIR}/UsageTests/ToStringWhich.tests.cpp
${SELF_TEST_DIR}/UsageTests/Tricky.tests.cpp
@@ -85,6 +100,7 @@ set(INTERNAL_HEADERS
${HEADER_DIR}/internal/catch_exception_translator_registry.h
${HEADER_DIR}/internal/catch_external_interfaces.h
${HEADER_DIR}/internal/catch_fatal_condition.h
${HEADER_DIR}/internal/catch_generators.hpp
${HEADER_DIR}/internal/catch_impl.hpp
${HEADER_DIR}/internal/catch_interfaces_capture.h
${HEADER_DIR}/internal/catch_interfaces_config.h
@@ -117,6 +133,7 @@ set(INTERNAL_HEADERS
${HEADER_DIR}/internal/catch_section.h
${HEADER_DIR}/internal/catch_section_info.h
${HEADER_DIR}/internal/catch_session.h
${HEADER_DIR}/internal/catch_singletons.hpp
${HEADER_DIR}/internal/catch_startup_exception_registry.h
${HEADER_DIR}/internal/catch_stream.h
${HEADER_DIR}/internal/catch_stringref.h
@@ -157,12 +174,15 @@ set(IMPL_SOURCES
${HEADER_DIR}/internal/catch_debug_console.cpp
${HEADER_DIR}/internal/catch_debugger.cpp
${HEADER_DIR}/internal/catch_decomposer.cpp
${HEADER_DIR}/internal/catch_enforce.cpp
${HEADER_DIR}/internal/catch_errno_guard.cpp
${HEADER_DIR}/internal/catch_exception_translator_registry.cpp
${HEADER_DIR}/internal/catch_fatal_condition.cpp
${HEADER_DIR}/internal/catch_generators.cpp
${HEADER_DIR}/internal/catch_interfaces_capture.cpp
${HEADER_DIR}/internal/catch_interfaces_config.cpp
${HEADER_DIR}/internal/catch_interfaces_exception.cpp
${HEADER_DIR}/internal/catch_interfaces_generatortracker.h
${HEADER_DIR}/internal/catch_interfaces_registry_hub.cpp
${HEADER_DIR}/internal/catch_interfaces_runner.cpp
${HEADER_DIR}/internal/catch_interfaces_testcase.cpp
@@ -183,6 +203,7 @@ set(IMPL_SOURCES
${HEADER_DIR}/internal/catch_section.cpp
${HEADER_DIR}/internal/catch_section_info.cpp
${HEADER_DIR}/internal/catch_session.cpp
${HEADER_DIR}/internal/catch_singletons.cpp
${HEADER_DIR}/internal/catch_startup_exception_registry.cpp
${HEADER_DIR}/internal/catch_stream.cpp
${HEADER_DIR}/internal/catch_stringref.cpp
@@ -247,7 +268,10 @@ include(CTest)
add_executable(SelfTest ${TEST_SOURCES} ${IMPL_SOURCES} ${REPORTER_SOURCES} ${SURROGATE_SOURCES} ${HEADERS})
target_include_directories(SelfTest PRIVATE ${HEADER_DIR})
if(USE_CPP14)
if(USE_CPP17)
message(STATUS "Enabling C++17")
set_property(TARGET SelfTest PROPERTY CXX_STANDARD 17)
elseif(USE_CPP14)
message(STATUS "Enabling C++14")
set_property(TARGET SelfTest PROPERTY CXX_STANDARD 14)
else()
@@ -300,7 +324,7 @@ set_tests_properties(ListTests PROPERTIES
add_test(NAME ListTags COMMAND $<TARGET_FILE:SelfTest> --list-tags)
set_tests_properties(ListTags PROPERTIES
PASS_REGULAR_EXPRESSION "[0-9]+ tags"
FAIL_REGULAR_EXPRESSION "[.]")
FAIL_REGULAR_EXPRESSION "\\[\\.\\]")
add_test(NAME ListReporters COMMAND $<TARGET_FILE:SelfTest> --list-reporters)
set_tests_properties(ListReporters PROPERTIES PASS_REGULAR_EXPRESSION "Available reporters:")
@@ -317,7 +341,7 @@ add_test(NAME NoTest COMMAND $<TARGET_FILE:SelfTest> -w NoTests "___nonexistent_
set_tests_properties(NoTest PROPERTIES PASS_REGULAR_EXPRESSION "No test cases matched")
# AppVeyor has a Python 2.7 in path, but doesn't have .py files as autorunnable
add_test(NAME ApprovalTests COMMAND python ${CATCH_DIR}/scripts/approvalTests.py $<TARGET_FILE:SelfTest>)
add_test(NAME ApprovalTests COMMAND ${PYTHON_EXECUTABLE} ${CATCH_DIR}/scripts/approvalTests.py $<TARGET_FILE:SelfTest>)
set_tests_properties(ApprovalTests PROPERTIES FAIL_REGULAR_EXPRESSION "Results differed")
if (CATCH_USE_VALGRIND)

View File

@@ -0,0 +1,135 @@
#
# Build extra tests.
#
# Requires CATCH_BUILD_EXTRA_TESTS to be defined 'true', see ../CMakeLists.txt.
#
cmake_minimum_required( VERSION 3.5 )
project( Catch2ExtraTests LANGUAGES CXX )
message( STATUS "Extra tests included" )
# define folders used:
set( TESTS_DIR ${CATCH_DIR}/projects/ExtraTests )
set( SINGLE_INCLUDE_PATH ${CATCH_DIR}/single_include )
add_executable(PrefixedMacros ${TESTS_DIR}/X01-PrefixedMacros.cpp)
target_compile_definitions( PrefixedMacros PRIVATE CATCH_CONFIG_PREFIX_ALL )
add_test(NAME CATCH_CONFIG_PREFIX_ALL COMMAND PrefixedMacros -s)
set_tests_properties(
CATCH_CONFIG_PREFIX_ALL
PROPERTIES
PASS_REGULAR_EXPRESSION "CATCH_"
FAIL_REGULAR_EXPRESSION
# The spaces are important -> They disambiguate between CATCH_REQUIRE
# and REQUIRE without prefix.
" REQUIRE; REQUIRE_FALSE; REQUIRE_THROWS; REQUIRE_THROWS_AS; REQUIRE_THROWS_WITH; REQUIRE_THROWS_MATCHES; REQUIRE_NOTHROW; CHECK; CHECK_FALSE; CHECKED_IF; CHECKED_ELSE; CHECK_NOFAIL; CHECK_THROWS; CHECK_THROWS_AS; CHECK_THROWS_WITH; CHECK_THROWS_MATCHES; CHECK_NOTHROW; REQUIRE_THAT; CHECK_THAT"
)
add_executable(DisabledMacros ${TESTS_DIR}/X02-DisabledMacros.cpp)
target_compile_definitions( DisabledMacros PRIVATE CATCH_CONFIG_DISABLE )
add_test(NAME CATCH_CONFIG_DISABLE-1 COMMAND DisabledMacros -s)
set_tests_properties(
CATCH_CONFIG_DISABLE-1
PROPERTIES
PASS_REGULAR_EXPRESSION "No tests ran"
FAIL_REGULAR_EXPRESSION "This should not happen"
)
add_test(NAME CATCH_CONFIG_DISABLE-2 COMMAND DisabledMacros --list-tests)
set_tests_properties(
CATCH_CONFIG_DISABLE-2
PROPERTIES
PASS_REGULAR_EXPRESSION "0 test cases"
)
add_executable( DisabledExceptions-DefaultHandler ${TESTS_DIR}/X03-DisabledExceptions-DefaultHandler.cpp )
add_executable( DisabledExceptions-CustomHandler ${TESTS_DIR}/X04-DisabledExceptions-CustomHandler.cpp )
foreach(target DisabledExceptions-DefaultHandler DisabledExceptions-CustomHandler)
target_compile_options( ${target}
PRIVATE
$<$<CXX_COMPILER_ID:MSVC>:/EHs-c-;/D_HAS_EXCEPTIONS=0>
$<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:GNU>,$<CXX_COMPILER_ID:AppleClang>>:-fno-exceptions>
# $<$<CXX_COMPILER_ID:Clang>:-fno-exceptions>
# $<$<CXX_COMPILER_ID:GNU>:-fno-exceptions>
)
endforeach()
add_test(NAME CATCH_CONFIG_DISABLE_EXCEPTIONS-1 COMMAND DisabledExceptions-DefaultHandler "Tests that run")
set_tests_properties(
CATCH_CONFIG_DISABLE_EXCEPTIONS-1
PROPERTIES
PASS_REGULAR_EXPRESSION "assertions: 4 \| 2 passed \| 2 failed"
FAIL_REGULAR_EXPRESSION "abort;terminate;fatal"
)
add_test(NAME CATCH_CONFIG_DISABLE_EXCEPTIONS-2 COMMAND DisabledExceptions-DefaultHandler "Tests that abort")
set_tests_properties(
CATCH_CONFIG_DISABLE_EXCEPTIONS-2
PROPERTIES
PASS_REGULAR_EXPRESSION "Catch will terminate"
)
add_test(NAME CATCH_CONFIG_DISABLE_EXCEPTIONS-3 COMMAND DisabledExceptions-CustomHandler "Tests that run")
set_tests_properties(
CATCH_CONFIG_DISABLE_EXCEPTIONS-3
PROPERTIES
PASS_REGULAR_EXPRESSION "assertions: 4 \| 2 passed \| 2 failed"
FAIL_REGULAR_EXPRESSION "====== CUSTOM HANDLER ======"
)
add_test(NAME CATCH_CONFIG_DISABLE_EXCEPTIONS-4 COMMAND DisabledExceptions-CustomHandler "Tests that abort")
set_tests_properties(
CATCH_CONFIG_DISABLE_EXCEPTIONS-4
PROPERTIES
PASS_REGULAR_EXPRESSION "====== CUSTOM HANDLER ======"
)
add_executable(FallbackStringifier ${TESTS_DIR}/X10-FallbackStringifier.cpp)
target_compile_definitions( FallbackStringifier PRIVATE CATCH_CONFIG_FALLBACK_STRINGIFIER=fallbackStringifier )
add_test(NAME FallbackStringifier COMMAND FallbackStringifier -r compact -s)
set_tests_properties(
FallbackStringifier
PROPERTIES
PASS_REGULAR_EXPRESSION "foo{} for: { !!! }"
)
add_executable(DisableStringification ${TESTS_DIR}/X11-DisableStringification.cpp)
target_compile_definitions( DisableStringification PRIVATE CATCH_CONFIG_DISABLE_STRINGIFICATION )
add_test(NAME CATCH_CONFIG_DISABLE_STRINGIFICATION COMMAND DisableStringification -r compact -s)
set_tests_properties(
CATCH_CONFIG_DISABLE_STRINGIFICATION
PROPERTIES
PASS_REGULAR_EXPRESSION "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION"
FAIL_REGULAR_EXPRESSION "Hidden{} == Hidden{}"
)
set( EXTRA_TEST_BINARIES
PrefixedMacros
DisabledMacros
DisabledExceptions-DefaultHandler
DisabledExceptions-CustomHandler
FallbackStringifier
DisableStringification
)
# Shared config
foreach( test ${EXTRA_TEST_BINARIES} )
set_property( TARGET ${test} PROPERTY CXX_STANDARD 11 )
set_property( TARGET ${test} PROPERTY CXX_STANDARD_REQUIRED ON )
set_property( TARGET ${test} PROPERTY CXX_EXTENSIONS OFF )
target_include_directories( ${test} PRIVATE ${SINGLE_INCLUDE_PATH} )
endforeach()

View File

@@ -0,0 +1,11 @@
Configuration options that are left default and thus are not properly tested
yet:
CATCH_CONFIG_COUNTER // Use __COUNTER__ to generate unique names for test cases
CATCH_CONFIG_WINDOWS_SEH // Enable SEH handling on Windows
CATCH_CONFIG_FAST_COMPILE // Sacrifices some (rather minor) features for compilation speed
CATCH_CONFIG_DISABLE_MATCHERS // Do not compile Matchers in this compilation unit
CATCH_CONFIG_POSIX_SIGNALS // Enable handling POSIX signals
CATCH_CONFIG_WINDOWS_CRTDBG // Enable leak checking using Windows's CRT Debug Heap
CATCH_CONFIG_DEFAULT_REPORTER
CATCH_CONFIG_ENABLE_ALL_STRINGMAKERS

View File

@@ -0,0 +1,83 @@
// X11-DisableStringification.cpp
// Test that Catch's prefixed macros compile and run properly.
#define CATCH_CONFIG_MAIN
// This won't provide full coverage, but it might be worth checking
// the other branch as well
#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE
#include <catch2/catch.hpp>
#include <type_traits>
#include <stdexcept>
[[noreturn]]
void this_throws() {
throw std::runtime_error("Some msg");
}
void this_doesnt_throw() {}
CATCH_TEST_CASE("PrefixedMacros") {
using namespace Catch::Matchers;
CATCH_REQUIRE( 1 == 1 );
CATCH_REQUIRE_FALSE( 1 != 1 );
CATCH_REQUIRE_THROWS(this_throws());
CATCH_REQUIRE_THROWS_AS(this_throws(), std::runtime_error);
CATCH_REQUIRE_THROWS_WITH(this_throws(), "Some msg");
CATCH_REQUIRE_THROWS_MATCHES(this_throws(), std::runtime_error, Predicate<std::runtime_error>([](std::runtime_error const&) { return true; }));
CATCH_REQUIRE_NOTHROW(this_doesnt_throw());
CATCH_CHECK( 1 == 1 );
CATCH_CHECK_FALSE( 1 != 1 );
CATCH_CHECKED_IF( 1 == 1 ) {
CATCH_SUCCEED("don't care");
} CATCH_CHECKED_ELSE ( 1 == 1 ) {
CATCH_SUCCEED("don't care");
}
CATCH_CHECK_NOFAIL(1 == 2);
CATCH_CHECK_THROWS(this_throws());
CATCH_CHECK_THROWS_AS(this_throws(), std::runtime_error);
CATCH_CHECK_THROWS_WITH(this_throws(), "Some msg");
CATCH_CHECK_THROWS_MATCHES(this_throws(), std::runtime_error, Predicate<std::runtime_error>([](std::runtime_error const&) { return true; }));
CATCH_CHECK_NOTHROW(this_doesnt_throw());
CATCH_REQUIRE_THAT("abcd", Equals("abcd"));
CATCH_CHECK_THAT("bdef", Equals("bdef"));
CATCH_INFO( "some info" );
CATCH_WARN( "some warn" );
CATCH_SECTION("some section") {
int i = 1;
CATCH_CAPTURE( i );
CATCH_DYNAMIC_SECTION("Dynamic section: " << i) {
CATCH_FAIL_CHECK( "failure" );
}
}
CATCH_STATIC_REQUIRE( std::is_void<void>::value );
CATCH_STATIC_REQUIRE_FALSE( std::is_void<int>::value );
}
CATCH_ANON_TEST_CASE() {
CATCH_FAIL("");
}
// Missing:
//
// #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
// #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
// #define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
//
// // "BDD-style" convenience wrappers
// #define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ )
// #define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ )
// #define CATCH_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Given: " << desc )
// #define CATCH_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " When: " << desc )
// #define CATCH_AND_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And when: " << desc )
// #define CATCH_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc )
// #define CATCH_AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc )
//

View File

@@ -0,0 +1,31 @@
// X02-DisabledMacros.cpp
// Test that CATCH_CONFIG_DISABLE turns off TEST_CASE autoregistration
// and expressions in assertion macros are not run.
#define CATCH_CONFIG_MAIN
#include <catch2/catch.hpp>
// CATCH_CONFIG_DISABLE also prevents reporter registration.
// We need to manually register at least one reporter for our tests
static Catch::ReporterRegistrar<Catch::ConsoleReporter> temporary( "console" );
#include <iostream>
struct foo {
foo(){
REQUIRE_NOTHROW( print() );
}
void print() const {
std::cout << "This should not happen\n";
}
};
// Construct foo, but `foo::print` should not be run
foo f;
// This test should not be run, because it won't be registered
TEST_CASE( "Disabled Macros" ) {
std::cout << "This should not happen\n";
FAIL();
}

View File

@@ -0,0 +1,23 @@
#define CATCH_CONFIG_MAIN
#include <catch2/catch.hpp>
TEST_CASE("Tests that run") {
// All of these should be run and be reported
CHECK(1 == 2);
CHECK(1 == 1);
CHECK(1 != 3);
CHECK(1 == 4);
}
TEST_CASE("Tests that abort") {
// Avoid abort and other exceptional exits -- there is no way
// to tell CMake that abort is the desired outcome of a test.
std::set_terminate([](){exit(1);});
REQUIRE(1 == 1);
REQUIRE(1 != 2);
REQUIRE(1 == 3);
// We should not get here, because the test above aborts
REQUIRE(1 != 4);
}

View File

@@ -0,0 +1,33 @@
#define CATCH_CONFIG_DISABLE_EXCEPTIONS_CUSTOM_HANDLER
#define CATCH_CONFIG_MAIN
#include <catch2/catch.hpp>
namespace Catch {
[[noreturn]]
void throw_exception(std::exception const& e) {
Catch::cerr() << "====== CUSTOM HANDLER ====== run terminates because an exception was thrown.\n"
<< "The message was: " << e.what() << '\n';
// Avoid abort and other exceptional exits -- there is no way
// to tell CMake that abort is the desired outcome of a test.
exit(1);
}
}
TEST_CASE("Tests that run") {
// All of these should be run and be reported
CHECK(1 == 2);
CHECK(1 == 1);
CHECK(1 != 3);
CHECK(1 == 4);
}
TEST_CASE("Tests that abort") {
REQUIRE(1 == 1);
REQUIRE(1 != 2);
REQUIRE(1 == 3);
// We should not get here, because the test above aborts
REQUIRE(1 != 4);
}

View File

@@ -0,0 +1,23 @@
// X10-FallbackStringifier.cpp
// Test that defining fallbackStringifier compiles
#include <string>
// A catch-all stringifier
template <typename T>
std::string fallbackStringifier(T const&) {
return "{ !!! }";
}
#define CATCH_CONFIG_MAIN
#include <catch2/catch.hpp>
struct foo {
explicit operator bool() const {
return true;
}
};
TEST_CASE("aa") {
REQUIRE(foo{});
}

View File

@@ -0,0 +1,16 @@
// X11-DisableStringification.cpp
// Test that stringification of original expression can be disabled
// this is a workaround for VS 2017 issue with Raw String literal
// and preprocessor token pasting. In other words, hopefully this test
// will be deleted soon :-)
#define CATCH_CONFIG_MAIN
#include <catch2/catch.hpp>
struct Hidden {};
bool operator==(Hidden, Hidden) { return true; }
TEST_CASE("DisableStringification") {
REQUIRE( Hidden{} == Hidden{} );
}

View File

@@ -13,6 +13,7 @@ Misc.tests.cpp:<line number>: passed:
Compilation.tests.cpp:<line number>: passed: std::memcmp(uarr, "123", sizeof(uarr)) == 0 for: 0 == 0 with 2 messages: 'uarr := "123"' and 'sarr := "456"'
Compilation.tests.cpp:<line number>: passed: std::memcmp(sarr, "456", sizeof(sarr)) == 0 for: 0 == 0 with 2 messages: 'uarr := "123"' and 'sarr := "456"'
Compilation.tests.cpp:<line number>: passed:
Compilation.tests.cpp:<line number>: passed: h1 == h2 for: [1403 helper] == [1403 helper]
Exception.tests.cpp:<line number>: failed: unexpected exception with message: 'answer := 42' with 1 message: 'expected exception'
Exception.tests.cpp:<line number>: failed: unexpected exception with message: 'answer := 42'; expression was: thisThrows() with 1 message: 'expected exception'
Exception.tests.cpp:<line number>: passed: thisThrows() with 1 message: 'answer := 42'
@@ -56,6 +57,106 @@ Tricky.tests.cpp:<line number>: passed: !is_true<false>::value for: true
Tricky.tests.cpp:<line number>: passed: !!is_true<true>::value for: true
Tricky.tests.cpp:<line number>: passed: is_true<true>::value for: true
Tricky.tests.cpp:<line number>: passed: !(is_true<false>::value) for: !false
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 101
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 102
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 103
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 104
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 105
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 106
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 107
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 108
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 109
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 110
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 101
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 102
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 103
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 104
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 105
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 106
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 107
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 108
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 109
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 110
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 101
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 102
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 103
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 104
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 105
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 106
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 107
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 108
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 109
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 110
Generators.tests.cpp:<line number>: passed: x < y for: 4 < 101
Generators.tests.cpp:<line number>: passed: x < y for: 4 < 102
Generators.tests.cpp:<line number>: passed: x < y for: 4 < 103
Generators.tests.cpp:<line number>: passed: x < y for: 4 < 104
Generators.tests.cpp:<line number>: passed: x < y for: 4 < 105
Generators.tests.cpp:<line number>: passed: x < y for: 4 < 106
Generators.tests.cpp:<line number>: passed: x < y for: 4 < 107
Generators.tests.cpp:<line number>: passed: x < y for: 4 < 108
Generators.tests.cpp:<line number>: passed: x < y for: 4 < 109
Generators.tests.cpp:<line number>: passed: x < y for: 4 < 110
Generators.tests.cpp:<line number>: passed: x < y for: 5 < 101
Generators.tests.cpp:<line number>: passed: x < y for: 5 < 102
Generators.tests.cpp:<line number>: passed: x < y for: 5 < 103
Generators.tests.cpp:<line number>: passed: x < y for: 5 < 104
Generators.tests.cpp:<line number>: passed: x < y for: 5 < 105
Generators.tests.cpp:<line number>: passed: x < y for: 5 < 106
Generators.tests.cpp:<line number>: passed: x < y for: 5 < 107
Generators.tests.cpp:<line number>: passed: x < y for: 5 < 108
Generators.tests.cpp:<line number>: passed: x < y for: 5 < 109
Generators.tests.cpp:<line number>: passed: x < y for: 5 < 110
Generators.tests.cpp:<line number>: passed: x < y for: 6 < 101
Generators.tests.cpp:<line number>: passed: x < y for: 6 < 102
Generators.tests.cpp:<line number>: passed: x < y for: 6 < 103
Generators.tests.cpp:<line number>: passed: x < y for: 6 < 104
Generators.tests.cpp:<line number>: passed: x < y for: 6 < 105
Generators.tests.cpp:<line number>: passed: x < y for: 6 < 106
Generators.tests.cpp:<line number>: passed: x < y for: 6 < 107
Generators.tests.cpp:<line number>: passed: x < y for: 6 < 108
Generators.tests.cpp:<line number>: passed: x < y for: 6 < 109
Generators.tests.cpp:<line number>: passed: x < y for: 6 < 110
Generators.tests.cpp:<line number>: passed: x < y for: 7 < 101
Generators.tests.cpp:<line number>: passed: x < y for: 7 < 102
Generators.tests.cpp:<line number>: passed: x < y for: 7 < 103
Generators.tests.cpp:<line number>: passed: x < y for: 7 < 104
Generators.tests.cpp:<line number>: passed: x < y for: 7 < 105
Generators.tests.cpp:<line number>: passed: x < y for: 7 < 106
Generators.tests.cpp:<line number>: passed: x < y for: 7 < 107
Generators.tests.cpp:<line number>: passed: x < y for: 7 < 108
Generators.tests.cpp:<line number>: passed: x < y for: 7 < 109
Generators.tests.cpp:<line number>: passed: x < y for: 7 < 110
Generators.tests.cpp:<line number>: passed: x < y for: 8 < 101
Generators.tests.cpp:<line number>: passed: x < y for: 8 < 102
Generators.tests.cpp:<line number>: passed: x < y for: 8 < 103
Generators.tests.cpp:<line number>: passed: x < y for: 8 < 104
Generators.tests.cpp:<line number>: passed: x < y for: 8 < 105
Generators.tests.cpp:<line number>: passed: x < y for: 8 < 106
Generators.tests.cpp:<line number>: passed: x < y for: 8 < 107
Generators.tests.cpp:<line number>: passed: x < y for: 8 < 108
Generators.tests.cpp:<line number>: passed: x < y for: 8 < 109
Generators.tests.cpp:<line number>: passed: x < y for: 8 < 110
Generators.tests.cpp:<line number>: passed: x < y for: 9 < 101
Generators.tests.cpp:<line number>: passed: x < y for: 9 < 102
Generators.tests.cpp:<line number>: passed: x < y for: 9 < 103
Generators.tests.cpp:<line number>: passed: x < y for: 9 < 104
Generators.tests.cpp:<line number>: passed: x < y for: 9 < 105
Generators.tests.cpp:<line number>: passed: x < y for: 9 < 106
Generators.tests.cpp:<line number>: passed: x < y for: 9 < 107
Generators.tests.cpp:<line number>: passed: x < y for: 9 < 108
Generators.tests.cpp:<line number>: passed: x < y for: 9 < 109
Generators.tests.cpp:<line number>: passed: x < y for: 9 < 110
Generators.tests.cpp:<line number>: passed: x < y for: 10 < 101
Generators.tests.cpp:<line number>: passed: x < y for: 10 < 102
Generators.tests.cpp:<line number>: passed: x < y for: 10 < 103
Generators.tests.cpp:<line number>: passed: x < y for: 10 < 104
Generators.tests.cpp:<line number>: passed: x < y for: 10 < 105
Generators.tests.cpp:<line number>: passed: x < y for: 10 < 106
Generators.tests.cpp:<line number>: passed: x < y for: 10 < 107
Generators.tests.cpp:<line number>: passed: x < y for: 10 < 108
Generators.tests.cpp:<line number>: passed: x < y for: 10 < 109
Generators.tests.cpp:<line number>: passed: x < y for: 10 < 110
Class.tests.cpp:<line number>: failed: s == "world" for: "hello" == "world"
Class.tests.cpp:<line number>: passed: s == "hello" for: "hello" == "hello"
Class.tests.cpp:<line number>: failed: m_a == 2 for: 1 == 2
@@ -123,16 +224,16 @@ Tricky.tests.cpp:<line number>: passed: y.v == 0 for: 0 == 0
Tricky.tests.cpp:<line number>: passed: 0 == y.v for: 0 == 0
ToStringGeneral.tests.cpp:<line number>: passed: true with 1 message: 'i := 2'
ToStringGeneral.tests.cpp:<line number>: passed: true with 1 message: '3'
ToStringGeneral.tests.cpp:<line number>: passed: tab == '/t' for: '/t' == '/t'
ToStringGeneral.tests.cpp:<line number>: passed: newline == '/n' for: '/n' == '/n'
ToStringGeneral.tests.cpp:<line number>: passed: carr_return == '/r' for: '/r' == '/r'
ToStringGeneral.tests.cpp:<line number>: passed: form_feed == '/f' for: '/f' == '/f'
ToStringGeneral.tests.cpp:<line number>: passed: tab == '\t' for: '\t' == '\t'
ToStringGeneral.tests.cpp:<line number>: passed: newline == '\n' for: '\n' == '\n'
ToStringGeneral.tests.cpp:<line number>: passed: carr_return == '\r' for: '\r' == '\r'
ToStringGeneral.tests.cpp:<line number>: passed: form_feed == '\f' for: '\f' == '\f'
ToStringGeneral.tests.cpp:<line number>: passed: space == ' ' for: ' ' == ' '
ToStringGeneral.tests.cpp:<line number>: passed: c == chars[i] for: 'a' == 'a'
ToStringGeneral.tests.cpp:<line number>: passed: c == chars[i] for: 'z' == 'z'
ToStringGeneral.tests.cpp:<line number>: passed: c == chars[i] for: 'A' == 'A'
ToStringGeneral.tests.cpp:<line number>: passed: c == chars[i] for: 'Z' == 'Z'
ToStringGeneral.tests.cpp:<line number>: passed: null_terminator == '/0' for: 0 == 0
ToStringGeneral.tests.cpp:<line number>: passed: null_terminator == '\0' for: 0 == 0
ToStringGeneral.tests.cpp:<line number>: passed: c == i for: 2 == 2
ToStringGeneral.tests.cpp:<line number>: passed: c == i for: 3 == 3
ToStringGeneral.tests.cpp:<line number>: passed: c == i for: 4 == 4
@@ -297,6 +398,48 @@ Matchers.tests.cpp:<line number>: passed: WithinAbs(1.f, 0.f)
Matchers.tests.cpp:<line number>: passed: WithinAbs(1.f, -1.f), std::domain_error
Matchers.tests.cpp:<line number>: passed: WithinULP(1.f, 0)
Matchers.tests.cpp:<line number>: passed: WithinULP(1.f, -1), std::domain_error
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "a"' and 'j := 8'
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "a"' and 'j := 9'
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "a"' and 'j := 10'
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "a"' and 'j := 2'
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "a"' and 'j := 3.141'
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "a"' and 'j := 1.379'
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "b"' and 'j := 8'
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "b"' and 'j := 9'
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "b"' and 'j := 10'
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "b"' and 'j := 2'
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "b"' and 'j := 3.141'
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "b"' and 'j := 1.379'
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "c"' and 'j := 8'
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "c"' and 'j := 9'
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "c"' and 'j := 10'
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "c"' and 'j := 2'
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "c"' and 'j := 3.141'
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "c"' and 'j := 1.379'
GeneratorsImpl.tests.cpp:<line number>: passed: gen.size() == 2 for: 2 == 2
GeneratorsImpl.tests.cpp:<line number>: passed: gen[0] == 1 for: 1 == 1
GeneratorsImpl.tests.cpp:<line number>: passed: gen[1] == 2 for: 2 == 2
GeneratorsImpl.tests.cpp:<line number>: passed: gen.size() == 4 for: 4 == 4
GeneratorsImpl.tests.cpp:<line number>: passed: gen[0] == 3 for: 3 == 3
GeneratorsImpl.tests.cpp:<line number>: passed: gen[1] == 1 for: 1 == 1
GeneratorsImpl.tests.cpp:<line number>: passed: gen[2] == 4 for: 4 == 4
GeneratorsImpl.tests.cpp:<line number>: passed: gen[3] == 1 for: 1 == 1
GeneratorsImpl.tests.cpp:<line number>: passed: gen.size() == 4 for: 4 == 4
GeneratorsImpl.tests.cpp:<line number>: passed: gen[0] == 1 for: 1 == 1
GeneratorsImpl.tests.cpp:<line number>: passed: gen[1] == 2 for: 2 == 2
GeneratorsImpl.tests.cpp:<line number>: passed: gen[2] == 9 for: 9 == 9
GeneratorsImpl.tests.cpp:<line number>: passed: gen[3] == 7 for: 7 == 7
GeneratorsImpl.tests.cpp:<line number>: passed: gen.size() == 2 for: 2 == 2
GeneratorsImpl.tests.cpp:<line number>: passed: gen[0] == 3 for: 3 == 3
GeneratorsImpl.tests.cpp:<line number>: passed: gen[1] == 1 for: 1 == 1
GeneratorsImpl.tests.cpp:<line number>: passed: gen.size() == 2 for: 2 == 2
GeneratorsImpl.tests.cpp:<line number>: passed: gen[0] == 3 for: 3 == 3
GeneratorsImpl.tests.cpp:<line number>: passed: gen[1] == 1 for: 1 == 1
GeneratorsImpl.tests.cpp:<line number>: passed: base->size() == 4 for: 4 == 4
GeneratorsImpl.tests.cpp:<line number>: passed: typed for: 0x<hex digits>
GeneratorsImpl.tests.cpp:<line number>: passed: typed->size() == 4 for: 4 == 4
GeneratorsImpl.tests.cpp:<line number>: passed: (*typed)[0] == 7 for: 7 == 7
GeneratorsImpl.tests.cpp:<line number>: passed: (*typed)[3] == 11 for: 11 == 11
Approx.tests.cpp:<line number>: passed: d >= Approx( 1.22 ) for: 1.23 >= Approx( 1.22 )
Approx.tests.cpp:<line number>: passed: d >= Approx( 1.23 ) for: 1.23 >= Approx( 1.23 )
Approx.tests.cpp:<line number>: passed: !(d >= Approx( 1.24 )) for: !(1.23 >= Approx( 1.24 ))
@@ -353,6 +496,8 @@ Exception.tests.cpp:<line number>: failed: unexpected exception with message: 'c
Tricky.tests.cpp:<line number>: passed: True for: {?}
Tricky.tests.cpp:<line number>: passed: !False for: true
Tricky.tests.cpp:<line number>: passed: !(False) for: !{?}
Compilation.tests.cpp:<line number>: passed: with 1 message: 'std::is_void<void>::value'
Compilation.tests.cpp:<line number>: passed: with 1 message: '!(std::is_void<int>::value)'
Condition.tests.cpp:<line number>: failed: data.int_seven > 7 for: 7 > 7
Condition.tests.cpp:<line number>: failed: data.int_seven < 7 for: 7 < 7
Condition.tests.cpp:<line number>: failed: data.int_seven > 8 for: 7 > 8
@@ -562,6 +707,8 @@ CmdLine.tests.cpp:<line number>: passed: config.reporterName == "xml" for: "xml"
CmdLine.tests.cpp:<line number>: passed: cli.parse({"test", "--reporter", "junit"}) for: {?}
CmdLine.tests.cpp:<line number>: passed: config.reporterName == "junit" for: "junit" == "junit"
CmdLine.tests.cpp:<line number>: passed: !(cli.parse({ "test", "-r", "xml", "-r", "junit" })) for: !{?}
CmdLine.tests.cpp:<line number>: passed: !result for: true
CmdLine.tests.cpp:<line number>: passed: result.errorMessage(), Contains("Unrecognized reporter") for: "Unrecognized reporter, 'unsupported'. Check available with --list-reporters" contains: "Unrecognized reporter"
CmdLine.tests.cpp:<line number>: passed: cli.parse({"test", "-b"}) for: {?}
CmdLine.tests.cpp:<line number>: passed: config.shouldDebugBreak == true for: true == true
CmdLine.tests.cpp:<line number>: passed: cli.parse({"test", "--break"}) for: {?}
@@ -598,6 +745,7 @@ Decomposition.tests.cpp:<line number>: failed: truthy(false) for: Hey, its truth
Matchers.tests.cpp:<line number>: failed: testStringForMatching(), Matches("this STRING contains 'abc' as a substring") for: "this string contains 'abc' as a substring" matches "this STRING contains 'abc' as a substring" case sensitively
Matchers.tests.cpp:<line number>: failed: testStringForMatching(), Matches("contains 'abc' as a substring") for: "this string contains 'abc' as a substring" matches "contains 'abc' as a substring" case sensitively
Matchers.tests.cpp:<line number>: failed: testStringForMatching(), Matches("this string contains 'abc' as a") for: "this string contains 'abc' as a substring" matches "this string contains 'abc' as a" case sensitively
Matchers.tests.cpp:<line number>: passed: actual, !UnorderedEquals(expected) for: { 'a', 'b' } not UnorderedEquals: { 'c', 'b' }
Message.tests.cpp:<line number>: passed: with 1 message: 'this is a success'
Message.tests.cpp:<line number>: passed:
BDD.tests.cpp:<line number>: passed: before == 0 for: 0 == 0
@@ -921,50 +1069,50 @@ Xml.tests.cpp:<line number>: passed: encode( stringWithQuotes ) == stringWithQuo
Xml.tests.cpp:<line number>: passed: encode( stringWithQuotes, Catch::XmlEncode::ForAttributes ) == "don't &quot;quote&quot; me on that" for: "don't &quot;quote&quot; me on that"
==
"don't &quot;quote&quot; me on that"
Xml.tests.cpp:<line number>: passed: encode( "[/x01]" ) == "[//x01]" for: "[/x01]" == "[/x01]"
Xml.tests.cpp:<line number>: passed: encode( "[/x7F]" ) == "[//x7F]" for: "[/x7F]" == "[/x7F]"
Xml.tests.cpp:<line number>: passed: encode( "[\x01]" ) == "[\\x01]" for: "[\x01]" == "[\x01]"
Xml.tests.cpp:<line number>: passed: encode( "[\x7F]" ) == "[\\x7F]" for: "[\x7F]" == "[\x7F]"
Xml.tests.cpp:<line number>: passed: encode(u8"Here be 👾") == u8"Here be 👾" for: "Here be 👾" == "Here be 👾"
Xml.tests.cpp:<line number>: passed: encode(u8"šš") == u8"šš" for: "šš" == "šš"
Xml.tests.cpp:<line number>: passed: encode("/xDF/xBF") == "/xDF/xBF" for: "߿" == "߿"
Xml.tests.cpp:<line number>: passed: encode("/xE0/xA0/x80") == "/xE0/xA0/x80" for: "ࠀ" == "ࠀ"
Xml.tests.cpp:<line number>: passed: encode("/xED/x9F/xBF") == "/xED/x9F/xBF" for: "퟿" == "퟿"
Xml.tests.cpp:<line number>: passed: encode("/xEE/x80/x80") == "/xEE/x80/x80" for: "" == ""
Xml.tests.cpp:<line number>: passed: encode("/xEF/xBF/xBF") == "/xEF/xBF/xBF" for: "￿" == "￿"
Xml.tests.cpp:<line number>: passed: encode("/xF0/x90/x80/x80") == "/xF0/x90/x80/x80" for: "𐀀" == "𐀀"
Xml.tests.cpp:<line number>: passed: encode("/xF4/x8F/xBF/xBF") == "/xF4/x8F/xBF/xBF" for: "􏿿" == "􏿿"
Xml.tests.cpp:<line number>: passed: encode("Here /xFF be 👾") == u8"Here //xFF be 👾" for: "Here /xFF be 👾" == "Here /xFF be 👾"
Xml.tests.cpp:<line number>: passed: encode("/xFF") == "//xFF" for: "/xFF" == "/xFF"
Xml.tests.cpp:<line number>: passed: encode("/xC5/xC5/xA0") == u8"//xC5Š" for: "/xC5Š" == "/xC5Š"
Xml.tests.cpp:<line number>: passed: encode("/xF4/x90/x80/x80") == u8"//xF4//x90//x80//x80" for: "/xF4/x90/x80/x80" == "/xF4/x90/x80/x80"
Xml.tests.cpp:<line number>: passed: encode("/xC0/x80") == u8"//xC0//x80" for: "/xC0/x80" == "/xC0/x80"
Xml.tests.cpp:<line number>: passed: encode("/xF0/x80/x80/x80") == u8"//xF0//x80//x80//x80" for: "/xF0/x80/x80/x80" == "/xF0/x80/x80/x80"
Xml.tests.cpp:<line number>: passed: encode("/xC1/xBF") == u8"//xC1//xBF" for: "/xC1/xBF" == "/xC1/xBF"
Xml.tests.cpp:<line number>: passed: encode("/xE0/x9F/xBF") == u8"//xE0//x9F//xBF" for: "/xE0/x9F/xBF" == "/xE0/x9F/xBF"
Xml.tests.cpp:<line number>: passed: encode("/xF0/x8F/xBF/xBF") == u8"//xF0//x8F//xBF//xBF" for: "/xF0/x8F/xBF/xBF" == "/xF0/x8F/xBF/xBF"
Xml.tests.cpp:<line number>: passed: encode("/xED/xA0/x80") == "/xED/xA0/x80" for: "<22><><EFBFBD>" == "<22><><EFBFBD>"
Xml.tests.cpp:<line number>: passed: encode("/xED/xAF/xBF") == "/xED/xAF/xBF" for: "<22><><EFBFBD>" == "<22><><EFBFBD>"
Xml.tests.cpp:<line number>: passed: encode("/xED/xB0/x80") == "/xED/xB0/x80" for: "<22><><EFBFBD>" == "<22><><EFBFBD>"
Xml.tests.cpp:<line number>: passed: encode("/xED/xBF/xBF") == "/xED/xBF/xBF" for: "<22><><EFBFBD>" == "<22><><EFBFBD>"
Xml.tests.cpp:<line number>: passed: encode("/x80") == u8"//x80" for: "/x80" == "/x80"
Xml.tests.cpp:<line number>: passed: encode("/x81") == u8"//x81" for: "/x81" == "/x81"
Xml.tests.cpp:<line number>: passed: encode("/xBC") == u8"//xBC" for: "/xBC" == "/xBC"
Xml.tests.cpp:<line number>: passed: encode("/xBF") == u8"//xBF" for: "/xBF" == "/xBF"
Xml.tests.cpp:<line number>: passed: encode("/xF5/x80/x80/x80") == u8"//xF5//x80//x80//x80" for: "/xF5/x80/x80/x80" == "/xF5/x80/x80/x80"
Xml.tests.cpp:<line number>: passed: encode("/xF6/x80/x80/x80") == u8"//xF6//x80//x80//x80" for: "/xF6/x80/x80/x80" == "/xF6/x80/x80/x80"
Xml.tests.cpp:<line number>: passed: encode("/xF7/x80/x80/x80") == u8"//xF7//x80//x80//x80" for: "/xF7/x80/x80/x80" == "/xF7/x80/x80/x80"
Xml.tests.cpp:<line number>: passed: encode("/xDE") == u8"//xDE" for: "/xDE" == "/xDE"
Xml.tests.cpp:<line number>: passed: encode("/xDF") == u8"//xDF" for: "/xDF" == "/xDF"
Xml.tests.cpp:<line number>: passed: encode("/xE0") == u8"//xE0" for: "/xE0" == "/xE0"
Xml.tests.cpp:<line number>: passed: encode("/xEF") == u8"//xEF" for: "/xEF" == "/xEF"
Xml.tests.cpp:<line number>: passed: encode("/xF0") == u8"//xF0" for: "/xF0" == "/xF0"
Xml.tests.cpp:<line number>: passed: encode("/xF4") == u8"//xF4" for: "/xF4" == "/xF4"
Xml.tests.cpp:<line number>: passed: encode("/xE0/x80") == u8"//xE0//x80" for: "/xE0/x80" == "/xE0/x80"
Xml.tests.cpp:<line number>: passed: encode("/xE0/xBF") == u8"//xE0//xBF" for: "/xE0/xBF" == "/xE0/xBF"
Xml.tests.cpp:<line number>: passed: encode("/xE1/x80") == u8"//xE1//x80" for: "/xE1/x80" == "/xE1/x80"
Xml.tests.cpp:<line number>: passed: encode("/xF0/x80") == u8"//xF0//x80" for: "/xF0/x80" == "/xF0/x80"
Xml.tests.cpp:<line number>: passed: encode("/xF4/x80") == u8"//xF4//x80" for: "/xF4/x80" == "/xF4/x80"
Xml.tests.cpp:<line number>: passed: encode("/xF0/x80/x80") == u8"//xF0//x80//x80" for: "/xF0/x80/x80" == "/xF0/x80/x80"
Xml.tests.cpp:<line number>: passed: encode("/xF4/x80/x80") == u8"//xF4//x80//x80" for: "/xF4/x80/x80" == "/xF4/x80/x80"
Xml.tests.cpp:<line number>: passed: encode("\xDF\xBF") == "\xDF\xBF" for: "߿" == "߿"
Xml.tests.cpp:<line number>: passed: encode("\xE0\xA0\x80") == "\xE0\xA0\x80" for: "ࠀ" == "ࠀ"
Xml.tests.cpp:<line number>: passed: encode("\xED\x9F\xBF") == "\xED\x9F\xBF" for: "퟿" == "퟿"
Xml.tests.cpp:<line number>: passed: encode("\xEE\x80\x80") == "\xEE\x80\x80" for: "" == ""
Xml.tests.cpp:<line number>: passed: encode("\xEF\xBF\xBF") == "\xEF\xBF\xBF" for: "￿" == "￿"
Xml.tests.cpp:<line number>: passed: encode("\xF0\x90\x80\x80") == "\xF0\x90\x80\x80" for: "𐀀" == "𐀀"
Xml.tests.cpp:<line number>: passed: encode("\xF4\x8F\xBF\xBF") == "\xF4\x8F\xBF\xBF" for: "􏿿" == "􏿿"
Xml.tests.cpp:<line number>: passed: encode("Here \xFF be 👾") == u8"Here \\xFF be 👾" for: "Here \xFF be 👾" == "Here \xFF be 👾"
Xml.tests.cpp:<line number>: passed: encode("\xFF") == "\\xFF" for: "\xFF" == "\xFF"
Xml.tests.cpp:<line number>: passed: encode("\xC5\xC5\xA0") == u8"\\xC5Š" for: "\xC5Š" == "\xC5Š"
Xml.tests.cpp:<line number>: passed: encode("\xF4\x90\x80\x80") == u8"\\xF4\\x90\\x80\\x80" for: "\xF4\x90\x80\x80" == "\xF4\x90\x80\x80"
Xml.tests.cpp:<line number>: passed: encode("\xC0\x80") == u8"\\xC0\\x80" for: "\xC0\x80" == "\xC0\x80"
Xml.tests.cpp:<line number>: passed: encode("\xF0\x80\x80\x80") == u8"\\xF0\\x80\\x80\\x80" for: "\xF0\x80\x80\x80" == "\xF0\x80\x80\x80"
Xml.tests.cpp:<line number>: passed: encode("\xC1\xBF") == u8"\\xC1\\xBF" for: "\xC1\xBF" == "\xC1\xBF"
Xml.tests.cpp:<line number>: passed: encode("\xE0\x9F\xBF") == u8"\\xE0\\x9F\\xBF" for: "\xE0\x9F\xBF" == "\xE0\x9F\xBF"
Xml.tests.cpp:<line number>: passed: encode("\xF0\x8F\xBF\xBF") == u8"\\xF0\\x8F\\xBF\\xBF" for: "\xF0\x8F\xBF\xBF" == "\xF0\x8F\xBF\xBF"
Xml.tests.cpp:<line number>: passed: encode("\xED\xA0\x80") == "\xED\xA0\x80" for: "<22><><EFBFBD>" == "<22><><EFBFBD>"
Xml.tests.cpp:<line number>: passed: encode("\xED\xAF\xBF") == "\xED\xAF\xBF" for: "<22><><EFBFBD>" == "<22><><EFBFBD>"
Xml.tests.cpp:<line number>: passed: encode("\xED\xB0\x80") == "\xED\xB0\x80" for: "<22><><EFBFBD>" == "<22><><EFBFBD>"
Xml.tests.cpp:<line number>: passed: encode("\xED\xBF\xBF") == "\xED\xBF\xBF" for: "<22><><EFBFBD>" == "<22><><EFBFBD>"
Xml.tests.cpp:<line number>: passed: encode("\x80") == u8"\\x80" for: "\x80" == "\x80"
Xml.tests.cpp:<line number>: passed: encode("\x81") == u8"\\x81" for: "\x81" == "\x81"
Xml.tests.cpp:<line number>: passed: encode("\xBC") == u8"\\xBC" for: "\xBC" == "\xBC"
Xml.tests.cpp:<line number>: passed: encode("\xBF") == u8"\\xBF" for: "\xBF" == "\xBF"
Xml.tests.cpp:<line number>: passed: encode("\xF5\x80\x80\x80") == u8"\\xF5\\x80\\x80\\x80" for: "\xF5\x80\x80\x80" == "\xF5\x80\x80\x80"
Xml.tests.cpp:<line number>: passed: encode("\xF6\x80\x80\x80") == u8"\\xF6\\x80\\x80\\x80" for: "\xF6\x80\x80\x80" == "\xF6\x80\x80\x80"
Xml.tests.cpp:<line number>: passed: encode("\xF7\x80\x80\x80") == u8"\\xF7\\x80\\x80\\x80" for: "\xF7\x80\x80\x80" == "\xF7\x80\x80\x80"
Xml.tests.cpp:<line number>: passed: encode("\xDE") == u8"\\xDE" for: "\xDE" == "\xDE"
Xml.tests.cpp:<line number>: passed: encode("\xDF") == u8"\\xDF" for: "\xDF" == "\xDF"
Xml.tests.cpp:<line number>: passed: encode("\xE0") == u8"\\xE0" for: "\xE0" == "\xE0"
Xml.tests.cpp:<line number>: passed: encode("\xEF") == u8"\\xEF" for: "\xEF" == "\xEF"
Xml.tests.cpp:<line number>: passed: encode("\xF0") == u8"\\xF0" for: "\xF0" == "\xF0"
Xml.tests.cpp:<line number>: passed: encode("\xF4") == u8"\\xF4" for: "\xF4" == "\xF4"
Xml.tests.cpp:<line number>: passed: encode("\xE0\x80") == u8"\\xE0\\x80" for: "\xE0\x80" == "\xE0\x80"
Xml.tests.cpp:<line number>: passed: encode("\xE0\xBF") == u8"\\xE0\\xBF" for: "\xE0\xBF" == "\xE0\xBF"
Xml.tests.cpp:<line number>: passed: encode("\xE1\x80") == u8"\\xE1\\x80" for: "\xE1\x80" == "\xE1\x80"
Xml.tests.cpp:<line number>: passed: encode("\xF0\x80") == u8"\\xF0\\x80" for: "\xF0\x80" == "\xF0\x80"
Xml.tests.cpp:<line number>: passed: encode("\xF4\x80") == u8"\\xF4\\x80" for: "\xF4\x80" == "\xF4\x80"
Xml.tests.cpp:<line number>: passed: encode("\xF0\x80\x80") == u8"\\xF0\\x80\\x80" for: "\xF0\x80\x80" == "\xF0\x80\x80"
Xml.tests.cpp:<line number>: passed: encode("\xF4\x80\x80") == u8"\\xF4\\x80\\x80" for: "\xF4\x80\x80" == "\xF4\x80\x80"
ToStringVector.tests.cpp:<line number>: passed: Catch::Detail::stringify( empty ) == "{ }" for: "{ }" == "{ }"
ToStringVector.tests.cpp:<line number>: passed: Catch::Detail::stringify( oneValue ) == "{ 42 }" for: "{ 42 }" == "{ 42 }"
ToStringVector.tests.cpp:<line number>: passed: Catch::Detail::stringify( twoValues ) == "{ 42, 250 }" for: "{ 42, 250 }" == "{ 42, 250 }"
@@ -1024,7 +1172,7 @@ Misc.tests.cpp:<line number>: passed:
Misc.tests.cpp:<line number>: passed: makeString( false ) != static_cast<char*>(0) for: "valid string" != {null string}
Misc.tests.cpp:<line number>: passed: makeString( true ) == static_cast<char*>(0) for: {null string} == {null string}
Tricky.tests.cpp:<line number>: passed: ptr.get() == 0 for: 0 == 0
ToStringPair.tests.cpp:<line number>: passed: ::Catch::Detail::stringify( pair ) == "{ { 42, /"Arthur/" }, { /"Ford/", 24 } }" for: "{ { 42, "Arthur" }, { "Ford", 24 } }"
ToStringPair.tests.cpp:<line number>: passed: ::Catch::Detail::stringify( pair ) == "{ { 42, \"Arthur\" }, { \"Ford\", 24 } }" for: "{ { 42, "Arthur" }, { "Ford", 24 } }"
==
"{ { 42, "Arthur" }, { "Ford", 24 } }"
Tricky.tests.cpp:<line number>: passed: p == 0 for: 0 == 0
@@ -1048,18 +1196,18 @@ String.tests.cpp:<line number>: passed: s == "didn|'t" for: "didn|'t" == "didn|'
Misc.tests.cpp:<line number>: failed: false with 1 message: '3'
Message.tests.cpp:<line number>: failed: false with 2 messages: 'hi' and 'i := 7'
ToStringGeneral.tests.cpp:<line number>: passed: Catch::Detail::stringify( emptyMap ) == "{ }" for: "{ }" == "{ }"
ToStringGeneral.tests.cpp:<line number>: passed: Catch::Detail::stringify( map ) == "{ { /"one/", 1 } }" for: "{ { "one", 1 } }" == "{ { "one", 1 } }"
ToStringGeneral.tests.cpp:<line number>: passed: Catch::Detail::stringify( map ) == "{ { /"abc/", 1 }, { /"def/", 2 }, { /"ghi/", 3 } }" for: "{ { "abc", 1 }, { "def", 2 }, { "ghi", 3 } }"
ToStringGeneral.tests.cpp:<line number>: passed: Catch::Detail::stringify( map ) == "{ { \"one\", 1 } }" for: "{ { "one", 1 } }" == "{ { "one", 1 } }"
ToStringGeneral.tests.cpp:<line number>: passed: Catch::Detail::stringify( map ) == "{ { \"abc\", 1 }, { \"def\", 2 }, { \"ghi\", 3 } }" for: "{ { "abc", 1 }, { "def", 2 }, { "ghi", 3 } }"
==
"{ { "abc", 1 }, { "def", 2 }, { "ghi", 3 } }"
ToStringPair.tests.cpp:<line number>: passed: ::Catch::Detail::stringify(value) == "{ 34, /"xyzzy/" }" for: "{ 34, "xyzzy" }" == "{ 34, "xyzzy" }"
ToStringPair.tests.cpp:<line number>: passed: ::Catch::Detail::stringify( value ) == "{ 34, /"xyzzy/" }" for: "{ 34, "xyzzy" }" == "{ 34, "xyzzy" }"
ToStringPair.tests.cpp:<line number>: passed: ::Catch::Detail::stringify(value) == "{ 34, \"xyzzy\" }" for: "{ 34, "xyzzy" }" == "{ 34, "xyzzy" }"
ToStringPair.tests.cpp:<line number>: passed: ::Catch::Detail::stringify( value ) == "{ 34, \"xyzzy\" }" for: "{ 34, "xyzzy" }" == "{ 34, "xyzzy" }"
ToStringGeneral.tests.cpp:<line number>: passed: Catch::Detail::stringify( emptySet ) == "{ }" for: "{ }" == "{ }"
ToStringGeneral.tests.cpp:<line number>: passed: Catch::Detail::stringify( set ) == "{ /"one/" }" for: "{ "one" }" == "{ "one" }"
ToStringGeneral.tests.cpp:<line number>: passed: Catch::Detail::stringify( set ) == "{ /"abc/", /"def/", /"ghi/" }" for: "{ "abc", "def", "ghi" }"
ToStringGeneral.tests.cpp:<line number>: passed: Catch::Detail::stringify( set ) == "{ \"one\" }" for: "{ "one" }" == "{ "one" }"
ToStringGeneral.tests.cpp:<line number>: passed: Catch::Detail::stringify( set ) == "{ \"abc\", \"def\", \"ghi\" }" for: "{ "abc", "def", "ghi" }"
==
"{ "abc", "def", "ghi" }"
ToStringPair.tests.cpp:<line number>: passed: ::Catch::Detail::stringify( pr ) == "{ { /"green/", 55 } }" for: "{ { "green", 55 } }"
ToStringPair.tests.cpp:<line number>: passed: ::Catch::Detail::stringify( pr ) == "{ { \"green\", 55 } }" for: "{ { "green", 55 } }"
==
"{ { "green", 55 } }"
Tricky.tests.cpp:<line number>: failed: std::string( "first" ) == "second" for: "first" == "second"
@@ -1093,11 +1241,15 @@ ToStringWhich.tests.cpp:<line number>: passed: ::Catch::Detail::stringify( v ) =
ToStringWhich.tests.cpp:<line number>: passed: ::Catch::Detail::stringify( v ) == "{ operator<<( has_operator ) }" for: "{ operator<<( has_operator ) }"
==
"{ operator<<( has_operator ) }"
Generators.tests.cpp:<line number>: passed: data.str.size() == data.len for: 3 == 3
Generators.tests.cpp:<line number>: passed: data.str.size() == data.len for: 3 == 3
Generators.tests.cpp:<line number>: passed: data.str.size() == data.len for: 5 == 5
Generators.tests.cpp:<line number>: passed: data.str.size() == data.len for: 4 == 4
Exception.tests.cpp:<line number>: failed: unexpected exception with message: 'Why would you throw a std::string?'
Misc.tests.cpp:<line number>: passed: result == "/"wide load/"" for: ""wide load"" == ""wide load""
Misc.tests.cpp:<line number>: passed: result == "/"wide load/"" for: ""wide load"" == ""wide load""
Misc.tests.cpp:<line number>: passed: result == "/"wide load/"" for: ""wide load"" == ""wide load""
Misc.tests.cpp:<line number>: passed: result == "/"wide load/"" for: ""wide load"" == ""wide load""
Misc.tests.cpp:<line number>: passed: result == "\"wide load\"" for: ""wide load"" == ""wide load""
Misc.tests.cpp:<line number>: passed: result == "\"wide load\"" for: ""wide load"" == ""wide load""
Misc.tests.cpp:<line number>: passed: result == "\"wide load\"" for: ""wide load"" == ""wide load""
Misc.tests.cpp:<line number>: passed: result == "\"wide load\"" for: ""wide load"" == ""wide load""
EnumToString.tests.cpp:<line number>: passed: ::Catch::Detail::stringify(e0) == "E2/V0" for: "E2/V0" == "E2/V0"
EnumToString.tests.cpp:<line number>: passed: ::Catch::Detail::stringify(e1) == "E2/V1" for: "E2/V1" == "E2/V1"
EnumToString.tests.cpp:<line number>: passed: ::Catch::Detail::stringify(e3) == "Unknown enum value 10" for: "Unknown enum value 10"
@@ -1114,17 +1266,17 @@ ToStringTuple.tests.cpp:<line number>: passed: "{ }" == ::Catch::Detail::stringi
ToStringTuple.tests.cpp:<line number>: passed: "1.2f" == ::Catch::Detail::stringify(float(1.2)) for: "1.2f" == "1.2f"
ToStringTuple.tests.cpp:<line number>: passed: "{ 1.2f, 0 }" == ::Catch::Detail::stringify(type{1.2f,0}) for: "{ 1.2f, 0 }" == "{ 1.2f, 0 }"
ToStringTuple.tests.cpp:<line number>: passed: "{ 0 }" == ::Catch::Detail::stringify(type{0}) for: "{ 0 }" == "{ 0 }"
ToStringTuple.tests.cpp:<line number>: passed: "{ 0, 42, /"Catch me/" }" == ::Catch::Detail::stringify(value) for: "{ 0, 42, "Catch me" }"
ToStringTuple.tests.cpp:<line number>: passed: "{ 0, 42, \"Catch me\" }" == ::Catch::Detail::stringify(value) for: "{ 0, 42, "Catch me" }"
==
"{ 0, 42, "Catch me" }"
ToStringTuple.tests.cpp:<line number>: passed: "{ /"hello/", /"world/" }" == ::Catch::Detail::stringify(type{"hello","world"}) for: "{ "hello", "world" }"
ToStringTuple.tests.cpp:<line number>: passed: "{ \"hello\", \"world\" }" == ::Catch::Detail::stringify(type{"hello","world"}) for: "{ "hello", "world" }"
==
"{ "hello", "world" }"
ToStringTuple.tests.cpp:<line number>: passed: "{ { 42 }, { }, 1.2f }" == ::Catch::Detail::stringify(value) for: "{ { 42 }, { }, 1.2f }"
==
"{ { 42 }, { }, 1.2f }"
ToStringVector.tests.cpp:<line number>: passed: ::Catch::Detail::stringify(v) == "{ }" for: "{ }" == "{ }"
ToStringVector.tests.cpp:<line number>: passed: ::Catch::Detail::stringify(v) == "{ { /"hello/" }, { /"world/" } }" for: "{ { "hello" }, { "world" } }"
ToStringVector.tests.cpp:<line number>: passed: ::Catch::Detail::stringify(v) == "{ { \"hello\" }, { \"world\" } }" for: "{ { "hello" }, { "world" } }"
==
"{ { "hello" }, { "world" } }"
ToStringVector.tests.cpp:<line number>: passed: ::Catch::Detail::stringify(bools) == "{ }" for: "{ }" == "{ }"
@@ -1137,8 +1289,8 @@ ToStringVector.tests.cpp:<line number>: passed: ::Catch::Detail::stringify(vv) =
ToStringVector.tests.cpp:<line number>: passed: ::Catch::Detail::stringify(vv) == "{ 42 }" for: "{ 42 }" == "{ 42 }"
ToStringVector.tests.cpp:<line number>: passed: ::Catch::Detail::stringify(vv) == "{ 42, 250 }" for: "{ 42, 250 }" == "{ 42, 250 }"
ToStringVector.tests.cpp:<line number>: passed: ::Catch::Detail::stringify(vv) == "{ }" for: "{ }" == "{ }"
ToStringVector.tests.cpp:<line number>: passed: ::Catch::Detail::stringify(vv) == "{ /"hello/" }" for: "{ "hello" }" == "{ "hello" }"
ToStringVector.tests.cpp:<line number>: passed: ::Catch::Detail::stringify(vv) == "{ /"hello/", /"world/" }" for: "{ "hello", "world" }"
ToStringVector.tests.cpp:<line number>: passed: ::Catch::Detail::stringify(vv) == "{ \"hello\" }" for: "{ "hello" }" == "{ "hello" }"
ToStringVector.tests.cpp:<line number>: passed: ::Catch::Detail::stringify(vv) == "{ \"hello\", \"world\" }" for: "{ "hello", "world" }"
==
"{ "hello", "world" }"
Misc.tests.cpp:<line number>: passed: v.size() == 5 for: 5 == 5

View File

@@ -3,6 +3,8 @@
<exe-name> is a <version> host application.
Run with -? for options
Randomness seeded to: 1
-------------------------------------------------------------------------------
#748 - captures with unexpected exceptions
outside assertions
@@ -1096,6 +1098,6 @@ due to unexpected exception with message:
Why would you throw a std::string?
===============================================================================
test cases: 208 | 155 passed | 49 failed | 4 failed as expected
assertions: 1081 | 952 passed | 108 failed | 21 failed as expected
test cases: 215 | 162 passed | 49 failed | 4 failed as expected
assertions: 1233 | 1104 passed | 108 failed | 21 failed as expected

File diff suppressed because it is too large Load Diff

View File

@@ -3,6 +3,8 @@
<exe-name> is a <version> host application.
Run with -? for options
Randomness seeded to: 1
-------------------------------------------------------------------------------
# A test name that starts with a #
-------------------------------------------------------------------------------
@@ -135,6 +137,18 @@ Compilation.tests.cpp:<line number>
Compilation.tests.cpp:<line number>:
PASSED:
-------------------------------------------------------------------------------
#1403
-------------------------------------------------------------------------------
Compilation.tests.cpp:<line number>
...............................................................................
Compilation.tests.cpp:<line number>:
PASSED:
REQUIRE( h1 == h2 )
with expansion:
[1403 helper] == [1403 helper]
-------------------------------------------------------------------------------
#748 - captures with unexpected exceptions
outside assertions
@@ -341,6 +355,6 @@ with expansion:
!true
===============================================================================
test cases: 14 | 11 passed | 1 failed | 2 failed as expected
assertions: 38 | 31 passed | 4 failed | 3 failed as expected
test cases: 15 | 12 passed | 1 failed | 2 failed as expected
assertions: 39 | 32 passed | 4 failed | 3 failed as expected

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<testsuitesloose text artifact
>
<testsuite name="<exe-name>" errors="17" failures="106" tests="1096" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
<testsuite name="<exe-name>" errors="17" failures="106" tests="1248" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
<testcase classname="<exe-name>.global" name="# A test name that starts with a #" time="{duration}"/>
<testcase classname="<exe-name>.global" name="#1005: Comparing pointer to int and long (NULL can be either on various systems)" time="{duration}"/>
<testcase classname="<exe-name>.global" name="#1027" time="{duration}"/>
@@ -9,6 +9,7 @@
<testcase classname="<exe-name>.global" name="#1175 - Hidden Test" time="{duration}"/>
<testcase classname="<exe-name>.global" name="#1238" time="{duration}"/>
<testcase classname="<exe-name>.(Fixture_1245&lt;int, int>)" name="#1245" time="{duration}"/>
<testcase classname="<exe-name>.global" name="#1403" time="{duration}"/>
<testcase classname="<exe-name>.global" name="#748 - captures with unexpected exceptions/outside assertions" time="{duration}">
<error type="TEST_CASE">
expected exception
@@ -69,6 +70,7 @@ Condition.tests.cpp:<line number>
<testcase classname="<exe-name>.global" name="(unimplemented) static bools can be evaluated/negation" time="{duration}"/>
<testcase classname="<exe-name>.global" name="(unimplemented) static bools can be evaluated/double negation" time="{duration}"/>
<testcase classname="<exe-name>.global" name="(unimplemented) static bools can be evaluated/direct" time="{duration}"/>
<testcase classname="<exe-name>.global" name="10x10 ints" time="{duration}"/>
<testcase classname="<exe-name>.TestClass" name="A METHOD_AS_TEST_CASE based test run that fails" time="{duration}">
<failure message="&quot;hello&quot; == &quot;world&quot;" type="REQUIRE">
Class.tests.cpp:<line number>
@@ -289,6 +291,14 @@ Message.tests.cpp:<line number>
<testcase classname="<exe-name>.global" name="Floating point matchers: float/ULPs" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: float/Composed" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: float/Constructor validation" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Generators/one" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Generators/two" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Generators impl/range" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Generators impl/fixed values" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Generators impl/combined" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Generators impl/values" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Generators impl/values2" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Generators impl/type erasure" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Greater-than inequalities with different epsilons" time="{duration}"/>
<testcase classname="<exe-name>.global" name="INFO and WARN do not abort tests" time="{duration}"/>
<testcase classname="<exe-name>.global" name="INFO gets logged on failure" time="{duration}">
@@ -365,6 +375,7 @@ Exception.tests.cpp:<line number>
</error>
</testcase>
<testcase classname="<exe-name>.global" name="Objects that evaluated in boolean contexts can be checked" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Optionally static assertions" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Ordering comparison checks that should fail" time="{duration}">
<failure message="7 > 7" type="CHECK">
Condition.tests.cpp:<line number>
@@ -478,6 +489,7 @@ Message.tests.cpp:<line number>
<testcase classname="<exe-name>.global" name="Process can be configured on command line/reporter/-r/xml" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Process can be configured on command line/reporter/--reporter/junit" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Process can be configured on command line/reporter/Only one reporter is accepted" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Process can be configured on command line/reporter/must match one of the available ones" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Process can be configured on command line/debugger/-b" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Process can be configured on command line/debugger/--break" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Process can be configured on command line/abort/-a aborts after first failure" time="{duration}"/>
@@ -509,12 +521,13 @@ Matchers.tests.cpp:<line number>
Matchers.tests.cpp:<line number>
</failure>
</testcase>
<testcase classname="<exe-name>.global" name="Regression test #1" time="{duration}"/>
<testcase classname="<exe-name>.global" name="SUCCEED counts as a test pass" time="{duration}"/>
<testcase classname="<exe-name>.global" name="SUCCEED does not require an argument" time="{duration}"/>
<testcase classname="<exe-name>.Fixture" name="Scenario: BDD tests requiring Fixtures to provide commonly-accessed data or methods/Given: No operations precede me" time="{duration}"/>
<testcase classname="<exe-name>.Fixture" name="Scenario: BDD tests requiring Fixtures to provide commonly-accessed data or methods/Given: No operations precede me/When: We get the count/Then: Subsequently values are higher" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Scenario: Do that thing with the thing/Given: This stuff exists/When: I do this/Then: it should do this" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Scenario: Do that thing with the thing/Given: This stuff exists/When: I do this/Then: it should do this/And: do that" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Scenario: Do that thing with the thing/Given: This stuff exists/And given: And some assumption/When: I do this/Then: it should do this" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Scenario: Do that thing with the thing/Given: This stuff exists/And given: And some assumption/When: I do this/Then: it should do this/And: do that" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Scenario: This is a really long scenario name to see how the list command deals with wrapping/Given: A section name that is so long that it cannot fit in a single console width/When: The test headers are printed as part of the normal running of the scenario/Then: The, deliberately very long and overly verbose (you see what I did there?) section names must wrap, along with an indent" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Scenario: Vector resizing affects size and capacity/Given: an empty vector" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Scenario: Vector resizing affects size and capacity/Given: an empty vector/When: it is made larger/Then: the size and capacity go up" time="{duration}"/>
@@ -855,6 +868,7 @@ Tricky.tests.cpp:<line number>
<testcase classname="<exe-name>.global" name="stringify( vectors&lt;has_maker> )" time="{duration}"/>
<testcase classname="<exe-name>.global" name="stringify( vectors&lt;has_maker_and_operator> )" time="{duration}"/>
<testcase classname="<exe-name>.global" name="stringify( vectors&lt;has_operator> )" time="{duration}"/>
<testcase classname="<exe-name>.global" name="strlen3" time="{duration}"/>
<testcase classname="<exe-name>.global" name="thrown std::strings are translated" time="{duration}">
<error type="TEST_CASE">
Why would you throw a std::string?

File diff suppressed because it is too large Load Diff

View File

@@ -280,7 +280,6 @@ TEST_CASE( "Process can be configured on command line", "[config][command-line]"
CHECK(config.processName == "");
}
SECTION("default - no arguments") {
auto result = cli.parse({"test"});
CHECK(result);
@@ -345,8 +344,15 @@ TEST_CASE( "Process can be configured on command line", "[config][command-line]"
SECTION("Only one reporter is accepted") {
REQUIRE_FALSE(cli.parse({ "test", "-r", "xml", "-r", "junit" }));
}
}
SECTION("must match one of the available ones") {
auto result = cli.parse({"test", "--reporter", "unsupported"});
CHECK(!result);
#ifndef CATCH_CONFIG_DISABLE_MATCHERS
REQUIRE_THAT(result.errorMessage(), Contains("Unrecognized reporter"));
#endif
}
}
SECTION("debugger") {
SECTION("-b") {

View File

@@ -0,0 +1,93 @@
#include "catch.hpp"
// Tests of generartor implementation details
TEST_CASE("Generators impl", "[impl]") {
using namespace Catch::Generators;
SECTION( "range" ) {
auto gen = range(1,3);
CHECK( gen.size() == 2 );
CHECK( gen[0] == 1 );
CHECK( gen[1] == 2 );
}
SECTION( "fixed values" ) {
auto gen = values( { 3, 1, 4, 1 } );
CHECK( gen.size() == 4 );
CHECK( gen[0] == 3 );
CHECK( gen[1] == 1 );
CHECK( gen[2] == 4 );
CHECK( gen[3] == 1 );
}
SECTION( "combined" ) {
auto gen = makeGenerators( range( 1, 3 ), values( { 9, 7 } ) );
CHECK( gen.size() == 4 );
CHECK( gen[0] == 1 );
CHECK( gen[1] == 2 );
CHECK( gen[2] == 9 );
CHECK( gen[3] == 7 );
}
SECTION( "values" ) {
auto gen = makeGenerators( 3, 1 );
CHECK( gen.size() == 2 );
CHECK( gen[0] == 3 );
CHECK( gen[1] == 1 );
}
SECTION( "values2" ) {
auto gen = makeGenerators( 3, 1 );
CHECK( gen.size() == 2 );
CHECK( gen[0] == 3 );
CHECK( gen[1] == 1 );
}
SECTION( "type erasure" ) {
auto gen = makeGenerators( range( 7, 10 ), 11 );
// Make type erased version
auto dynCopy = pf::make_unique<Generators<int>>( std::move( gen ) );
std::unique_ptr<GeneratorBase const> base = std::move( dynCopy );
// Only thing we can do is ask for the size
CHECK( base->size() == 4 );
// Restore typed version
auto typed = dynamic_cast<Generators<int> const*>( base.get() );
REQUIRE( typed );
CHECK( typed->size() == 4 );
CHECK( (*typed)[0] == 7 );
CHECK( (*typed)[3] == 11 );
}
}
TEST_CASE("Generators impl - random", "[approvals]") {
using namespace Catch::Generators;
SECTION( "random range" ) {
auto gen = random( 3, 9 );
CHECK( gen.size() == 6 );
for( size_t i = 0; i < 6; ++i ) {
CHECK( gen[i] >= 3 );
CHECK( gen[i] <= 8 );
if( i > 0 )
CHECK( gen[i] != gen[i-1] );
}
}
SECTION( "random selection" ) {
auto gen = random<int>( 10 );
CHECK( gen.size() == 10 );
for( size_t i = 0; i < 10; ++i ) {
if( i > 0 )
CHECK( gen[i] != gen[i-1] );
}
}
}

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