Compare commits

..

44 Commits

Author SHA1 Message Date
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
81 changed files with 5578 additions and 572 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
@@ -242,7 +242,7 @@ matrix:
- 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
install:
- DEPS_DIR="${TRAVIS_BUILD_DIR}/deps"
@@ -263,7 +263,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} -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.0)
# 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/4wRGoJ1WzLjRM7HZ)
[![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.0/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.0"
description = "A modern, C++-native, header-only, framework for unit-tests, TDD and BDD"
author = "philsquared"
generators = "cmake"

View File

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

View File

@@ -19,8 +19,8 @@ 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*.
@@ -34,16 +34,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 +57,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
@@ -200,6 +200,40 @@ By default, Catch does not stringify some types from the standard library. This
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

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

View File

@@ -45,7 +45,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 +94,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,5 +1,34 @@
<a id="top"></a>
# 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

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

@@ -10,8 +10,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;
}
```
@@ -24,10 +24,10 @@ If you don't want to provide an ```operator <<``` overload, or you want to conve
```
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 );
}
};
}
@@ -56,7 +56,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

@@ -85,6 +85,7 @@ foreach( name ${TARGETS_ALL} )
target_include_directories( ${name} PRIVATE ${HEADER_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" )

View File

@@ -10,7 +10,7 @@
#define TWOBLUECUBES_CATCH_HPP_INCLUDED
#define CATCH_VERSION_MAJOR 2
#define CATCH_VERSION_MINOR 3
#define CATCH_VERSION_MINOR 4
#define CATCH_VERSION_PATCH 0
#ifdef __clang__
@@ -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__ )
@@ -147,11 +148,12 @@
// "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 +192,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__ )
@@ -211,11 +213,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,6 +279,7 @@ 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 )
@@ -340,6 +344,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

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

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

@@ -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
@@ -131,7 +132,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
@@ -179,6 +185,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 +202,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

@@ -13,16 +13,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

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

@@ -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)
@@ -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 );
@@ -251,11 +254,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 +276,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

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

@@ -37,7 +37,7 @@ namespace Catch {
}
Version const& libraryVersion() {
static Version version( 2, 3, 0, "", 0 );
static Version version( 2, 4, 0, "", 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

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

@@ -15,7 +15,7 @@ if "%CONFIGURATION%"=="Debug" (
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
cmake -H. -BBuild -A%PLATFORM% -DUSE_WMAIN=%wmain% -DCATCH_BUILD_EXAMPLES=ON -DCATCH_BUILD_EXTRA_TESTS=ON
) else (
@REM # This is just a plain debug build
cmake -H. -BBuild -A%PLATFORM% -DUSE_WMAIN=%wmain%

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,6 +31,7 @@ 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
@@ -85,6 +99,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 +132,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 +173,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 +202,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
@@ -317,7 +337,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,76 @@
// X11-DisableStringification.cpp
// Test that Catch's prefixed macros compile and run properly.
#define CATCH_CONFIG_MAIN
#include <catch2/catch.hpp>
#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_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

@@ -56,6 +56,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
@@ -297,6 +397,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 ))
@@ -1093,6 +1235,10 @@ 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""

View File

@@ -1096,6 +1096,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: 212 | 159 passed | 49 failed | 4 failed as expected
assertions: 1227 | 1098 passed | 108 failed | 21 failed as expected

File diff suppressed because it is too large Load Diff

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="1242" 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}"/>
@@ -69,6 +69,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 +290,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}">
@@ -513,8 +522,8 @@ Matchers.tests.cpp:<line number>
<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 +864,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

@@ -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] );
}
}
}

View File

