Add MessageDifferencer::set_unpack_any to allow disabling Any unpacking. PiperOrigin-RevId: 1018289831
diff --git a/src/google/protobuf/util/message_differencer.cc b/src/google/protobuf/util/message_differencer.cc index 8b8a1d5..27cd1e1 100644 --- a/src/google/protobuf/util/message_differencer.cc +++ b/src/google/protobuf/util/message_differencer.cc
@@ -609,7 +609,8 @@ const Message& message2, int unpacked_any, std::vector<SpecificField>* parent_fields) { // Expand google.protobuf.Any payload if possible. - if (message1.GetDescriptor()->full_name() == internal::kAnyFullTypeName) { + if (unpack_any_ && + message1.GetDescriptor()->full_name() == internal::kAnyFullTypeName) { std::unique_ptr<Message> data1; std::unique_ptr<Message> data2; if (unpack_any_field_.UnpackAny(message1, &data1) &&
diff --git a/src/google/protobuf/util/message_differencer.h b/src/google/protobuf/util/message_differencer.h index d3f0b80..d3e21b4 100644 --- a/src/google/protobuf/util/message_differencer.h +++ b/src/google/protobuf/util/message_differencer.h
@@ -88,6 +88,7 @@ // Note on handling of google.protobuf.Any: MessageDifferencer automatically // unpacks Any::value into a Message and compares its individual fields. // Messages encoded in a repeated Any cannot be compared using TreatAsMap. +// This can be disabled with set_unpack_any(false). // // Note on thread-safety: MessageDifferencer is *not* thread-safe. You need to // guard it with a lock to use the same MessageDifferencer instance from @@ -564,6 +565,13 @@ report_ignores_ = report_ignores; } + // Tells the differencer whether or not to unpack google.protobuf.Any + // messages and compare their payloads field by field. When false, Any + // messages are compared as regular messages (i.e. by their raw type_url and + // value bytes). This method must be called before Compare. The default for a + // new differencer is true. + void set_unpack_any(bool unpack_any) { unpack_any_ = unpack_any; } + // Sets the scope of the comparison (as defined in the Scope enumeration // above) that is used by this differencer when determining which fields to // compare between the messages. @@ -967,6 +975,7 @@ bool report_moves_; bool report_ignores_; bool force_compare_no_presence_ = false; + bool unpack_any_ = true; std::string* output_string_;
diff --git a/src/google/protobuf/util/message_differencer_unittest.cc b/src/google/protobuf/util/message_differencer_unittest.cc index 3be1e3c..b387eec 100644 --- a/src/google/protobuf/util/message_differencer_unittest.cc +++ b/src/google/protobuf/util/message_differencer_unittest.cc
@@ -60,6 +60,7 @@ namespace { using ::google::protobuf::internal::UnsetFieldsMetadataMessageDifferencerTestUtil; +using ::testing::HasSubstr; proto3_unittest::TestNoPresenceField MakeTestNoPresenceField() { @@ -4300,6 +4301,45 @@ R"(type_url: ".+/proto2_unittest.TestField\" -> ".+/proto2_unittest.ForeignMessage")")); } +TEST(AnyTest, UnpackAnyDisabled) { + proto2_unittest::TestField value1, value2; + value1.set_a(20); + value2.set_a(21); + + proto2_unittest::TestAny m1, m2; + ABSL_CHECK(m1.mutable_any_value()->PackFrom(value1)); + ABSL_CHECK(m2.mutable_any_value()->PackFrom(value2)); + util::MessageDifferencer message_differencer; + message_differencer.set_unpack_any(false); + std::string difference_string; + message_differencer.ReportDifferencesToString(&difference_string); + EXPECT_FALSE(message_differencer.Compare(m1, m2)); + // The Any is compared as a regular message, so the diff is on the raw value. + EXPECT_THAT(difference_string, HasSubstr("modified: any_value.value: ")); +} + +TEST(AnyTest, UnpackAnyDisabledComparesRawBytes) { + // Two different encodings of the same logical payload: equal when unpacked, + // but not equal when compared by raw bytes. + proto2_unittest::TestAny m1, m2; + m1.mutable_any_value()->set_type_url( + "type.googleapis.com/proto2_unittest.TestField"); + m1.mutable_any_value()->set_value(absl::string_view("\x08\x01", 2)); + m2.mutable_any_value()->set_type_url( + "type.googleapis.com/proto2_unittest.TestField"); + m2.mutable_any_value()->set_value(absl::string_view("\x08\x00\x08\x01", 4)); + + util::MessageDifferencer unpacking_differencer; + EXPECT_TRUE(unpacking_differencer.Compare(m1, m2)); + + util::MessageDifferencer raw_differencer; + raw_differencer.set_unpack_any(false); + EXPECT_FALSE(raw_differencer.Compare(m1, m2)); + + m2.mutable_any_value()->set_value(m1.any_value().value()); + EXPECT_TRUE(raw_differencer.Compare(m1, m2)); +} + TEST(Anytest, TreatAsSet) { proto2_unittest::TestField value1, value2; value1.set_a(20);