matcher.h 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. #pragma once
  2. #include <google/protobuf/util/message_differencer.h>
  3. #include <util/generic/string.h>
  4. #include <gmock/gmock.h>
  5. #include <ostream>
  6. namespace NGTest {
  7. // Protobuf message compare options
  8. struct TProtoCompareOptions {
  9. using EScope = google::protobuf::util::MessageDifferencer::Scope;
  10. using EMessageFieldComparison = google::protobuf::util::MessageDifferencer::MessageFieldComparison;
  11. using ERepeatedFieldComparison = google::protobuf::util::MessageDifferencer::RepeatedFieldComparison;
  12. using EFloatComparison = google::protobuf::util::DefaultFieldComparator::FloatComparison;
  13. // Sets the scope of the comparison
  14. EScope Scope = EScope::FULL;
  15. // Unset fields comparison method
  16. EMessageFieldComparison MessageFieldComparison = EMessageFieldComparison::EQUIVALENT;
  17. // Sets the type of comparison for repeated field
  18. ERepeatedFieldComparison RepeatedFieldComparison = ERepeatedFieldComparison::AS_LIST;
  19. // Floats and doubles are comparison method
  20. EFloatComparison FloatComparison = EFloatComparison::EXACT;
  21. // if true comparator will treat to float or double fields are equal when both are NaN
  22. bool TreatNanAsEqual = true;
  23. };
  24. // Implements the protobuf message equality matcher, which matches two messages using MessageDifferencer.
  25. template <typename T>
  26. class TEqualsProtoMatcher {
  27. public:
  28. TEqualsProtoMatcher(T expected, const TProtoCompareOptions& options)
  29. : Expected_(expected)
  30. , Options_(options)
  31. {
  32. }
  33. TEqualsProtoMatcher(const TEqualsProtoMatcher& other) = default;
  34. TEqualsProtoMatcher(TEqualsProtoMatcher&& other) = default;
  35. TEqualsProtoMatcher& operator=(const TEqualsProtoMatcher& other) = delete;
  36. TEqualsProtoMatcher& operator=(TEqualsProtoMatcher&& other) = delete;
  37. template <class X>
  38. operator ::testing::Matcher<X>() const {
  39. return ::testing::MakeMatcher(new TImpl<X>(Expected_, Options_));
  40. }
  41. private:
  42. // Implements the protobuf message equality matcher as a Matcher<X>.
  43. template <class X>
  44. class TImpl : public ::testing::MatcherInterface<X> {
  45. public:
  46. TImpl(T expected, const TProtoCompareOptions& options)
  47. : Expected_(expected)
  48. , Options_(options)
  49. {
  50. }
  51. bool MatchAndExplain(X actual, ::testing::MatchResultListener* listener) const override {
  52. google::protobuf::util::DefaultFieldComparator cmp;
  53. cmp.set_float_comparison(Options_.FloatComparison);
  54. cmp.set_treat_nan_as_equal(Options_.TreatNanAsEqual);
  55. google::protobuf::util::MessageDifferencer md;
  56. md.set_scope(Options_.Scope);
  57. md.set_message_field_comparison(Options_.MessageFieldComparison);
  58. md.set_repeated_field_comparison(Options_.RepeatedFieldComparison);
  59. md.set_field_comparator(&cmp);
  60. TString diff;
  61. md.ReportDifferencesToString(&diff);
  62. if (!md.Compare(actual, ::testing::internal::Unwrap(Expected_))) {
  63. if (listener->IsInterested()) {
  64. *listener << diff.c_str();
  65. }
  66. return false;
  67. } else {
  68. if (listener->IsInterested()) {
  69. *listener << "is equal.";
  70. }
  71. return true;
  72. }
  73. }
  74. void DescribeTo(::std::ostream* os) const override {
  75. *os << "message is equal to ";
  76. ::testing::internal::UniversalPrint(::testing::internal::Unwrap(Expected_), os);
  77. }
  78. void DescribeNegationTo(::std::ostream* os) const override {
  79. *os << "message isn't equal to ";
  80. ::testing::internal::UniversalPrint(::testing::internal::Unwrap(Expected_), os);
  81. }
  82. private:
  83. const T Expected_;
  84. const TProtoCompareOptions Options_;
  85. };
  86. private:
  87. const T Expected_;
  88. const TProtoCompareOptions Options_;
  89. };
  90. /**
  91. * Matcher that checks that protobuf messages are equal.
  92. *
  93. * Example:
  94. *
  95. * ```c++
  96. * EXPECT_THAT(actualMessage, EqualsProto(std::ref(expectedMessage));
  97. * ```
  98. * NOTE: according to the documentation there is a similar matcher in the internal gtest implementation of Google
  99. * and it may appear in the opensource in course of this `https://github.com/google/googletest/issues/1761`
  100. */
  101. template <class T>
  102. TEqualsProtoMatcher<T> EqualsProto(T expected, const TProtoCompareOptions& options = {}) {
  103. return {expected, options};
  104. }
  105. template <typename T>
  106. TEqualsProtoMatcher<T> EqualsProtoStrict(T expected) {
  107. return EqualsProto(expected, TProtoCompareOptions{
  108. // Either both fields must be present, or none of them (unset != default value)
  109. .MessageFieldComparison = TProtoCompareOptions::EMessageFieldComparison::EQUAL,
  110. });
  111. }
  112. }