123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132 |
- #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,
- });
- }
- }
|