diff options
| author | Martin Hořeňovský | 2019-10-13 23:44:18 +0200 |
|---|---|---|
| committer | Martin Hořeňovský | 2019-10-13 23:44:18 +0200 |
| commit | 7c9f92bc1c6e82ad5b6af8dff9f97af880fae9c6 (patch) | |
| tree | d8bc58457176ac973c4a4c8f60c34cdb154af151 | |
| parent | a92a7d02290eae896413a7d96e4875587c0dcd42 (diff) | |
| download | catch3-2.10.0.tar.gz | |
v2.10.0v2.10.0
| -rw-r--r-- | CMakeLists.txt | 2 | ||||
| -rw-r--r-- | README.md | 4 | ||||
| -rw-r--r-- | docs/configuration.md | 2 | ||||
| -rw-r--r-- | docs/generators.md | 4 | ||||
| -rw-r--r-- | docs/matchers.md | 4 | ||||
| -rw-r--r-- | docs/release-notes.md | 45 | ||||
| -rw-r--r-- | include/catch.hpp | 4 | ||||
| -rw-r--r-- | include/internal/catch_version.cpp | 2 | ||||
| -rw-r--r-- | single_include/catch2/catch.hpp | 930 | ||||
| -rw-r--r-- | single_include/catch2/catch_reporter_teamcity.hpp | 3 |
10 files changed, 665 insertions, 335 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 0abdbe82..edb91c43 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ if(NOT DEFINED PROJECT_NAME) set(NOT_SUBPROJECT ON) endif() -project(Catch2 LANGUAGES CXX VERSION 2.9.2) +project(Catch2 LANGUAGES CXX VERSION 2.10.0) if (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR) message(FATAL_ERROR "Building in-source is not supported! Create a build dir and remove ${CMAKE_SOURCE_DIR}/CMakeCache.txt") @@ -5,11 +5,11 @@ [](https://travis-ci.org/catchorg/Catch2) [](https://ci.appveyor.com/project/catchorg/catch2) [](https://codecov.io/gh/catchorg/Catch2) -[](https://wandbox.org/permlink/8YrGVqYqqSC4Sc5R) +[](https://wandbox.org/permlink/00GdTUbFWaV3bNah) [](https://discord.gg/4CWS9zD) -<a href="https://github.com/catchorg/Catch2/releases/download/v2.9.2/catch.hpp">The latest version of the single header can be downloaded directly using this link</a> +<a href="https://github.com/catchorg/Catch2/releases/download/v2.10.0/catch.hpp">The latest version of the single header can be downloaded directly using this link</a> ## Catch2 is released! diff --git a/docs/configuration.md b/docs/configuration.md index ec042c23..599bb9ae 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -158,7 +158,7 @@ by using `_NO_` in the macro, e.g. `CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS`. CATCH_CONFIG_ANDROID_LOGWRITE // Use android's logging system for debug output CATCH_CONFIG_GLOBAL_NEXTAFTER // Use nextafter{,f,l} instead of std::nextafter -> [`CATCH_CONFIG_ANDROID_LOGWRITE`](https://github.com/catchorg/Catch2/issues/1743) and [`CATCH_CONFIG_GLOBAL_NEXTAFTER`](https://github.com/catchorg/Catch2/pull/1739) were introduced in Catch X.Y.Z +> [`CATCH_CONFIG_ANDROID_LOGWRITE`](https://github.com/catchorg/Catch2/issues/1743) and [`CATCH_CONFIG_GLOBAL_NEXTAFTER`](https://github.com/catchorg/Catch2/pull/1739) were introduced in Catch 2.10.0 Currently Catch enables `CATCH_CONFIG_WINDOWS_SEH` only when compiled with MSVC, because some versions of MinGW do not have the necessary Win32 API support. diff --git a/docs/generators.md b/docs/generators.md index 34565a50..61276f3c 100644 --- a/docs/generators.md +++ b/docs/generators.md @@ -54,7 +54,7 @@ a test case, > `ChunkGenerator<T>`, `RandomIntegerGenerator<Integral>`, `RandomFloatGenerator<Float>` and `RangeGenerator<T>` were introduced in Catch 2.7.0. -> `IteratorGenerator<T>` was introduced in Catch X.Y.Z. +> `IteratorGenerator<T>` was introduced in Catch 2.10.0. The generators also have associated helper functions that infer their type, making their usage much nicer. These are @@ -76,7 +76,7 @@ type, making their usage much nicer. These are > `chunk()`, `random()` and both `range()` functions were introduced in Catch 2.7.0. -> `from_range` has been introduced in Catch X.Y.Z +> `from_range` has been introduced in Catch 2.10.0 And can be used as shown in the example below to create a generator that returns 100 odd random number: diff --git a/docs/matchers.md b/docs/matchers.md index f10ae918..af2071e3 100644 --- a/docs/matchers.md +++ b/docs/matchers.md @@ -90,7 +90,7 @@ the helpers for this matcher, `WithinRel(double target, double margin)`, `WithinRel(float target)`. The latter two provide a default epsilon of machine epsilon * 100. -> `WithinRel` matcher was introduced in Catch X.Y.Z +> `WithinRel` matcher was introduced in Catch 2.10.0 ### Generic matchers Catch also aims to provide a set of generic matchers. Currently this set @@ -120,7 +120,7 @@ is `ExceptionMessageMatcher`, and we also provide a helper function The matched exception must publicly derive from `std::exception` and the message matching is done _exactly_, including case. -> `ExceptionMessageMatcher` was introduced in Catch X.Y.Z +> `ExceptionMessageMatcher` was introduced in Catch 2.10.0 Example use: ```cpp diff --git a/docs/release-notes.md b/docs/release-notes.md index 204cea34..0af35c67 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ # Release notes **Contents**<br> +[2.10.0](#2100)<br> [2.9.2](#292)<br> [2.9.1](#291)<br> [2.9.0](#290)<br> @@ -28,6 +29,50 @@ [Even Older versions](#even-older-versions)<br> + +## 2.10.0 + +### Fixes +* `TEMPLATE_LIST_TEST_CASE` now properly handles non-copyable and non-movable types (#1729) +* Fixed compilation error on Solaris caused by a system header defining macro `TT` (#1722, #1723) +* `REGISTER_ENUM` will now fail at compilation time if the registered enum is too large +* Removed use of `std::is_same_v` in C++17 mode (#1757) +* Fixed parsing of escaped special characters when reading test specs from a file (#1767, #1769) + + +### Improvements +* Trailing and leading whitespace in test/section specs are now ignored. +* Writing to Android debug log now uses `__android_log_write` instead of `__android_log_print` +* Android logging support can now be turned on/off at compile time (#1743) + * The toggle is `CATCH_CONFIG_ANDROID_LOGWRITE` +* Added a generator that returns elements of a range + * Use via `from_range(from, to)` or `from_range(container)` +* Added support for CRTs that do not provide `std::nextafter` (#1739) + * They must still provide global `nextafter{f,l,}` + * Enabled via `CATCH_CONFIG_GLOBAL_NEXTAFTER` +* Special cased `Approx(inf)` not to match non-infinite values + * Very strictly speaking this might be a breaking change, but it should match user expectations better +* The output of benchmarking through the Console reporter when `--benchmark-no-analysis` is set is now much simpler (#1768) +* Added a matcher that can be used for checking an exceptions message (#1649, #1728) + * The matcher helper function is called `Message` + * The exception must publicly derive from `std::exception` + * The matching is done exactly, including case and whitespace +* Added a matcher that can be used for checking relative equality of floating point numbers (#1746) + * Unlike `Approx`, it considers both sides when determining the allowed margin + * Special cases `NaN` and `INFINITY` to match user expectations + * The matcher helper function is called `WithinRel` +* The ULP matcher now allows for any possible distance between the two numbers +* The random number generators now use Catch-global instance of RNG (#1734, #1736) + * This means that nested random number generators actually generate different numbers + + +### Miscellaneous +* In-repo PNGs have been optimized to lower overhead of using Catch2 via git clone +* Catch2 now uses its own implementation of the URBG concept + * In the future we also plan to use our own implementation of the distributions from `<random>` to provide cross-platform repeatability of random results + + + ## 2.9.2 ### Fixes diff --git a/include/catch.hpp b/include/catch.hpp index dba005ad..5d38092e 100644 --- a/include/catch.hpp +++ b/include/catch.hpp @@ -10,8 +10,8 @@ #define TWOBLUECUBES_CATCH_HPP_INCLUDED #define CATCH_VERSION_MAJOR 2 -#define CATCH_VERSION_MINOR 9 -#define CATCH_VERSION_PATCH 2 +#define CATCH_VERSION_MINOR 10 +#define CATCH_VERSION_PATCH 0 #ifdef __clang__ # pragma clang system_header diff --git a/include/internal/catch_version.cpp b/include/internal/catch_version.cpp index 03fded91..bb5b0616 100644 --- a/include/internal/catch_version.cpp +++ b/include/internal/catch_version.cpp @@ -37,7 +37,7 @@ namespace Catch { } Version const& libraryVersion() { - static Version version( 2, 9, 2, "", 0 ); + static Version version( 2, 10, 0, "", 0 ); return version; } diff --git a/single_include/catch2/catch.hpp b/single_include/catch2/catch.hpp index 5feb2a4b..391db530 100644 --- a/single_include/catch2/catch.hpp +++ b/single_include/catch2/catch.hpp @@ -1,6 +1,6 @@ /* - * Catch v2.9.2 - * Generated: 2019-08-08 13:35:12.279703 + * Catch v2.10.0 + * Generated: 2019-10-13 22:24:46.755734 * ---------------------------------------------------------- * This file has been merged from multiple headers. Please don't edit it directly * Copyright (c) 2019 Two Blue Cubes Ltd. All rights reserved. @@ -14,8 +14,8 @@ #define CATCH_VERSION_MAJOR 2 -#define CATCH_VERSION_MINOR 9 -#define CATCH_VERSION_PATCH 2 +#define CATCH_VERSION_MINOR 10 +#define CATCH_VERSION_PATCH 0 #ifdef __clang__ # pragma clang system_header @@ -186,6 +186,7 @@ namespace Catch { // Android somehow still does not support std::to_string #if defined(__ANDROID__) # define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING +# define CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE #endif //////////////////////////////////////////////////////////////////////////////// @@ -286,49 +287,43 @@ namespace Catch { #define CATCH_CONFIG_COLOUR_NONE #endif -//////////////////////////////////////////////////////////////////////////////// -// Check if string_view is available and usable -// The check is split apart to work around v140 (VS2015) preprocessor issue... -#if defined(__has_include) -#if __has_include(<string_view>) && defined(CATCH_CPP17_OR_GREATER) -# define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW -#endif +#if defined(__UCLIBC__) +#define CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER #endif -//////////////////////////////////////////////////////////////////////////////// -// Check if optional is available and usable -#if defined(__has_include) -# if __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER) -# define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL -# endif // __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER) -#endif // __has_include - -//////////////////////////////////////////////////////////////////////////////// -// Check if byte is available and usable +// Various stdlib support checks that require __has_include #if defined(__has_include) -# if __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER) -# define CATCH_INTERNAL_CONFIG_CPP17_BYTE -# endif // __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER) -#endif // __has_include - -//////////////////////////////////////////////////////////////////////////////// -// Check if variant is available and usable -#if defined(__has_include) -# if __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER) -# if defined(__clang__) && (__clang_major__ < 8) - // work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852 - // fix should be in clang 8, workaround in libstdc++ 8.2 -# include <ciso646> -# if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) -# define CATCH_CONFIG_NO_CPP17_VARIANT -# else -# define CATCH_INTERNAL_CONFIG_CPP17_VARIANT -# endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) -# else -# define CATCH_INTERNAL_CONFIG_CPP17_VARIANT -# endif // defined(__clang__) && (__clang_major__ < 8) -# endif // __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER) -#endif // __has_include + // Check if string_view is available and usable + #if __has_include(<string_view>) && defined(CATCH_CPP17_OR_GREATER) + # define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW + #endif + + // Check if optional is available and usable + # if __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER) + # define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL + # endif // __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER) + + // Check if byte is available and usable + # if __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER) + # define CATCH_INTERNAL_CONFIG_CPP17_BYTE + # endif // __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER) + + // Check if variant is available and usable + # if __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER) + # if defined(__clang__) && (__clang_major__ < 8) + // work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852 + // fix should be in clang 8, workaround in libstdc++ 8.2 + # include <ciso646> + # if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) + # define CATCH_CONFIG_NO_CPP17_VARIANT + # else + # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT + # endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) + # else + # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT + # endif // defined(__clang__) && (__clang_major__ < 8) + # endif // __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER) +#endif // defined(__has_include) #if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) # define CATCH_CONFIG_COUNTER @@ -389,6 +384,14 @@ namespace Catch { # define CATCH_CONFIG_USE_ASYNC #endif +#if defined(CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_NO_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_ANDROID_LOGWRITE) +# define CATCH_CONFIG_ANDROID_LOGWRITE +#endif + +#if defined(CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_NO_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_GLOBAL_NEXTAFTER) +# define CATCH_CONFIG_GLOBAL_NEXTAFTER +#endif + #if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS # define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS @@ -468,7 +471,7 @@ namespace Catch { SourceLineInfo( SourceLineInfo&& ) noexcept = default; SourceLineInfo& operator = ( SourceLineInfo&& ) noexcept = default; - bool empty() const noexcept; + bool empty() const noexcept { return file[0] == '\0'; } bool operator == ( SourceLineInfo const& other ) const noexcept; bool operator < ( SourceLineInfo const& other ) const noexcept; @@ -551,6 +554,7 @@ namespace Catch { #include <cstddef> #include <string> #include <iosfwd> +#include <cassert> namespace Catch { @@ -564,6 +568,7 @@ namespace Catch { class StringRef { public: using size_type = std::size_t; + using const_iterator = const char*; private: friend struct StringRefTestAccess; @@ -619,7 +624,9 @@ namespace Catch { return *this; } - operator std::string() const; + explicit operator std::string() const { + return std::string(m_start, m_size); + } void swap( StringRef& other ) noexcept; @@ -627,7 +634,10 @@ namespace Catch { auto operator == ( StringRef const& other ) const noexcept -> bool; auto operator != ( StringRef const& other ) const noexcept -> bool; - auto operator[] ( size_type index ) const noexcept -> char; + auto operator[] ( size_type index ) const noexcept -> char { + assert(index < m_size); + return m_start[index]; + } public: // named queries auto empty() const noexcept -> bool { @@ -637,7 +647,6 @@ namespace Catch { return m_size; } - auto numberOfCharacters() const noexcept -> size_type; auto c_str() const -> char const*; public: // substrings and searches @@ -647,15 +656,15 @@ namespace Catch { // Note that the pointer can change when if the StringRef is a substring auto currentData() const noexcept -> char const*; + public: // iterators + const_iterator begin() const { return m_start; } + const_iterator end() const { return m_start + m_size; } + private: // ownership queries - may not be consistent between calls auto isOwned() const noexcept -> bool; auto isSubstring() const noexcept -> bool; }; - auto operator + ( StringRef const& lhs, StringRef const& rhs ) -> std::string; - auto operator + ( StringRef const& lhs, char const* rhs ) -> std::string; - auto operator + ( char const* lhs, StringRef const& rhs ) -> std::string; - auto operator += ( std::string& lhs, StringRef const& sr ) -> std::string&; auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&; @@ -670,38 +679,6 @@ inline auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noex } // end catch_stringref.h -// start catch_type_traits.hpp - - -#include <type_traits> - -namespace Catch{ - -#ifdef CATCH_CPP17_OR_GREATER - template <typename...> - inline constexpr auto is_unique = std::true_type{}; - - template <typename T, typename... Rest> - inline constexpr auto is_unique<T, Rest...> = std::bool_constant< - (!std::is_same_v<T, Rest> && ...) && is_unique<Rest...> - >{}; -#else - -template <typename...> -struct is_unique : std::true_type{}; - -template <typename T0, typename T1, typename... Rest> -struct is_unique<T0, T1, Rest...> : std::integral_constant -<bool, - !std::is_same<T0, T1>::value - && is_unique<T0, Rest...>::value - && is_unique<T1, Rest...>::value ->{}; - -#endif -} - -// end catch_type_traits.hpp // start catch_preprocessor.hpp @@ -814,7 +791,7 @@ struct is_unique<T0, T1, Rest...> : std::integral_constant template<template <typename...> class Final, template< typename...> class...Containers, typename...Types>\ constexpr auto create(TypeList<Types...>) noexcept -> decltype(append(Final<>{}, rewrap<Containers>(Types{}...)...)) { return {}; }\ template<template <typename...> class Final, template <typename...> class List, typename...Ts>\ - constexpr auto convert(List<Ts...>) noexcept -> decltype(append(Final<>{},TypeList<Ts>{}...)) { return {}; } + constexpr auto convert(const List<Ts...>& ) noexcept -> decltype(append(Final<>{},TypeList<Ts>{}...)) { return {}; } #define INTERNAL_CATCH_NTTP_1(signature, ...)\ template<INTERNAL_CATCH_REMOVE_PARENS(signature)> struct Nttp{};\ @@ -1443,7 +1420,7 @@ namespace Catch { namespace Detail { struct EnumInfo { StringRef m_name; - std::vector<std::pair<int, std::string>> m_values; + std::vector<std::pair<int, StringRef>> m_values; ~EnumInfo(); @@ -1458,6 +1435,7 @@ namespace Catch { template<typename E> Detail::EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::initializer_list<E> values ) { + static_assert(sizeof(int) >= sizeof(E), "Cannot serialize enum to int"); std::vector<int> intValues; intValues.reserve( values.size() ); for( auto enumValue : values ) @@ -1539,9 +1517,9 @@ namespace Catch { template<typename T> class IsStreamInsertable { - template<typename SS, typename TT> + template<typename Stream, typename U> static auto test(int) - -> decltype(std::declval<SS&>() << std::declval<TT>(), std::true_type()); + -> decltype(std::declval<Stream&>() << std::declval<U>(), std::true_type()); template<typename, typename> static auto test(...)->std::false_type; @@ -2144,7 +2122,7 @@ namespace Catch { \ template<> struct StringMaker<enumName> { \ static std::string convert( enumName value ) { \ static const auto& enumInfo = ::Catch::getMutableRegistryHub().getMutableEnumValuesRegistry().registerEnum( #enumName, #__VA_ARGS__, { __VA_ARGS__ } ); \ - return enumInfo.lookup( static_cast<int>( value ) ); \ + return static_cast<std::string>(enumInfo.lookup( static_cast<int>( value ) )); \ } \ }; \ } @@ -3154,7 +3132,10 @@ namespace Catch { bool contains( std::string const& s, std::string const& infix ); void toLowerInPlace( std::string& s ); std::string toLower( std::string const& s ); + //! Returns a new string without whitespace at the start/end std::string trim( std::string const& str ); + //! Returns a substring of the original ref without whitespace. Beware lifetimes! + StringRef trim(StringRef ref); // !!! Be aware, returns refs into original string - make sure original string outlives them std::vector<StringRef> splitStringRef( StringRef str, char delimiter ); @@ -3335,10 +3316,34 @@ using Matchers::Impl::MatcherBase; } // namespace Catch // end catch_matchers.h -// start catch_matchers_floating.h +// start catch_matchers_exception.hpp -#include <type_traits> -#include <cmath> +namespace Catch { +namespace Matchers { +namespace Exception { + +class ExceptionMessageMatcher : public MatcherBase<std::exception> { + std::string m_message; +public: + + ExceptionMessageMatcher(std::string const& message): + m_message(message) + {} + + bool match(std::exception const& ex) const override; + + std::string describe() const override; +}; + +} // namespace Exception + +Exception::ExceptionMessageMatcher Message(std::string const& message); + +} // namespace Matchers +} // namespace Catch + +// end catch_matchers_exception.hpp +// start catch_matchers_floating.h namespace Catch { namespace Matchers { @@ -3357,22 +3362,43 @@ namespace Matchers { }; struct WithinUlpsMatcher : MatcherBase<double> { - WithinUlpsMatcher(double target, int ulps, FloatingPointKind baseType); + WithinUlpsMatcher(double target, uint64_t ulps, FloatingPointKind baseType); bool match(double const& matchee) const override; std::string describe() const override; private: double m_target; - int m_ulps; + uint64_t m_ulps; FloatingPointKind m_type; }; + // Given IEEE-754 format for floats and doubles, we can assume + // that float -> double promotion is lossless. Given this, we can + // assume that if we do the standard relative comparison of + // |lhs - rhs| <= epsilon * max(fabs(lhs), fabs(rhs)), then we get + // the same result if we do this for floats, as if we do this for + // doubles that were promoted from floats. + struct WithinRelMatcher : MatcherBase<double> { + WithinRelMatcher(double target, double epsilon); + bool match(double const& matchee) const override; + std::string describe() const override; + private: + double m_target; + double m_epsilon; + }; + } // namespace Floating // The following functions create the actual matcher objects. // This allows the types to be inferred - Floating::WithinUlpsMatcher WithinULP(double target, int maxUlpDiff); - Floating::WithinUlpsMatcher WithinULP(float target, int maxUlpDiff); + Floating::WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff); + Floating::WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff); Floating::WithinAbsMatcher WithinAbs(double target, double margin); + Floating::WithinRelMatcher WithinRel(double target, double eps); + // defaults epsilon to 100*numeric_limits<double>::epsilon() + Floating::WithinRelMatcher WithinRel(double target); + Floating::WithinRelMatcher WithinRel(float target, float eps); + // defaults epsilon to 100*numeric_limits<float>::epsilon() + Floating::WithinRelMatcher WithinRel(float target); } // namespace Matchers } // namespace Catch @@ -3797,13 +3823,13 @@ namespace Catch { (Catch::ReusableStringStream() << __VA_ARGS__).str() #define CATCH_INTERNAL_ERROR(...) \ - Catch::throw_logic_error(CATCH_MAKE_MSG( CATCH_INTERNAL_LINEINFO << ": Internal Catch2 error: " << __VA_ARGS__)); + Catch::throw_logic_error(CATCH_MAKE_MSG( CATCH_INTERNAL_LINEINFO << ": Internal Catch2 error: " << __VA_ARGS__)) #define CATCH_ERROR(...) \ - Catch::throw_domain_error(CATCH_MAKE_MSG( __VA_ARGS__ )); + Catch::throw_domain_error(CATCH_MAKE_MSG( __VA_ARGS__ )) #define CATCH_RUNTIME_ERROR(...) \ - Catch::throw_runtime_error(CATCH_MAKE_MSG( __VA_ARGS__ )); + Catch::throw_runtime_error(CATCH_MAKE_MSG( __VA_ARGS__ )) #define CATCH_ENFORCE( condition, ... ) \ do{ if( !(condition) ) CATCH_ERROR( __VA_ARGS__ ); } while(false) @@ -3869,7 +3895,7 @@ namespace Generators { template<typename T> class FixedValuesGenerator final : public IGenerator<T> { static_assert(!std::is_same<T, bool>::value, - "ValuesGenerator does not support bools because of std::vector<bool>" + "FixedValuesGenerator does not support bools because of std::vector<bool>" "specialization, use SingleValue Generator instead."); std::vector<T> m_values; size_t m_idx = 0; @@ -4294,6 +4320,9 @@ namespace Catch { } void cleanUpContext(); + + class SimplePcg32; + SimplePcg32& rng(); } // end catch_context.h @@ -4440,6 +4469,56 @@ namespace Catch { } // end catch_interfaces_config.h +// start catch_random_number_generator.h + +#include <cstdint> + +namespace Catch { + + // This is a simple implementation of C++11 Uniform Random Number + // Generator. It does not provide all operators, because Catch2 + // does not use it, but it should behave as expected inside stdlib's + // distributions. + // The implementation is based on the PCG family (http://pcg-random.org) + class SimplePcg32 { + using state_type = std::uint64_t; + public: + using result_type = std::uint32_t; + static constexpr result_type min() { + return 0; + } + static constexpr result_type max() { + return static_cast<result_type>(-1); + } + + // Provide some default initial state for the default constructor + SimplePcg32():SimplePcg32(0xed743cc4U) {} + + explicit SimplePcg32(result_type seed_); + + void seed(result_type seed_); + void discard(uint64_t skip); + + result_type operator()(); + + private: + friend bool operator==(SimplePcg32 const& lhs, SimplePcg32 const& rhs); + friend bool operator!=(SimplePcg32 const& lhs, SimplePcg32 const& rhs); + + // In theory we also need operator<< and operator>> + // In practice we do not use them, so we will skip them for now + + std::uint64_t m_state; + // This part of the state determines which "stream" of the numbers + // is chosen -- we take it as a constant for Catch2, so we only + // need to deal with seeding the main state. + // Picked by reading 8 bytes from `/dev/random` :-) + static const std::uint64_t s_inc = (0x13ed0cc53f939476ULL << 1ULL) | 1ULL; + }; + +} // end namespace Catch + +// end catch_random_number_generator.h #include <random> namespace Catch { @@ -4447,14 +4526,13 @@ namespace Generators { template <typename Float> class RandomFloatingGenerator final : public IGenerator<Float> { - // FIXME: What is the right seed? - std::minstd_rand m_rand; + Catch::SimplePcg32& m_rng; std::uniform_real_distribution<Float> m_dist; Float m_current_number; public: RandomFloatingGenerator(Float a, Float b): - m_rand(getCurrentContext().getConfig()->rngSeed()), + m_rng(rng()), m_dist(a, b) { static_cast<void>(next()); } @@ -4463,20 +4541,20 @@ public: return m_current_number; } bool next() override { - m_current_number = m_dist(m_rand); + m_current_number = m_dist(m_rng); return true; } }; template <typename Integer> class RandomIntegerGenerator final : public IGenerator<Integer> { - std::minstd_rand m_rand; + Catch::SimplePcg32& m_rng; std::uniform_int_distribution<Integer> m_dist; Integer m_current_number; public: RandomIntegerGenerator(Integer a, Integer b): - m_rand(getCurrentContext().getConfig()->rngSeed()), + m_rng(rng()), m_dist(a, b) { static_cast<void>(next()); } @@ -4485,7 +4563,7 @@ public: return m_current_number; } bool next() override { - m_current_number = m_dist(m_rand); + m_current_number = m_dist(m_rng); return true; } }; @@ -4555,6 +4633,45 @@ GeneratorWrapper<T> range(T const& start, T const& end) { return GeneratorWrapper<T>(pf::make_unique<RangeGenerator<T>>(start, end)); } +template <typename T> +class IteratorGenerator final : public IGenerator<T> { + static_assert(!std::is_same<T, bool>::value, + "IteratorGenerator currently does not support bools" + "because of std::vector<bool> specialization"); + + std::vector<T> m_elems; + size_t m_current = 0; +public: + template <typename InputIterator, typename InputSentinel> + IteratorGenerator(InputIterator first, InputSentinel last):m_elems(first, last) { + if (m_elems.empty()) { + Catch::throw_exception(GeneratorException("IteratorGenerator received no valid values")); + } + } + + T const& get() const override { + return m_elems[m_current]; + } + + bool next() override { + ++m_current; + return m_current != m_elems.size(); + } +}; + +template <typename InputIterator, + typename InputSentinel, + typename ResultType = typename std::iterator_traits<InputIterator>::value_type> +GeneratorWrapper<ResultType> from_range(InputIterator from, InputSentinel to) { + return GeneratorWrapper<ResultType>(pf::make_unique<IteratorGenerator<ResultType>>(from, to)); +} + +template <typename Container, + typename ResultType = typename Container::value_type> +GeneratorWrapper<ResultType> from_range(Container const& cnt) { + return GeneratorWrapper<ResultType>(pf::make_unique<IteratorGenerator<ResultType>>(cnt.begin(), cnt.end())); +} + } // namespace Generators } // namespace Catch @@ -4900,7 +5017,7 @@ namespace Catch virtual bool matches( std::string const& str ) const; private: - std::string adjustCase( std::string const& str ) const; + std::string normaliseString( std::string const& str ) const; CaseSensitive::Choice m_caseSensitivity; WildcardPosition m_wildcard = NoWildcard; std::string m_pattern; @@ -5007,8 +5124,10 @@ namespace Catch { class TestSpecParser { enum Mode{ None, Name, QuotedName, Tag, EscapedName }; Mode m_mode = None; + Mode lastMode = None; bool m_exclusion = false; std::size_t m_pos = 0; + std::size_t m_realPatternPos = 0; std::string m_arg; std::string m_substring; std::string m_patternName; @@ -5032,6 +5151,8 @@ namespace Catch { void endMode(); void escape(); bool isControlChar( char c ) const; + void saveLastMode(); + void revertBackToLastMode(); template<typename T> void addPattern() { @@ -7292,6 +7413,7 @@ namespace TestCaseTracking { class SectionTracker : public TrackerBase { std::vector<std::string> m_filters; + std::string m_trimmed_name; public: SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ); @@ -7583,7 +7705,8 @@ namespace Detail { bool Approx::equalityComparisonImpl(const double other) const { // First try with fixed margin, then compute margin based on epsilon, scale and Approx's value // Thanks to Richard Harris for his help refining the scaled margin value - return marginComparison(m_value, other, m_margin) || marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(m_value))); + return marginComparison(m_value, other, m_margin) + || marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(std::isinf(m_value)? 0 : m_value))); } void Approx::setMargin(double newMargin) { @@ -7868,6 +7991,8 @@ namespace Catch { bool m_includeSuccessfulResults; }; + void seedRng(IConfig const& config); + unsigned int rngSeed(); } // end namespace Catch // end catch_run_context.h @@ -8014,7 +8139,7 @@ namespace Catch { } bool AssertionResult: |