diff options
author | hitsedesen <hitsedesen@yandex-team.com> | 2024-12-16 07:06:04 +0300 |
---|---|---|
committer | hitsedesen <hitsedesen@yandex-team.com> | 2024-12-16 07:56:51 +0300 |
commit | a95c560962ff44014b66b1350c2b9b02de458475 (patch) | |
tree | 5469217a064f3c31da60d3982be801d0b2f7c9ee /library/cpp | |
parent | 26c23ae261d7a209eaf95502876ee4dd4d74fcca (diff) | |
download | ydb-a95c560962ff44014b66b1350c2b9b02de458475.tar.gz |
YT: Add unchecked enums to protobuf interop
commit_hash:b1009a56f6e70d65c67b72f3079ed71e43b48a7c
Diffstat (limited to 'library/cpp')
-rw-r--r-- | library/cpp/testing/gtest_protobuf/matcher.h | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/library/cpp/testing/gtest_protobuf/matcher.h b/library/cpp/testing/gtest_protobuf/matcher.h new file mode 100644 index 0000000000..006e56ee3d --- /dev/null +++ b/library/cpp/testing/gtest_protobuf/matcher.h @@ -0,0 +1,132 @@ +#pragma once + +#include <google/protobuf/util/message_differencer.h> +#include <util/generic/string.h> + +#include <gmock/gmock.h> + +#include <ostream> + +namespace NGTest { + // Protobuf message compare options + struct TProtoCompareOptions { + using EScope = google::protobuf::util::MessageDifferencer::Scope; + using EMessageFieldComparison = google::protobuf::util::MessageDifferencer::MessageFieldComparison; + using ERepeatedFieldComparison = google::protobuf::util::MessageDifferencer::RepeatedFieldComparison; + using EFloatComparison = google::protobuf::util::DefaultFieldComparator::FloatComparison; + + // Sets the scope of the comparison + EScope Scope = EScope::FULL; + // Unset fields comparison method + EMessageFieldComparison MessageFieldComparison = EMessageFieldComparison::EQUIVALENT; + // Sets the type of comparison for repeated field + ERepeatedFieldComparison RepeatedFieldComparison = ERepeatedFieldComparison::AS_LIST; + // Floats and doubles are comparison method + EFloatComparison FloatComparison = EFloatComparison::EXACT; + // if true comparator will treat to float or double fields are equal when both are NaN + bool TreatNanAsEqual = true; + }; + + // Implements the protobuf message equality matcher, which matches two messages using MessageDifferencer. + template <typename T> + class TEqualsProtoMatcher { + public: + TEqualsProtoMatcher(T expected, const TProtoCompareOptions& options) + : Expected_(expected) + , Options_(options) + { + } + TEqualsProtoMatcher(const TEqualsProtoMatcher& other) = default; + TEqualsProtoMatcher(TEqualsProtoMatcher&& other) = default; + + TEqualsProtoMatcher& operator=(const TEqualsProtoMatcher& other) = delete; + TEqualsProtoMatcher& operator=(TEqualsProtoMatcher&& other) = delete; + + template <class X> + operator ::testing::Matcher<X>() const { + return ::testing::MakeMatcher(new TImpl<X>(Expected_, Options_)); + } + + private: + // Implements the protobuf message equality matcher as a Matcher<X>. + template <class X> + class TImpl : public ::testing::MatcherInterface<X> { + public: + TImpl(T expected, const TProtoCompareOptions& options) + : Expected_(expected) + , Options_(options) + { + } + + bool MatchAndExplain(X actual, ::testing::MatchResultListener* listener) const override { + google::protobuf::util::DefaultFieldComparator cmp; + cmp.set_float_comparison(Options_.FloatComparison); + cmp.set_treat_nan_as_equal(Options_.TreatNanAsEqual); + + google::protobuf::util::MessageDifferencer md; + md.set_scope(Options_.Scope); + md.set_message_field_comparison(Options_.MessageFieldComparison); + md.set_repeated_field_comparison(Options_.RepeatedFieldComparison); + md.set_field_comparator(&cmp); + + TString diff; + md.ReportDifferencesToString(&diff); + + if (!md.Compare(actual, ::testing::internal::Unwrap(Expected_))) { + if (listener->IsInterested()) { + *listener << diff.c_str(); + } + return false; + } else { + if (listener->IsInterested()) { + *listener << "is equal."; + } + return true; + } + } + + void DescribeTo(::std::ostream* os) const override { + *os << "message is equal to "; + ::testing::internal::UniversalPrint(::testing::internal::Unwrap(Expected_), os); + } + + void DescribeNegationTo(::std::ostream* os) const override { + *os << "message isn't equal to "; + ::testing::internal::UniversalPrint(::testing::internal::Unwrap(Expected_), os); + } + + private: + const T Expected_; + const TProtoCompareOptions Options_; + }; + + private: + const T Expected_; + const TProtoCompareOptions Options_; + }; + + /** + * Matcher that checks that protobuf messages are equal. + * + * Example: + * + * ```c++ + * EXPECT_THAT(actualMessage, EqualsProto(std::ref(expectedMessage)); + * ``` + * NOTE: according to the documentation there is a similar matcher in the internal gtest implementation of Google + * and it may appear in the opensource in course of this `https://github.com/google/googletest/issues/1761` + */ + + template <class T> + TEqualsProtoMatcher<T> EqualsProto(T expected, const TProtoCompareOptions& options = {}) { + return {expected, options}; + } + + template <typename T> + TEqualsProtoMatcher<T> EqualsProtoStrict(T expected) { + return EqualsProto(expected, TProtoCompareOptions{ + // Either both fields must be present, or none of them (unset != default value) + .MessageFieldComparison = TProtoCompareOptions::EMessageFieldComparison::EQUAL, + }); + } +} |