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 /single_include/catch2 | |
| parent | a92a7d02290eae896413a7d96e4875587c0dcd42 (diff) | |
| download | catch3-2.10.0.tar.gz | |
v2.10.0v2.10.0
Diffstat (limited to 'single_include/catch2')
| -rw-r--r-- | single_include/catch2/catch.hpp | 930 | ||||
| -rw-r--r-- | single_include/catch2/catch_reporter_teamcity.hpp | 3 |
2 files changed, 609 insertions, 324 deletions
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::hasExpression() const { - return m_info.capturedExpression[0] != 0; + return !m_info.capturedExpression.empty(); } bool AssertionResult::hasMessage() const { @@ -8022,16 +8147,22 @@ namespace Catch { } std::string AssertionResult::getExpression() const { - if( isFalseTest( m_info.resultDisposition ) ) - return "!(" + m_info.capturedExpression + ")"; - else - return m_info.capturedExpression; + // Possibly overallocating by 3 characters should be basically free + std::string expr; expr.reserve(m_info.capturedExpression.size() + 3); + if (isFalseTest(m_info.resultDisposition)) { + expr += "!("; + } + expr += m_info.capturedExpression; + if (isFalseTest(m_info.resultDisposition)) { + expr += ')'; + } + return expr; } std::string AssertionResult::getExpressionInMacro() const { std::string expr; - if( m_info.macroName[0] == 0 ) - expr = m_info.capturedExpression; + if( m_info.macroName.empty() ) + expr = static_cast<std::string>(m_info.capturedExpression); else { expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 ); expr += m_info.macroName; @@ -9587,9 +9718,6 @@ namespace Catch { namespace Catch { - bool SourceLineInfo::empty() const noexcept { - return file[0] == '\0'; - } bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const noexcept { return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0); } @@ -9625,11 +9753,23 @@ namespace Catch { : m_data( data ), m_stream( openStream() ) { + // We need to trim filter specs to avoid trouble with superfluous + // whitespace (esp. important for bdd macros, as those are manually + // aligned with whitespace). + + for (auto& elem : m_data.testsOrTags) { + elem = trim(elem); + } + for (auto& elem : m_data.sectionsToRun) { + elem = trim(elem); + } + TestSpecParser parser(ITagAliasRegistry::get()); - if (!data.testsOrTags.empty()) { + if (!m_data.testsOrTags.empty()) { m_hasTestFilters = true; - for( auto const& testOrTags : data.testsOrTags ) - parser.parse( testOrTags ); + for (auto const& testOrTags : m_data.testsOrTags) { + parser.parse(testOrTags); + } } m_testSpec = parser.testSpec(); } @@ -9974,6 +10114,12 @@ namespace Catch { IContext::~IContext() = default; IMutableContext::~IMutableContext() = default; Context::~Context() = default; + + SimplePcg32& rng() { + static SimplePcg32 s_rng; + return s_rng; + } + } // end catch_context.cpp // start catch_debug_console.cpp @@ -9987,12 +10133,12 @@ namespace Catch { } // end catch_debug_console.h -#if defined(__ANDROID__) +#if defined(CATCH_CONFIG_ANDROID_LOGWRITE) #include <android/log.h> namespace Catch { void writeToDebugConsole( std::string const& text ) { - __android_log_print( ANDROID_LOG_DEBUG, "Catch", text.c_str() ); + __android_log_write( ANDROID_LOG_DEBUG, "Catch", text.c_str() ); } } @@ -10193,7 +10339,7 @@ namespace Catch { EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::vector<int> const& values) override; }; - std::vector<std::string> parseEnums( StringRef enums ); + std::vector<StringRef> parseEnums( StringRef enums ); } // Detail @@ -10210,13 +10356,25 @@ namespace Catch { namespace Detail { - std::vector<std::string> parseEnums( StringRef enums ) { + namespace { + // Extracts the actual name part of an enum instance + // In other words, it returns the Blue part of Bikeshed::Colour::Blue + StringRef extractInstanceName(StringRef enumInstance) { + // Find last occurence of ":" + size_t name_start = enumInstance.size(); + while (name_start > 0 && enumInstance[name_start - 1] != ':') { + --name_start; + } + return enumInstance.substr(name_start, enumInstance.size() - name_start); + } + } + + std::vector<StringRef> parseEnums( StringRef enums ) { auto enumValues = splitStringRef( enums, ',' ); - std::vector<std::string> parsed; + std::vector<StringRef> parsed; parsed.reserve( enumValues.size() ); for( auto const& enumValue : enumValues ) { - auto identifiers = splitStringRef( enumValue, ':' ); - parsed.push_back( Catch::trim( identifiers.back() ) ); + parsed.push_back(trim(extractInstanceName(enumValue))); } return parsed; } @@ -10228,7 +10386,7 @@ namespace Catch { if( valueToName.first == value ) return valueToName.second; } - return "{** unexpected enum value **}"; + return "{** unexpected enum value **}"_sr; } std::unique_ptr<EnumInfo> makeEnumInfo( StringRef enumName, StringRef allValueNames, std::vector<int> const& values ) { @@ -10246,10 +10404,8 @@ namespace Catch { } EnumInfo const& EnumValuesRegistry::registerEnum( StringRef enumName, StringRef allValueNames, std::vector<int> const& values ) { - auto enumInfo = makeEnumInfo( enumName, allValueNames, values ); - EnumInfo* raw = enumInfo.get(); - m_enumInfos.push_back( std::move( enumInfo ) ); - return *raw; + m_enumInfos.push_back(makeEnumInfo(enumName, allValueNames, values)); + return *m_enumInfos.back(); } } // Detail @@ -10527,22 +10683,6 @@ namespace Catch { // end catch_fatal_condition.cpp // start catch_generators.cpp -// start catch_random_number_generator.h - -#include <algorithm> -#include <random> - -namespace Catch { - - struct IConfig; - - std::mt19937& rng(); - void seedRng( IConfig const& config ); - unsigned int rngSeed(); - -} - -// end catch_random_number_generator.h #include <limits> #include <set> @@ -10998,6 +11138,29 @@ using Matchers::Impl::MatcherBase; } // namespace Catch // end catch_matchers.cpp +// start catch_matchers_exception.cpp + +namespace Catch { +namespace Matchers { +namespace Exception { + +bool ExceptionMessageMatcher::match(std::exception const& ex) const { + return ex.what() == m_message; +} + +std::string ExceptionMessageMatcher::describe() const { + return "exception message matches \"" + m_message + "\""; +} + +} +Exception::ExceptionMessageMatcher Message(std::string const& message) { + return Exception::ExceptionMessageMatcher(message); +} + +// namespace Exception +} // namespace Matchers +} // namespace Catch +// end catch_matchers_exception.cpp // start catch_matchers_floating.cpp // start catch_polyfills.hpp @@ -11026,85 +11189,115 @@ namespace Catch { } // end namespace Catch // end catch_to_string.hpp +#include <algorithm> +#include <cmath> #include <cstdlib> #include <cstdint> #include <cstring> #include <sstream> +#include <type_traits> #include <iomanip> #include <limits> namespace Catch { -namespace Matchers { -namespace Floating { -enum class FloatingPointKind : uint8_t { - Float, - Double -}; -} -} -} - namespace { -template <typename T> -struct Converter; - -template <> -struct Converter<float> { - static_assert(sizeof(float) == sizeof(int32_t), "Important ULP matcher assumption violated"); - Converter(float f) { + int32_t convert(float f) { + static_assert(sizeof(float) == sizeof(int32_t), "Important ULP matcher assumption violated"); + int32_t i; std::memcpy(&i, &f, sizeof(f)); + return i; } - int32_t i; -}; -template <> -struct Converter<double> { - static_assert(sizeof(double) == sizeof(int64_t), "Important ULP matcher assumption violated"); - Converter(double d) { + int64_t convert(double d) { + static_assert(sizeof(double) == sizeof(int64_t), "Important ULP matcher assumption violated"); + int64_t i; std::memcpy(&i, &d, sizeof(d)); + return i; } - int64_t i; -}; -template <typename T> -auto convert(T t) -> Converter<T> { - return Converter<T>(t); -} + template <typename FP> + bool almostEqualUlps(FP lhs, FP rhs, uint64_t maxUlpDiff) { + // Comparison with NaN should always be false. + // This way we can rule it out before getting into the ugly details + if (Catch::isnan(lhs) || Catch::isnan(rhs)) { + return false; + } -template <typename FP> -bool almostEqualUlps(FP lhs, FP rhs, int maxUlpDiff) { - // Comparison with NaN should always be false. - // This way we can rule it out before getting into the ugly details - if (Catch::isnan(lhs) || Catch::isnan(rhs)) { - return false; + auto lc = convert(lhs); |