// Copyright Catch2 Authors // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE.txt or copy at // https://www.boost.org/LICENSE_1_0.txt) // SPDX-License-Identifier: BSL-1.0 // Catch v3.3.2 // Generated: 2023-02-26 10:28:46.785908 // ---------------------------------------------------------- // This file is an amalgamation of multiple different files. // You probably shouldn't edit it directly. // ---------------------------------------------------------- #ifndef CATCH_AMALGAMATED_HPP_INCLUDED #define CATCH_AMALGAMATED_HPP_INCLUDED /** \file * 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. */ #ifndef CATCH_ALL_HPP_INCLUDED #define CATCH_ALL_HPP_INCLUDED /** \file * 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. */ #ifndef CATCH_BENCHMARK_ALL_HPP_INCLUDED #define CATCH_BENCHMARK_ALL_HPP_INCLUDED // Adapted from donated nonius code. #ifndef CATCH_BENCHMARK_HPP_INCLUDED #define CATCH_BENCHMARK_HPP_INCLUDED #ifndef CATCH_INTERFACES_CONFIG_HPP_INCLUDED #define CATCH_INTERFACES_CONFIG_HPP_INCLUDED #ifndef CATCH_NONCOPYABLE_HPP_INCLUDED #define CATCH_NONCOPYABLE_HPP_INCLUDED namespace Catch { namespace Detail { //! Deriving classes become noncopyable and nonmovable class NonCopyable { NonCopyable( NonCopyable const& ) = delete; NonCopyable( NonCopyable&& ) = delete; NonCopyable& operator=( NonCopyable const& ) = delete; NonCopyable& operator=( NonCopyable&& ) = delete; protected: NonCopyable() noexcept = default; }; } // namespace Detail } // namespace Catch #endif // CATCH_NONCOPYABLE_HPP_INCLUDED #ifndef CATCH_STRINGREF_HPP_INCLUDED #define CATCH_STRINGREF_HPP_INCLUDED #include #include #include #include #include namespace Catch { /// A non-owning string class (similar to the forthcoming std::string_view) /// Note that, because a StringRef may be a substring of another string, /// it may not be null terminated. class StringRef { public: using size_type = std::size_t; using const_iterator = const char*; private: static constexpr char const* const s_empty = ""; char const* m_start = s_empty; size_type m_size = 0; public: // construction constexpr StringRef() noexcept = default; StringRef( char const* rawChars ) noexcept; constexpr StringRef( char const* rawChars, size_type size ) noexcept : m_start( rawChars ), m_size( size ) {} StringRef( std::string const& stdString ) noexcept : m_start( stdString.c_str() ), m_size( stdString.size() ) {} explicit operator std::string() const { return std::string(m_start, m_size); } public: // operators auto operator == ( StringRef other ) const noexcept -> bool { return m_size == other.m_size && (std::memcmp( m_start, other.m_start, m_size ) == 0); } auto operator != (StringRef other) const noexcept -> bool { return !(*this == other); } constexpr auto operator[] ( size_type index ) const noexcept -> char { assert(index < m_size); return m_start[index]; } bool operator<(StringRef rhs) const noexcept; public: // named queries constexpr auto empty() const noexcept -> bool { return m_size == 0; } constexpr auto size() const noexcept -> size_type { return m_size; } // Returns a substring of [start, start + length). // If start + length > size(), then the substring is [start, start + size()). // If start > size(), then the substring is empty. constexpr StringRef substr(size_type start, size_type length) const noexcept { if (start < m_size) { const auto shortened_size = m_size - start; return StringRef(m_start + start, (shortened_size < length) ? shortened_size : length); } else { return StringRef(); } } // Returns the current start pointer. May not be null-terminated. constexpr char const* data() const noexcept { return m_start; } constexpr const_iterator begin() const { return m_start; } constexpr const_iterator end() const { return m_start + m_size; } friend std::string& operator += (std::string& lhs, StringRef sr); friend std::ostream& operator << (std::ostream& os, StringRef sr); friend std::string operator+(StringRef lhs, StringRef rhs); /** * Provides a three-way comparison with rhs * * Returns negative number if lhs < rhs, 0 if lhs == rhs, and a positive * number if lhs > rhs */ int compare( StringRef rhs ) const; }; constexpr auto operator ""_sr( char const* rawChars, std::size_t size ) noexcept -> StringRef { return StringRef( rawChars, size ); } } // namespace Catch constexpr auto operator ""_catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef { return Catch::StringRef( rawChars, size ); } #endif // CATCH_STRINGREF_HPP_INCLUDED #include #include #include #include namespace Catch { enum class Verbosity { Quiet = 0, Normal, High }; struct WarnAbout { enum What { Nothing = 0x00, //! A test case or leaf section did not run any assertions NoAssertions = 0x01, //! A command line test spec matched no test cases UnmatchedTestSpec = 0x02, }; }; enum class ShowDurations { DefaultForReporter, Always, Never }; enum class TestRunOrder { Declared, LexicographicallySorted, Randomized }; enum class ColourMode : std::uint8_t { //! Let Catch2 pick implementation based on platform detection PlatformDefault, //! Use ANSI colour code escapes ANSI, //! Use Win32 console colour API Win32, //! Don't use any colour None }; struct WaitForKeypress { enum When { Never, BeforeStart = 1, BeforeExit = 2, BeforeStartAndExit = BeforeStart | BeforeExit }; }; class TestSpec; class IStream; class IConfig : public Detail::NonCopyable { public: virtual ~IConfig(); virtual bool allowThrows() const = 0; virtual StringRef name() const = 0; virtual bool includeSuccessfulResults() const = 0; virtual bool shouldDebugBreak() const = 0; virtual bool warnAboutMissingAssertions() const = 0; virtual bool warnAboutUnmatchedTestSpecs() const = 0; virtual bool zeroTestsCountAsSuccess() const = 0; virtual int abortAfter() const = 0; virtual bool showInvisibles() const = 0; virtual ShowDurations showDurations() const = 0; virtual double minDuration() const = 0; virtual TestSpec const& testSpec() const = 0; virtual bool hasTestFilters() const = 0; virtual std::vector const& getTestsOrTags() const = 0; virtual TestRunOrder runOrder() const = 0; virtual uint32_t rngSeed() const = 0; virtual unsigned int shardCount() const = 0; virtual unsigned int shardIndex() const = 0; virtual ColourMode defaultColourMode() const = 0; virtual std::vector const& getSectionsToRun() const = 0; virtual Verbosity verbosity() const = 0; virtual bool skipBenchmarks() const = 0; virtual bool benchmarkNoAnalysis() const = 0; virtual unsigned int benchmarkSamples() const = 0; virtual double benchmarkConfidenceInterval() const = 0; virtual unsigned int benchmarkResamples() const = 0; virtual std::chrono::milliseconds benchmarkWarmupTime() const = 0; }; } #endif // CATCH_INTERFACES_CONFIG_HPP_INCLUDED #ifndef CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED #define CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED // Detect a number of compiler features - by compiler // The following features are defined: // // 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 // **************** // In general each macro has a _NO_ form // (e.g. CATCH_CONFIG_NO_POSIX_SIGNALS) which disables the feature. // Many features, at point of detection, define an _INTERNAL_ macro, so they // can be combined, en-mass, with the _NO_ forms later. #ifndef CATCH_PLATFORM_HPP_INCLUDED #define CATCH_PLATFORM_HPP_INCLUDED // See e.g.: // https://opensource.apple.com/source/CarbonHeaders/CarbonHeaders-18.1/TargetConditionals.h.auto.html #ifdef __APPLE__ # include # if (defined(TARGET_OS_OSX) && TARGET_OS_OSX == 1) || \ (defined(TARGET_OS_MAC) && TARGET_OS_MAC == 1) # define CATCH_PLATFORM_MAC # elif (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE == 1) # define CATCH_PLATFORM_IPHONE # endif #elif defined(linux) || defined(__linux) || defined(__linux__) # define CATCH_PLATFORM_LINUX #elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || defined(__MINGW32__) # define CATCH_PLATFORM_WINDOWS # if defined( WINAPI_FAMILY ) && ( WINAPI_FAMILY == WINAPI_FAMILY_APP ) # define CATCH_PLATFORM_WINDOWS_UWP # endif #elif defined(__ORBIS__) || defined(__PROSPERO__) # define CATCH_PLATFORM_PLAYSTATION #endif #endif // CATCH_PLATFORM_HPP_INCLUDED #ifdef __cplusplus # if (__cplusplus >= 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L) # define CATCH_CPP14_OR_GREATER # endif # if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) # define CATCH_CPP17_OR_GREATER # endif #endif // Only GCC compiler should be used in this block, so other compilers trying to // mask themselves as GCC should be ignored. #if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && !defined(__CUDACC__) && !defined(__LCC__) && !defined(__NVCOMPILER) # define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" ) # define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" ) // This only works on GCC 9+. so we have to also add a global suppression of Wparentheses // for older versions of GCC. # define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ _Pragma( "GCC diagnostic ignored \"-Wparentheses\"" ) # define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ _Pragma( "GCC diagnostic ignored \"-Wunused-variable\"" ) # define CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS \ _Pragma( "GCC diagnostic ignored \"-Wuseless-cast\"" ) # define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) #endif #if defined(__NVCOMPILER) # define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "diag push" ) # define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "diag pop" ) # define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS _Pragma( "diag_suppress declared_but_not_referenced" ) #endif #if defined(__CUDACC__) && !defined(__clang__) # ifdef __NVCC_DIAG_PRAGMA_SUPPORT__ // New pragmas introduced in CUDA 11.5+ # define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "nv_diagnostic push" ) # define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "nv_diagnostic pop" ) # define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS _Pragma( "nv_diag_suppress 177" ) # else # define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS _Pragma( "diag_suppress 177" ) # endif #endif // clang-cl defines _MSC_VER as well as __clang__, which could cause the // start/stop internal suppression macros to be double defined. #if defined(__clang__) && !defined(_MSC_VER) # define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic push" ) # define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic pop" ) #endif // __clang__ && !_MSC_VER #if defined(__clang__) // As of this writing, IBM XL's implementation of __builtin_constant_p has a bug // which results in calls to destructors being emitted for each temporary, // without a matching initialization. In practice, this can result in something // like `std::string::~string` being called on an uninitialized value. // // For example, this code will likely segfault under IBM XL: // ``` // REQUIRE(std::string("12") + "34" == "1234") // ``` // // Similarly, NVHPC's implementation of `__builtin_constant_p` has a bug which // results in calls to the immediately evaluated lambda expressions to be // reported as unevaluated lambdas. // https://developer.nvidia.com/nvidia_bug/3321845. // // Therefore, `CATCH_INTERNAL_IGNORE_BUT_WARN` is not implemented. # if !defined(__ibmxl__) && !defined(__CUDACC__) && !defined( __NVCOMPILER ) # define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) /* NOLINT(cppcoreguidelines-pro-type-vararg, hicpp-vararg) */ # endif # define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \ _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"") # define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) # define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" ) # define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \ _Pragma( "clang diagnostic ignored \"-Wgnu-zero-variadic-macro-arguments\"" ) # define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \ _Pragma( "clang diagnostic ignored \"-Wunused-template\"" ) # define CATCH_INTERNAL_SUPPRESS_COMMA_WARNINGS \ _Pragma( "clang diagnostic ignored \"-Wcomma\"" ) #endif // __clang__ //////////////////////////////////////////////////////////////////////////////// // We know some environments not to support full POSIX signals #if defined( CATCH_PLATFORM_WINDOWS ) || \ defined( CATCH_PLATFORM_PLAYSTATION ) || \ defined( __CYGWIN__ ) || \ defined( __QNX__ ) || \ defined( __EMSCRIPTEN__ ) || \ defined( __DJGPP__ ) || \ defined( __OS400__ ) # define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS #else # define CATCH_INTERNAL_CONFIG_POSIX_SIGNALS #endif //////////////////////////////////////////////////////////////////////////////// // Assume that some platforms do not support getenv. #if defined(CATCH_PLATFORM_WINDOWS_UWP) || defined(CATCH_PLATFORM_PLAYSTATION) # define CATCH_INTERNAL_CONFIG_NO_GETENV #else # define CATCH_INTERNAL_CONFIG_GETENV #endif //////////////////////////////////////////////////////////////////////////////// // Android somehow still does not support std::to_string #if defined(__ANDROID__) # define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING #endif //////////////////////////////////////////////////////////////////////////////// // Not all Windows environments support SEH properly #if defined(__MINGW32__) # define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH #endif //////////////////////////////////////////////////////////////////////////////// // PS4 #if defined(__ORBIS__) # define CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE #endif //////////////////////////////////////////////////////////////////////////////// // Cygwin #ifdef __CYGWIN__ // Required for some versions of Cygwin to declare gettimeofday // see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin # define _BSD_SOURCE // some versions of cygwin (most) do not support std::to_string. Use the libstd check. // https://gcc.gnu.org/onlinedocs/gcc-4.8.2/libstdc++/api/a01053_source.html line 2812-2813 # if !((__cplusplus >= 201103L) && defined(_GLIBCXX_USE_C99) \ && !defined(_GLIBCXX_HAVE_BROKEN_VSWPRINTF)) # define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING # endif #endif // __CYGWIN__ //////////////////////////////////////////////////////////////////////////////// // Visual C++ #if defined(_MSC_VER) // We want to defer to nvcc-specific warning suppression if we are compiled // with nvcc masquerading for MSVC. # if !defined( __CUDACC__ ) # define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ __pragma( warning( push ) ) # define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ __pragma( warning( pop ) ) # endif // Universal Windows platform does not support SEH // Or console colours (or console at all...) # if defined(CATCH_PLATFORM_WINDOWS_UWP) # define CATCH_INTERNAL_CONFIG_NO_COLOUR_WIN32 # else # define CATCH_INTERNAL_CONFIG_WINDOWS_SEH # endif // MSVC traditional preprocessor needs some workaround for __VA_ARGS__ // _MSVC_TRADITIONAL == 0 means new conformant preprocessor // _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor # if !defined(__clang__) // Handle Clang masquerading for msvc # if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL) # define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR # endif // MSVC_TRADITIONAL # endif // __clang__ #endif // _MSC_VER #if defined(_REENTRANT) || defined(_MSC_VER) // Enable async processing, as -pthread is specified or no additional linking is required # define CATCH_INTERNAL_CONFIG_USE_ASYNC #endif // _MSC_VER //////////////////////////////////////////////////////////////////////////////// // 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 //////////////////////////////////////////////////////////////////////////////// // Embarcadero C++Build #if defined(__BORLANDC__) #define CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN #endif //////////////////////////////////////////////////////////////////////////////// // RTX is a special version of Windows that is real time. // This means that it is detected as Windows, but does not provide // the same set of capabilities as real Windows does. #if defined(UNDER_RTSS) || defined(RTX64_BUILD) #define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH #define CATCH_INTERNAL_CONFIG_NO_ASYNC #define CATCH_INTERNAL_CONFIG_NO_COLOUR_WIN32 #endif #if !defined(_GLIBCXX_USE_C99_MATH_TR1) #define CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER #endif // Various stdlib support checks that require __has_include #if defined(__has_include) // Check if string_view is available and usable #if __has_include() && defined(CATCH_CPP17_OR_GREATER) # define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW #endif // Check if optional is available and usable # if __has_include() && defined(CATCH_CPP17_OR_GREATER) # define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) // Check if byte is available and usable # if __has_include() && defined(CATCH_CPP17_OR_GREATER) # include # if defined(__cpp_lib_byte) && (__cpp_lib_byte > 0) # define CATCH_INTERNAL_CONFIG_CPP17_BYTE # endif # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) // Check if variant is available and usable # if __has_include() && defined(CATCH_CPP17_OR_GREATER) # if defined(__clang__) && (__clang_major__ < 8) // work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852 // fix should be in clang 8, workaround in libstdc++ 8.2 # include # if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) # define CATCH_CONFIG_NO_CPP17_VARIANT # else # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT # endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) # else # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT # endif // defined(__clang__) && (__clang_major__ < 8) # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) #endif // defined(__has_include) #if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) && !defined(CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH) # define CATCH_CONFIG_WINDOWS_SEH #endif // This is set by default, because we assume that unix compilers are posix-signal-compatible by default. #if defined(CATCH_INTERNAL_CONFIG_POSIX_SIGNALS) && !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS) # define CATCH_CONFIG_POSIX_SIGNALS #endif #if defined(CATCH_INTERNAL_CONFIG_GETENV) && !defined(CATCH_INTERNAL_CONFIG_NO_GETENV) && !defined(CATCH_CONFIG_NO_GETENV) && !defined(CATCH_CONFIG_GETENV) # define CATCH_CONFIG_GETENV #endif #if !defined(CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_CPP11_TO_STRING) # define CATCH_CONFIG_CPP11_TO_STRING #endif #if defined(CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_NO_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_CPP17_OPTIONAL) # define CATCH_CONFIG_CPP17_OPTIONAL #endif #if defined(CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_NO_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_CPP17_STRING_VIEW) # define CATCH_CONFIG_CPP17_STRING_VIEW #endif #if defined(CATCH_INTERNAL_CONFIG_CPP17_VARIANT) && !defined(CATCH_CONFIG_NO_CPP17_VARIANT) && !defined(CATCH_CONFIG_CPP17_VARIANT) # define CATCH_CONFIG_CPP17_VARIANT #endif #if defined(CATCH_INTERNAL_CONFIG_CPP17_BYTE) && !defined(CATCH_CONFIG_NO_CPP17_BYTE) && !defined(CATCH_CONFIG_CPP17_BYTE) # define CATCH_CONFIG_CPP17_BYTE #endif #if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) # define CATCH_INTERNAL_CONFIG_NEW_CAPTURE #endif #if defined(CATCH_INTERNAL_CONFIG_NEW_CAPTURE) && !defined(CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NEW_CAPTURE) # define CATCH_CONFIG_NEW_CAPTURE #endif #if !defined( CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED ) && \ !defined( CATCH_CONFIG_DISABLE_EXCEPTIONS ) && \ !defined( CATCH_CONFIG_NO_DISABLE_EXCEPTIONS ) # define CATCH_CONFIG_DISABLE_EXCEPTIONS #endif #if defined(CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_NO_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_POLYFILL_ISNAN) # define CATCH_CONFIG_POLYFILL_ISNAN #endif #if defined(CATCH_INTERNAL_CONFIG_USE_ASYNC) && !defined(CATCH_INTERNAL_CONFIG_NO_ASYNC) && !defined(CATCH_CONFIG_NO_USE_ASYNC) && !defined(CATCH_CONFIG_USE_ASYNC) # define CATCH_CONFIG_USE_ASYNC #endif #if defined(CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_NO_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_GLOBAL_NEXTAFTER) # define CATCH_CONFIG_GLOBAL_NEXTAFTER #endif // Even if we do not think the compiler has that warning, we still have // to provide a macro that can be used by the code. #if !defined(CATCH_INTERNAL_START_WARNINGS_SUPPRESSION) # define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION #endif #if !defined(CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION) # define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION #endif #if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS #endif #if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS #endif #if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS #endif #if !defined(CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS #endif #if !defined(CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS #endif // The goal of this macro is to avoid evaluation of the arguments, but // still have the compiler warn on problems inside... #if !defined(CATCH_INTERNAL_IGNORE_BUT_WARN) # define CATCH_INTERNAL_IGNORE_BUT_WARN(...) #endif #if defined(__APPLE__) && defined(__apple_build_version__) && (__clang_major__ < 10) # undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS #elif defined(__clang__) && (__clang_major__ < 5) # undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS #endif #if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS #endif #if !defined(CATCH_INTERNAL_SUPPRESS_COMMA_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_COMMA_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 #if defined(CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_NO_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) #define CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #endif #if defined( CATCH_PLATFORM_WINDOWS ) && \ !defined( CATCH_CONFIG_COLOUR_WIN32 ) && \ !defined( CATCH_CONFIG_NO_COLOUR_WIN32 ) && \ !defined( CATCH_INTERNAL_CONFIG_NO_COLOUR_WIN32 ) # define CATCH_CONFIG_COLOUR_WIN32 #endif #if defined( CATCH_CONFIG_SHARED_LIBRARY ) && defined( _MSC_VER ) && \ !defined( CATCH_CONFIG_STATIC ) # ifdef Catch2_EXPORTS # define CATCH_EXPORT //__declspec( dllexport ) // not needed # else # define CATCH_EXPORT __declspec( dllimport ) # endif #else # define CATCH_EXPORT #endif #endif // CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED #ifndef CATCH_CONTEXT_HPP_INCLUDED #define CATCH_CONTEXT_HPP_INCLUDED namespace Catch { class IResultCapture; class IConfig; class IContext { public: virtual ~IContext(); // = default virtual IResultCapture* getResultCapture() = 0; virtual IConfig const* getConfig() const = 0; }; class IMutableContext : public IContext { public: ~IMutableContext() override; // = default virtual void setResultCapture( IResultCapture* resultCapture ) = 0; virtual void setConfig( IConfig const* config ) = 0; private: CATCH_EXPORT static IMutableContext* currentContext; friend IMutableContext& getCurrentMutableContext(); friend void cleanUpContext(); static void createContext(); }; inline IMutableContext& getCurrentMutableContext() { if( !IMutableContext::currentContext ) IMutableContext::createContext(); // NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn) return *IMutableContext::currentContext; } inline IContext& getCurrentContext() { return getCurrentMutableContext(); } void cleanUpContext(); class SimplePcg32; SimplePcg32& sharedRng(); } #endif // CATCH_CONTEXT_HPP_INCLUDED #ifndef CATCH_INTERFACES_REPORTER_HPP_INCLUDED #define CATCH_INTERFACES_REPORTER_HPP_INCLUDED #ifndef CATCH_SECTION_INFO_HPP_INCLUDED #define CATCH_SECTION_INFO_HPP_INCLUDED #ifndef CATCH_MOVE_AND_FORWARD_HPP_INCLUDED #define CATCH_MOVE_AND_FORWARD_HPP_INCLUDED #include //! Replacement for std::move with better compile time performance #define CATCH_MOVE(...) static_cast&&>(__VA_ARGS__) //! Replacement for std::forward with better compile time performance #define CATCH_FORWARD(...) static_cast(__VA_ARGS__) #endif // CATCH_MOVE_AND_FORWARD_HPP_INCLUDED #ifndef CATCH_SOURCE_LINE_INFO_HPP_INCLUDED #define CATCH_SOURCE_LINE_INFO_HPP_INCLUDED #include #include namespace Catch { struct SourceLineInfo { SourceLineInfo() = delete; constexpr SourceLineInfo( char const* _file, std::size_t _line ) noexcept: file( _file ), line( _line ) {} bool operator == ( SourceLineInfo const& other ) const noexcept; bool operator < ( SourceLineInfo const& other ) const noexcept; char const* file; std::size_t line; friend std::ostream& operator << (std::ostream& os, SourceLineInfo const& info); }; } #define CATCH_INTERNAL_LINEINFO \ ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) #endif // CATCH_SOURCE_LINE_INFO_HPP_INCLUDED #ifndef CATCH_TOTALS_HPP_INCLUDED #define CATCH_TOTALS_HPP_INCLUDED #include namespace Catch { struct Counts { Counts operator - ( Counts const& other ) const; Counts& operator += ( Counts const& other ); std::uint64_t total() const; bool allPassed() const; bool allOk() const; std::uint64_t passed = 0; std::uint64_t failed = 0; std::uint64_t failedButOk = 0; std::uint64_t skipped = 0; }; struct Totals { Totals operator - ( Totals const& other ) const; Totals& operator += ( Totals const& other ); Totals delta( Totals const& prevTotals ) const; Counts assertions; Counts testCases; }; } #endif // CATCH_TOTALS_HPP_INCLUDED #include namespace Catch { struct SectionInfo { // The last argument is ignored, so that people can write // SECTION("ShortName", "Proper description that is long") and // still use the `-c` flag comfortably. SectionInfo( SourceLineInfo const& _lineInfo, std::string _name, const char* const = nullptr ): name(CATCH_MOVE(_name)), lineInfo(_lineInfo) {} std::string name; SourceLineInfo lineInfo; }; struct SectionEndInfo { SectionInfo sectionInfo; Counts prevAssertions; double durationInSeconds; }; } // end namespace Catch #endif // CATCH_SECTION_INFO_HPP_INCLUDED #ifndef CATCH_ASSERTION_RESULT_HPP_INCLUDED #define CATCH_ASSERTION_RESULT_HPP_INCLUDED #ifndef CATCH_ASSERTION_INFO_HPP_INCLUDED #define CATCH_ASSERTION_INFO_HPP_INCLUDED #ifndef CATCH_RESULT_TYPE_HPP_INCLUDED #define CATCH_RESULT_TYPE_HPP_INCLUDED namespace Catch { // ResultWas::OfType enum struct ResultWas { enum OfType { Unknown = -1, Ok = 0, Info = 1, Warning = 2, // TODO: Should explicit skip be considered "not OK" (cf. isOk)? I.e., should it have the failure bit? ExplicitSkip = 4, FailureBit = 0x10, ExpressionFailed = FailureBit | 1, ExplicitFailure = FailureBit | 2, Exception = 0x100 | FailureBit, ThrewException = Exception | 1, DidntThrowException = Exception | 2, FatalErrorCondition = 0x200 | FailureBit }; }; bool isOk( ResultWas::OfType resultType ); bool isJustInfo( int flags ); // ResultDisposition::Flags enum struct ResultDisposition { enum Flags { Normal = 0x01, ContinueOnFailure = 0x02, // Failures fail test, but execution continues FalseTest = 0x04, // Prefix expression with ! SuppressFail = 0x08 // Failures are reported but do not fail the test }; }; ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ); bool shouldContinueOnFailure( int flags ); inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; } bool shouldSuppressFailure( int flags ); } // end namespace Catch #endif // CATCH_RESULT_TYPE_HPP_INCLUDED namespace Catch { struct AssertionInfo { // AssertionInfo() = delete; StringRef macroName; SourceLineInfo lineInfo; StringRef capturedExpression; ResultDisposition::Flags resultDisposition; }; } // end namespace Catch #endif // CATCH_ASSERTION_INFO_HPP_INCLUDED #ifndef CATCH_LAZY_EXPR_HPP_INCLUDED #define CATCH_LAZY_EXPR_HPP_INCLUDED #include namespace Catch { class ITransientExpression; class LazyExpression { friend class AssertionHandler; friend struct AssertionStats; friend class RunContext; ITransientExpression const* m_transientExpression = nullptr; bool m_isNegated; public: LazyExpression( bool isNegated ): m_isNegated(isNegated) {} LazyExpression(LazyExpression const& other) = default; LazyExpression& operator = ( LazyExpression const& ) = delete; explicit operator bool() const { return m_transientExpression != nullptr; } friend auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream&; }; } // namespace Catch #endif // CATCH_LAZY_EXPR_HPP_INCLUDED #include namespace Catch { struct AssertionResultData { AssertionResultData() = delete; AssertionResultData( ResultWas::OfType _resultType, LazyExpression const& _lazyExpression ); std::string message; mutable std::string reconstructedExpression; LazyExpression lazyExpression; ResultWas::OfType resultType; std::string reconstructExpression() const; }; class AssertionResult { public: AssertionResult() = delete; AssertionResult( AssertionInfo const& info, AssertionResultData&& data ); bool isOk() const; bool succeeded() const; ResultWas::OfType getResultType() const; bool hasExpression() const; bool hasMessage() const; std::string getExpression() const; std::string getExpressionInMacro() const; bool hasExpandedExpression() const; std::string getExpandedExpression() const; StringRef getMessage() const; SourceLineInfo getSourceInfo() const; StringRef getTestMacroName() const; //protected: AssertionInfo m_info; AssertionResultData m_resultData; }; } // end namespace Catch #endif // CATCH_ASSERTION_RESULT_HPP_INCLUDED #ifndef CATCH_MESSAGE_INFO_HPP_INCLUDED #define CATCH_MESSAGE_INFO_HPP_INCLUDED #ifndef CATCH_INTERFACES_CAPTURE_HPP_INCLUDED #define CATCH_INTERFACES_CAPTURE_HPP_INCLUDED #include #include #ifndef CATCH_UNIQUE_PTR_HPP_INCLUDED #define CATCH_UNIQUE_PTR_HPP_INCLUDED #include #include namespace Catch { namespace Detail { /** * A reimplementation of `std::unique_ptr` for improved compilation performance * * Does not support arrays nor custom deleters. */ template class unique_ptr { T* m_ptr; public: constexpr unique_ptr(std::nullptr_t = nullptr): m_ptr{} {} explicit constexpr unique_ptr(T* ptr): m_ptr(ptr) {} template ::value>> unique_ptr(unique_ptr&& from): m_ptr(from.release()) {} template ::value>> unique_ptr& operator=(unique_ptr&& from) { reset(from.release()); return *this; } unique_ptr(unique_ptr const&) = delete; unique_ptr& operator=(unique_ptr const&) = delete; unique_ptr(unique_ptr&& rhs) noexcept: m_ptr(rhs.m_ptr) { rhs.m_ptr = nullptr; } unique_ptr& operator=(unique_ptr&& rhs) noexcept { reset(rhs.release()); return *this; } ~unique_ptr() { delete m_ptr; } T& operator*() { assert(m_ptr); return *m_ptr; } T const& operator*() const { assert(m_ptr); return *m_ptr; } T* operator->() noexcept { assert(m_ptr); return m_ptr; } T const* operator->() const noexcept { assert(m_ptr); return m_ptr; } T* get() { return m_ptr; } T const* get() const { return m_ptr; } void reset(T* ptr = nullptr) { delete m_ptr; m_ptr = ptr; } T* release() { auto temp = m_ptr; m_ptr = nullptr; return temp; } explicit operator bool() const { return m_ptr; } friend void swap(unique_ptr& lhs, unique_ptr& rhs) { auto temp = lhs.m_ptr; lhs.m_ptr = rhs.m_ptr; rhs.m_ptr = temp; } }; //! Specialization to cause compile-time error for arrays template class unique_ptr; template unique_ptr make_unique(Args&&... args) { return unique_ptr(new T(CATCH_FORWARD(args)...)); } } // end namespace Detail } // end namespace Catch #endif // CATCH_UNIQUE_PTR_HPP_INCLUDED namespace Catch { class AssertionResult; struct AssertionInfo; struct SectionInfo; struct SectionEndInfo; struct MessageInfo; struct MessageBuilder; struct Counts; struct AssertionReaction; struct SourceLineInfo; class ITransientExpression; class IGeneratorTracker; struct BenchmarkInfo; template > struct BenchmarkStats; namespace Generators { class GeneratorUntypedBase; using GeneratorBasePtr = Catch::Detail::unique_ptr; } class IResultCapture { public: virtual ~IResultCapture(); virtual bool sectionStarted( StringRef sectionName, SourceLineInfo const& sectionLineInfo, Counts& assertions ) = 0; virtual void sectionEnded( SectionEndInfo&& endInfo ) = 0; virtual void sectionEndedEarly( SectionEndInfo&& endInfo ) = 0; virtual IGeneratorTracker* acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) = 0; virtual IGeneratorTracker* createGeneratorTracker( StringRef generatorName, SourceLineInfo lineInfo, Generators::GeneratorBasePtr&& generator ) = 0; virtual void benchmarkPreparing( StringRef name ) = 0; virtual void benchmarkStarting( BenchmarkInfo const& info ) = 0; virtual void benchmarkEnded( BenchmarkStats<> const& stats ) = 0; virtual void benchmarkFailed( StringRef error ) = 0; virtual void pushScopedMessage( MessageInfo const& message ) = 0; virtual void popScopedMessage( MessageInfo const& message ) = 0; virtual void emplaceUnscopedMessage( MessageBuilder&& builder ) = 0; virtual void handleFatalErrorCondition( StringRef message ) = 0; virtual void handleExpr ( AssertionInfo const& info, ITransientExpression const& expr, AssertionReaction& reaction ) = 0; virtual void handleMessage ( AssertionInfo const& info, ResultWas::OfType resultType, StringRef message, AssertionReaction& reaction ) = 0; virtual void handleUnexpectedExceptionNotThrown ( AssertionInfo const& info, AssertionReaction& reaction ) = 0; virtual void handleUnexpectedInflightException ( AssertionInfo const& info, std::string const& message, AssertionReaction& reaction ) = 0; virtual void handleIncomplete ( AssertionInfo const& info ) = 0; virtual void handleNonExpr ( AssertionInfo const &info, ResultWas::OfType resultType, AssertionReaction &reaction ) = 0; virtual bool lastAssertionPassed() = 0; virtual void assertionPassed() = 0; // Deprecated, do not use: virtual std::string getCurrentTestName() const = 0; virtual const AssertionResult* getLastResult() const = 0; virtual void exceptionEarlyReported() = 0; }; IResultCapture& getResultCapture(); } #endif // CATCH_INTERFACES_CAPTURE_HPP_INCLUDED #include namespace Catch { struct MessageInfo { MessageInfo( StringRef _macroName, SourceLineInfo const& _lineInfo, ResultWas::OfType _type ); StringRef macroName; std::string message; SourceLineInfo lineInfo; ResultWas::OfType type; unsigned int sequence; bool operator == (MessageInfo const& other) const { return sequence == other.sequence; } bool operator < (MessageInfo const& other) const { return sequence < other.sequence; } private: static unsigned int globalCount; }; } // end namespace Catch #endif // CATCH_MESSAGE_INFO_HPP_INCLUDED // Adapted from donated nonius code. #ifndef CATCH_ESTIMATE_HPP_INCLUDED #define CATCH_ESTIMATE_HPP_INCLUDED namespace Catch { namespace Benchmark { template struct Estimate { Duration point; Duration lower_bound; Duration upper_bound; double confidence_interval; template operator Estimate() const { return { point, lower_bound, upper_bound, confidence_interval }; } }; } // namespace Benchmark } // namespace Catch #endif // CATCH_ESTIMATE_HPP_INCLUDED // Adapted from donated nonius code. #ifndef CATCH_OUTLIER_CLASSIFICATION_HPP_INCLUDED #define CATCH_OUTLIER_CLASSIFICATION_HPP_INCLUDED namespace Catch { namespace Benchmark { struct OutlierClassification { int samples_seen = 0; int low_severe = 0; // more than 3 times IQR below Q1 int low_mild = 0; // 1.5 to 3 times IQR below Q1 int high_mild = 0; // 1.5 to 3 times IQR above Q3 int high_severe = 0; // more than 3 times IQR above Q3 int total() const { return low_severe + low_mild + high_mild + high_severe; } }; } // namespace Benchmark } // namespace Catch #endif // CATCH_OUTLIERS_CLASSIFICATION_HPP_INCLUDED #include #include #include #include namespace Catch { struct ReporterDescription; struct ListenerDescription; struct TagInfo; struct TestCaseInfo; class TestCaseHandle; class IConfig; class IStream; enum class ColourMode : std::uint8_t; struct ReporterConfig { ReporterConfig( IConfig const* _fullConfig, Detail::unique_ptr _stream, ColourMode colourMode, std::map customOptions ); ReporterConfig( ReporterConfig&& ) = default; ReporterConfig& operator=( ReporterConfig&& ) = default; ~ReporterConfig(); // = default Detail::unique_ptr takeStream() &&; IConfig const* fullConfig() const; ColourMode colourMode() const; std::map const& customOptions() const; private: Detail::unique_ptr m_stream; IConfig const* m_fullConfig; ColourMode m_colourMode; std::map m_customOptions; }; struct TestRunInfo { constexpr TestRunInfo(StringRef _name) : name(_name) {} StringRef name; }; struct AssertionStats { AssertionStats( AssertionResult const& _assertionResult, std::vector const& _infoMessages, Totals const& _totals ); AssertionStats( AssertionStats const& ) = default; AssertionStats( AssertionStats && ) = default; AssertionStats& operator = ( AssertionStats const& ) = delete; AssertionStats& operator = ( AssertionStats && ) = delete; AssertionResult assertionResult; std::vector infoMessages; Totals totals; }; struct SectionStats { SectionStats( SectionInfo&& _sectionInfo, Counts const& _assertions, double _durationInSeconds, bool _missingAssertions ); SectionInfo sectionInfo; Counts assertions; double durationInSeconds; bool missingAssertions; }; struct TestCaseStats { TestCaseStats( TestCaseInfo const& _testInfo, Totals const& _totals, std::string&& _stdOut, std::string&& _stdErr, bool _aborting ); TestCaseInfo const * testInfo; Totals totals; std::string stdOut; std::string stdErr; bool aborting; }; struct TestRunStats { TestRunStats( TestRunInfo const& _runInfo, Totals const& _totals, bool _aborting ); TestRunInfo runInfo; Totals totals; bool aborting; }; struct BenchmarkInfo { std::string name; double estimatedDuration; int iterations; unsigned int samples; unsigned int resamples; double clockResolution; double clockCost; }; template struct BenchmarkStats { BenchmarkInfo info; std::vector samples; Benchmark::Estimate mean; Benchmark::Estimate standardDeviation; Benchmark::OutlierClassification outliers; double outlierVariance; template operator BenchmarkStats() const { std::vector samples2; samples2.reserve(samples.size()); for (auto const& sample : samples) { samples2.push_back(Duration2(sample)); } return { info, CATCH_MOVE(samples2), mean, standardDeviation, outliers, outlierVariance, }; } }; //! By setting up its preferences, a reporter can modify Catch2's behaviour //! in some regards, e.g. it can request Catch2 to capture writes to //! stdout/stderr during test execution, and pass them to the reporter. struct ReporterPreferences { //! Catch2 should redirect writes to stdout and pass them to the //! reporter bool shouldRedirectStdOut = false; //! Catch2 should call `Reporter::assertionEnded` even for passing //! assertions bool shouldReportAllAssertions = false; }; /** * The common base for all reporters and event listeners * * Implementing classes must also implement: * * //! User-friendly description of the reporter/listener type * static std::string getDescription() * * Generally shouldn't be derived from by users of Catch2 directly, * instead they should derive from one of the utility bases that * derive from this class. */ class IEventListener { protected: //! Derived classes can set up their preferences here ReporterPreferences m_preferences; //! The test run's config as filled in from CLI and defaults IConfig const* m_config; public: IEventListener( IConfig const* config ): m_config( config ) {} virtual ~IEventListener(); // = default; // Implementing class must also provide the following static methods: // static std::string getDescription(); ReporterPreferences const& getPreferences() const { return m_preferences; } //! Called when no test cases match provided test spec virtual void noMatchingTestCases( StringRef unmatchedSpec ) = 0; //! Called for all invalid test specs from the cli virtual void reportInvalidTestSpec( StringRef invalidArgument ) = 0; /** * Called once in a testing run before tests are started * * Not called if tests won't be run (e.g. only listing will happen) */ virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0; //! Called _once_ for each TEST_CASE, no matter how many times it is entered virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0; //! Called _every time_ a TEST_CASE is entered, including repeats (due to sections) virtual void testCasePartialStarting( TestCaseInfo const& testInfo, uint64_t partNumber ) = 0; //! Called when a `SECTION` is being entered. Not called for skipped sections virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0; //! Called when user-code is being probed before the actual benchmark runs virtual void benchmarkPreparing( StringRef benchmarkName ) = 0; //! Called after probe but before the user-code is being benchmarked virtual void benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) = 0; //! Called with the benchmark results if benchmark successfully finishes virtual void benchmarkEnded( BenchmarkStats<> const& benchmarkStats ) = 0; //! Called if running the benchmarks fails for any reason virtual void benchmarkFailed( StringRef benchmarkName ) = 0; //! Called before assertion success/failure is evaluated virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0; //! Called after assertion was fully evaluated virtual void assertionEnded( AssertionStats const& assertionStats ) = 0; //! Called after a `SECTION` has finished running virtual void sectionEnded( SectionStats const& sectionStats ) = 0; //! Called _every time_ a TEST_CASE is entered, including repeats (due to sections) virtual void testCasePartialEnded(TestCaseStats const& testCaseStats, uint64_t partNumber ) = 0; //! Called _once_ for each TEST_CASE, no matter how many times it is entered virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0; /** * Called once after all tests in a testing run are finished * * Not called if tests weren't run (e.g. only listings happened) */ virtual void testRunEnded( TestRunStats const& testRunStats ) = 0; /** * Called with test cases that are skipped due to the test run aborting. * NOT called for test cases that are explicitly skipped using the `SKIP` macro. * * Deprecated - will be removed in the next major release. */ virtual void skipTest( TestCaseInfo const& testInfo ) = 0; //! Called if a fatal error (signal/structured exception) occured virtual void fatalErrorEncountered( StringRef error ) = 0; //! Writes out information about provided reporters using reporter-specific format virtual void listReporters(std::vector const& descriptions) = 0; //! Writes out the provided listeners descriptions using reporter-specific format virtual void listListeners(std::vector const& descriptions) = 0; //! Writes out information about provided tests using reporter-specific format virtual void listTests(std::vector const& tests) = 0; //! Writes out information about the provided tags using reporter-specific format virtual void listTags(std::vector const& tags) = 0; }; using IEventListenerPtr = Detail::unique_ptr; } // end namespace Catch #endif // CATCH_INTERFACES_REPORTER_HPP_INCLUDED #ifndef CATCH_UNIQUE_NAME_HPP_INCLUDED #define CATCH_UNIQUE_NAME_HPP_INCLUDED /** \file * 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. */ #ifndef CATCH_CONFIG_COUNTER_HPP_INCLUDED #define CATCH_CONFIG_COUNTER_HPP_INCLUDED #if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L ) #define CATCH_INTERNAL_CONFIG_COUNTER #endif #if defined( CATCH_INTERNAL_CONFIG_COUNTER ) && \ !defined( CATCH_CONFIG_NO_COUNTER ) && \ !defined( CATCH_CONFIG_COUNTER ) # define CATCH_CONFIG_COUNTER #endif #endif // CATCH_CONFIG_COUNTER_HPP_INCLUDED #define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line #define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) #ifdef CATCH_CONFIG_COUNTER # define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ ) #else # define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) #endif #endif // CATCH_UNIQUE_NAME_HPP_INCLUDED // Adapted from donated nonius code. #ifndef CATCH_CHRONOMETER_HPP_INCLUDED #define CATCH_CHRONOMETER_HPP_INCLUDED // Adapted from donated nonius code. #ifndef CATCH_CLOCK_HPP_INCLUDED #define CATCH_CLOCK_HPP_INCLUDED #include #include namespace Catch { namespace Benchmark { template using ClockDuration = typename Clock::duration; template using FloatDuration = std::chrono::duration; template using TimePoint = typename Clock::time_point; using default_clock = std::chrono::steady_clock; template struct now { TimePoint operator()() const { return Clock::now(); } }; using fp_seconds = std::chrono::duration>; } // namespace Benchmark } // namespace Catch #endif // CATCH_CLOCK_HPP_INCLUDED // Adapted from donated nonius code. #ifndef CATCH_OPTIMIZER_HPP_INCLUDED #define CATCH_OPTIMIZER_HPP_INCLUDED #if defined(_MSC_VER) # include // atomic_thread_fence #endif #include namespace Catch { namespace Benchmark { #if defined(__GNUC__) || defined(__clang__) template inline void keep_memory(T* p) { asm volatile("" : : "g"(p) : "memory"); } inline void keep_memory() { asm volatile("" : : : "memory"); } namespace Detail { inline void optimizer_barrier() { keep_memory(); } } // namespace Detail #elif defined(_MSC_VER) #pragma optimize("", off) template inline void keep_memory(T* p) { // thanks @milleniumbug *reinterpret_cast(p) = *reinterpret_cast(p); } // TODO equivalent keep_memory() #pragma optimize("", on) namespace Detail { inline void optimizer_barrier() { std::atomic_thread_fence(std::memory_order_seq_cst); } } // namespace Detail #endif template inline void deoptimize_value(T&& x) { keep_memory(&x); } template inline auto invoke_deoptimized(Fn&& fn, Args&&... args) -> std::enable_if_t::value> { deoptimize_value(CATCH_FORWARD(fn) (CATCH_FORWARD(args)...)); } template inline auto invoke_deoptimized(Fn&& fn, Args&&... args) -> std::enable_if_t::value> { CATCH_FORWARD(fn) (CATCH_FORWARD(args)...); } } // namespace Benchmark } // namespace Catch #endif // CATCH_OPTIMIZER_HPP_INCLUDED // Adapted from donated nonius code. #ifndef CATCH_COMPLETE_INVOKE_HPP_INCLUDED #define CATCH_COMPLETE_INVOKE_HPP_INCLUDED #ifndef CATCH_TEST_FAILURE_EXCEPTION_HPP_INCLUDED #define CATCH_TEST_FAILURE_EXCEPTION_HPP_INCLUDED namespace Catch { //! Used to signal that an assertion macro failed struct TestFailureException{}; /** * Outlines throwing of `TestFailureException` into a single TU * * Also handles `CATCH_CONFIG_DISABLE_EXCEPTIONS` for callers. */ [[noreturn]] void throw_test_failure_exception(); //! Used to signal that the remainder of a test should be skipped struct TestSkipException{}; } // namespace Catch #endif // CATCH_TEST_FAILURE_EXCEPTION_HPP_INCLUDED #ifndef CATCH_META_HPP_INCLUDED #define CATCH_META_HPP_INCLUDED #include namespace Catch { template struct true_given : std::true_type {}; struct is_callable_tester { template static true_given()(std::declval()...))> test(int); template static std::false_type test(...); }; template struct is_callable; template struct is_callable : decltype(is_callable_tester::test(0)) {}; #if defined(__cpp_lib_is_invocable) && __cpp_lib_is_invocable >= 201703 // std::result_of is deprecated in C++17 and removed in C++20. Hence, it is // replaced with std::invoke_result here. template using FunctionReturnType = std::remove_reference_t>>; #else template using FunctionReturnType = std::remove_reference_t>>; #endif } // namespace Catch namespace mpl_{ struct na; } #endif // CATCH_META_HPP_INCLUDED #ifndef CATCH_INTERFACES_REGISTRY_HUB_HPP_INCLUDED #define CATCH_INTERFACES_REGISTRY_HUB_HPP_INCLUDED #include namespace Catch { class TestCaseHandle; struct TestCaseInfo; class ITestCaseRegistry; class IExceptionTranslatorRegistry; class IExceptionTranslator; class IReporterRegistry; class IReporterFactory; class ITagAliasRegistry; class ITestInvoker; class IMutableEnumValuesRegistry; struct SourceLineInfo; class StartupExceptionRegistry; class EventListenerFactory; using IReporterFactoryPtr = Detail::unique_ptr; class IRegistryHub { public: virtual ~IRegistryHub(); // = default virtual IReporterRegistry const& getReporterRegistry() const = 0; virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0; virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0; virtual IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const = 0; virtual StartupExceptionRegistry const& getStartupExceptionRegistry() const = 0; }; class IMutableRegistryHub { public: virtual ~IMutableRegistryHub(); // = default virtual void registerReporter( std::string const& name, IReporterFactoryPtr factory ) = 0; virtual void registerListener( Detail::unique_ptr factory ) = 0; virtual void registerTest(Detail::unique_ptr&& testInfo, Detail::unique_ptr&& invoker) = 0; virtual void registerTranslator( Detail::unique_ptr&& translator ) = 0; virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) = 0; virtual void registerStartupException() noexcept = 0; virtual IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() = 0; }; IRegistryHub const& getRegistryHub(); IMutableRegistryHub& getMutableRegistryHub(); void cleanUp(); std::string translateActiveException(); } #endif // CATCH_INTERFACES_REGISTRY_HUB_HPP_INCLUDED #include namespace Catch { namespace Benchmark { namespace Detail { template struct CompleteType { using type = T; }; template <> struct CompleteType { struct type {}; }; template using CompleteType_t = typename CompleteType::type; template struct CompleteInvoker { template static Result invoke(Fun&& fun, Args&&... args) { return CATCH_FORWARD(fun)(CATCH_FORWARD(args)...); } }; template <> struct CompleteInvoker { template static CompleteType_t invoke(Fun&& fun, Args&&... args) { CATCH_FORWARD(fun)(CATCH_FORWARD(args)...); return {}; } }; // invoke and not return void :( template CompleteType_t> complete_invoke(Fun&& fun, Args&&... args) { return CompleteInvoker>::invoke(CATCH_FORWARD(fun), CATCH_FORWARD(args)...); } } // namespace Detail template Detail::CompleteType_t> user_code(Fun&& fun) { return Detail::complete_invoke(CATCH_FORWARD(fun)); } } // namespace Benchmark } // namespace Catch #endif // CATCH_COMPLETE_INVOKE_HPP_INCLUDED namespace Catch { namespace Benchmark { namespace Detail { struct ChronometerConcept { virtual void start() = 0; virtual void finish() = 0; virtual ~ChronometerConcept(); // = default; ChronometerConcept() = default; ChronometerConcept(ChronometerConcept const&) = default; ChronometerConcept& operator=(ChronometerConcept const&) = default; }; template struct ChronometerModel final : public ChronometerConcept { void start() override { started = Clock::now(); } void finish() override { finished = Clock::now(); } ClockDuration elapsed() const { return finished - started; } TimePoint started; TimePoint finished; }; } // namespace Detail struct Chronometer { public: template void measure(Fun&& fun) { measure(CATCH_FORWARD(fun), is_callable()); } int runs() const { return repeats; } Chronometer(Detail::ChronometerConcept& meter, int repeats_) : impl(&meter) , repeats(repeats_) {} private: template void measure(Fun&& fun, std::false_type) { measure([&fun](int) { return fun(); }, std::true_type()); } template void measure(Fun&& fun, std::true_type) { Detail::optimizer_barrier(); impl->start(); for (int i = 0; i < repeats; ++i) invoke_deoptimized(fun, i); impl->finish(); Detail::optimizer_barrier(); } Detail::ChronometerConcept* impl; int repeats; }; } // namespace Benchmark } // namespace Catch #endif // CATCH_CHRONOMETER_HPP_INCLUDED // Adapted from donated nonius code. #ifndef CATCH_ENVIRONMENT_HPP_INCLUDED #define CATCH_ENVIRONMENT_HPP_INCLUDED namespace Catch { namespace Benchmark { template struct EnvironmentEstimate { Duration mean; OutlierClassification outliers; template operator EnvironmentEstimate() const { return { mean, outliers }; } }; template struct Environment { using clock_type = Clock; EnvironmentEstimate> clock_resolution; EnvironmentEstimate> clock_cost; }; } // namespace Benchmark } // namespace Catch #endif // CATCH_ENVIRONMENT_HPP_INCLUDED // Adapted from donated nonius code. #ifndef CATCH_EXECUTION_PLAN_HPP_INCLUDED #define CATCH_EXECUTION_PLAN_HPP_INCLUDED // Adapted from donated nonius code. #ifndef CATCH_BENCHMARK_FUNCTION_HPP_INCLUDED #define CATCH_BENCHMARK_FUNCTION_HPP_INCLUDED #include namespace Catch { namespace Benchmark { namespace Detail { template struct is_related : std::is_same, std::decay_t> {}; /// We need to reinvent std::function because every piece of code that might add overhead /// in a measurement context needs to have consistent performance characteristics so that we /// can account for it in the measurement. /// Implementations of std::function with optimizations that aren't always applicable, like /// small buffer optimizations, are not uncommon. /// This is effectively an implementation of std::function without any such optimizations; /// it may be slow, but it is consistently slow. struct BenchmarkFunction { private: struct callable { virtual void call(Chronometer meter) const = 0; virtual Catch::Detail::unique_ptr clone() const = 0; virtual ~callable(); // = default; callable() = default; callable(callable const&) = default; callable& operator=(callable const&) = default; }; template struct model : public callable { model(Fun&& fun_) : fun(CATCH_MOVE(fun_)) {} model(Fun const& fun_) : fun(fun_) {} Catch::Detail::unique_ptr clone() const override { return Catch::Detail::make_unique>( *this ); } void call(Chronometer meter) const override { call(meter, is_callable()); } void call(Chronometer meter, std::true_type) const { fun(meter); } void call(Chronometer meter, std::false_type) const { meter.measure(fun); } Fun fun; }; struct do_nothing { void operator()() const {} }; template BenchmarkFunction(model* c) : f(c) {} public: BenchmarkFunction() : f(new model{ {} }) {} template ::value, int> = 0> BenchmarkFunction(Fun&& fun) : f(new model>(CATCH_FORWARD(fun))) {} BenchmarkFunction( BenchmarkFunction&& that ) noexcept: f( CATCH_MOVE( that.f ) ) {} BenchmarkFunction(BenchmarkFunction const& that) : f(that.f->clone()) {} BenchmarkFunction& operator=( BenchmarkFunction&& that ) noexcept { f = CATCH_MOVE( that.f ); return *this; } BenchmarkFunction& operator=(BenchmarkFunction const& that) { f = that.f->clone(); return *this; } void operator()(Chronometer meter) const { f->call(meter); } private: Catch::Detail::unique_ptr f; }; } // namespace Detail } // namespace Benchmark } // namespace Catch #endif // CATCH_BENCHMARK_FUNCTION_HPP_INCLUDED // Adapted from donated nonius code. #ifndef CATCH_REPEAT_HPP_INCLUDED #define CATCH_REPEAT_HPP_INCLUDED #include namespace Catch { namespace Benchmark { namespace Detail { template struct repeater { void operator()(int k) const { for (int i = 0; i < k; ++i) { fun(); } } Fun fun; }; template repeater> repeat(Fun&& fun) { return { CATCH_FORWARD(fun) }; } } // namespace Detail } // namespace Benchmark } // namespace Catch #endif // CATCH_REPEAT_HPP_INCLUDED // Adapted from donated nonius code. #ifndef CATCH_RUN_FOR_AT_LEAST_HPP_INCLUDED #define CATCH_RUN_FOR_AT_LEAST_HPP_INCLUDED // Adapted from donated nonius code. #ifndef CATCH_MEASURE_HPP_INCLUDED #define CATCH_MEASURE_HPP_INCLUDED // Adapted from donated nonius code. #ifndef CATCH_TIMING_HPP_INCLUDED #define CATCH_TIMING_HPP_INCLUDED #include namespace Catch { namespace Benchmark { template struct Timing { Duration elapsed; Result result; int iterations; }; template using TimingOf = Timing, Detail::CompleteType_t>>; } // namespace Benchmark } // namespace Catch #endif // CATCH_TIMING_HPP_INCLUDED namespace Catch { namespace Benchmark { namespace Detail { template TimingOf measure(Fun&& fun, Args&&... args) { auto start = Clock::now(); auto&& r = Detail::complete_invoke(fun, CATCH_FORWARD(args)...); auto end = Clock::now(); auto delta = end - start; return { delta, CATCH_FORWARD(r), 1 }; } } // namespace Detail } // namespace Benchmark } // namespace Catch #endif // CATCH_MEASURE_HPP_INCLUDED #include namespace Catch { namespace Benchmark { namespace Detail { template TimingOf measure_one(Fun&& fun, int iters, std::false_type) { return Detail::measure(fun, iters); } template TimingOf measure_one(Fun&& fun, int iters, std::true_type) { Detail::ChronometerModel meter; auto&& result = Detail::complete_invoke(fun, Chronometer(meter, iters)); return { meter.elapsed(), CATCH_MOVE(result), iters }; } template using run_for_at_least_argument_t = std::conditional_t::value, Chronometer, int>; [[noreturn]] void throw_optimized_away_error(); template TimingOf> run_for_at_least(ClockDuration how_long, const int initial_iterations, Fun&& fun) { auto iters = initial_iterations; while (iters < (1 << 30)) { auto&& Timing = measure_one(fun, iters, is_callable()); if (Timing.elapsed >= how_long) { return { Timing.elapsed, CATCH_MOVE(Timing.result), iters }; } iters *= 2; } throw_optimized_away_error(); } } // namespace Detail } // namespace Benchmark } // namespace Catch #endif // CATCH_RUN_FOR_AT_LEAST_HPP_INCLUDED #include #include namespace Catch { namespace Benchmark { template struct ExecutionPlan { int iterations_per_sample; Duration estimated_duration; Detail::BenchmarkFunction benchmark; Duration warmup_time; int warmup_iterations; template operator ExecutionPlan() const { return { iterations_per_sample, estimated_duration, benchmark, warmup_time, warmup_iterations }; } template std::vector> run(const IConfig &cfg, Environment> env) const { // warmup a bit Detail::run_for_at_least(std::chrono::duration_cast>(warmup_time), warmup_iterations, Detail::repeat(now{})); std::vector> times; times.reserve(cfg.benchmarkSamples()); std::generate_n(std::back_inserter(times), cfg.benchmarkSamples(), [this, env] { Detail::ChronometerModel model; this->benchmark(Chronometer(model, iterations_per_sample)); auto sample_time = model.elapsed() - env.clock_cost.mean; if (sample_time < FloatDuration::zero()) sample_time = FloatDuration::zero(); return sample_time / iterations_per_sample; }); return times; } }; } // namespace Benchmark } // namespace Catch #endif // CATCH_EXECUTION_PLAN_HPP_INCLUDED // Adapted from donated nonius code. #ifndef CATCH_ESTIMATE_CLOCK_HPP_INCLUDED #define CATCH_ESTIMATE_CLOCK_HPP_INCLUDED // Adapted from donated nonius code. #ifndef CATCH_STATS_HPP_INCLUDED #define CATCH_STATS_HPP_INCLUDED #include #include #include #include #include namespace Catch { namespace Benchmark { namespace Detail { using sample = std::vector; // Used when we know we want == comparison of two doubles // to centralize warning suppression bool directCompare( double lhs, double rhs ); double weighted_average_quantile(int k, int q, std::vector::iterator first, std::vector::iterator last); template OutlierClassification classify_outliers(Iterator first, Iterator last) { std::vector copy(first, last); auto q1 = weighted_average_quantile(1, 4, copy.begin(), copy.end()); auto q3 = weighted_average_quantile(3, 4, copy.begin(), copy.end()); auto iqr = q3 - q1; auto los = q1 - (iqr * 3.); auto lom = q1 - (iqr * 1.5); auto him = q3 + (iqr * 1.5); auto his = q3 + (iqr * 3.); OutlierClassification o; for (; first != last; ++first) { auto&& t = *first; if (t < los) ++o.low_severe; else if (t < lom) ++o.low_mild; else if (t > his) ++o.high_severe; else if (t > him) ++o.high_mild; ++o.samples_seen; } return o; } template double mean(Iterator first, Iterator last) { auto count = last - first; double sum = std::accumulate(first, last, 0.); return sum / static_cast(count); } template sample jackknife(Estimator&& estimator, Iterator first, Iterator last) { auto n = static_cast(last - first); auto second = first; ++second; sample results; results.reserve(n); for (auto it = first; it != last; ++it) { std::iter_swap(it, first); results.push_back(estimator(second, last)); } return results; } inline double normal_cdf(double x) { return std::erfc(-x / std::sqrt(2.0)) / 2.0; } double erfc_inv(double x); double normal_quantile(double p); template Estimate bootstrap(double confidence_level, Iterator first, Iterator last, sample const& resample, Estimator&& estimator) { auto n_samples = last - first; double point = estimator(first, last); // Degenerate case with a single sample if (n_samples == 1) return { point, point, point, confidence_level }; sample jack = jackknife(estimator, first, last); double jack_mean = mean(jack.begin(), jack.end()); double sum_squares, sum_cubes; std::tie(sum_squares, sum_cubes) = std::accumulate(jack.begin(), jack.end(), std::make_pair(0., 0.), [jack_mean](std::pair sqcb, double x) -> std::pair { auto d = jack_mean - x; auto d2 = d * d; auto d3 = d2 * d; return { sqcb.first + d2, sqcb.second + d3 }; }); double accel = sum_cubes / (6 * std::pow(sum_squares, 1.5)); long n = static_cast(resample.size()); double prob_n = std::count_if(resample.begin(), resample.end(), [point](double x) { return x < point; }) / static_cast(n); // degenerate case with uniform samples if ( directCompare( prob_n, 0. ) ) { return { point, point, point, confidence_level }; } double bias = normal_quantile(prob_n); double z1 = normal_quantile((1. - confidence_level) / 2.); auto cumn = [n]( double x ) -> long { return std::lround( normal_cdf( x ) * static_cast(n) ); }; auto a = [bias, accel](double b) { return bias + b / (1. - accel * b); }; double b1 = bias + z1; double b2 = bias - z1; double a1 = a(b1); double a2 = a(b2); auto lo = static_cast((std::max)(cumn(a1), 0l)); auto hi = static_cast((std::min)(cumn(a2), n - 1)); return { point, resample[lo], resample[hi], confidence_level }; } double outlier_variance(Estimate mean, Estimate stddev, int n); struct bootstrap_analysis { Estimate mean; Estimate standard_deviation; double outlier_variance; }; bootstrap_analysis analyse_samples(double confidence_level, unsigned int n_resamples, std::vector::iterator first, std::vector::iterator last); } // namespace Detail } // namespace Benchmark } // namespace Catch #endif // CATCH_STATS_HPP_INCLUDED #include #include #include #include namespace Catch { namespace Benchmark { namespace Detail { template std::vector resolution(int k) { std::vector> times; times.reserve(static_cast(k + 1)); std::generate_n(std::back_inserter(times), k + 1, now{}); std::vector deltas; deltas.reserve(static_cast(k)); std::transform(std::next(times.begin()), times.end(), times.begin(), std::back_inserter(deltas), [](TimePoint a, TimePoint b) { return static_cast((a - b).count()); }); return deltas; } const auto warmup_iterations = 10000; const auto warmup_time = std::chrono::milliseconds(100); const auto minimum_ticks = 1000; const auto warmup_seed = 10000; const auto clock_resolution_estimation_time = std::chrono::milliseconds(500); const auto clock_cost_estimation_time_limit = std::chrono::seconds(1); const auto clock_cost_estimation_tick_limit = 100000; const auto clock_cost_estimation_time = std::chrono::milliseconds(10); const auto clock_cost_estimation_iterations = 10000; template int warmup() { return run_for_at_least(std::chrono::duration_cast>(warmup_time), warmup_seed, &resolution) .iterations; } template EnvironmentEstimate> estimate_clock_resolution(int iterations) { auto r = run_for_at_least(std::chrono::duration_cast>(clock_resolution_estimation_time), iterations, &resolution) .result; return { FloatDuration(mean(r.begin(), r.end())), classify_outliers(r.begin(), r.end()), }; } template EnvironmentEstimate> estimate_clock_cost(FloatDuration resolution) { auto time_limit = (std::min)( resolution * clock_cost_estimation_tick_limit, FloatDuration(clock_cost_estimation_time_limit)); auto time_clock = [](int k) { return Detail::measure([k] { for (int i = 0; i < k; ++i) { volatile auto ignored = Clock::now(); (void)ignored; } }).elapsed; }; time_clock(1); int iters = clock_cost_estimation_iterations; auto&& r = run_for_at_least(std::chrono::duration_cast>(clock_cost_estimation_time), iters, time_clock); std::vector times; int nsamples = static_cast(std::ceil(time_limit / r.elapsed)); times.reserve(static_cast(nsamples)); std::generate_n(std::back_inserter(times), nsamples, [time_clock, &r] { return static_cast((time_clock(r.iterations) / r.iterations).count()); }); return { FloatDuration(mean(times.begin(), times.end())), classify_outliers(times.begin(), times.end()), }; } template Environment> measure_environment() { #if defined(__clang__) # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wexit-time-destructors" #endif static Catch::Detail::unique_ptr>> env; #if defined(__clang__) # pragma clang diagnostic pop #endif if (env) { return *env; } auto iters = Detail::warmup(); auto resolution = Detail::estimate_clock_resolution(iters); auto cost = Detail::estimate_clock_cost(resolution.mean); env = Catch::Detail::make_unique>>( Environment>{resolution, cost} ); return *env; } } // namespace Detail } // namespace Benchmark } // namespace Catch #endif // CATCH_ESTIMATE_CLOCK_HPP_INCLUDED // Adapted from donated nonius code. #ifndef CATCH_ANALYSE_HPP_INCLUDED #define CATCH_ANALYSE_HPP_INCLUDED // Adapted from donated nonius code. #ifndef CATCH_SAMPLE_ANALYSIS_HPP_INCLUDED #define CATCH_SAMPLE_ANALYSIS_HPP_INCLUDED #include #include #include namespace Catch { namespace Benchmark { template struct SampleAnalysis { std::vector samples; Estimate mean; Estimate standard_deviation; OutlierClassification outliers; double outlier_variance; template operator SampleAnalysis() const { std::vector samples2; samples2.reserve(samples.size()); std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](Duration d) { return Duration2(d); }); return { CATCH_MOVE(samples2), mean, standard_deviation, outliers, outlier_variance, }; } }; } // namespace Benchmark } // namespace Catch #endif // CATCH_SAMPLE_ANALYSIS_HPP_INCLUDED #include #include #include namespace Catch { namespace Benchmark { namespace Detail { template SampleAnalysis analyse(const IConfig &cfg, Environment, Iterator first, Iterator last) { if (!cfg.benchmarkNoAnalysis()) { std::vector samples; samples.reserve(static_cast(last - first)); std::transform(first, last, std::back_inserter(samples), [](Duration d) { return d.count(); }); auto analysis = Catch::Benchmark::Detail::analyse_samples(cfg.benchmarkConfidenceInterval(), cfg.benchmarkResamples(), samples.begin(), samples.end()); auto outliers = Catch::Benchmark::Detail::classify_outliers(samples.begin(), samples.end()); auto wrap_estimate = [](Estimate e) { return Estimate { Duration(e.point), Duration(e.lower_bound), Duration(e.upper_bound), e.confidence_interval, }; }; std::vector samples2; samples2.reserve(samples.size()); std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](double d) { return Duration(d); }); return { CATCH_MOVE(samples2), wrap_estimate(analysis.mean), wrap_estimate(analysis.standard_deviation), outliers, analysis.outlier_variance, }; } else { std::vector samples; samples.reserve(static_cast(last - first)); Duration mean = Duration(0); int i = 0; for (auto it = first; it < last; ++it, ++i) { samples.push_back(Duration(*it)); mean += Duration(*it); } mean /= i; return { CATCH_MOVE(samples), Estimate{mean, mean, mean, 0.0}, Estimate{Duration(0), Duration(0), Duration(0), 0.0}, OutlierClassification{}, 0.0 }; } } } // namespace Detail } // namespace Benchmark } // namespace Catch #endif // CATCH_ANALYSE_HPP_INCLUDED #include #include #include #include #include namespace Catch { namespace Benchmark { struct Benchmark { Benchmark(std::string&& benchmarkName) : name(CATCH_MOVE(benchmarkName)) {} template Benchmark(std::string&& benchmarkName , FUN &&func) : fun(CATCH_MOVE(func)), name(CATCH_MOVE(benchmarkName)) {} template ExecutionPlan> prepare(const IConfig &cfg, Environment> env) const { auto min_time = env.clock_resolution.mean * Detail::minimum_ticks; auto run_time = std::max(min_time, std::chrono::duration_cast(cfg.benchmarkWarmupTime())); auto&& test = Detail::run_for_at_least(std::chrono::duration_cast>(run_time), 1, fun); int new_iters = static_cast(std::ceil(min_time * test.iterations / test.elapsed)); return { new_iters, test.elapsed / test.iterations * new_iters * cfg.benchmarkSamples(), fun, std::chrono::duration_cast>(cfg.benchmarkWarmupTime()), Detail::warmup_iterations }; } template void run() { auto const* cfg = getCurrentContext().getConfig(); auto env = Detail::measure_environment(); getResultCapture().benchmarkPreparing(name); CATCH_TRY{ auto plan = user_code([&] { return prepare(*cfg, env); }); BenchmarkInfo info { CATCH_MOVE(name), plan.estimated_duration.count(), plan.iterations_per_sample, cfg->benchmarkSamples(), cfg->benchmarkResamples(), env.clock_resolution.mean.count(), env.clock_cost.mean.count() }; getResultCapture().benchmarkStarting(info); auto samples = user_code([&] { return plan.template run(*cfg, env); }); auto analysis = Detail::analyse(*cfg, env, samples.begin(), samples.end()); BenchmarkStats> stats{ CATCH_MOVE(info), CATCH_MOVE(analysis.samples), analysis.mean, analysis.standard_deviation, analysis.outliers, analysis.outlier_variance }; getResultCapture().benchmarkEnded(stats); } CATCH_CATCH_ANON (TestFailureException) { getResultCapture().benchmarkFailed("Benchmark failed due to failed assertion"_sr); } CATCH_CATCH_ALL{ getResultCapture().benchmarkFailed(translateActiveException()); // We let the exception go further up so that the // test case is marked as failed. std::rethrow_exception(std::current_exception()); } } // sets lambda to be used in fun *and* executes benchmark! template ::value, int> = 0> Benchmark & operator=(Fun func) { auto const* cfg = getCurrentContext().getConfig(); if (!cfg->skipBenchmarks()) { fun = Detail::BenchmarkFunction(func); run(); } return *this; } explicit operator bool() { return true; } private: Detail::BenchmarkFunction fun; std::string name; }; } } // namespace Catch #define INTERNAL_CATCH_GET_1_ARG(arg1, arg2, ...) arg1 #define INTERNAL_CATCH_GET_2_ARG(arg1, arg2, ...) arg2 #define INTERNAL_CATCH_BENCHMARK(BenchmarkName, name, benchmarkIndex)\ if( Catch::Benchmark::Benchmark BenchmarkName{name} ) \ BenchmarkName = [&](int benchmarkIndex) #define INTERNAL_CATCH_BENCHMARK_ADVANCED(BenchmarkName, name)\ if( Catch::Benchmark::Benchmark BenchmarkName{name} ) \ BenchmarkName = [&] #if defined(CATCH_CONFIG_PREFIX_ALL) #define CATCH_BENCHMARK(...) \ INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(CATCH2_INTERNAL_BENCHMARK_), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,)) #define CATCH_BENCHMARK_ADVANCED(name) \ INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(CATCH2_INTERNAL_BENCHMARK_), name) #else #define BENCHMARK(...) \ INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(CATCH2_INTERNAL_BENCHMARK_), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,)) #define BENCHMARK_ADVANCED(name) \ INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(CATCH2_INTERNAL_BENCHMARK_), name) #endif #endif // CATCH_BENCHMARK_HPP_INCLUDED // Adapted from donated nonius code. #ifndef CATCH_CONSTRUCTOR_HPP_INCLUDED #define CATCH_CONSTRUCTOR_HPP_INCLUDED #include namespace Catch { namespace Benchmark { namespace Detail { template struct ObjectStorage { ObjectStorage() = default; ObjectStorage(const ObjectStorage& other) { new(&data) T(other.stored_object()); } ObjectStorage(ObjectStorage&& other) { new(data) T(CATCH_MOVE(other.stored_object())); } ~ObjectStorage() { destruct_on_exit(); } template void construct(Args&&... args) { new (data) T(CATCH_FORWARD(args)...); } template std::enable_if_t destruct() { stored_object().~T(); } private: // If this is a constructor benchmark, destruct the underlying object template void destruct_on_exit(std::enable_if_t* = nullptr) { destruct(); } // Otherwise, don't template void destruct_on_exit(std::enable_if_t* = nullptr) { } #if defined( __GNUC__ ) && __GNUC__ <= 6 # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wstrict-aliasing" #endif T& stored_object() { return *reinterpret_cast( data ); } T const& stored_object() const { return *reinterpret_cast( data ); } #if defined( __GNUC__ ) && __GNUC__ <= 6 # pragma GCC diagnostic pop #endif alignas( T ) unsigned char data[sizeof( T )]{}; }; } // namespace Detail template using storage_for = Detail::ObjectStorage; template using destructable_object = Detail::ObjectStorage; } // namespace Benchmark } // namespace Catch #endif // CATCH_CONSTRUCTOR_HPP_INCLUDED #endif // CATCH_BENCHMARK_ALL_HPP_INCLUDED #ifndef CATCH_APPROX_HPP_INCLUDED #define CATCH_APPROX_HPP_INCLUDED #ifndef CATCH_TOSTRING_HPP_INCLUDED #define CATCH_TOSTRING_HPP_INCLUDED #include #include #include #include /** \file * 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`. */ #ifndef CATCH_CONFIG_WCHAR_HPP_INCLUDED #define CATCH_CONFIG_WCHAR_HPP_INCLUDED // We assume that WCHAR should be enabled by default, and only disabled // for a shortlist (so far only DJGPP) of compilers. #if defined(__DJGPP__) # define CATCH_INTERNAL_CONFIG_NO_WCHAR #endif // __DJGPP__ #if !defined( CATCH_INTERNAL_CONFIG_NO_WCHAR ) && \ !defined( CATCH_CONFIG_NO_WCHAR ) && \ !defined( CATCH_CONFIG_WCHAR ) # define CATCH_CONFIG_WCHAR #endif #endif // CATCH_CONFIG_WCHAR_HPP_INCLUDED #ifndef CATCH_REUSABLE_STRING_STREAM_HPP_INCLUDED #define CATCH_REUSABLE_STRING_STREAM_HPP_INCLUDED #include #include #include #include namespace Catch { class ReusableStringStream : Detail::NonCopyable { std::size_t m_index; std::ostream* m_oss; public: ReusableStringStream(); ~ReusableStringStream(); //! Returns the serialized state std::string str() const; //! Sets internal state to `str` void str(std::string const& str); #if defined(__GNUC__) && !defined(__clang__) #pragma GCC diagnostic push // Old versions of GCC do not understand -Wnonnull-compare #pragma GCC diagnostic ignored "-Wpragmas" // Streaming a function pointer triggers Waddress and Wnonnull-compare // on GCC, because it implicitly converts it to bool and then decides // that the check it uses (a? true : false) is tautological and cannot // be null... #pragma GCC diagnostic ignored "-Waddress" #pragma GCC diagnostic ignored "-Wnonnull-compare" #endif template auto operator << ( T const& value ) -> ReusableStringStream& { *m_oss << value; return *this; } #if defined(__GNUC__) && !defined(__clang__) #pragma GCC diagnostic pop #endif auto get() -> std::ostream& { return *m_oss; } }; } #endif // CATCH_REUSABLE_STRING_STREAM_HPP_INCLUDED #ifndef CATCH_VOID_TYPE_HPP_INCLUDED #define CATCH_VOID_TYPE_HPP_INCLUDED namespace Catch { namespace Detail { template struct make_void { using type = void; }; template using void_t = typename make_void::type; } // namespace Detail } // namespace Catch #endif // CATCH_VOID_TYPE_HPP_INCLUDED #ifndef CATCH_INTERFACES_ENUM_VALUES_REGISTRY_HPP_INCLUDED #define CATCH_INTERFACES_ENUM_VALUES_REGISTRY_HPP_INCLUDED #include namespace Catch { namespace Detail { struct EnumInfo { StringRef m_name; std::vector> m_values; ~EnumInfo(); StringRef lookup( int value ) const; }; } // namespace Detail class IMutableEnumValuesRegistry { public: virtual ~IMutableEnumValuesRegistry(); // = default; virtual Detail::EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::vector const& values ) = 0; template Detail::EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::initializer_list values ) { static_assert(sizeof(int) >= sizeof(E), "Cannot serialize enum to int"); std::vector intValues; intValues.reserve( values.size() ); for( auto enumValue : values ) intValues.push_back( static_cast( enumValue ) ); return registerEnum( enumName, allEnums, intValues ); } }; } // Catch #endif // CATCH_INTERFACES_ENUM_VALUES_REGISTRY_HPP_INCLUDED #ifdef CATCH_CONFIG_CPP17_STRING_VIEW #include #endif #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4180) // We attempt to stream a function (address) by const&, which MSVC complains about but is harmless #endif // We need a dummy global operator<< so we can bring it into Catch namespace later struct Catch_global_namespace_dummy{}; std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy); namespace Catch { // Bring in global namespace operator<< for ADL lookup in // `IsStreamInsertable` below. using ::operator<<; namespace Detail { inline std::size_t catch_strnlen(const char *str, std::size_t n) { auto ret = std::char_traits::find(str, n, '\0'); if (ret != nullptr) { return static_cast(ret - str); } return n; } constexpr StringRef unprintableString = "{?}"_sr; //! Encases `string in quotes, and optionally escapes invisibles std::string convertIntoString( StringRef string, bool escapeInvisibles ); //! Encases `string` in quotes, and escapes invisibles if user requested //! it via CLI std::string convertIntoString( StringRef string ); std::string rawMemoryToString( const void *object, std::size_t size ); template std::string rawMemoryToString( const T& object ) { return rawMemoryToString( &object, sizeof(object) ); } template class IsStreamInsertable { template static auto test(int) -> decltype(std::declval() << std::declval(), std::true_type()); template static auto test(...)->std::false_type; public: static const bool value = decltype(test(0))::value; }; template std::string convertUnknownEnumToString( E e ); template std::enable_if_t< !std::is_enum::value && !std::is_base_of::value, std::string> convertUnstreamable( T const& ) { return std::string(Detail::unprintableString); } template std::enable_if_t< !std::is_enum::value && std::is_base_of::value, std::string> convertUnstreamable(T const& ex) { return ex.what(); } template std::enable_if_t< std::is_enum::value, std::string> convertUnstreamable( T const& value ) { return convertUnknownEnumToString( value ); } #if defined(_MANAGED) //! Convert a CLR string to a utf8 std::string template std::string clrReferenceToString( T^ ref ) { if (ref == nullptr) return std::string("null"); auto bytes = System::Text::Encoding::UTF8->GetBytes(ref->ToString()); cli::pin_ptr p = &bytes[0]; return std::string(reinterpret_cast(p), bytes->Length); } #endif } // namespace Detail // If we decide for C++14, change these to enable_if_ts template struct StringMaker { template static std::enable_if_t<::Catch::Detail::IsStreamInsertable::value, std::string> convert(const Fake& value) { ReusableStringStream rss; // NB: call using the function-like syntax to avoid ambiguity with // user-defined templated operator<< under clang. rss.operator<<(value); return rss.str(); } template static std::enable_if_t::value, std::string> convert( const Fake& value ) { #if !defined(CATCH_CONFIG_FALLBACK_STRINGIFIER) return Detail::convertUnstreamable(value); #else return CATCH_CONFIG_FALLBACK_STRINGIFIER(value); #endif } }; namespace Detail { // This function dispatches all stringification requests inside of Catch. // Should be preferably called fully qualified, like ::Catch::Detail::stringify template std::string stringify(const T& e) { return ::Catch::StringMaker>>::convert(e); } template std::string convertUnknownEnumToString( E e ) { return ::Catch::Detail::stringify(static_cast>(e)); } #if defined(_MANAGED) template std::string stringify( T^ e ) { return ::Catch::StringMaker::convert(e); } #endif } // namespace Detail // Some predefined specializations template<> struct StringMaker { static std::string convert(const std::string& str); }; #ifdef CATCH_CONFIG_CPP17_STRING_VIEW template<> struct StringMaker { static std::string convert(std::string_view str); }; #endif template<> struct StringMaker { static std::string convert(char const * str); }; template<> struct StringMaker { static std::string convert(char * str); }; #if defined(CATCH_CONFIG_WCHAR) template<> struct StringMaker { static std::string convert(const std::wstring& wstr); }; # ifdef CATCH_CONFIG_CPP17_STRING_VIEW template<> struct StringMaker { static std::string convert(std::wstring_view str); }; # endif template<> struct StringMaker { static std::string convert(wchar_t const * str); }; template<> struct StringMaker { static std::string convert(wchar_t * str); }; #endif // CATCH_CONFIG_WCHAR template struct StringMaker { static std::string convert(char const* str) { return Detail::convertIntoString( StringRef( str, Detail::catch_strnlen( str, SZ ) ) ); } }; template struct StringMaker { static std::string convert(signed char const* str) { auto reinterpreted = reinterpret_cast(str); return Detail::convertIntoString( StringRef(reinterpreted, Detail::catch_strnlen(reinterpreted, SZ))); } }; template struct StringMaker { static std::string convert(unsigned char const* str) { auto reinterpreted = reinterpret_cast(str); return Detail::convertIntoString( StringRef(reinterpreted, Detail::catch_strnlen(reinterpreted, SZ))); } }; #if defined(CATCH_CONFIG_CPP17_BYTE) template<> struct StringMaker { static std::string convert(std::byte value); }; #endif // defined(CATCH_CONFIG_CPP17_BYTE) template<> struct StringMaker { static std::string convert(int value); }; template<> struct StringMaker { static std::string convert(long value); }; template<> struct StringMaker { static std::string convert(long long value); }; template<> struct StringMaker { static std::string convert(unsigned int value); }; template<> struct StringMaker { static std::string convert(unsigned long value); }; template<> struct StringMaker { static std::string convert(unsigned long long value); }; template<> struct StringMaker { static std::string convert(bool b) { using namespace std::string_literals; return b ? "true"s : "false"s; } }; template<> struct StringMaker { static std::string convert(char c); }; template<> struct StringMaker { static std::string convert(signed char c); }; template<> struct StringMaker { static std::string convert(unsigned char c); }; template<> struct StringMaker { static std::string convert(std::nullptr_t) { using namespace std::string_literals; return "nullptr"s; } }; template<> struct StringMaker { static std::string convert(float value); CATCH_EXPORT static int precision; }; template<> struct StringMaker { static std::string convert(double value); CATCH_EXPORT static int precision; }; template struct StringMaker { template static std::string convert(U* p) { if (p) { return ::Catch::Detail::rawMemoryToString(p); } else { return "nullptr"; } } }; template struct StringMaker { static std::string convert(R C::* p) { if (p) { return ::Catch::Detail::rawMemoryToString(p); } else { return "nullptr"; } } }; #if defined(_MANAGED) template struct StringMaker { static std::string convert( T^ ref ) { return ::Catch::Detail::clrReferenceToString(ref); } }; #endif namespace Detail { template std::string rangeToString(InputIterator first, Sentinel last) { ReusableStringStream rss; rss << "{ "; if (first != last) { rss << ::Catch::Detail::stringify(*first); for (++first; first != last; ++first) rss << ", " << ::Catch::Detail::stringify(*first); } rss << " }"; return rss.str(); } } } // namespace Catch ////////////////////////////////////////////////////// // Separate std-lib types stringification, so it can be selectively enabled // This means that we do not bring in their headers #if defined(CATCH_CONFIG_ENABLE_ALL_STRINGMAKERS) # define CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER # define CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER # define CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER # define CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER #endif // Separate std::pair specialization #if defined(CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER) #include namespace Catch { template struct StringMaker > { static std::string convert(const std::pair& pair) { ReusableStringStream rss; rss << "{ " << ::Catch::Detail::stringify(pair.first) << ", " << ::Catch::Detail::stringify(pair.second) << " }"; return rss.str(); } }; } #endif // CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER #if defined(CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER) && defined(CATCH_CONFIG_CPP17_OPTIONAL) #include namespace Catch { template struct StringMaker > { static std::string convert(const std::optional& optional) { if (optional.has_value()) { return ::Catch::Detail::stringify(*optional); } else { return "{ }"; } } }; } #endif // CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER // Separate std::tuple specialization #if defined(CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER) #include namespace Catch { namespace Detail { template< typename Tuple, std::size_t N = 0, bool = (N < std::tuple_size::value) > struct TupleElementPrinter { static void print(const Tuple& tuple, std::ostream& os) { os << (N ? ", " : " ") << ::Catch::Detail::stringify(std::get(tuple)); TupleElementPrinter::print(tuple, os); } }; template< typename Tuple, std::size_t N > struct TupleElementPrinter { static void print(const Tuple&, std::ostream&) {} }; } template struct StringMaker> { static std::string convert(const std::tuple& tuple) { ReusableStringStream rss; rss << '{'; Detail::TupleElementPrinter>::print(tuple, rss.get()); rss << " }"; return rss.str(); } }; } #endif // CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER #if defined(CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER) && defined(CATCH_CONFIG_CPP17_VARIANT) #include namespace Catch { template<> struct StringMaker { static std::string convert(const std::monostate&) { return "{ }"; } }; template struct StringMaker> { static std::string convert(const std::variant& variant) { if (variant.valueless_by_exception()) { return "{valueless variant}"; } else { return std::visit( [](const auto& value) { return ::Catch::Detail::stringify(value); }, variant ); } } }; } #endif // CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER namespace Catch { // Import begin/ end from std here using std::begin; using std::end; namespace Detail { template struct is_range_impl : std::false_type {}; template struct is_range_impl()))>> : std::true_type {}; } // namespace Detail template struct is_range : Detail::is_range_impl {}; #if defined(_MANAGED) // Managed types are never ranges template struct is_range { static const bool value = false; }; #endif template std::string rangeToString( Range const& range ) { return ::Catch::Detail::rangeToString( begin( range ), end( range ) ); } // Handle vector specially template std::string rangeToString( std::vector const& v ) { ReusableStringStream rss; rss << "{ "; bool first = true; for( bool b : v ) { if( first ) first = false; else rss << ", "; rss << ::Catch::Detail::stringify( b ); } rss << " }"; return rss.str(); } template struct StringMaker::value && !::Catch::Detail::IsStreamInsertable::value>> { static std::string convert( R const& range ) { return rangeToString( range ); } }; template struct StringMaker { static std::string convert(T const(&arr)[SZ]) { return rangeToString(arr); } }; } // namespace Catch // Separate std::chrono::duration specialization #include #include #include namespace Catch { template struct ratio_string { static std::string symbol() { Catch::ReusableStringStream rss; rss << '[' << Ratio::num << '/' << Ratio::den << ']'; return rss.str(); } }; template <> struct ratio_string { static char symbol() { return 'a'; } }; template <> struct ratio_string { static char symbol() { return 'f'; } }; template <> struct ratio_string { static char symbol() { return 'p'; } }; template <> struct ratio_string { static char symbol() { return 'n'; } }; template <> struct ratio_string { static char symbol() { return 'u'; } }; template <> struct ratio_string { static char symbol() { return 'm'; } }; //////////// // std::chrono::duration specializations template struct StringMaker> { static std::string convert(std::chrono::duration const& duration) { ReusableStringStream rss; rss << duration.count() << ' ' << ratio_string::symbol() << 's'; return rss.str(); } }; template struct StringMaker>> { static std::string convert(std::chrono::duration> const& duration) { ReusableStringStream rss; rss << duration.count() << " s"; return rss.str(); } }; template struct StringMaker>> { static std::string convert(std::chrono::duration> const& duration) { ReusableStringStream rss; rss << duration.count() << " m"; return rss.str(); } }; template struct StringMaker>> { static std::string convert(std::chrono::duration> const& duration) { ReusableStringStream rss; rss << duration.count() << " h"; return rss.str(); } }; //////////// // std::chrono::time_point specialization // Generic time_point cannot be specialized, only std::chrono::time_point template struct StringMaker> { static std::string convert(std::chrono::time_point const& time_point) { return ::Catch::Detail::stringify(time_point.time_since_epoch()) + " since epoch"; } }; // std::chrono::time_point specialization template struct StringMaker> { static std::string convert(std::chrono::time_point const& time_point) { auto converted = std::chrono::system_clock::to_time_t(time_point); #ifdef _MSC_VER std::tm timeInfo = {}; gmtime_s(&timeInfo, &converted); #else std::tm* timeInfo = std::gmtime(&converted); #endif auto const timeStampSize = sizeof("2017-01-16T17:06:45Z"); char timeStamp[timeStampSize]; const char * const fmt = "%Y-%m-%dT%H:%M:%SZ"; #ifdef _MSC_VER std::strftime(timeStamp, timeStampSize, fmt, &timeInfo); #else std::strftime(timeStamp, timeStampSize, fmt, timeInfo); #endif return std::string(timeStamp, timeStampSize - 1); } }; } #define INTERNAL_CATCH_REGISTER_ENUM( enumName, ... ) \ namespace Catch { \ template<> struct StringMaker { \ static std::string convert( enumName value ) { \ static const auto& enumInfo = ::Catch::getMutableRegistryHub().getMutableEnumValuesRegistry().registerEnum( #enumName, #__VA_ARGS__, { __VA_ARGS__ } ); \ return static_cast(enumInfo.lookup( static_cast( value ) )); \ } \ }; \ } #define CATCH_REGISTER_ENUM( enumName, ... ) INTERNAL_CATCH_REGISTER_ENUM( enumName, __VA_ARGS__ ) #ifdef _MSC_VER #pragma warning(pop) #endif #endif // CATCH_TOSTRING_HPP_INCLUDED #include namespace Catch { class Approx { private: bool equalityComparisonImpl(double other) const; // Sets and validates the new margin (margin >= 0) void setMargin(double margin); // Sets and validates the new epsilon (0 < epsilon < 1) void setEpsilon(double epsilon); public: explicit Approx ( double value ); static Approx custom(); Approx operator-() const; template ::value>> Approx operator()( T const& value ) const { Approx approx( static_cast(value) ); approx.m_epsilon = m_epsilon; approx.m_margin = m_margin; approx.m_scale = m_scale; return approx; } template ::value>> explicit Approx( T const& value ): Approx(static_cast(value)) {} template ::value>> friend bool operator == ( const T& lhs, Approx const& rhs ) { auto lhs_v = static_cast(lhs); return rhs.equalityComparisonImpl(lhs_v); } template ::value>> friend bool operator == ( Approx const& lhs, const T& rhs ) { return operator==( rhs, lhs ); } template ::value>> friend bool operator != ( T const& lhs, Approx const& rhs ) { return !operator==( lhs, rhs ); } template ::value>> friend bool operator != ( Approx const& lhs, T const& rhs ) { return !operator==( rhs, lhs ); } template ::value>> friend bool operator <= ( T const& lhs, Approx const& rhs ) { return static_cast(lhs) < rhs.m_value || lhs == rhs; } template ::value>> friend bool operator <= ( Approx const& lhs, T const& rhs ) { return lhs.m_value < static_cast(rhs) || lhs == rhs; } template ::value>> friend bool operator >= ( T const& lhs, Approx const& rhs ) { return static_cast(lhs) > rhs.m_value || lhs == rhs; } template ::value>> friend bool operator >= ( Approx const& lhs, T const& rhs ) { return lhs.m_value > static_cast(rhs) || lhs == rhs; } template ::value>> Approx& epsilon( T const& newEpsilon ) { const auto epsilonAsDouble = static_cast(newEpsilon); setEpsilon(epsilonAsDouble); return *this; } template ::value>> Approx& margin( T const& newMargin ) { const auto marginAsDouble = static_cast(newMargin); setMargin(marginAsDouble); return *this; } template ::value>> Approx& scale( T const& newScale ) { m_scale = static_cast(newScale); return *this; } std::string toString() const; private: double m_epsilon; double m_margin; double m_scale; double m_value; }; namespace literals { Approx operator ""_a(long double val); Approx operator ""_a(unsigned long long val); } // end namespace literals template<> struct StringMaker { static std::string convert(Catch::Approx const& value); }; } // end namespace Catch #endif // CATCH_APPROX_HPP_INCLUDED #ifndef CATCH_CONFIG_HPP_INCLUDED #define CATCH_CONFIG_HPP_INCLUDED #ifndef CATCH_TEST_SPEC_HPP_INCLUDED #define CATCH_TEST_SPEC_HPP_INCLUDED #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wpadded" #endif #ifndef CATCH_WILDCARD_PATTERN_HPP_INCLUDED #define CATCH_WILDCARD_PATTERN_HPP_INCLUDED #ifndef CATCH_CASE_SENSITIVE_HPP_INCLUDED #define CATCH_CASE_SENSITIVE_HPP_INCLUDED namespace Catch { enum class CaseSensitive { Yes, No }; } // namespace Catch #endif // CATCH_CASE_SENSITIVE_HPP_INCLUDED #include namespace Catch { class WildcardPattern { enum WildcardPosition { NoWildcard = 0, WildcardAtStart = 1, WildcardAtEnd = 2, WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd }; public: WildcardPattern( std::string const& pattern, CaseSensitive caseSensitivity ); bool matches( std::string const& str ) const; private: std::string normaliseString( std::string const& str ) const; CaseSensitive m_caseSensitivity; WildcardPosition m_wildcard = NoWildcard; std::string m_pattern; }; } #endif // CATCH_WILDCARD_PATTERN_HPP_INCLUDED #include #include #include namespace Catch { class IConfig; struct TestCaseInfo; class TestCaseHandle; class TestSpec { class Pattern { public: explicit Pattern( std::string const& name ); virtual ~Pattern(); virtual bool matches( TestCaseInfo const& testCase ) const = 0; std::string const& name() const; private: virtual void serializeTo( std::ostream& out ) const = 0; // Writes string that would be reparsed into the pattern friend std::ostream& operator<<(std::ostream& out, Pattern const& pattern) { pattern.serializeTo( out ); return out; } std::string const m_name; }; class NamePattern : public Pattern { public: explicit NamePattern( std::string const& name, std::string const& filterString ); bool matches( TestCaseInfo const& testCase ) const override; private: void serializeTo( std::ostream& out ) const override; WildcardPattern m_wildcardPattern; }; class TagPattern : public Pattern { public: explicit TagPattern( std::string const& tag, std::string const& filterString ); bool matches( TestCaseInfo const& testCase ) const override; private: void serializeTo( std::ostream& out ) const override; std::string m_tag; }; struct Filter { std::vector> m_required; std::vector> m_forbidden; //! Serializes this filter into a string that would be parsed into //! an equivalent filter void serializeTo( std::ostream& out ) const; friend std::ostream& operator<<(std::ostream& out, Filter const& f) { f.serializeTo( out ); return out; } bool matches( TestCaseInfo const& testCase ) const; }; static std::string extractFilterName( Filter const& filter ); public: struct FilterMatch { std::string name; std::vector tests; }; using Matches = std::vector; using vectorStrings = std::vector; bool hasFilters() const; bool matches( TestCaseInfo const& testCase ) const; Matches matchesByFilter( std::vector const& testCases, IConfig const& config ) const; const vectorStrings & getInvalidSpecs() const; private: std::vector m_filters; std::vector m_invalidSpecs; friend class TestSpecParser; //! Serializes this test spec into a string that would be parsed into //! equivalent test spec void serializeTo( std::ostream& out ) const; friend std::ostream& operator<<(std::ostream& out, TestSpec const& spec) { spec.serializeTo( out ); return out; } }; } #ifdef __clang__ #pragma clang diagnostic pop #endif #endif // CATCH_TEST_SPEC_HPP_INCLUDED #ifndef CATCH_OPTIONAL_HPP_INCLUDED #define CATCH_OPTIONAL_HPP_INCLUDED #include namespace Catch { // An optional type template class Optional { public: Optional() : nullableValue( nullptr ) {} Optional( T const& _value ) : nullableValue( new( storage ) T( _value ) ) {} Optional( Optional const& _other ) : nullableValue( _other ? new( storage ) T( *_other ) : nullptr ) {} ~Optional() { reset(); } Optional& operator= ( Optional const& _other ) { if( &_other != this ) { reset(); if( _other ) nullableValue = new( storage ) T( *_other ); } return *this; } Optional& operator = ( T const& _value ) { reset(); nullableValue = new( storage ) T( _value ); return *this; } void reset() { if( nullableValue ) nullableValue->~T(); nullableValue = nullptr; } T& operator*() { assert(nullableValue); return *nullableValue; } T const& operator*() const { assert(nullableValue); return *nullableValue; } T* operator->() { assert(nullableValue); return nullableValue; } const T* operator->() const { assert(nullableValue); return nullableValue; } T valueOr( T const& defaultValue ) const { return nullableValue ? *nullableValue : defaultValue; } bool some() const { return nullableValue != nullptr; } bool none() const { return nullableValue == nullptr; } bool operator !() const { return nullableValue == nullptr; } explicit operator bool() const { return some(); } friend bool operator==(Optional const& a, Optional const& b) { if (a.none() && b.none()) { return true; } else if (a.some() && b.some()) { return *a == *b; } else { return false; } } friend bool operator!=(Optional const& a, Optional const& b) { return !( a == b ); } private: T *nullableValue; alignas(alignof(T)) char storage[sizeof(T)]; }; } // end namespace Catch #endif // CATCH_OPTIONAL_HPP_INCLUDED #ifndef CATCH_RANDOM_SEED_GENERATION_HPP_INCLUDED #define CATCH_RANDOM_SEED_GENERATION_HPP_INCLUDED #include namespace Catch { enum class GenerateFrom { Time, RandomDevice, //! Currently equivalent to RandomDevice, but can change at any point Default }; std::uint32_t generateRandomSeed(GenerateFrom from); } // end namespace Catch #endif // CATCH_RANDOM_SEED_GENERATION_HPP_INCLUDED #ifndef CATCH_REPORTER_SPEC_PARSER_HPP_INCLUDED #define CATCH_REPORTER_SPEC_PARSER_HPP_INCLUDED #ifndef CATCH_CONSOLE_COLOUR_HPP_INCLUDED #define CATCH_CONSOLE_COLOUR_HPP_INCLUDED #include #include namespace Catch { enum class ColourMode : std::uint8_t; class IStream; struct Colour { enum Code { None = 0, White, Red, Green, Blue, Cyan, Yellow, Grey, Bright = 0x10, BrightRed = Bright | Red, BrightGreen = Bright | Green, LightGrey = Bright | Grey, BrightWhite = Bright | White, BrightYellow = Bright | Yellow, // By intention FileName = LightGrey, Warning = BrightYellow, ResultError = BrightRed, ResultSuccess = BrightGreen, ResultExpectedFailure = Warning, Error = BrightRed, Success = Green, Skip = LightGrey, OriginalExpression = Cyan, ReconstructedExpression = BrightYellow, SecondaryText = LightGrey, Headers = White }; }; class ColourImpl { protected: //! The associated stream of this ColourImpl instance IStream* m_stream; public: ColourImpl( IStream* stream ): m_stream( stream ) {} //! RAII wrapper around writing specific colour of text using specific //! colour impl into a stream. class ColourGuard { ColourImpl const* m_colourImpl; Colour::Code m_code; bool m_engaged = false; public: //! Does **not** engage the guard/start the colour ColourGuard( Colour::Code code, ColourImpl const* colour ); ColourGuard( ColourGuard const& rhs ) = delete; ColourGuard& operator=( ColourGuard const& rhs ) = delete; ColourGuard( ColourGuard&& rhs ) noexcept; ColourGuard& operator=( ColourGuard&& rhs ) noexcept; //! Removes colour _if_ the guard was engaged ~ColourGuard(); /** * Explicitly engages colour for given stream. * * The API based on operator<< should be preferred. */ ColourGuard& engage( std::ostream& stream ) &; /** * Explicitly engages colour for given stream. * * The API based on operator<< should be preferred. */ ColourGuard&& engage( std::ostream& stream ) &&; private: //! Engages the guard and starts using colour friend std::ostream& operator<<( std::ostream& lhs, ColourGuard& guard ) { guard.engageImpl( lhs ); return lhs; } //! Engages the guard and starts using colour friend std::ostream& operator<<( std::ostream& lhs, ColourGuard&& guard) { guard.engageImpl( lhs ); return lhs; } void engageImpl( std::ostream& stream ); }; virtual ~ColourImpl(); // = default /** * Creates a guard object for given colour and this colour impl * * **Important:** * the guard starts disengaged, and has to be engaged explicitly. */ ColourGuard guardColour( Colour::Code colourCode ); private: virtual void use( Colour::Code colourCode ) const = 0; }; //! Provides ColourImpl based on global config and target compilation platform Detail::unique_ptr makeColourImpl( ColourMode colourSelection, IStream* stream ); //! Checks if specific colour impl has been compiled into the binary bool isColourImplAvailable( ColourMode colourSelection ); } // end namespace Catch #endif // CATCH_CONSOLE_COLOUR_HPP_INCLUDED #include #include #include namespace Catch { enum class ColourMode : std::uint8_t; namespace Detail { //! Splits the reporter spec into reporter name and kv-pair options std::vector splitReporterSpec( StringRef reporterSpec ); Optional stringToColourMode( StringRef colourMode ); } /** * Structured reporter spec that a reporter can be created from * * Parsing has been validated, but semantics have not. This means e.g. * that the colour mode is known to Catch2, but it might not be * compiled into the binary, and the output filename might not be * openable. */ class ReporterSpec { std::string m_name; Optional m_outputFileName; Optional m_colourMode; std::map m_customOptions; friend bool operator==( ReporterSpec const& lhs, ReporterSpec const& rhs ); friend bool operator!=( ReporterSpec const& lhs, ReporterSpec const& rhs ) { return !( lhs == rhs ); } public: ReporterSpec( std::string name, Optional outputFileName, Optional colourMode, std::map customOptions ); std::string const& name() const { return m_name; } Optional const& outputFile() const { return m_outputFileName; } Optional const& colourMode() const { return m_colourMode; } std::map const& customOptions() const { return m_customOptions; } }; /** * Parses provided reporter spec string into * * Returns empty optional on errors, e.g. * * field that is not first and not a key+value pair * * duplicated keys in kv pair * * unknown catch reporter option * * empty key/value in an custom kv pair * * ... */ Optional parseReporterSpec( StringRef reporterSpec ); } #endif // CATCH_REPORTER_SPEC_PARSER_HPP_INCLUDED #include #include #include #include namespace Catch { class IStream; /** * `ReporterSpec` but with the defaults filled in. * * Like `ReporterSpec`, the semantics are unchecked. */ struct ProcessedReporterSpec { std::string name; std::string outputFilename; ColourMode colourMode; std::map customOptions; friend bool operator==( ProcessedReporterSpec const& lhs, ProcessedReporterSpec const& rhs ); friend bool operator!=( ProcessedReporterSpec const& lhs, ProcessedReporterSpec const& rhs ) { return !( lhs == rhs ); } }; struct ConfigData { bool listTests = false; bool listTags = false; bool listReporters = false; bool listListeners = false; bool showSuccessfulTests = false; bool shouldDebugBreak = false; bool noThrow = false; bool showHelp = false; bool showInvisibles = false; bool filenamesAsTags = false; bool libIdentify = false; bool allowZeroTests = false; int abortAfter = -1; uint32_t rngSeed = generateRandomSeed(GenerateFrom::Default); unsigned int shardCount = 1; unsigned int shardIndex = 0; bool skipBenchmarks = false; bool benchmarkNoAnalysis = false; unsigned int benchmarkSamples = 100; double benchmarkConfidenceInterval = 0.95; unsigned int benchmarkResamples = 100000; std::chrono::milliseconds::rep benchmarkWarmupTime = 100; Verbosity verbosity = Verbosity::Normal; WarnAbout::What warnings = WarnAbout::Nothing; ShowDurations showDurations = ShowDurations::DefaultForReporter; double minDuration = -1; TestRunOrder runOrder = TestRunOrder::Declared; ColourMode defaultColourMode = ColourMode::PlatformDefault; WaitForKeypress::When waitForKeypress = WaitForKeypress::Never; std::string defaultOutputFilename; std::string name; std::string processName; std::vector reporterSpecifications; std::vector testsOrTags; std::vector sectionsToRun; }; class Config : public IConfig { public: Config() = default; Config( ConfigData const& data ); ~Config() override; // = default in the cpp file bool listTests() const; bool listTags() const; bool listReporters() const; bool listListeners() const; std::vector const& getReporterSpecs() const; std::vector const& getProcessedReporterSpecs() const; std::vector const& getTestsOrTags() const override; std::vector const& getSectionsToRun() const override; TestSpec const& testSpec() const override; bool hasTestFilters() const override; bool showHelp() const; // IConfig interface bool allowThrows() const override; StringRef name() const override; bool includeSuccessfulResults() const override; bool warnAboutMissingAssertions() const override; bool warnAboutUnmatchedTestSpecs() const override; bool zeroTestsCountAsSuccess() const override; ShowDurations showDurations() const override; double minDuration() const override; TestRunOrder runOrder() const override; uint32_t rngSeed() const override; unsigned int shardCount() const override; unsigned int shardIndex() const override; ColourMode defaultColourMode() const override; bool shouldDebugBreak() const override; int abortAfter() const override; bool showInvisibles() const override; Verbosity verbosity() const override; bool skipBenchmarks() const override; bool benchmarkNoAnalysis() const override; unsigned int benchmarkSamples() const override; double benchmarkConfidenceInterval() const override; unsigned int benchmarkResamples() const override; std::chrono::milliseconds benchmarkWarmupTime() const override; private: // Reads Bazel env vars and applies them to the config void readBazelEnvVars(); ConfigData m_data; std::vector m_processedReporterSpecs; TestSpec m_testSpec; bool m_hasTestFilters = false; }; } // end namespace Catch #endif // CATCH_CONFIG_HPP_INCLUDED #ifndef CATCH_GET_RANDOM_SEED_HPP_INCLUDED #define CATCH_GET_RANDOM_SEED_HPP_INCLUDED #include namespace Catch { //! Returns Catch2's current RNG seed. std::uint32_t getSeed(); } #endif // CATCH_GET_RANDOM_SEED_HPP_INCLUDED #ifndef CATCH_MESSAGE_HPP_INCLUDED #define CATCH_MESSAGE_HPP_INCLUDED #ifndef CATCH_STREAM_END_STOP_HPP_INCLUDED #define CATCH_STREAM_END_STOP_HPP_INCLUDED namespace Catch { // Use this in variadic streaming macros to allow // << +StreamEndStop // as well as // << stuff +StreamEndStop struct StreamEndStop { StringRef operator+() const { return StringRef(); } template friend T const& operator+( T const& value, StreamEndStop ) { return value; } }; } // namespace Catch #endif // CATCH_STREAM_END_STOP_HPP_INCLUDED #include #include namespace Catch { struct SourceLineInfo; struct MessageStream { template MessageStream& operator << ( T const& value ) { m_stream << value; return *this; } ReusableStringStream m_stream; }; struct MessageBuilder : MessageStream { MessageBuilder( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType type ): m_info(macroName, lineInfo, type) {} template MessageBuilder&& operator << ( T const& value ) && { m_stream << value; return CATCH_MOVE(*this); } MessageInfo m_info; }; class ScopedMessage { public: explicit ScopedMessage( MessageBuilder&& builder ); ScopedMessage( ScopedMessage& duplicate ) = delete; ScopedMessage( ScopedMessage&& old ) noexcept; ~ScopedMessage(); MessageInfo m_info; bool m_moved = false; }; class Capturer { std::vector m_messages; IResultCapture& m_resultCapture = getResultCapture(); size_t m_captured = 0; public: Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names ); Capturer(Capturer const&) = delete; Capturer& operator=(Capturer const&) = delete; ~Capturer(); void captureValue( size_t index, std::string const& value ); template void captureValues( size_t index, T const& value ) { captureValue( index, Catch::Detail::stringify( value ) ); } template void captureValues( size_t index, T const& value, Ts const&... values ) { captureValue( index, Catch::Detail::stringify(value) ); captureValues( index+1, values... ); } }; } // end namespace Catch /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \ do { \ 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, ... ) \ Catch::Capturer varName( macroName##_catch_sr, \ CATCH_INTERNAL_LINEINFO, \ Catch::ResultWas::Info, \ #__VA_ARGS__##_catch_sr ); \ varName.captureValues( 0, __VA_ARGS__ ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_INFO( macroName, log ) \ const Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage )( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_UNSCOPED_INFO( macroName, log ) \ Catch::getResultCapture().emplaceUnscopedMessage( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log ) #if defined(CATCH_CONFIG_PREFIX_ALL) && !defined(CATCH_CONFIG_DISABLE) #define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg ) #define CATCH_UNSCOPED_INFO( msg ) INTERNAL_CATCH_UNSCOPED_INFO( "CATCH_UNSCOPED_INFO", msg ) #define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( "CATCH_WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg ) #define CATCH_CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CATCH_CAPTURE", __VA_ARGS__ ) #elif defined(CATCH_CONFIG_PREFIX_ALL) && defined(CATCH_CONFIG_DISABLE) #define CATCH_INFO( msg ) (void)(0) #define CATCH_UNSCOPED_INFO( msg ) (void)(0) #define CATCH_WARN( msg ) (void)(0) #define CATCH_CAPTURE( ... ) (void)(0) #elif !defined(CATCH_CONFIG_PREFIX_ALL) && !defined(CATCH_CONFIG_DISABLE) #define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg ) #define UNSCOPED_INFO( msg ) INTERNAL_CATCH_UNSCOPED_INFO( "UNSCOPED_INFO", msg ) #define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg ) #define CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CAPTURE", __VA_ARGS__ ) #elif !defined(CATCH_CONFIG_PREFIX_ALL) && defined(CATCH_CONFIG_DISABLE) #define INFO( msg ) (void)(0) #define UNSCOPED_INFO( msg ) (void)(0) #define WARN( msg ) (void)(0) #define CAPTURE( ... ) (void)(0) #endif // end of user facing macro declarations #endif // CATCH_MESSAGE_HPP_INCLUDED #ifndef CATCH_SESSION_HPP_INCLUDED #define CATCH_SESSION_HPP_INCLUDED #ifndef CATCH_COMMANDLINE_HPP_INCLUDED #define CATCH_COMMANDLINE_HPP_INCLUDED #ifndef CATCH_CLARA_HPP_INCLUDED #define CATCH_CLARA_HPP_INCLUDED #if defined( __clang__ ) # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wweak-vtables" # pragma clang diagnostic ignored "-Wshadow" # pragma clang diagnostic ignored "-Wdeprecated" #endif #if defined( __GNUC__ ) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wsign-conversion" #endif #ifndef CLARA_CONFIG_OPTIONAL_TYPE # ifdef __has_include # if __has_include( ) && __cplusplus >= 201703L # include # define CLARA_CONFIG_OPTIONAL_TYPE std::optional # endif # endif #endif #include #include #include #include #include #include #include namespace Catch { namespace Clara { class Args; class Parser; // enum of result types from a parse enum class ParseResultType { Matched, NoMatch, ShortCircuitAll, ShortCircuitSame }; struct accept_many_t {}; constexpr accept_many_t accept_many {}; namespace Detail { struct fake_arg { template operator T(); }; template struct is_unary_function : std::false_type {}; template struct is_unary_function< F, Catch::Detail::void_t()( fake_arg() ) ) > > : std::true_type {}; // Traits for extracting arg and return type of lambdas (for single // argument lambdas) template struct UnaryLambdaTraits : UnaryLambdaTraits {}; template struct UnaryLambdaTraits { static const bool isValid = false; }; template struct UnaryLambdaTraits { static const bool isValid = true; using ArgType = std::remove_const_t>; using ReturnType = ReturnT; }; class TokenStream; // Wraps a token coming from a token stream. These may not directly // correspond to strings as a single string may encode an option + // its argument if the : or = form is used enum class TokenType { Option, Argument }; struct Token { TokenType type; std::string token; }; // Abstracts iterators into args as a stream of tokens, with option // arguments uniformly handled class TokenStream { using Iterator = std::vector::const_iterator; Iterator it; Iterator itEnd; std::vector m_tokenBuffer; void loadBuffer(); public: explicit TokenStream( Args const& args ); TokenStream( Iterator it, Iterator itEnd ); explicit operator bool() const { return !m_tokenBuffer.empty() || it != itEnd; } size_t count() const { return m_tokenBuffer.size() + ( itEnd - it ); } Token operator*() const { assert( !m_tokenBuffer.empty() ); return m_tokenBuffer.front(); } Token const* operator->() const { assert( !m_tokenBuffer.empty() ); return &m_tokenBuffer.front(); } TokenStream& operator++(); }; //! Denotes type of a parsing result enum class ResultType { Ok, ///< No errors LogicError, ///< Error in user-specified arguments for ///< construction RuntimeError ///< Error in parsing inputs }; class ResultBase { protected: ResultBase( ResultType type ): m_type( type ) {} virtual ~ResultBase(); // = default; ResultBase(ResultBase const&) = default; ResultBase& operator=(ResultBase const&) = default; ResultBase(ResultBase&&) = default; ResultBase& operator=(ResultBase&&) = default; virtual void enforceOk() const = 0; ResultType m_type; }; template class ResultValueBase : public ResultBase { public: auto value() const -> T const& { enforceOk(); return m_value; } protected: ResultValueBase( ResultType type ): ResultBase( type ) {} ResultValueBase( ResultValueBase const& other ): ResultBase( other ) { if ( m_type == ResultType::Ok ) new ( &m_value ) T( other.m_value ); } ResultValueBase( ResultType, T const& value ): ResultBase( ResultType::Ok ) { new ( &m_value ) T( value ); } auto operator=( ResultValueBase const& other ) -> ResultValueBase& { if ( m_type == ResultType::Ok ) m_value.~T(); ResultBase::operator=( other ); if ( m_type == ResultType::Ok ) new ( &m_value ) T( other.m_value ); return *this; } ~ResultValueBase() override { if ( m_type == ResultType::Ok ) m_value.~T(); } union { T m_value; }; }; template <> class ResultValueBase : public ResultBase { protected: using ResultBase::ResultBase; }; template class BasicResult : public ResultValueBase { public: template explicit BasicResult( BasicResult const& other ): ResultValueBase( other.type() ), m_errorMessage( other.errorMessage() ) { assert( type() != ResultType::Ok ); } template static auto ok( U const& value ) -> BasicResult { return { ResultType::Ok, value }; } static auto ok() -> BasicResult { return { ResultType::Ok }; } static auto logicError( std::string&& message ) -> BasicResult { return { ResultType::LogicError, CATCH_MOVE(message) }; } static auto runtimeError( std::string&& message ) -> BasicResult { return { ResultType::RuntimeError, CATCH_MOVE(message) }; } explicit operator bool() const { return m_type == ResultType::Ok; } auto type() const -> ResultType { return m_type; } auto errorMessage() const -> std::string const& { return m_errorMessage; } protected: void enforceOk() const override { // Errors shouldn't reach this point, but if they do // the actual error message will be in m_errorMessage assert( m_type != ResultType::LogicError ); assert( m_type != ResultType::RuntimeError ); if ( m_type != ResultType::Ok ) std::abort(); } std::string m_errorMessage; // Only populated if resultType is an error BasicResult( ResultType type, std::string&& message ): ResultValueBase( type ), m_errorMessage( CATCH_MOVE(message) ) { assert( m_type != ResultType::Ok ); } using ResultValueBase::ResultValueBase; using ResultBase::m_type; }; class ParseState { public: ParseState( ParseResultType type, TokenStream const& remainingTokens ); ParseResultType type() const { return m_type; } TokenStream const& remainingTokens() const { return m_remainingTokens; } private: ParseResultType m_type; TokenStream m_remainingTokens; }; using Result = BasicResult; using ParserResult = BasicResult; using InternalParseResult = BasicResult; struct HelpColumns { std::string left; std::string right; }; template ParserResult convertInto( std::string const& source, T& target ) { std::stringstream ss( source ); ss >> target; if ( ss.fail() ) { return ParserResult::runtimeError( "Unable to convert '" + source + "' to destination type" ); } else { return ParserResult::ok( ParseResultType::Matched ); } } ParserResult convertInto( std::string const& source, std::string& target ); ParserResult convertInto( std::string const& source, bool& target ); #ifdef CLARA_CONFIG_OPTIONAL_TYPE template auto convertInto( std::string const& source, CLARA_CONFIG_OPTIONAL_TYPE& target ) -> ParserResult { T temp; auto result = convertInto( source, temp ); if ( result ) target = CATCH_MOVE( temp ); return result; } #endif // CLARA_CONFIG_OPTIONAL_TYPE struct BoundRef : Catch::Detail::NonCopyable { virtual ~BoundRef() = default; virtual bool isContainer() const; virtual bool isFlag() const; }; struct BoundValueRefBase : BoundRef { virtual auto setValue( std::string const& arg ) -> ParserResult = 0; }; struct BoundFlagRefBase : BoundRef { virtual auto setFlag( bool flag ) -> ParserResult = 0; bool isFlag() const override; }; template struct BoundValueRef : BoundValueRefBase { T& m_ref; explicit BoundValueRef( T& ref ): m_ref( ref ) {} ParserResult setValue( std::string const& arg ) override { return convertInto( arg, m_ref ); } }; template struct BoundValueRef> : BoundValueRefBase { std::vector& m_ref; explicit BoundValueRef( std::vector& ref ): m_ref( ref ) {} auto isContainer() const -> bool override { return true; } auto setValue( std::string const& arg ) -> ParserResult override { T temp; auto result = convertInto( arg, temp ); if ( result ) m_ref.push_back( temp ); return result; } }; struct BoundFlagRef : BoundFlagRefBase { bool& m_ref; explicit BoundFlagRef( bool& ref ): m_ref( ref ) {} ParserResult setFlag( bool flag ) override; }; template struct LambdaInvoker { static_assert( std::is_same::value, "Lambda must return void or clara::ParserResult" ); template static auto invoke( L const& lambda, ArgType const& arg ) -> ParserResult { return lambda( arg ); } }; template <> struct LambdaInvoker { template static auto invoke( L const& lambda, ArgType const& arg ) -> ParserResult { lambda( arg ); return ParserResult::ok( ParseResultType::Matched ); } }; template auto invokeLambda( L const& lambda, std::string const& arg ) -> ParserResult { ArgType temp{}; auto result = convertInto( arg, temp ); return !result ? result : LambdaInvoker::ReturnType>::invoke( lambda, temp ); } template struct BoundLambda : BoundValueRefBase { L m_lambda; static_assert( UnaryLambdaTraits::isValid, "Supplied lambda must take exactly one argument" ); explicit BoundLambda( L const& lambda ): m_lambda( lambda ) {} auto setValue( std::string const& arg ) -> ParserResult override { return invokeLambda::ArgType>( m_lambda, arg ); } }; template struct BoundManyLambda : BoundLambda { explicit BoundManyLambda( L const& lambda ): BoundLambda( lambda ) {} bool isContainer() const override { return true; } }; template struct BoundFlagLambda : BoundFlagRefBase { L m_lambda; static_assert( UnaryLambdaTraits::isValid, "Supplied lambda must take exactly one argument" ); static_assert( std::is_same::ArgType, bool>::value, "flags must be boolean" ); explicit BoundFlagLambda( L const& lambda ): m_lambda( lambda ) {} auto setFlag( bool flag ) -> ParserResult override { return LambdaInvoker::ReturnType>::invoke( m_lambda, flag ); } }; enum class Optionality { Optional, Required }; class ParserBase { public: virtual ~ParserBase() = default; virtual auto validate() const -> Result { return Result::ok(); } virtual auto parse( std::string const& exeName, TokenStream const& tokens ) const -> InternalParseResult = 0; virtual size_t cardinality() const; InternalParseResult parse( Args const& args ) const; }; template class ComposableParserImpl : public ParserBase { public: template auto operator|( T const& other ) const -> Parser; }; // Common code and state for Args and Opts template class ParserRefImpl : public ComposableParserImpl { protected: Optionality m_optionality = Optionality::Optional; std::shared_ptr m_ref; std::string m_hint; std::string m_description; explicit ParserRefImpl( std::shared_ptr const& ref ): m_ref( ref ) {} public: template ParserRefImpl( accept_many_t, LambdaT const& ref, std::string const& hint ): m_ref( std::make_shared>( ref ) ), m_hint( hint ) {} template ::value>> ParserRefImpl( T& ref, std::string const& hint ): m_ref( std::make_shared>( ref ) ), m_hint( hint ) {} template ::value>> ParserRefImpl( LambdaT const& ref, std::string const& hint ): m_ref( std::make_shared>( ref ) ), m_hint( hint ) {} auto operator()( std::string const& description ) -> DerivedT& { m_description = description; return static_cast( *this ); } auto optional() -> DerivedT& { m_optionality = Optionality::Optional; return static_cast( *this ); } auto required() -> DerivedT& { m_optionality = Optionality::Required; return static_cast( *this ); } auto isOptional() const -> bool { return m_optionality == Optionality::Optional; } auto cardinality() const -> size_t override { if ( m_ref->isContainer() ) return 0; else return 1; } std::string const& hint() const { return m_hint; } }; } // namespace detail // A parser for arguments class Arg : public Detail::ParserRefImpl { public: using ParserRefImpl::ParserRefImpl; using ParserBase::parse; Detail::InternalParseResult parse(std::string const&, Detail::TokenStream const& tokens) const override; }; // A parser for options class Opt : public Detail::ParserRefImpl { protected: std::vector m_optNames; public: template explicit Opt(LambdaT const& ref) : ParserRefImpl( std::make_shared>(ref)) {} explicit Opt(bool& ref); template ::value>> Opt( LambdaT const& ref, std::string const& hint ): ParserRefImpl( ref, hint ) {} template Opt( accept_many_t, LambdaT const& ref, std::string const& hint ): ParserRefImpl( accept_many, ref, hint ) {} template ::value>> Opt( T& ref, std::string const& hint ): ParserRefImpl( ref, hint ) {} auto operator[](std::string const& optName) -> Opt& { m_optNames.push_back(optName); return *this; } std::vector getHelpColumns() const; bool isMatch(std::string const& optToken) const; using ParserBase::parse; Detail::InternalParseResult parse(std::string const&, Detail::TokenStream const& tokens) const override; Detail::Result validate() const override; }; // Specifies the name of the executable class ExeName : public Detail::ComposableParserImpl { std::shared_ptr m_name; std::shared_ptr m_ref; public: ExeName(); explicit ExeName(std::string& ref); template explicit ExeName(LambdaT const& lambda) : ExeName() { m_ref = std::make_shared>(lambda); } // The exe name is not parsed out of the normal tokens, but is // handled specially Detail::InternalParseResult parse(std::string const&, Detail::TokenStream const& tokens) const override; std::string const& name() const { return *m_name; } Detail::ParserResult set(std::string const& newName); }; // A Combined parser class Parser : Detail::ParserBase { mutable ExeName m_exeName; std::vector m_options; std::vector m_args; public: auto operator|=(ExeName const& exeName) -> Parser& { m_exeName = exeName; return *this; } auto operator|=(Arg const& arg) -> Parser& { m_args.push_back(arg); return *this; } auto operator|=(Opt const& opt) -> Parser& { m_options.push_back(opt); return *this; } Parser& operator|=(Parser const& other); template auto operator|(T const& other) const -> Parser { return Parser(*this) |= other; } std::vector getHelpColumns() const; void writeToStream(std::ostream& os) const; friend auto operator<<(std::ostream& os, Parser const& parser) -> std::ostream& { parser.writeToStream(os); return os; } Detail::Result validate() const override; using ParserBase::parse; Detail::InternalParseResult parse(std::string const& exeName, Detail::TokenStream const& tokens) const override; }; // Transport for raw args (copied from main args, or supplied via // init list for testing) class Args { friend Detail::TokenStream; std::string m_exeName; std::vector m_args; public: Args(int argc, char const* const* argv); Args(std::initializer_list args); std::string const& exeName() const { return m_exeName; } }; // Convenience wrapper for option parser that specifies the help option struct Help : Opt { Help(bool& showHelpFlag); }; // Result type for parser operation using Detail::ParserResult; namespace Detail { template template Parser ComposableParserImpl::operator|(T const& other) const { return Parser() | static_cast(*this) | other; } } } // namespace Clara } // namespace Catch #if defined( __clang__ ) # pragma clang diagnostic pop #endif #if defined( __GNUC__ ) # pragma GCC diagnostic pop #endif #endif // CATCH_CLARA_HPP_INCLUDED namespace Catch { struct ConfigData; Clara::Parser makeCommandLineParser( ConfigData& config ); } // end namespace Catch #endif // CATCH_COMMANDLINE_HPP_INCLUDED namespace Catch { class Session : Detail::NonCopyable { public: Session(); ~Session(); void showHelp() const; void libIdentify(); int applyCommandLine( int argc, char const * const * argv ); #if defined(CATCH_CONFIG_WCHAR) && defined(_WIN32) && defined(UNICODE) int applyCommandLine( int argc, wchar_t const * const * argv ); #endif void useConfigData( ConfigData const& configData ); template int run(int argc, CharT const * const argv[]) { if (m_startupExceptions) return 1; int returnCode = applyCommandLine(argc, argv); if (returnCode == 0) returnCode = run(); return returnCode; } int run(); Clara::Parser const& cli() const; void cli( Clara::Parser const& newParser ); ConfigData& configData(); Config& config(); private: int runInternal(); Clara::Parser m_cli; ConfigData m_configData; Detail::unique_ptr m_config; bool m_startupExceptions = false; }; } // end namespace Catch #endif // CATCH_SESSION_HPP_INCLUDED #ifndef CATCH_TAG_ALIAS_HPP_INCLUDED #define CATCH_TAG_ALIAS_HPP_INCLUDED #include namespace Catch { struct TagAlias { TagAlias(std::string const& _tag, SourceLineInfo _lineInfo): tag(_tag), lineInfo(_lineInfo) {} std::string tag; SourceLineInfo lineInfo; }; } // end namespace Catch #endif // CATCH_TAG_ALIAS_HPP_INCLUDED #ifndef CATCH_TAG_ALIAS_AUTOREGISTRAR_HPP_INCLUDED #define CATCH_TAG_ALIAS_AUTOREGISTRAR_HPP_INCLUDED namespace Catch { struct RegistrarForTagAliases { RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); }; } // end namespace Catch #define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION #endif // CATCH_TAG_ALIAS_AUTOREGISTRAR_HPP_INCLUDED #ifndef CATCH_TEMPLATE_TEST_MACROS_HPP_INCLUDED #define CATCH_TEMPLATE_TEST_MACROS_HPP_INCLUDED // We need this suppression to leak, because it took until GCC 10 // for the front end to handle local suppression via _Pragma properly // inside templates (so `TEMPLATE_TEST_CASE` and co). // **THIS IS DIFFERENT FOR STANDARD TESTS, WHERE GCC 9 IS SUFFICIENT** #if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && __GNUC__ < 10 #pragma GCC diagnostic ignored "-Wparentheses" #endif #ifndef CATCH_TEST_MACROS_HPP_INCLUDED #define CATCH_TEST_MACROS_HPP_INCLUDED #ifndef CATCH_TEST_MACRO_IMPL_HPP_INCLUDED #define CATCH_TEST_MACRO_IMPL_HPP_INCLUDED #ifndef CATCH_ASSERTION_HANDLER_HPP_INCLUDED #define CATCH_ASSERTION_HANDLER_HPP_INCLUDED #ifndef CATCH_DECOMPOSER_HPP_INCLUDED #define CATCH_DECOMPOSER_HPP_INCLUDED #ifndef CATCH_COMPARE_TRAITS_HPP_INCLUDED #define CATCH_COMPARE_TRAITS_HPP_INCLUDED #include namespace Catch { namespace Detail { #if defined( __GNUC__ ) && !defined( __clang__ ) # pragma GCC diagnostic push // GCC likes to complain about comparing bool with 0, in the decltype() // that defines the comparable traits below. # pragma GCC diagnostic ignored "-Wbool-compare" // "ordered comparison of pointer with integer zero" same as above, // but it does not have a separate warning flag to suppress # pragma GCC diagnostic ignored "-Wextra" // Did you know that comparing floats with `0` directly // is super-duper dangerous in unevaluated context? # pragma GCC diagnostic ignored "-Wfloat-equal" #endif #if defined( __clang__ ) # pragma clang diagnostic push // Did you know that comparing floats with `0` directly // is super-duper dangerous in unevaluated context? # pragma clang diagnostic ignored "-Wfloat-equal" #endif #define CATCH_DEFINE_COMPARABLE_TRAIT( id, op ) \ template \ struct is_##id##_comparable : std::false_type {}; \ template \ struct is_##id##_comparable< \ T, \ U, \ void_t() op std::declval() )>> \ : std::true_type {}; \ template \ struct is_##id##_0_comparable : std::false_type {}; \ template \ struct is_##id##_0_comparable() op 0 )>> \ : std::true_type {}; // We need all 6 pre-spaceship comparison ops: <, <=, >, >=, ==, != CATCH_DEFINE_COMPARABLE_TRAIT( lt, < ) CATCH_DEFINE_COMPARABLE_TRAIT( le, <= ) CATCH_DEFINE_COMPARABLE_TRAIT( gt, > ) CATCH_DEFINE_COMPARABLE_TRAIT( ge, >= ) CATCH_DEFINE_COMPARABLE_TRAIT( eq, == ) CATCH_DEFINE_COMPARABLE_TRAIT( ne, != ) #undef CATCH_DEFINE_COMPARABLE_TRAIT #if defined( __GNUC__ ) && !defined( __clang__ ) # pragma GCC diagnostic pop #endif #if defined( __clang__ ) # pragma clang diagnostic pop #endif } // namespace Detail } // namespace Catch #endif // CATCH_COMPARE_TRAITS_HPP_INCLUDED #ifndef CATCH_LOGICAL_TRAITS_HPP_INCLUDED #define CATCH_LOGICAL_TRAITS_HPP_INCLUDED #include namespace Catch { namespace Detail { #if defined( __cpp_lib_logical_traits ) && __cpp_lib_logical_traits >= 201510 using std::conjunction; using std::disjunction; using std::negation; #else template struct conjunction : std::true_type {}; template struct conjunction : B1 {}; template struct conjunction : std::conditional_t, B1> {}; template struct disjunction : std::false_type {}; template struct disjunction : B1 {}; template struct disjunction : std::conditional_t> {}; template struct negation : std::integral_constant {}; #endif } // namespace Detail } // namespace Catch #endif // CATCH_LOGICAL_TRAITS_HPP_INCLUDED #include #include #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4389) // '==' : signed/unsigned mismatch #pragma warning(disable:4018) // more "signed/unsigned mismatch" #pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform) #pragma warning(disable:4180) // qualifier applied to function type has no meaning #pragma warning(disable:4800) // Forcing result to true or false #endif #ifdef __clang__ # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wsign-compare" #elif defined __GNUC__ # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wsign-compare" #endif namespace Catch { template struct always_false : std::false_type {}; class ITransientExpression { bool m_isBinaryExpression; bool m_result; public: auto isBinaryExpression() const -> bool { return m_isBinaryExpression; } auto getResult() const -> bool { return m_result; } virtual void streamReconstructedExpression( std::ostream &os ) const = 0; ITransientExpression( bool isBinaryExpression, bool result ) : m_isBinaryExpression( isBinaryExpression ), m_result( result ) {} ITransientExpression() = default; ITransientExpression(ITransientExpression const&) = default; ITransientExpression& operator=(ITransientExpression const&) = default; // We don't actually need a virtual destructor, but many static analysers // complain if it's not here :-( virtual ~ITransientExpression(); // = default; friend std::ostream& operator<<(std::ostream& out, ITransientExpression const& expr) { expr.streamReconstructedExpression(out); return out; } }; void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ); template class BinaryExpr : public ITransientExpression { LhsT m_lhs; StringRef m_op; RhsT m_rhs; void streamReconstructedExpression( std::ostream &os ) const override { formatReconstructedExpression ( os, Catch::Detail::stringify( m_lhs ), m_op, Catch::Detail::stringify( m_rhs ) ); } public: BinaryExpr( bool comparisonResult, LhsT lhs, StringRef op, RhsT rhs ) : ITransientExpression{ true, comparisonResult }, m_lhs( lhs ), m_op( op ), m_rhs( rhs ) {} template auto operator && ( T ) const -> BinaryExpr const { static_assert(always_false::value, "chained comparisons are not supported inside assertions, " "wrap the expression inside parentheses, or decompose it"); } template auto operator || ( T ) const -> BinaryExpr const { static_assert(always_false::value, "chained comparisons are not supported inside assertions, " "wrap the expression inside parentheses, or decompose it"); } template auto operator == ( T ) const -> BinaryExpr const { static_assert(always_false::value, "chained comparisons are not supported inside assertions, " "wrap the expression inside parentheses, or decompose it"); } template auto operator != ( T ) const -> BinaryExpr const { static_assert(always_false::value, "chained comparisons are not supported inside assertions, " "wrap the expression inside parentheses, or decompose it"); } template auto operator > ( T ) const -> BinaryExpr const { static_assert(always_false::value, "chained comparisons are not supported inside assertions, " "wrap the expression inside parentheses, or decompose it"); } template auto operator < ( T ) const -> BinaryExpr const { static_assert(always_false::value, "chained comparisons are not supported inside assertions, " "wrap the expression inside parentheses, or decompose it"); } template auto operator >= ( T ) const -> BinaryExpr const { static_assert(always_false::value, "chained comparisons are not supported inside assertions, " "wrap the expression inside parentheses, or decompose it"); } template auto operator <= ( T ) const -> BinaryExpr const { static_assert(always_false::value, "chained comparisons are not supported inside assertions, " "wrap the expression inside parentheses, or decompose it"); } }; template class UnaryExpr : public ITransientExpression { LhsT m_lhs; void streamReconstructedExpression( std::ostream &os ) const override { os << Catch::Detail::stringify( m_lhs ); } public: explicit UnaryExpr( LhsT lhs ) : ITransientExpression{ false, static_cast(lhs) }, m_lhs( lhs ) {} }; template class ExprLhs { LhsT m_lhs; public: explicit ExprLhs( LhsT lhs ) : m_lhs( lhs ) {} #define CATCH_INTERNAL_DEFINE_EXPRESSION_EQUALITY_OPERATOR( id, op ) \ template \ friend auto operator op( ExprLhs&& lhs, RhsT&& rhs ) \ ->std::enable_if_t< \ Detail::conjunction, \ Detail::negation>>>::value, \ BinaryExpr> { \ return { \ static_cast( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \ } \ template \ friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \ ->std::enable_if_t< \ Detail::conjunction, \ std::is_arithmetic>::value, \ BinaryExpr> { \ return { \ static_cast( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \ } \ template \ friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \ ->std::enable_if_t< \ Detail::conjunction< \ Detail::negation>, \ Detail::is_eq_0_comparable, \ /* We allow long because we want `ptr op NULL` to be accepted */ \ Detail::disjunction, \ std::is_same>>::value, \ BinaryExpr> { \ if ( rhs != 0 ) { throw_test_failure_exception(); } \ return { \ static_cast( lhs.m_lhs op 0 ), lhs.m_lhs, #op##_sr, rhs }; \ } \ template \ friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \ ->std::enable_if_t< \ Detail::conjunction< \ Detail::negation>, \ Detail::is_eq_0_comparable, \ /* We allow long because we want `ptr op NULL` to be accepted */ \ Detail::disjunction, \ std::is_same>>::value, \ BinaryExpr> { \ if ( lhs.m_lhs != 0 ) { throw_test_failure_exception(); } \ return { static_cast( 0 op rhs ), lhs.m_lhs, #op##_sr, rhs }; \ } CATCH_INTERNAL_DEFINE_EXPRESSION_EQUALITY_OPERATOR( eq, == ) CATCH_INTERNAL_DEFINE_EXPRESSION_EQUALITY_OPERATOR( ne, != ) #undef CATCH_INTERNAL_DEFINE_EXPRESSION_EQUALITY_OPERATOR #define CATCH_INTERNAL_DEFINE_EXPRESSION_COMPARISON_OPERATOR( id, op ) \ template \ friend auto operator op( ExprLhs&& lhs, RhsT&& rhs ) \ ->std::enable_if_t< \ Detail::conjunction, \ Detail::negation>>>::value, \ BinaryExpr> { \ return { \ static_cast( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \ } \ template \ friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \ ->std::enable_if_t< \ Detail::conjunction, \ std::is_arithmetic>::value, \ BinaryExpr> { \ return { \ static_cast( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \ } \ template \ friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \ ->std::enable_if_t< \ Detail::conjunction< \ Detail::negation>, \ Detail::is_##id##_0_comparable, \ std::is_same>::value, \ BinaryExpr> { \ if ( rhs != 0 ) { throw_test_failure_exception(); } \ return { \ static_cast( lhs.m_lhs op 0 ), lhs.m_lhs, #op##_sr, rhs }; \ } \ template \ friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \ ->std::enable_if_t< \ Detail::conjunction< \ Detail::negation>, \ Detail::is_##id##_0_comparable, \ std::is_same>::value, \ BinaryExpr> { \ if ( lhs.m_lhs != 0 ) { throw_test_failure_exception(); } \ return { static_cast( 0 op rhs ), lhs.m_lhs, #op##_sr, rhs }; \ } CATCH_INTERNAL_DEFINE_EXPRESSION_COMPARISON_OPERATOR( lt, < ) CATCH_INTERNAL_DEFINE_EXPRESSION_COMPARISON_OPERATOR( le, <= ) CATCH_INTERNAL_DEFINE_EXPRESSION_COMPARISON_OPERATOR( gt, > ) CATCH_INTERNAL_DEFINE_EXPRESSION_COMPARISON_OPERATOR( ge, >= ) #undef CATCH_INTERNAL_DEFINE_EXPRESSION_COMPARISON_OPERATOR #define CATCH_INTERNAL_DEFINE_EXPRESSION_OPERATOR( op ) \ template \ friend auto operator op( ExprLhs&& lhs, RhsT&& rhs ) \ ->std::enable_if_t< \ !std::is_arithmetic>::value, \ BinaryExpr> { \ return { \ static_cast( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \ } \ template \ friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \ ->std::enable_if_t::value, \ BinaryExpr> { \ return { \ static_cast( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \ } CATCH_INTERNAL_DEFINE_EXPRESSION_OPERATOR(|) CATCH_INTERNAL_DEFINE_EXPRESSION_OPERATOR(&) CATCH_INTERNAL_DEFINE_EXPRESSION_OPERATOR(^) #undef CATCH_INTERNAL_DEFINE_EXPRESSION_OPERATOR template friend auto operator && ( ExprLhs &&, RhsT && ) -> BinaryExpr { static_assert(always_false::value, "operator&& is not supported inside assertions, " "wrap the expression inside parentheses, or decompose it"); } template friend auto operator || ( ExprLhs &&, RhsT && ) -> BinaryExpr { static_assert(always_false::value, "operator|| is not supported inside assertions, " "wrap the expression inside parentheses, or decompose it"); } auto makeUnaryExpr() const -> UnaryExpr { return UnaryExpr{ m_lhs }; } }; struct Decomposer { template>::value, int> = 0> friend auto operator <= ( Decomposer &&, T && lhs ) -> ExprLhs { return ExprLhs{ lhs }; } template::value, int> = 0> friend auto operator <= ( Decomposer &&, T value ) -> ExprLhs { return ExprLhs{ value }; } }; } // end namespace Catch #ifdef _MSC_VER #pragma warning(pop) #endif #ifdef __clang__ # pragma clang diagnostic pop #elif defined __GNUC__ # pragma GCC diagnostic pop #endif #endif // CATCH_DECOMPOSER_HPP_INCLUDED #include namespace Catch { class IResultCapture; struct AssertionReaction { bool shouldDebugBreak = false; bool shouldThrow = false; bool shouldSkip = false; }; class AssertionHandler { AssertionInfo m_assertionInfo; AssertionReaction m_reaction; bool m_completed = false; IResultCapture& m_resultCapture; public: AssertionHandler ( StringRef macroName, SourceLineInfo const& lineInfo, StringRef capturedExpression, ResultDisposition::Flags resultDisposition ); ~AssertionHandler() { if ( !m_completed ) { m_resultCapture.handleIncomplete( m_assertionInfo ); } } template void handleExpr( ExprLhs const& expr ) { handleExpr( expr.makeUnaryExpr() ); } void handleExpr( ITransientExpression const& expr ); void handleMessage(ResultWas::OfType resultType, StringRef message); void handleExceptionThrownAsExpected(); void handleUnexpectedExceptionNotThrown(); void handleExceptionNotThrownAsExpected(); void handleThrowingCallSkipped(); void handleUnexpectedInflightException(); void complete(); void setCompleted(); // query auto allowThrows() const -> bool; }; void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str ); } // namespace Catch #endif // CATCH_ASSERTION_HANDLER_HPP_INCLUDED // We need this suppression to leak, because it took until GCC 10 // for the front end to handle local suppression via _Pragma properly #if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && __GNUC__ <= 9 #pragma GCC diagnostic ignored "-Wparentheses" #endif #if !defined(CATCH_CONFIG_DISABLE) #if !defined(CATCH_CONFIG_DISABLE_STRINGIFICATION) #define CATCH_INTERNAL_STRINGIFY(...) #__VA_ARGS__##_catch_sr #else #define CATCH_INTERNAL_STRINGIFY(...) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION"_catch_sr #endif #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* // macros. #define INTERNAL_CATCH_TRY #define INTERNAL_CATCH_CATCH( capturer ) #else // CATCH_CONFIG_FAST_COMPILE #define INTERNAL_CATCH_TRY try #define INTERNAL_CATCH_CATCH( handler ) catch(...) { handler.handleUnexpectedInflightException(); } #endif #define INTERNAL_CATCH_REACT( handler ) handler.complete(); /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \ do { /* NOLINT(bugprone-infinite-loop) */ \ /* The expression should not be evaluated, but warnings should hopefully be checked */ \ CATCH_INTERNAL_IGNORE_BUT_WARN(__VA_ARGS__); \ Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \ INTERNAL_CATCH_TRY { \ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ catchAssertionHandler.handleExpr( Catch::Decomposer() <= __VA_ARGS__ ); \ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \ INTERNAL_CATCH_REACT( catchAssertionHandler ) \ } while( (void)0, (false) && static_cast( !!(__VA_ARGS__) ) ) // the expression here is never evaluated at runtime but it forces the compiler to give it a look // The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&. /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_IF( macroName, resultDisposition, ... ) \ INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \ if( Catch::getResultCapture().lastAssertionPassed() ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_ELSE( macroName, resultDisposition, ... ) \ INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \ if( !Catch::getResultCapture().lastAssertionPassed() ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, ... ) \ do { \ Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \ try { \ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS \ static_cast(__VA_ARGS__); \ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ catchAssertionHandler.handleExceptionNotThrownAsExpected(); \ } \ catch( ... ) { \ catchAssertionHandler.handleUnexpectedInflightException(); \ } \ INTERNAL_CATCH_REACT( catchAssertionHandler ) \ } while( false ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_THROWS( macroName, resultDisposition, ... ) \ do { \ Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition); \ if( catchAssertionHandler.allowThrows() ) \ try { \ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS \ static_cast(__VA_ARGS__); \ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ } \ catch( ... ) { \ catchAssertionHandler.handleExceptionThrownAsExpected(); \ } \ else \ catchAssertionHandler.handleThrowingCallSkipped(); \ INTERNAL_CATCH_REACT( catchAssertionHandler ) \ } while( false ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \ do { \ Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr) ", " CATCH_INTERNAL_STRINGIFY(exceptionType), resultDisposition ); \ if( catchAssertionHandler.allowThrows() ) \ try { \ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS \ static_cast(expr); \ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ } \ catch( exceptionType const& ) { \ catchAssertionHandler.handleExceptionThrownAsExpected(); \ } \ catch( ... ) { \ catchAssertionHandler.handleUnexpectedInflightException(); \ } \ else \ catchAssertionHandler.handleThrowingCallSkipped(); \ INTERNAL_CATCH_REACT( catchAssertionHandler ) \ } while( false ) /////////////////////////////////////////////////////////////////////////////// // 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_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ if( catchAssertionHandler.allowThrows() ) \ try { \ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS \ static_cast(__VA_ARGS__); \ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ } \ catch( ... ) { \ Catch::handleExceptionMatchExpr( catchAssertionHandler, matcher ); \ } \ else \ catchAssertionHandler.handleThrowingCallSkipped(); \ INTERNAL_CATCH_REACT( catchAssertionHandler ) \ } while( false ) #endif // CATCH_CONFIG_DISABLE #endif // CATCH_TEST_MACRO_IMPL_HPP_INCLUDED #ifndef CATCH_SECTION_HPP_INCLUDED #define CATCH_SECTION_HPP_INCLUDED #ifndef CATCH_TIMER_HPP_INCLUDED #define CATCH_TIMER_HPP_INCLUDED #include namespace Catch { class Timer { uint64_t m_nanoseconds = 0; public: void start(); auto getElapsedNanoseconds() const -> uint64_t; auto getElapsedMicroseconds() const -> uint64_t; auto getElapsedMilliseconds() const -> unsigned int; auto getElapsedSeconds() const -> double; }; } // namespace Catch #endif // CATCH_TIMER_HPP_INCLUDED namespace Catch { class Section : Detail::NonCopyable { public: Section( SectionInfo&& info ); Section( SourceLineInfo const& _lineInfo, StringRef _name, const char* const = nullptr ); ~Section(); // This indicates whether the section should be executed or not explicit operator bool() const; private: SectionInfo m_info; Counts m_assertions; bool m_sectionIncluded; Timer m_timer; }; } // end namespace Catch #define INTERNAL_CATCH_SECTION( ... ) \ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::Section( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) \ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION #define INTERNAL_CATCH_DYNAMIC_SECTION( ... ) \ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, (Catch::ReusableStringStream() << __VA_ARGS__).str() ) ) \ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION #endif // CATCH_SECTION_HPP_INCLUDED #ifndef CATCH_TEST_REGISTRY_HPP_INCLUDED #define CATCH_TEST_REGISTRY_HPP_INCLUDED #ifndef CATCH_INTERFACES_TESTCASE_HPP_INCLUDED #define CATCH_INTERFACES_TESTCASE_HPP_INCLUDED #include namespace Catch { class TestSpec; struct TestCaseInfo; class ITestInvoker { public: virtual void invoke () const = 0; virtual ~ITestInvoker(); // = default }; class TestCaseHandle; class IConfig; class ITestCaseRegistry { public: virtual ~ITestCaseRegistry(); // = default // TODO: this exists only for adding filenames to test cases -- let's expose this in a saner way later virtual std::vector const& getAllInfos() const = 0; virtual std::vector const& getAllTests() const = 0; virtual std::vector const& getAllTestsSorted( IConfig const& config ) const = 0; }; bool isThrowSafe( TestCaseHandle const& testCase, IConfig const& config ); bool matchTest( TestCaseHandle const& testCase, TestSpec const& testSpec, IConfig const& config ); std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); std::vector const& getAllTestCasesSorted( IConfig const& config ); } #endif // CATCH_INTERFACES_TESTCASE_HPP_INCLUDED #ifndef CATCH_PREPROCESSOR_REMOVE_PARENS_HPP_INCLUDED #define CATCH_PREPROCESSOR_REMOVE_PARENS_HPP_INCLUDED #define INTERNAL_CATCH_EXPAND1( param ) INTERNAL_CATCH_EXPAND2( param ) #define INTERNAL_CATCH_EXPAND2( ... ) INTERNAL_CATCH_NO##__VA_ARGS__ #define INTERNAL_CATCH_DEF( ... ) INTERNAL_CATCH_DEF __VA_ARGS__ #define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF #define INTERNAL_CATCH_REMOVE_PARENS( ... ) \ INTERNAL_CATCH_EXPAND1( INTERNAL_CATCH_DEF __VA_ARGS__ ) #endif // CATCH_PREPROCESSOR_REMOVE_PARENS_HPP_INCLUDED // GCC 5 and older do not properly handle disabling unused-variable warning // with a _Pragma. This means that we have to leak the suppression to the // user code as well :-( #if defined(__GNUC__) && !defined(__clang__) && __GNUC__ <= 5 #pragma GCC diagnostic ignored "-Wunused-variable" #endif namespace Catch { template class TestInvokerAsMethod : public ITestInvoker { void (C::*m_testAsMethod)(); public: TestInvokerAsMethod( void (C::*testAsMethod)() ) noexcept : m_testAsMethod( testAsMethod ) {} void invoke() const override { C obj; (obj.*m_testAsMethod)(); } }; Detail::unique_ptr makeTestInvoker( void(*testAsFunction)() ); template Detail::unique_ptr makeTestInvoker( void (C::*testAsMethod)() ) { return Detail::make_unique>( testAsMethod ); } struct NameAndTags { constexpr NameAndTags( StringRef name_ = StringRef(), StringRef tags_ = StringRef() ) noexcept: name( name_ ), tags( tags_ ) {} StringRef name; StringRef tags; }; struct AutoReg : Detail::NonCopyable { AutoReg( Detail::unique_ptr invoker, SourceLineInfo const& lineInfo, StringRef classOrMethod, NameAndTags const& nameAndTags ) noexcept; }; } // end namespace Catch #if defined(CATCH_CONFIG_DISABLE) #define INTERNAL_CATCH_TESTCASE_NO_REGISTRATION( TestName, ... ) \ static inline void TestName() #define INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION( TestName, ClassName, ... ) \ namespace{ \ struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName) { \ void test(); \ }; \ } \ void TestName::test() #endif /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \ static void TestName(); \ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ namespace{ const Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &TestName ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ static void TestName() #define INTERNAL_CATCH_TESTCASE( ... ) \ INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), __VA_ARGS__ ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ namespace { \ const Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( \ Catch::makeTestInvoker( &QualifiedMethod ), \ CATCH_INTERNAL_LINEINFO, \ "&" #QualifiedMethod##_catch_sr, \ Catch::NameAndTags{ __VA_ARGS__ } ); \ } /* NOLINT */ \ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ namespace{ \ struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName) { \ void test(); \ }; \ const Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( \ Catch::makeTestInvoker( &TestName::test ), \ CATCH_INTERNAL_LINEINFO, \ #ClassName##_catch_sr, \ Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \ } \ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ void TestName::test() #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \ INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), ClassName, __VA_ARGS__ ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \ do { \ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( Function ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ } while(false) #endif // CATCH_TEST_REGISTRY_HPP_INCLUDED // All of our user-facing macros support configuration toggle, that // forces them to be defined prefixed with CATCH_. We also like to // support another toggle that can minimize (disable) their implementation. // Given this, we have 4 different configuration options below #if defined(CATCH_CONFIG_PREFIX_ALL) && !defined(CATCH_CONFIG_DISABLE) #define CATCH_REQUIRE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ ) #define CATCH_REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) #define CATCH_REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, __VA_ARGS__ ) #define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr ) #define CATCH_REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ ) #define CATCH_CHECK( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) #define CATCH_CHECK_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) #define CATCH_CHECKED_IF( ... ) INTERNAL_CATCH_IF( "CATCH_CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ ) #define CATCH_CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CATCH_CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ ) #define CATCH_CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ ) #define CATCH_CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) #define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr ) #define CATCH_CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __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__ ) #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) #define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) #define CATCH_DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ ) #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ ) #define CATCH_FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) #define CATCH_SKIP( ... ) INTERNAL_CATCH_MSG( "SKIP", Catch::ResultWas::ExplicitSkip, Catch::ResultDisposition::Normal, __VA_ARGS__ ) #if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE) #define CATCH_STATIC_REQUIRE( ... ) static_assert( __VA_ARGS__ , #__VA_ARGS__ ); CATCH_SUCCEED( #__VA_ARGS__ ) #define CATCH_STATIC_REQUIRE_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); CATCH_SUCCEED( #__VA_ARGS__ ) #define CATCH_STATIC_CHECK( ... ) static_assert( __VA_ARGS__ , #__VA_ARGS__ ); CATCH_SUCCEED( #__VA_ARGS__ ) #define CATCH_STATIC_CHECK_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); CATCH_SUCCEED( #__VA_ARGS__ ) #else #define CATCH_STATIC_REQUIRE( ... ) CATCH_REQUIRE( __VA_ARGS__ ) #define CATCH_STATIC_REQUIRE_FALSE( ... ) CATCH_REQUIRE_FALSE( __VA_ARGS__ ) #define CATCH_STATIC_CHECK( ... ) CATCH_CHECK( __VA_ARGS__ ) #define CATCH_STATIC_CHECK_FALSE( ... ) CATCH_CHECK_FALSE( __VA_ARGS__ ) #endif // "BDD-style" convenience wrappers #define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ ) #define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) #define CATCH_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Given: " << desc ) #define CATCH_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 ) #elif defined(CATCH_CONFIG_PREFIX_ALL) && defined(CATCH_CONFIG_DISABLE) // ^^ prefixed, implemented | vv prefixed, disabled #define CATCH_REQUIRE( ... ) (void)(0) #define CATCH_REQUIRE_FALSE( ... ) (void)(0) #define CATCH_REQUIRE_THROWS( ... ) (void)(0) #define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) (void)(0) #define CATCH_REQUIRE_NOTHROW( ... ) (void)(0) #define CATCH_CHECK( ... ) (void)(0) #define CATCH_CHECK_FALSE( ... ) (void)(0) #define CATCH_CHECKED_IF( ... ) if (__VA_ARGS__) #define CATCH_CHECKED_ELSE( ... ) if (!(__VA_ARGS__)) #define CATCH_CHECK_NOFAIL( ... ) (void)(0) #define CATCH_CHECK_THROWS( ... ) (void)(0) #define CATCH_CHECK_THROWS_AS( expr, exceptionType ) (void)(0) #define CATCH_CHECK_NOTHROW( ... ) (void)(0) #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ )) #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ )) #define CATCH_METHOD_AS_TEST_CASE( method, ... ) #define CATCH_REGISTER_TEST_CASE( Function, ... ) (void)(0) #define CATCH_SECTION( ... ) #define CATCH_DYNAMIC_SECTION( ... ) #define CATCH_FAIL( ... ) (void)(0) #define CATCH_FAIL_CHECK( ... ) (void)(0) #define CATCH_SUCCEED( ... ) (void)(0) #define CATCH_SKIP( ... ) (void)(0) #define CATCH_STATIC_REQUIRE( ... ) (void)(0) #define CATCH_STATIC_REQUIRE_FALSE( ... ) (void)(0) #define CATCH_STATIC_CHECK( ... ) (void)(0) #define CATCH_STATIC_CHECK_FALSE( ... ) (void)(0) // "BDD-style" convenience wrappers #define CATCH_SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ )) #define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), className ) #define CATCH_GIVEN( desc ) #define CATCH_AND_GIVEN( desc ) #define CATCH_WHEN( desc ) #define CATCH_AND_WHEN( desc ) #define CATCH_THEN( desc ) #define CATCH_AND_THEN( desc ) #elif !defined(CATCH_CONFIG_PREFIX_ALL) && !defined(CATCH_CONFIG_DISABLE) // ^^ prefixed, disabled | vv unprefixed, implemented #define REQUIRE( ... ) INTERNAL_CATCH_TEST( "REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ ) #define REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) #define REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "REQUIRE_THROWS", Catch::ResultDisposition::Normal, __VA_ARGS__ ) #define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr ) #define REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ ) #define CHECK( ... ) INTERNAL_CATCH_TEST( "CHECK", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) #define CHECK_FALSE( ... ) INTERNAL_CATCH_TEST( "CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) #define CHECKED_IF( ... ) INTERNAL_CATCH_IF( "CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ ) #define CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ ) #define CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ ) #define CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) #define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr ) #define CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) #define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) #define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) #define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) #define DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ ) #define FAIL( ... ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ ) #define FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) #define SUCCEED( ... ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) #define SKIP( ... ) INTERNAL_CATCH_MSG( "SKIP", Catch::ResultWas::ExplicitSkip, Catch::ResultDisposition::Normal, __VA_ARGS__ ) #if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE) #define STATIC_REQUIRE( ... ) static_assert( __VA_ARGS__, #__VA_ARGS__ ); SUCCEED( #__VA_ARGS__ ) #define STATIC_REQUIRE_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); SUCCEED( "!(" #__VA_ARGS__ ")" ) #define STATIC_CHECK( ... ) static_assert( __VA_ARGS__, #__VA_ARGS__ ); SUCCEED( #__VA_ARGS__ ) #define STATIC_CHECK_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); SUCCEED( "!(" #__VA_ARGS__ ")" ) #else #define STATIC_REQUIRE( ... ) REQUIRE( __VA_ARGS__ ) #define STATIC_REQUIRE_FALSE( ... ) REQUIRE_FALSE( __VA_ARGS__ ) #define STATIC_CHECK( ... ) CHECK( __VA_ARGS__ ) #define STATIC_CHECK_FALSE( ... ) CHECK_FALSE( __VA_ARGS__ ) #endif // "BDD-style" convenience wrappers #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 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 ) #elif !defined(CATCH_CONFIG_PREFIX_ALL) && defined(CATCH_CONFIG_DISABLE) // ^^ unprefixed, implemented | vv unprefixed, disabled #define REQUIRE( ... ) (void)(0) #define REQUIRE_FALSE( ... ) (void)(0) #define REQUIRE_THROWS( ... ) (void)(0) #define REQUIRE_THROWS_AS( expr, exceptionType ) (void)(0) #define REQUIRE_NOTHROW( ... ) (void)(0) #define CHECK( ... ) (void)(0) #define CHECK_FALSE( ... ) (void)(0) #define CHECKED_IF( ... ) if (__VA_ARGS__) #define CHECKED_ELSE( ... ) if (!(__VA_ARGS__)) #define CHECK_NOFAIL( ... ) (void)(0) #define CHECK_THROWS( ... ) (void)(0) #define CHECK_THROWS_AS( expr, exceptionType ) (void)(0) #define CHECK_NOTHROW( ... ) (void)(0) #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), __VA_ARGS__) #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ )) #define METHOD_AS_TEST_CASE( method, ... ) #define REGISTER_TEST_CASE( Function, ... ) (void)(0) #define SECTION( ... ) #define DYNAMIC_SECTION( ... ) #define FAIL( ... ) (void)(0) #define FAIL_CHECK( ... ) (void)(0) #define SUCCEED( ... ) (void)(0) #define SKIP( ... ) (void)(0) #define STATIC_REQUIRE( ... ) (void)(0) #define STATIC_REQUIRE_FALSE( ... ) (void)(0) #define STATIC_CHECK( ... ) (void)(0) #define STATIC_CHECK_FALSE( ... ) (void)(0) // "BDD-style" convenience wrappers #define SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ) ) #define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), className ) #define GIVEN( desc ) #define AND_GIVEN( desc ) #define WHEN( desc ) #define AND_WHEN( desc ) #define THEN( desc ) #define AND_THEN( desc ) #endif // ^^ unprefixed, disabled // end of user facing macros #endif // CATCH_TEST_MACROS_HPP_INCLUDED #ifndef CATCH_TEMPLATE_TEST_REGISTRY_HPP_INCLUDED #define CATCH_TEMPLATE_TEST_REGISTRY_HPP_INCLUDED #ifndef CATCH_PREPROCESSOR_HPP_INCLUDED #define CATCH_PREPROCESSOR_HPP_INCLUDED #if defined(__GNUC__) // We need to silence "empty __VA_ARGS__ warning", and using just _Pragma does not work #pragma GCC system_header #endif #define CATCH_RECURSION_LEVEL0(...) __VA_ARGS__ #define CATCH_RECURSION_LEVEL1(...) CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(__VA_ARGS__))) #define CATCH_RECURSION_LEVEL2(...) CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(__VA_ARGS__))) #define CATCH_RECURSION_LEVEL3(...) CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(__VA_ARGS__))) #define CATCH_RECURSION_LEVEL4(...) CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(__VA_ARGS__))) #define CATCH_RECURSION_LEVEL5(...) CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(__VA_ARGS__))) #ifdef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define INTERNAL_CATCH_EXPAND_VARGS(...) __VA_ARGS__ // MSVC needs more evaluations #define CATCH_RECURSION_LEVEL6(...) CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(__VA_ARGS__))) #define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL6(CATCH_RECURSION_LEVEL6(__VA_ARGS__)) #else #define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL5(__VA_ARGS__) #endif #define CATCH_REC_END(...) #define CATCH_REC_OUT #define CATCH_EMPTY() #define CATCH_DEFER(id) id CATCH_EMPTY() #define CATCH_REC_GET_END2() 0, CATCH_REC_END #define CATCH_REC_GET_END1(...) CATCH_REC_GET_END2 #define CATCH_REC_GET_END(...) CATCH_REC_GET_END1 #define CATCH_REC_NEXT0(test, next, ...) next CATCH_REC_OUT #define CATCH_REC_NEXT1(test, next) CATCH_DEFER ( CATCH_REC_NEXT0 ) ( test, next, 0) #define CATCH_REC_NEXT(test, next) CATCH_REC_NEXT1(CATCH_REC_GET_END test, next) #define CATCH_REC_LIST0(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) #define CATCH_REC_LIST1(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0) ) ( f, peek, __VA_ARGS__ ) #define CATCH_REC_LIST2(f, x, peek, ...) f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) #define CATCH_REC_LIST0_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ ) #define CATCH_REC_LIST1_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0_UD) ) ( f, userdata, peek, __VA_ARGS__ ) #define CATCH_REC_LIST2_UD(f, userdata, x, peek, ...) f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ ) // Applies the function macro `f` to each of the remaining parameters, inserts commas between the results, // and passes userdata as the first parameter to each invocation, // e.g. CATCH_REC_LIST_UD(f, x, a, b, c) evaluates to f(x, a), f(x, b), f(x, c) #define CATCH_REC_LIST_UD(f, userdata, ...) CATCH_RECURSE(CATCH_REC_LIST2_UD(f, userdata, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) #define CATCH_REC_LIST(f, ...) CATCH_RECURSE(CATCH_REC_LIST2(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) #define INTERNAL_CATCH_STRINGIZE(...) INTERNAL_CATCH_STRINGIZE2(__VA_ARGS__) #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define INTERNAL_CATCH_STRINGIZE2(...) #__VA_ARGS__ #define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) #else // MSVC is adding extra space and needs another indirection to expand INTERNAL_CATCH_NOINTERNAL_CATCH_DEF #define INTERNAL_CATCH_STRINGIZE2(...) INTERNAL_CATCH_STRINGIZE3(__VA_ARGS__) #define INTERNAL_CATCH_STRINGIZE3(...) #__VA_ARGS__ #define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) (INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) + 1) #endif #define INTERNAL_CATCH_MAKE_NAMESPACE2(...) ns_##__VA_ARGS__ #define INTERNAL_CATCH_MAKE_NAMESPACE(name) INTERNAL_CATCH_MAKE_NAMESPACE2(name) #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) decltype(get_wrapper()) #define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__)) #else #define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) INTERNAL_CATCH_EXPAND_VARGS(decltype(get_wrapper())) #define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__))) #endif #define INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(...)\ CATCH_REC_LIST(INTERNAL_CATCH_MAKE_TYPE_LIST,__VA_ARGS__) #define INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_0) INTERNAL_CATCH_REMOVE_PARENS(_0) #define INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_0, _1) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_1) #define INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_0, _1, _2) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_1, _2) #define INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_0, _1, _2, _3) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_1, _2, _3) #define INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_0, _1, _2, _3, _4) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_1, _2, _3, _4) #define INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_0, _1, _2, _3, _4, _5) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_1, _2, _3, _4, _5) #define INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_0, _1, _2, _3, _4, _5, _6) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_1, _2, _3, _4, _5, _6) #define INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_0, _1, _2, _3, _4, _5, _6, _7) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_1, _2, _3, _4, _5, _6, _7) #define INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_1, _2, _3, _4, _5, _6, _7, _8) #define INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9) #define INTERNAL_CATCH_REMOVE_PARENS_11_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10) #define INTERNAL_CATCH_VA_NARGS_IMPL(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N #define INTERNAL_CATCH_TYPE_GEN\ template struct TypeList {};\ template\ constexpr auto get_wrapper() noexcept -> TypeList { return {}; }\ template class...> struct TemplateTypeList{};\ template class...Cs>\ constexpr auto get_wrapper() noexcept -> TemplateTypeList { return {}; }\ template\ struct append;\ template\ struct rewrap;\ template class, typename...>\ struct create;\ template class, typename>\ struct convert;\ \ template \ struct append { using type = T; };\ template< template class L1, typename...E1, template class L2, typename...E2, typename...Rest>\ struct append, L2, Rest...> { using type = typename append, Rest...>::type; };\ template< template class L1, typename...E1, typename...Rest>\ struct append, TypeList, Rest...> { using type = L1; };\ \ template< template class Container, template class List, typename...elems>\ struct rewrap, List> { using type = TypeList>; };\ template< template class Container, template class List, class...Elems, typename...Elements>\ struct rewrap, List, Elements...> { using type = typename append>, typename rewrap, Elements...>::type>::type; };\ \ template