@@ -38,11 +38,14 @@ namespace { namespace BDDTests {
SCENARIO("Do that thing with the thing", "[Tags]") {
GIVEN("This stuff exists") {
// make stuff exist
WHEN("I do this") {
// do this
THEN("it should do this") {
REQUIRE(itDoesThis());
AND_THEN("do that")REQUIRE(itDoesThat());
AND_GIVEN("And some assumption") {
// Validate assumption
WHEN("I do this") {
// do this
THEN("it should do this") {
REQUIRE(itDoesThis());
AND_THEN("do that")REQUIRE(itDoesThat());
}
}
}
}

View File

@@ -18,6 +18,7 @@
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wweak-vtables"
#pragma clang diagnostic ignored "-Wmissing-noreturn"
#pragma clang diagnostic ignored "-Wunreachable-code"
#endif
namespace { namespace ExceptionTests {

View File

@@ -0,0 +1,134 @@
#include "catch.hpp"
// Examples of usage of Generators
// This test doesn't do much - it just shows how you can have several generators, of different
// types (ie `i` and `j` are different types), can be sequenced using `,` and
// can be expressed as named generators (like range) or as individual values.
// Generators can be mixed with SECTIONs.
// At time of writing the generated values are not automatically reported as part of the test
// name or associated values - so we explicitly CAPTURE then (run this with `-s` to see them).
// We could also incorporate them into the section names using DYNAMIC_SECTION. See the BDD
// example later for more information.
TEST_CASE("Generators") {
auto i = GENERATE( as<std::string>(), "a", "b", "c" );
SECTION( "one" ) {
auto j = GENERATE( range( 8, 11 ), 2 );
CAPTURE( i, j );
SUCCEED();
}
SECTION( "two" ) {
auto j = GENERATE( 3.141, 1.379 );
CAPTURE( i, j );
SUCCEED();
}
}
// This one generates the cross-product of two ranges.
// It's mostly here to demonstrate the performance which, at time of writing,
// leaves a lot to be desired.
TEST_CASE( "100x100 ints", "[.][approvals]" ) {
auto x = GENERATE( range( 0,100 ) );
auto y = GENERATE( range( 200,300 ) );
CHECK( x < y );
}
// smaller version
TEST_CASE( "10x10 ints" ) {
auto x = GENERATE( range( 1,11 ) );
auto y = GENERATE( range( 101, 111 ) );
CHECK( x < y );
}
// Some of the following tests use structured bindings for convenience and so are
// conditionally compiled using the de-facto (and soon to be formally) standard
// feature macros
#ifdef __cpp_structured_bindings
// One way to do pairs of values (actual/ expected?)
// For a simple case like this I'd recommend writing out a series of REQUIREs
// but it demonstrates a possible usage.
// Spelling out the pair like this is a bit verbose, so read on for better examples
// - the use of structured bindings here is an optional convenience
TEST_CASE( "strlen", "[.][approvals]" ) {
auto [test_input, expected] = GENERATE( values<std::pair<std::string_view, size_t>>({
{"one", 3},
{"two", 3},
{"three", 5},
{"four", 4}
}));
REQUIRE( test_input.size() == expected );
}
// A nicer way to do pairs (or more) of values - using the table generator.
// Note, you must specify the types up-front.
TEST_CASE( "strlen2", "[.][approvals]" ) {
auto [test_input, expected] = GENERATE( table<std::string, size_t>({
{"one", 3},
{"two", 3},
{"three", 5},
{"four", 4}
}));
REQUIRE( test_input.size() == expected );
}
#endif
// An alternate way of doing data tables without structure bindings
// - I'd prefer to have the Data class within the test case but gcc 4.x doesn't seem to like it
struct Data { std::string str; size_t len; };
TEST_CASE( "strlen3" ) {
auto data = GENERATE( values<Data>({
{"one", 3},
{"two", 3},
{"three", 5},
{"four", 4}
}));
REQUIRE( data.str.size() == data.len );
}
// A nod towards property-based testing - generate a random selection of numbers
// in a range and assert on global properties those numbers.
static auto square( int i ) -> int { return i*i; }
TEST_CASE( "Random numbers in a range", "[.][approvals]" ) {
auto x = GENERATE( random( -10000, 10000 ) );
CAPTURE( x );
REQUIRE( square(x) >= 0 );
}
#ifdef __cpp_structured_bindings
// Based on example from https://docs.cucumber.io/gherkin/reference/#scenario-outline
// (thanks to https://github.com/catchorg/Catch2/issues/850#issuecomment-399504851)
// Note that GIVEN, WHEN, and THEN now forward onto DYNAMIC_SECTION instead of SECTION.
// DYNAMIC_SECTION takes its name as a stringstream-style expression, so can be formatted using
// variables in scope - such as the generated variables here. This reads quite nicely in the
// test name output (the full scenario description).
static auto eatCucumbers( int start, int eat ) -> int { return start-eat; }
SCENARIO("Eating cucumbers", "[.][approvals]") {
auto [start, eat, left] = GENERATE( table<int,int,int> ({
{ 12, 5, 7 },
{ 20, 5, 15 }
}));
GIVEN( "there are " << start << " cucumbers" )
WHEN( "I eat " << eat << " cucumbers" )
THEN( "I should have " << left << " cucumbers" ) {
REQUIRE( eatCucumbers( start, eat ) == left );
}
}
#endif

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env python
from __future__ import print_function
from __future__ import print_function
import io
import os
@@ -13,8 +13,8 @@ import scriptCommon
from scriptCommon import catchPath
if os.name == 'nt':
# Enable console colours on windows
os.system('')
# Enable console colours on windows
os.system('')
rootPath = os.path.join(catchPath, 'projects/SelfTest/Baselines')
@@ -98,7 +98,6 @@ def filterLine(line, isCompact):
# go from \ in windows paths to /
line = line.replace('\\', '/')
# strip source line numbers
m = filelocParser.match(line)
if m:
@@ -112,7 +111,7 @@ def filterLine(line, isCompact):
if isCompact:
line = line.replace(': FAILED', ': failed')
line = line.replace(': PASSED', ': passed')
# strip Catch version number
line = versionParser.sub("<version>", line)
@@ -180,19 +179,19 @@ print("Running approvals against executable:")
print(" " + cmdPath)
### Keep default reporters here
# ## Keep default reporters here ##
# Standard console reporter
approve("console.std", ["~[!nonportable]~[!benchmark]~[approvals]", "--order", "lex"])
approve("console.std", ["~[!nonportable]~[!benchmark]~[approvals]", "--order", "lex", "--rng-seed", "0"])
# console reporter, include passes, warn about No Assertions
approve("console.sw", ["~[!nonportable]~[!benchmark]~[approvals]", "-s", "-w", "NoAssertions", "--order", "lex"])
approve("console.sw", ["~[!nonportable]~[!benchmark]~[approvals]", "-s", "-w", "NoAssertions", "--order", "lex", "--rng-seed", "0"])
# console reporter, include passes, warn about No Assertions, limit failures to first 4
approve("console.swa4", ["~[!nonportable]~[!benchmark]~[approvals]", "-s", "-w", "NoAssertions", "-x", "4", "--order", "lex"])
approve("console.swa4", ["~[!nonportable]~[!benchmark]~[approvals]", "-s", "-w", "NoAssertions", "-x", "4", "--order", "lex", "--rng-seed", "0"])
# junit reporter, include passes, warn about No Assertions
approve("junit.sw", ["~[!nonportable]~[!benchmark]~[approvals]", "-s", "-w", "NoAssertions", "-r", "junit", "--order", "lex"])
approve("junit.sw", ["~[!nonportable]~[!benchmark]~[approvals]", "-s", "-w", "NoAssertions", "-r", "junit", "--order", "lex", "--rng-seed", "0"])
# xml reporter, include passes, warn about No Assertions
approve("xml.sw", ["~[!nonportable]~[!benchmark]~[approvals]", "-s", "-w", "NoAssertions", "-r", "xml", "--order", "lex"])
approve("xml.sw", ["~[!nonportable]~[!benchmark]~[approvals]", "-s", "-w", "NoAssertions", "-r", "xml", "--order", "lex", "--rng-seed", "0"])
# compact reporter, include passes, warn about No Assertions
approve('compact.sw', ['~[!nonportable]~[!benchmark]~[approvals]', '-s', '-w', 'NoAssertions', '-r', 'compact', '--order', 'lex'])
approve('compact.sw', ['~[!nonportable]~[!benchmark]~[approvals]', '-s', '-w', 'NoAssertions', '-r', 'compact', '--order', 'lex', "--rng-seed", "0"])
if overallResult != 0:
print("If these differences are expected, run approve.py to approve new baselines.")

View File

@@ -46,7 +46,7 @@ def generate(v):
outDir = os.path.dirname(outputPath)
if not os.path.exists(outDir):
os.makedirs(outDir)
out = io.open( outputPath, 'w', newline='\n')
out = io.open( outputPath, 'w', newline='\n', encoding='utf-8')
def write( line ):
if globals['includeImpl'] or globals['implIfDefs'] == -1:

File diff suppressed because it is too large Load Diff

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

@@ -10,7 +10,7 @@ class CatchConanTest(ConanFile):
settings = "os", "compiler", "arch", "build_type"
username = getenv("CONAN_USERNAME", "philsquared")
channel = getenv("CONAN_CHANNEL", "testing")
requires = "Catch/2.3.0@%s/%s" % (username, channel)
requires = "Catch/2.4.0@%s/%s" % (username, channel)
def build(self):
cmake = CMake(self)