File catch_amalgamated.hpp

Parent directory (include)

Definition (include/catch_amalgamated.hpp)

Detailed Description

This is a convenience header for Catch2. It includes all of Catch2 headers.

Generally the Catch2 users should use specific includes they need, but this header can be used instead for ease-of-experimentation, or just plain convenience, at the cost of (significantly) increased compilation times.

When a new header is added to either the top level folder, or to the corresponding internal subfolder, it should be added here. Headers added to the various subparts (e.g. matchers, generators, etc…), should go their respective catch-all headers.

This is a convenience header for Catch2’s benchmarking. It includes all of Catch2 headers related to benchmarking.

Generally the Catch2 users should use specific includes they need, but this header can be used instead for ease-of-experimentation, or just plain convenience, at the cost of (significantly) increased compilation times.

When a new header is added to either the benchmark folder, or to the corresponding internal (detail) subfolder, it should be added here.

Wrapper for the CONFIG configuration option

When generating internal unique names, there are two options. Either we mix in the current line number, or mix in an incrementing number. We prefer the latter, using __COUNTER__, but users might want to use the former.

Wrapper for the WCHAR configuration option

We want to support platforms that do not provide wchar_t, so we sometimes have to disable providing wchar_t overloads through Catch2, e.g. the StringMaker specialization for std::wstring.

Wrapper for the CATCH_CONFIG_PREFIX_MESSAGES configuration option

CATCH_CONFIG_PREFIX_ALL can be used to avoid clashes with other macros by prepending CATCH_. This may not be desirable if the only clashes are with logger macros such as INFO and WARN. In this cases CATCH_CONFIG_PREFIX_MESSAGES can be used to only prefix a small subset of relevant macros.

Why does decomposing look the way it does:

Conceptually, decomposing is simple. We change REQUIRE( a == b ) into Decomposer{} <= a == b, so that Decomposer{} <= a is evaluated first, and our custom operator is used for a == b, because a is transformed into ExprLhs<T&> and then into BinaryExpr<T&, U&>.

In practice, decomposing ends up a mess, because we have to support various fun things.

  1. Types that are only comparable with literal 0, and they do this by comparing against a magic type with pointer constructor and deleted other constructors. Example: REQUIRE((a <=> b) == 0) in libstdc++

  2. Types that are only comparable with literal 0, and they do this by comparing against a magic type with consteval integer constructor. Example: REQUIRE((a <=> b) == 0) in current MSVC STL.

  3. Types that have no linkage, and so we cannot form a reference to them. Example: some implementations of traits.

  4. Starting with C++20, when the compiler sees a == b, it also uses b == a when constructing the overload set. For us this means that when the compiler handles ExprLhs<T> == b, it also tries to resolve the overload set for b == ExprLhs<T>.

To accomodate these use cases, decomposer ended up rather complex.

  1. These types are handled by adding SFINAE overloads to our comparison operators, checking whether T == U are comparable with the given operator, and if not, whether T (or U) are comparable with literal 0. If yes, the overload compares T (or U) with 0 literal inline in the definition.

Note that for extra correctness, we check that the other type is either an int (literal 0 is captured as int by templates), or a long (some platforms use 0L for NULL and we want to support that for pointer comparisons).

  1. For these types, is_foo_comparable<T, int> is true, but letting them fall into the overload that actually does T == int causes compilation error. Handling them requires that the decomposition is constexpr, so that P2564R3 applies and the consteval from their accompanying magic type is propagated through the constexpr call stack.

However this is not enough to handle these types automatically, because our default is to capture types by reference, to avoid runtime copies. While these references cannot become dangling, they outlive the constexpr context and thus the default capture path cannot be actually constexpr.

The solution is to capture these types by value, by explicitly specializing Catch::capture_by_value for them. Catch2 provides specialization for ``std::foo_ordering``s, but users can specialize the trait for their own types as well.

  1. If a type has no linkage, we also cannot capture it by reference. The solution is once again to capture them by value. We handle the common cases by using std::is_arithmetic as the default for Catch::capture_by_value, but that is only a some-effort heuristic. But as with 2), users can specialize capture_by_value for their own types as needed.

  2. To support C++20 and make the SFINAE on our decomposing operators work, the SFINAE has to happen in return type, rather than in a template type. This is due to our use of logical type traits (conjunction/disjunction/negation), that we use to workaround an issue in older (9-) versions of GCC. I still blame C++20 for this, because without the comparison order switching, the logical traits could still be used in template type.

There are also other side concerns, e.g. supporting both REQUIRE(a) and REQUIRE(a == b), or making REQUIRE_THAT(a, IsEqual(b)) slot nicely into the same expression handling logic, but these are rather straightforward and add only a bit of complexity (e.g. common base class for decomposed expressions).

Wrapper for the STATIC_ANALYSIS_SUPPORT configuration option

Some of Catch2’s macros can be defined differently to work better with static analysis tools, like clang-tidy or coverity. Currently the main use case is to show that SECTION``s are executed exclusively, and not all in one run of a ``TEST_CASE.

This is a convenience header for Catch2’s Generator support. It includes all of Catch2 headers related to generators.

Generally the Catch2 users should use specific includes they need, but this header can be used instead for ease-of-experimentation, or just plain convenience, at the cost of (significantly) increased compilation times.

When a new header is added to either the generators folder, or to the corresponding internal subfolder, it should be added here.

Includes

  • algorithm

  • cassert

  • chrono

  • climits

  • cmath

  • cstddef

  • cstdint

  • cstring

  • ctime

  • exception

  • iosfwd

  • map

  • memory

  • ostream

  • ratio

  • sstream

  • string

  • tuple

  • type_traits

  • vector

Included By

Namespaces

Classes

Enums

Functions

Defines

Typedefs

Variables