From 2b06b12ca24b464a455c0eaae2e5be094424ef91 Mon Sep 17 00:00:00 2001 From: JordanTheToaster Date: Tue, 29 Apr 2025 07:22:17 +0100 Subject: [PATCH] 3rdparty: Update googletest to v1.16.0 --- 3rdparty/googletest/README.md | 8 +- .../googlemock/include/gmock/gmock-actions.h | 67 +++++-- .../googlemock/include/gmock/gmock-matchers.h | 189 ++++++++++++------ .../include/gmock/gmock-more-actions.h | 7 +- .../include/gmock/gmock-spec-builders.h | 10 +- .../include/gmock/internal/gmock-port.h | 1 + .../googlemock/src/gmock-cardinalities.cc | 8 +- 3rdparty/googletest/googletest/README.md | 2 +- .../googletest/include/gtest/gtest-matchers.h | 6 +- .../googletest/include/gtest/gtest-printers.h | 39 ++++ .../include/gtest/internal/gtest-port.h | 8 + 3rdparty/googletest/googletest/src/gtest.cc | 105 ++++++---- 12 files changed, 320 insertions(+), 130 deletions(-) diff --git a/3rdparty/googletest/README.md b/3rdparty/googletest/README.md index f50c670534..151b3263b6 100644 --- a/3rdparty/googletest/README.md +++ b/3rdparty/googletest/README.md @@ -9,7 +9,7 @@ GoogleTest now follows the We recommend [updating to the latest commit in the `main` branch as often as possible](https://github.com/abseil/abseil-cpp/blob/master/FAQ.md#what-is-live-at-head-and-how-do-i-do-it). We do publish occasional semantic versions, tagged with -`v${major}.${minor}.${patch}` (e.g. `v1.15.0`). +`v${major}.${minor}.${patch}` (e.g. `v1.16.0`). #### Documentation Updates @@ -17,12 +17,12 @@ Our documentation is now live on GitHub Pages at https://google.github.io/googletest/. We recommend browsing the documentation on GitHub Pages rather than directly in the repository. -#### Release 1.15.0 +#### Release 1.16.0 -[Release 1.15.0](https://github.com/google/googletest/releases/tag/v1.15.0) is +[Release 1.16.0](https://github.com/google/googletest/releases/tag/v1.16.0) is now available. -The 1.15.x branch requires at least C++14. +The 1.16.x branch requires at least C++14. #### Continuous Integration diff --git a/3rdparty/googletest/googlemock/include/gmock/gmock-actions.h b/3rdparty/googletest/googlemock/include/gmock/gmock-actions.h index cd12996955..aa47079948 100644 --- a/3rdparty/googletest/googlemock/include/gmock/gmock-actions.h +++ b/3rdparty/googletest/googlemock/include/gmock/gmock-actions.h @@ -1493,6 +1493,7 @@ class DoAllAction { // providing a call operator because even with a particular set of arguments // they don't have a fixed return type. + // We support conversion to OnceAction whenever the sub-action does. template >::value, @@ -1501,6 +1502,21 @@ class DoAllAction { return std::move(final_action_); } + // We also support conversion to OnceAction whenever the sub-action supports + // conversion to Action (since any Action can also be a OnceAction). + template < + typename R, typename... Args, + typename std::enable_if< + conjunction< + negation< + std::is_convertible>>, + std::is_convertible>>::value, + int>::type = 0> + operator OnceAction() && { // NOLINT + return Action(std::move(final_action_)); + } + + // We support conversion to Action whenever the sub-action does. template < typename R, typename... Args, typename std::enable_if< @@ -1580,16 +1596,16 @@ class DoAllAction : Base({}, std::forward(other_actions)...), initial_action_(std::forward(initial_action)) {} - template ...)>>, - std::is_convertible>>::value, - int>::type = 0> + // We support conversion to OnceAction whenever both the initial action and + // the rest support conversion to OnceAction. + template < + typename R, typename... Args, + typename std::enable_if< + conjunction...)>>, + std::is_convertible>>::value, + int>::type = 0> operator OnceAction() && { // NOLINT // Return an action that first calls the initial action with arguments // filtered through InitialActionArgType, then forwards arguments directly @@ -1612,12 +1628,34 @@ class DoAllAction }; } + // We also support conversion to OnceAction whenever the initial action + // supports conversion to Action (since any Action can also be a OnceAction). + // + // The remaining sub-actions must also be compatible, but we don't need to + // special case them because the base class deals with them. + template < + typename R, typename... Args, + typename std::enable_if< + conjunction< + negation...)>>>, + std::is_convertible...)>>, + std::is_convertible>>::value, + int>::type = 0> + operator OnceAction() && { // NOLINT + return DoAll( + Action...)>(std::move(initial_action_)), + std::move(static_cast(*this))); + } + + // We support conversion to Action whenever both the initial action and the + // rest support conversion to Action. template < typename R, typename... Args, typename std::enable_if< conjunction< - // Both the initial action and the rest must support conversion to - // Action. std::is_convertible...)>>, std::is_convertible>>::value, @@ -1665,8 +1703,9 @@ template struct ReturnArgAction { template ::type> - auto operator()(Args&&... args) const -> decltype(std::get( - std::forward_as_tuple(std::forward(args)...))) { + auto operator()(Args&&... args) const + -> decltype(std::get( + std::forward_as_tuple(std::forward(args)...))) { return std::get(std::forward_as_tuple(std::forward(args)...)); } }; diff --git a/3rdparty/googletest/googlemock/include/gmock/gmock-matchers.h b/3rdparty/googletest/googlemock/include/gmock/gmock-matchers.h index 063ee6ca25..e979544c72 100644 --- a/3rdparty/googletest/googlemock/include/gmock/gmock-matchers.h +++ b/3rdparty/googletest/googlemock/include/gmock/gmock-matchers.h @@ -408,13 +408,22 @@ class MatcherCastImpl> { } private: - class Impl : public MatcherInterface { + // If it's possible to implicitly convert a `const T&` to U, then `Impl` can + // take that as input to avoid a copy. Otherwise, such as when `T` is a + // non-const reference type or a type explicitly constructible only from a + // non-const reference, then `Impl` must use `T` as-is (potentially copying). + using ImplArgT = + typename std::conditional::value, + const T&, T>::type; + + class Impl : public MatcherInterface { public: explicit Impl(const Matcher& source_matcher) : source_matcher_(source_matcher) {} // We delegate the matching logic to the source matcher. - bool MatchAndExplain(T x, MatchResultListener* listener) const override { + bool MatchAndExplain(ImplArgT x, + MatchResultListener* listener) const override { using FromType = typename std::remove_cv::type>::type>::type; using ToType = typename std::remove_cv> { // Do the cast to `U` explicitly if necessary. // Otherwise, let implicit conversions do the trick. - using CastType = - typename std::conditional::value, - T&, U>::type; + using CastType = typename std::conditional< + std::is_convertible::value, ImplArgT&, U>::type; return source_matcher_.MatchAndExplain(static_cast(x), listener); @@ -528,18 +536,16 @@ inline Matcher SafeMatcherCast(const M& polymorphic_matcher_or_value) { // safely convert a Matcher to a Matcher (i.e. Matcher is // contravariant): just keep a copy of the original Matcher, convert the // argument from type T to U, and then pass it to the underlying Matcher. -// The only exception is when U is a reference and T is not, as the +// The only exception is when U is a non-const reference and T is not, as the // underlying Matcher may be interested in the argument's address, which -// is not preserved in the conversion from T to U. +// cannot be preserved in the conversion from T to U (since a copy of the input +// T argument would be required to provide a non-const reference U). template inline Matcher SafeMatcherCast(const Matcher& matcher) { // Enforce that T can be implicitly converted to U. static_assert(std::is_convertible::value, - "T must be implicitly convertible to U"); - // Enforce that we are not converting a non-reference type T to a reference - // type U. - static_assert(std::is_reference::value || !std::is_reference::value, - "cannot convert non reference arg to reference"); + "T must be implicitly convertible to U (and T must be a " + "non-const reference if U is a non-const reference)"); // In case both T and U are arithmetic types, enforce that the // conversion is not lossy. typedef GTEST_REMOVE_REFERENCE_AND_CONST_(T) RawT; @@ -561,6 +567,11 @@ Matcher A(); // and MUST NOT BE USED IN USER CODE!!! namespace internal { +// Used per go/ranked-overloads for dispatching. +struct Rank0 {}; +struct Rank1 : Rank0 {}; +using HighestRank = Rank1; + // If the explanation is not empty, prints it to the ostream. inline void PrintIfNotEmpty(const std::string& explanation, ::std::ostream* os) { @@ -1300,34 +1311,48 @@ class AllOfMatcherImpl : public MatcherInterface { bool MatchAndExplain(const T& x, MatchResultListener* listener) const override { - // If either matcher1_ or matcher2_ doesn't match x, we only need - // to explain why one of them fails. + // This method uses matcher's explanation when explaining the result. + // However, if matcher doesn't provide one, this method uses matcher's + // description. std::string all_match_result; - - for (size_t i = 0; i < matchers_.size(); ++i) { + for (const Matcher& matcher : matchers_) { StringMatchResultListener slistener; - if (matchers_[i].MatchAndExplain(x, &slistener)) { - if (all_match_result.empty()) { - all_match_result = slistener.str(); + // Return explanation for first failed matcher. + if (!matcher.MatchAndExplain(x, &slistener)) { + const std::string explanation = slistener.str(); + if (!explanation.empty()) { + *listener << explanation; } else { - std::string result = slistener.str(); - if (!result.empty()) { - all_match_result += ", and "; - all_match_result += result; - } + *listener << "which doesn't match (" << Describe(matcher) << ")"; } - } else { - *listener << slistener.str(); return false; } + // Keep track of explanations in case all matchers succeed. + std::string explanation = slistener.str(); + if (explanation.empty()) { + explanation = Describe(matcher); + } + if (all_match_result.empty()) { + all_match_result = explanation; + } else { + if (!explanation.empty()) { + all_match_result += ", and "; + all_match_result += explanation; + } + } } - // Otherwise we need to explain why *both* of them match. *listener << all_match_result; return true; } private: + // Returns matcher description as a string. + std::string Describe(const Matcher& matcher) const { + StringMatchResultListener listener; + matcher.DescribeTo(listener.stream()); + return listener.str(); + } const std::vector> matchers_; }; @@ -1405,34 +1430,55 @@ class AnyOfMatcherImpl : public MatcherInterface { bool MatchAndExplain(const T& x, MatchResultListener* listener) const override { + // This method uses matcher's explanation when explaining the result. + // However, if matcher doesn't provide one, this method uses matcher's + // description. std::string no_match_result; - - // If either matcher1_ or matcher2_ matches x, we just need to - // explain why *one* of them matches. - for (size_t i = 0; i < matchers_.size(); ++i) { + for (const Matcher& matcher : matchers_) { StringMatchResultListener slistener; - if (matchers_[i].MatchAndExplain(x, &slistener)) { - *listener << slistener.str(); - return true; - } else { - if (no_match_result.empty()) { - no_match_result = slistener.str(); + // Return explanation for first match. + if (matcher.MatchAndExplain(x, &slistener)) { + const std::string explanation = slistener.str(); + if (!explanation.empty()) { + *listener << explanation; } else { - std::string result = slistener.str(); - if (!result.empty()) { - no_match_result += ", and "; - no_match_result += result; - } + *listener << "which matches (" << Describe(matcher) << ")"; + } + return true; + } + // Keep track of explanations in case there is no match. + std::string explanation = slistener.str(); + if (explanation.empty()) { + explanation = DescribeNegation(matcher); + } + if (no_match_result.empty()) { + no_match_result = explanation; + } else { + if (!explanation.empty()) { + no_match_result += ", and "; + no_match_result += explanation; } } } - // Otherwise we need to explain why *both* of them fail. *listener << no_match_result; return false; } private: + // Returns matcher description as a string. + std::string Describe(const Matcher& matcher) const { + StringMatchResultListener listener; + matcher.DescribeTo(listener.stream()); + return listener.str(); + } + + std::string DescribeNegation(const Matcher& matcher) const { + StringMatchResultListener listener; + matcher.DescribeNegationTo(listener.stream()); + return listener.str(); + } + const std::vector> matchers_; }; @@ -1483,7 +1529,7 @@ class SomeOfArrayMatcher { } private: - const ::std::vector matchers_; + const std::vector> matchers_; }; template @@ -2235,6 +2281,9 @@ class ResultOfMatcher { class Impl : public MatcherInterface { using ResultType = decltype(CallableTraits::template Invoke( std::declval(), std::declval())); + using InnerType = std::conditional_t< + std::is_lvalue_reference::value, + const typename std::remove_reference::type&, ResultType>; public: template @@ -2242,7 +2291,7 @@ class ResultOfMatcher { const CallableStorageType& callable, const M& matcher) : result_description_(result_description), callable_(callable), - matcher_(MatcherCast(matcher)) {} + matcher_(MatcherCast(matcher)) {} void DescribeTo(::std::ostream* os) const override { if (result_description_.empty()) { @@ -2272,7 +2321,7 @@ class ResultOfMatcher { // takes a non-const reference as argument. // Also, specifying template argument explicitly is needed because T could // be a non-const reference (e.g. Matcher). - ResultType result = + InnerType result = CallableTraits::template Invoke(callable_, obj); return MatchPrintAndExplain(result, matcher_, listener); } @@ -2285,7 +2334,7 @@ class ResultOfMatcher { // use stateful callables with ResultOf(), which doesn't guarantee // how many times the callable will be invoked. mutable CallableStorageType callable_; - const Matcher matcher_; + const Matcher matcher_; }; // class Impl const std::string result_description_; @@ -2920,10 +2969,6 @@ class EachMatcher { const M inner_matcher_; }; -// Use go/ranked-overloads for dispatching. -struct Rank0 {}; -struct Rank1 : Rank0 {}; - namespace pair_getters { using std::get; template @@ -3255,6 +3300,11 @@ auto UnpackStructImpl(const T& t, std::make_index_sequence<19>, char) { const auto& [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s] = t; return std::tie(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s); } +template +auto UnpackStructImpl(const T& u, std::make_index_sequence<20>, char) { + const auto& [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t] = u; + return std::tie(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t); +} #endif // defined(__cpp_structured_bindings) template @@ -3769,7 +3819,7 @@ class UnorderedElementsAreArrayMatcher { private: UnorderedMatcherRequire::Flags match_flags_; - ::std::vector matchers_; + std::vector> matchers_; }; // Implements ElementsAreArray(). @@ -3790,7 +3840,7 @@ class ElementsAreArrayMatcher { } private: - const ::std::vector matchers_; + const std::vector> matchers_; }; // Given a 2-tuple matcher tm of type Tuple2Matcher and a value second @@ -3877,6 +3927,21 @@ GTEST_API_ std::string FormatMatcherDescription( bool negation, const char* matcher_name, const std::vector& param_names, const Strings& param_values); +// Overloads to support `OptionalMatcher` being used with a type that either +// supports implicit conversion to bool or a `has_value()` method. +template +auto IsOptionalEngaged(const Optional& optional, + Rank1) -> decltype(!!optional) { + // The use of double-negation here is to preserve historical behavior where + // the matcher used `operator!` rather than directly using `operator bool`. + return !static_cast(!optional); +} +template +auto IsOptionalEngaged(const Optional& optional, + Rank0) -> decltype(!optional.has_value()) { + return optional.has_value(); +} + // Implements a matcher that checks the value of a optional<> type variable. template class OptionalMatcher { @@ -3909,7 +3974,7 @@ class OptionalMatcher { bool MatchAndExplain(Optional optional, MatchResultListener* listener) const override { - if (!optional) { + if (!IsOptionalEngaged(optional, HighestRank())) { *listener << "which is not engaged"; return false; } @@ -4742,9 +4807,10 @@ Pointwise(const TupleMatcher& tuple_matcher, const Container& rhs) { // Supports the Pointwise(m, {a, b, c}) syntax. template -inline internal::PointwiseMatcher> Pointwise( - const TupleMatcher& tuple_matcher, std::initializer_list rhs) { - return Pointwise(tuple_matcher, std::vector(rhs)); +inline internal::PointwiseMatcher>> +Pointwise(const TupleMatcher& tuple_matcher, std::initializer_list rhs) { + return Pointwise(tuple_matcher, std::vector>(rhs)); } // UnorderedPointwise(pair_matcher, rhs) matches an STL-style @@ -4906,7 +4972,7 @@ inline internal::UnorderedElementsAreArrayMatcher IsSupersetOf( // - {1} matches IsSubsetOf({Gt(0), Lt(0)}), as 1 matches Gt(0). // - {1, -1} matches IsSubsetOf({Lt(0), Gt(0)}), as 1 matches Gt(0) and -1 // matches Lt(0). -// - {1, 2} doesn't matches IsSubsetOf({Gt(0), Lt(0)}), even though 1 and 2 both +// - {1, 2} doesn't match IsSubsetOf({Gt(0), Lt(0)}), even though 1 and 2 both // match Gt(0). The reason is that different matchers must be used for // elements in different slots of the container. // @@ -5231,9 +5297,10 @@ inline InnerMatcher AllArgs(const InnerMatcher& matcher) { } // Returns a matcher that matches the value of an optional<> type variable. -// The matcher implementation only uses '!arg' and requires that the optional<> -// type has a 'value_type' member type and that '*arg' is of type 'value_type' -// and is printable using 'PrintToString'. It is compatible with +// The matcher implementation only uses '!arg' (or 'arg.has_value()' if '!arg` +// isn't a valid expression) and requires that the optional<> type has a +// 'value_type' member type and that '*arg' is of type 'value_type' and is +// printable using 'PrintToString'. It is compatible with // std::optional/std::experimental::optional. // Note that to compare an optional type variable against nullopt you should // use Eq(nullopt) and not Eq(Optional(nullopt)). The latter implies that the diff --git a/3rdparty/googletest/googlemock/include/gmock/gmock-more-actions.h b/3rdparty/googletest/googlemock/include/gmock/gmock-more-actions.h index e341d47fca..55294dbdbd 100644 --- a/3rdparty/googletest/googlemock/include/gmock/gmock-more-actions.h +++ b/3rdparty/googletest/googlemock/include/gmock/gmock-more-actions.h @@ -601,9 +601,10 @@ template struct InvokeArgumentAction { template ::type> - auto operator()(Args &&...args) const -> decltype(internal::InvokeArgument( - std::get(std::forward_as_tuple(std::forward(args)...)), - std::declval()...)) { + auto operator()(Args &&...args) const + -> decltype(internal::InvokeArgument( + std::get(std::forward_as_tuple(std::forward(args)...)), + std::declval()...)) { internal::FlatTuple args_tuple(FlatTupleConstructTag{}, std::forward(args)...); return params.Apply([&](const Params &...unpacked_params) { diff --git a/3rdparty/googletest/googlemock/include/gmock/gmock-spec-builders.h b/3rdparty/googletest/googlemock/include/gmock/gmock-spec-builders.h index 78ca15d05e..c4c42b7c59 100644 --- a/3rdparty/googletest/googlemock/include/gmock/gmock-spec-builders.h +++ b/3rdparty/googletest/googlemock/include/gmock/gmock-spec-builders.h @@ -868,7 +868,7 @@ class GTEST_API_ ExpectationBase { Clause last_clause_; mutable bool action_count_checked_; // Under mutex_. mutable Mutex mutex_; // Protects action_count_checked_. -}; // class ExpectationBase +}; // class ExpectationBase template class TypedExpectation; @@ -1838,9 +1838,8 @@ R FunctionMocker::InvokeWith(ArgumentTuple&& args) // Doing so slows down compilation dramatically because the *constructor* of // std::function is re-instantiated with different template // parameters each time. - const UninterestingCallCleanupHandler report_uninteresting_call = { - reaction, ss - }; + const UninterestingCallCleanupHandler report_uninteresting_call = {reaction, + ss}; return PerformActionAndPrintResult(nullptr, std::move(args), ss.str(), ss); } @@ -1890,8 +1889,7 @@ R FunctionMocker::InvokeWith(ArgumentTuple&& args) // std::function is re-instantiated with different template // parameters each time. const FailureCleanupHandler handle_failures = { - ss, why, loc, untyped_expectation, found, is_excessive - }; + ss, why, loc, untyped_expectation, found, is_excessive}; return PerformActionAndPrintResult(untyped_action, std::move(args), ss.str(), ss); diff --git a/3rdparty/googletest/googlemock/include/gmock/internal/gmock-port.h b/3rdparty/googletest/googlemock/include/gmock/internal/gmock-port.h index e9d9e32a7a..42d36d2f12 100644 --- a/3rdparty/googletest/googlemock/include/gmock/internal/gmock-port.h +++ b/3rdparty/googletest/googlemock/include/gmock/internal/gmock-port.h @@ -42,6 +42,7 @@ #include #include + #include #include diff --git a/3rdparty/googletest/googlemock/src/gmock-cardinalities.cc b/3rdparty/googletest/googlemock/src/gmock-cardinalities.cc index 92cde3484a..a7283aaf1c 100644 --- a/3rdparty/googletest/googlemock/src/gmock-cardinalities.cc +++ b/3rdparty/googletest/googlemock/src/gmock-cardinalities.cc @@ -53,12 +53,12 @@ class BetweenCardinalityImpl : public CardinalityInterface { : min_(min >= 0 ? min : 0), max_(max >= min_ ? max : min_) { std::stringstream ss; if (min < 0) { - ss << "The invocation lower bound must be >= 0, " - << "but is actually " << min << "."; + ss << "The invocation lower bound must be >= 0, " << "but is actually " + << min << "."; internal::Expect(false, __FILE__, __LINE__, ss.str()); } else if (max < 0) { - ss << "The invocation upper bound must be >= 0, " - << "but is actually " << max << "."; + ss << "The invocation upper bound must be >= 0, " << "but is actually " + << max << "."; internal::Expect(false, __FILE__, __LINE__, ss.str()); } else if (min > max) { ss << "The invocation upper bound (" << max diff --git a/3rdparty/googletest/googletest/README.md b/3rdparty/googletest/googletest/README.md index a7d9aa3258..5de23c5ed2 100644 --- a/3rdparty/googletest/googletest/README.md +++ b/3rdparty/googletest/googletest/README.md @@ -25,7 +25,7 @@ When building GoogleTest as a standalone project, the typical workflow starts with ``` -git clone https://github.com/google/googletest.git -b v1.15.0 +git clone https://github.com/google/googletest.git -b v1.16.0 cd googletest # Main directory of the cloned repository. mkdir build # Create a directory to hold the build output. cd build diff --git a/3rdparty/googletest/googletest/include/gtest/gtest-matchers.h b/3rdparty/googletest/googletest/include/gtest/gtest-matchers.h index eae210e99d..78160f0e41 100644 --- a/3rdparty/googletest/googletest/include/gtest/gtest-matchers.h +++ b/3rdparty/googletest/googletest/include/gtest/gtest-matchers.h @@ -67,10 +67,10 @@ namespace testing { // To implement a matcher Foo for type T, define: // 1. a class FooMatcherMatcher that implements the matcher interface: // using is_gtest_matcher = void; -// bool MatchAndExplain(const T&, std::ostream*); +// bool MatchAndExplain(const T&, std::ostream*) const; // (MatchResultListener* can also be used instead of std::ostream*) -// void DescribeTo(std::ostream*); -// void DescribeNegationTo(std::ostream*); +// void DescribeTo(std::ostream*) const; +// void DescribeNegationTo(std::ostream*) const; // // 2. a factory function that creates a Matcher object from a // FooMatcherMatcher. diff --git a/3rdparty/googletest/googletest/include/gtest/gtest-printers.h b/3rdparty/googletest/googletest/include/gtest/gtest-printers.h index b2822bcde2..198a769349 100644 --- a/3rdparty/googletest/googletest/include/gtest/gtest-printers.h +++ b/3rdparty/googletest/googletest/include/gtest/gtest-printers.h @@ -126,6 +126,10 @@ #include // NOLINT #endif // GTEST_INTERNAL_HAS_STD_SPAN +#if GTEST_INTERNAL_HAS_COMPARE_LIB +#include // NOLINT +#endif // GTEST_INTERNAL_HAS_COMPARE_LIB + namespace testing { // Definitions in the internal* namespaces are subject to change without notice. @@ -782,6 +786,41 @@ void PrintTo(const std::shared_ptr& ptr, std::ostream* os) { (PrintSmartPointer)(ptr, os, 0); } +#if GTEST_INTERNAL_HAS_COMPARE_LIB +template +void PrintOrderingHelper(T ordering, std::ostream* os) { + if (ordering == T::less) { + *os << "(less)"; + } else if (ordering == T::greater) { + *os << "(greater)"; + } else if (ordering == T::equivalent) { + *os << "(equivalent)"; + } else { + *os << "(unknown ordering)"; + } +} + +inline void PrintTo(std::strong_ordering ordering, std::ostream* os) { + if (ordering == std::strong_ordering::equal) { + *os << "(equal)"; + } else { + PrintOrderingHelper(ordering, os); + } +} + +inline void PrintTo(std::partial_ordering ordering, std::ostream* os) { + if (ordering == std::partial_ordering::unordered) { + *os << "(unordered)"; + } else { + PrintOrderingHelper(ordering, os); + } +} + +inline void PrintTo(std::weak_ordering ordering, std::ostream* os) { + PrintOrderingHelper(ordering, os); +} +#endif + // Helper function for printing a tuple. T must be instantiated with // a tuple type. template diff --git a/3rdparty/googletest/googletest/include/gtest/internal/gtest-port.h b/3rdparty/googletest/googletest/include/gtest/internal/gtest-port.h index 8d27c2c4f7..ca18513e77 100644 --- a/3rdparty/googletest/googletest/include/gtest/internal/gtest-port.h +++ b/3rdparty/googletest/googletest/include/gtest/internal/gtest-port.h @@ -2533,4 +2533,12 @@ using Variant = ::std::variant; #define GTEST_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL 1 #endif +#if (defined(__cpp_lib_three_way_comparison) || \ + (GTEST_INTERNAL_HAS_INCLUDE() && \ + GTEST_INTERNAL_CPLUSPLUS_LANG >= 201907L)) +#define GTEST_INTERNAL_HAS_COMPARE_LIB 1 +#else +#define GTEST_INTERNAL_HAS_COMPARE_LIB 0 +#endif + #endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ diff --git a/3rdparty/googletest/googletest/src/gtest.cc b/3rdparty/googletest/googletest/src/gtest.cc index 6662a13ce1..7ff825468c 100644 --- a/3rdparty/googletest/googletest/src/gtest.cc +++ b/3rdparty/googletest/googletest/src/gtest.cc @@ -1660,10 +1660,25 @@ std::string GetBoolAssertionFailureMessage( return msg.GetString(); } -// Helper function for implementing ASSERT_NEAR. +// Helper function for implementing ASSERT_NEAR. Treats infinity as a specific +// value, such that comparing infinity to infinity is equal, the distance +// between -infinity and +infinity is infinity, and infinity <= infinity is +// true. AssertionResult DoubleNearPredFormat(const char* expr1, const char* expr2, const char* abs_error_expr, double val1, double val2, double abs_error) { + // We want to return success when the two values are infinity and at least + // one of the following is true: + // * The values are the same-signed infinity. + // * The error limit itself is infinity. + // This is done here so that we don't end up with a NaN when calculating the + // difference in values. + if (std::isinf(val1) && std::isinf(val2) && + (std::signbit(val1) == std::signbit(val2) || + (abs_error > 0.0 && std::isinf(abs_error)))) { + return AssertionSuccess(); + } + const double diff = fabs(val1 - val2); if (diff <= abs_error) return AssertionSuccess(); @@ -3974,6 +3989,12 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener { static void OutputXmlTestSuiteForTestResult(::std::ostream* stream, const TestResult& result); + // Streams a test case XML stanza containing the given test result. + // + // Requires: result.Failed() + static void OutputXmlTestCaseForTestResult(::std::ostream* stream, + const TestResult& result); + // Streams an XML representation of a TestResult object. static void OutputXmlTestResult(::std::ostream* stream, const TestResult& result); @@ -3991,16 +4012,11 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener { static void PrintXmlUnitTest(::std::ostream* stream, const UnitTest& unit_test); - // Produces a string representing the test properties in a result as space - // delimited XML attributes based on the property key="value" pairs. - // When the std::string is not empty, it includes a space at the beginning, - // to delimit this attribute from prior attributes. - static std::string TestPropertiesAsXmlAttributes(const TestResult& result); - // Streams an XML representation of the test properties of a TestResult // object. static void OutputXmlTestProperties(std::ostream* stream, - const TestResult& result); + const TestResult& result, + const std::string& indent); // The output file. const std::string output_file_; @@ -4221,6 +4237,15 @@ void XmlUnitTestResultPrinter::OutputXmlTestSuiteForTestResult( FormatEpochTimeInMillisAsIso8601(result.start_timestamp())); *stream << ">"; + OutputXmlTestCaseForTestResult(stream, result); + + // Complete the test suite. + *stream << " \n"; +} + +// Streams a test case XML stanza containing the given test result. +void XmlUnitTestResultPrinter::OutputXmlTestCaseForTestResult( + ::std::ostream* stream, const TestResult& result) { // Output the boilerplate for a minimal test case with a single test. *stream << " \n"; } // Prints an XML representation of a TestInfo object. @@ -4328,7 +4350,7 @@ void XmlUnitTestResultPrinter::OutputXmlTestResult(::std::ostream* stream, if (failures == 0 && skips == 0) { *stream << ">\n"; } - OutputXmlTestProperties(stream, result); + OutputXmlTestProperties(stream, result, /*indent=*/" "); *stream << " \n"; } } @@ -4357,13 +4379,18 @@ void XmlUnitTestResultPrinter::PrintXmlTestSuite(std::ostream* stream, OutputXmlAttribute( stream, kTestsuite, "timestamp", FormatEpochTimeInMillisAsIso8601(test_suite.start_timestamp())); - *stream << TestPropertiesAsXmlAttributes(test_suite.ad_hoc_test_result()); } *stream << ">\n"; + OutputXmlTestProperties(stream, test_suite.ad_hoc_test_result(), + /*indent=*/" "); for (int i = 0; i < test_suite.total_test_count(); ++i) { if (test_suite.GetTestInfo(i)->is_reportable()) OutputXmlTestInfo(stream, test_suite.name(), *test_suite.GetTestInfo(i)); } + if (test_suite.ad_hoc_test_result().Failed()) { + OutputXmlTestCaseForTestResult(stream, test_suite.ad_hoc_test_result()); + } + *stream << " \n"; } @@ -4393,11 +4420,12 @@ void XmlUnitTestResultPrinter::PrintXmlUnitTest(std::ostream* stream, OutputXmlAttribute(stream, kTestsuites, "random_seed", StreamableToString(unit_test.random_seed())); } - *stream << TestPropertiesAsXmlAttributes(unit_test.ad_hoc_test_result()); OutputXmlAttribute(stream, kTestsuites, "name", "AllTests"); *stream << ">\n"; + OutputXmlTestProperties(stream, unit_test.ad_hoc_test_result(), + /*indent=*/" "); for (int i = 0; i < unit_test.total_test_suite_count(); ++i) { if (unit_test.GetTestSuite(i)->reportable_test_count() > 0) PrintXmlTestSuite(stream, *unit_test.GetTestSuite(i)); @@ -4434,21 +4462,8 @@ void XmlUnitTestResultPrinter::PrintXmlTestsList( *stream << "\n"; } -// Produces a string representing the test properties in a result as space -// delimited XML attributes based on the property key="value" pairs. -std::string XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes( - const TestResult& result) { - Message attributes; - for (int i = 0; i < result.test_property_count(); ++i) { - const TestProperty& property = result.GetTestProperty(i); - attributes << " " << property.key() << "=" << "\"" - << EscapeXmlAttribute(property.value()) << "\""; - } - return attributes.GetString(); -} - void XmlUnitTestResultPrinter::OutputXmlTestProperties( - std::ostream* stream, const TestResult& result) { + std::ostream* stream, const TestResult& result, const std::string& indent) { const std::string kProperties = "properties"; const std::string kProperty = "property"; @@ -4456,15 +4471,15 @@ void XmlUnitTestResultPrinter::OutputXmlTestProperties( return; } - *stream << " <" << kProperties << ">\n"; + *stream << indent << "<" << kProperties << ">\n"; for (int i = 0; i < result.test_property_count(); ++i) { const TestProperty& property = result.GetTestProperty(i); - *stream << " <" << kProperty; + *stream << indent << " <" << kProperty; *stream << " name=\"" << EscapeXmlAttribute(property.key()) << "\""; *stream << " value=\"" << EscapeXmlAttribute(property.value()) << "\""; *stream << "/>\n"; } - *stream << " \n"; + *stream << indent << "\n"; } // End XmlUnitTestResultPrinter @@ -4503,6 +4518,12 @@ class JsonUnitTestResultPrinter : public EmptyTestEventListener { static void OutputJsonTestSuiteForTestResult(::std::ostream* stream, const TestResult& result); + // Streams a test case JSON stanza containing the given test result. + // + // Requires: result.Failed() + static void OutputJsonTestCaseForTestResult(::std::ostream* stream, + const TestResult& result); + // Streams a JSON representation of a TestResult object. static void OutputJsonTestResult(::std::ostream* stream, const TestResult& result); @@ -4673,6 +4694,15 @@ void JsonUnitTestResultPrinter::OutputJsonTestSuiteForTestResult( } *stream << Indent(6) << "\"testsuite\": [\n"; + OutputJsonTestCaseForTestResult(stream, result); + + // Finish the test suite. + *stream << "\n" << Indent(6) << "]\n" << Indent(4) << "}"; +} + +// Streams a test case JSON stanza containing the given test result. +void JsonUnitTestResultPrinter::OutputJsonTestCaseForTestResult( + ::std::ostream* stream, const TestResult& result) { // Output the boilerplate for a new test case. *stream << Indent(8) << "{\n"; OutputJsonKey(stream, "testcase", "name", "", Indent(10)); @@ -4689,9 +4719,6 @@ void JsonUnitTestResultPrinter::OutputJsonTestSuiteForTestResult( // Output the actual test result. OutputJsonTestResult(stream, result); - - // Finish the test suite. - *stream << "\n" << Indent(6) << "]\n" << Indent(4) << "}"; } // Prints a JSON representation of a TestInfo object. @@ -4836,6 +4863,16 @@ void JsonUnitTestResultPrinter::PrintJsonTestSuite( OutputJsonTestInfo(stream, test_suite.name(), *test_suite.GetTestInfo(i)); } } + + // If there was a failure in the test suite setup or teardown include that in + // the output. + if (test_suite.ad_hoc_test_result().Failed()) { + if (comma) { + *stream << ",\n"; + } + OutputJsonTestCaseForTestResult(stream, test_suite.ad_hoc_test_result()); + } + *stream << "\n" << kIndent << "]\n" << Indent(4) << "}"; }