// Protocol Buffers - Google's data interchange format // Copyright 2008 Google Inc. All rights reserved. // https://developers.google.com/protocol-buffers/ // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Author: jschorr@google.com (Joseph Schorr) // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. // // TODO(ksroka): Move some of these tests to field_comparator_test.cc. #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace google { namespace protobuf { namespace { const FieldDescriptor* GetFieldDescriptor( const Message& message, const string& field_name) { std::vector field_path = Split(field_name, ".", true); const Descriptor* descriptor = message.GetDescriptor(); const FieldDescriptor* field = NULL; for (int i = 0; i < field_path.size(); i++) { field = descriptor->FindFieldByName(field_path[i]); descriptor = field->message_type(); } return field; } void ExpectEqualsWithDifferencer(util::MessageDifferencer* differencer, const Message& msg1, const Message& msg2) { differencer->set_scope(util::MessageDifferencer::FULL); EXPECT_TRUE(differencer->Compare(msg1, msg2)); differencer->set_scope(util::MessageDifferencer::PARTIAL); EXPECT_TRUE(differencer->Compare(msg1, msg2)); } TEST(MessageDifferencerTest, BasicEqualityTest) { // Create the testing protos unittest::TestAllTypes msg1; unittest::TestAllTypes msg2; TestUtil::SetAllFields(&msg1); TestUtil::SetAllFields(&msg2); // Compare EXPECT_TRUE(util::MessageDifferencer::Equals(msg1, msg2)); } TEST(MessageDifferencerTest, BasicInequalityTest) { // Create the testing protos unittest::TestAllTypes msg1; unittest::TestAllTypes msg2; TestUtil::SetAllFields(&msg1); TestUtil::SetAllFields(&msg2); msg1.set_optional_int32(-1); // Compare EXPECT_FALSE(util::MessageDifferencer::Equals(msg1, msg2)); } TEST(MessageDifferencerTest, RepeatedFieldInequalityTest) { // Create the testing protos unittest::TestAllTypes msg1; unittest::TestAllTypes msg2; TestUtil::SetAllFields(&msg1); TestUtil::SetAllFields(&msg2); msg1.add_repeated_int32(-1); // Compare EXPECT_FALSE(util::MessageDifferencer::Equals(msg1, msg2)); } TEST(MessageDifferencerTest, MapFieldEqualityTest) { // Create the testing protos unittest::TestMap msg1; unittest::TestMap msg2; MapReflectionTester tester(unittest::TestMap::descriptor()); tester.SetMapFieldsViaReflection(&msg1); tester.SetMapFieldsViaReflection(&msg2); tester.SwapMapsViaReflection(&msg1); // Compare EXPECT_TRUE(util::MessageDifferencer::Equals(msg1, msg2)); } TEST(MessageDifferencerTest, BasicPartialEqualityTest) { // Create the testing protos unittest::TestAllTypes msg1; unittest::TestAllTypes msg2; TestUtil::SetAllFields(&msg1); TestUtil::SetAllFields(&msg2); // Compare util::MessageDifferencer differencer; differencer.set_scope(util::MessageDifferencer::PARTIAL); EXPECT_TRUE(differencer.Compare(msg1, msg2)); } TEST(MessageDifferencerTest, PartialEqualityTestExtraField) { // Create the testing protos unittest::TestAllTypes msg1; unittest::TestAllTypes msg2; TestUtil::SetAllFields(&msg1); TestUtil::SetAllFields(&msg2); msg1.clear_optional_int32(); // Compare util::MessageDifferencer differencer; differencer.set_scope(util::MessageDifferencer::PARTIAL); EXPECT_TRUE(differencer.Compare(msg1, msg2)); } TEST(MessageDifferencerTest, PartialEqualityTestSkipRequiredField) { // Create the testing protos unittest::TestRequired msg1; unittest::TestRequired msg2; msg1.set_a(401); msg2.set_a(401); msg2.set_b(402); // Compare util::MessageDifferencer differencer; differencer.set_scope(util::MessageDifferencer::PARTIAL); EXPECT_TRUE(differencer.Compare(msg1, msg2)); } TEST(MessageDifferencerTest, BasicPartialInequalityTest) { // Create the testing protos unittest::TestAllTypes msg1; unittest::TestAllTypes msg2; TestUtil::SetAllFields(&msg1); TestUtil::SetAllFields(&msg2); msg1.set_optional_int32(-1); // Compare util::MessageDifferencer differencer; differencer.set_scope(util::MessageDifferencer::PARTIAL); EXPECT_FALSE(differencer.Compare(msg1, msg2)); } TEST(MessageDifferencerTest, PartialInequalityMissingFieldTest) { // Create the testing protos unittest::TestAllTypes msg1; unittest::TestAllTypes msg2; TestUtil::SetAllFields(&msg1); TestUtil::SetAllFields(&msg2); msg2.clear_optional_int32(); // Compare util::MessageDifferencer differencer; differencer.set_scope(util::MessageDifferencer::PARTIAL); EXPECT_FALSE(differencer.Compare(msg1, msg2)); } TEST(MessageDifferencerTest, RepeatedFieldPartialInequalityTest) { // Create the testing protos unittest::TestAllTypes msg1; unittest::TestAllTypes msg2; TestUtil::SetAllFields(&msg1); TestUtil::SetAllFields(&msg2); msg1.add_repeated_int32(-1); // Compare util::MessageDifferencer differencer; differencer.set_scope(util::MessageDifferencer::PARTIAL); EXPECT_FALSE(differencer.Compare(msg1, msg2)); } TEST(MessageDifferencerTest, BasicEquivalencyTest) { // Create the testing protos unittest::TestAllTypes msg1; unittest::TestAllTypes msg2; TestUtil::SetAllFields(&msg1); TestUtil::SetAllFields(&msg2); // Compare EXPECT_TRUE(util::MessageDifferencer::Equivalent(msg1, msg2)); } TEST(MessageDifferencerTest, EquivalencyNotEqualTest) { // Create the testing protos unittest::TestAllTypes msg1; unittest::TestAllTypes msg2; TestUtil::SetAllFields(&msg1); TestUtil::SetAllFields(&msg2); msg1.clear_optional_int32(); msg2.set_optional_int32(0); // Compare EXPECT_FALSE(util::MessageDifferencer::Equals(msg1, msg2)); EXPECT_TRUE(util::MessageDifferencer::Equivalent(msg1, msg2)); } TEST(MessageDifferencerTest, BasicInequivalencyTest) { // Create the testing protos unittest::TestAllTypes msg1; unittest::TestAllTypes msg2; TestUtil::SetAllFields(&msg1); TestUtil::SetAllFields(&msg2); msg1.set_optional_int32(-1); // Compare EXPECT_FALSE(util::MessageDifferencer::Equivalent(msg1, msg2)); } TEST(MessageDifferencerTest, BasicEquivalencyNonSetTest) { // Create the testing protos unittest::TestAllTypes msg1; unittest::TestAllTypes msg2; // Compare EXPECT_TRUE(util::MessageDifferencer::Equivalent(msg1, msg2)); } TEST(MessageDifferencerTest, BasicInequivalencyNonSetTest) { // Create the testing protos unittest::TestAllTypes msg1; unittest::TestAllTypes msg2; msg1.set_optional_int32(-1); // Compare EXPECT_FALSE(util::MessageDifferencer::Equivalent(msg1, msg2)); } TEST(MessageDifferencerTest, BasicPartialEquivalencyTest) { // Create the testing protos unittest::TestAllTypes msg1; unittest::TestAllTypes msg2; TestUtil::SetAllFields(&msg1); TestUtil::SetAllFields(&msg2); // Compare util::MessageDifferencer differencer; differencer.set_message_field_comparison( util::MessageDifferencer::EQUIVALENT); differencer.set_scope(util::MessageDifferencer::PARTIAL); EXPECT_TRUE(differencer.Compare(msg1, msg2)); } TEST(MessageDifferencerTest, PartialEquivalencyNotEqualTest) { // Create the testing protos unittest::TestAllTypes msg1; unittest::TestAllTypes msg2; TestUtil::SetAllFields(&msg1); TestUtil::SetAllFields(&msg2); msg1.set_optional_int32(0); msg2.clear_optional_int32(); // Compare EXPECT_FALSE(util::MessageDifferencer::Equals(msg1, msg2)); util::MessageDifferencer differencer; differencer.set_message_field_comparison( util::MessageDifferencer::EQUIVALENT); differencer.set_scope(util::MessageDifferencer::PARTIAL); EXPECT_TRUE(differencer.Compare(msg1, msg2)); } TEST(MessageDifferencerTest, PartialEquivalencyTestExtraField) { // Create the testing protos unittest::TestAllTypes msg1; unittest::TestAllTypes msg2; TestUtil::SetAllFields(&msg1); TestUtil::SetAllFields(&msg2); msg1.clear_optional_int32(); // Compare util::MessageDifferencer differencer; differencer.set_message_field_comparison( util::MessageDifferencer::EQUIVALENT); differencer.set_scope(util::MessageDifferencer::PARTIAL); EXPECT_TRUE(differencer.Compare(msg1, msg2)); } TEST(MessageDifferencerTest, PartialEquivalencyTestSkipRequiredField) { // Create the testing protos unittest::TestRequired msg1; unittest::TestRequired msg2; msg1.set_a(401); msg2.set_a(401); msg2.set_b(402); // Compare util::MessageDifferencer differencer; differencer.set_message_field_comparison( util::MessageDifferencer::EQUIVALENT); differencer.set_scope(util::MessageDifferencer::PARTIAL); EXPECT_TRUE(differencer.Compare(msg1, msg2)); } TEST(MessageDifferencerTest, BasicPartialInequivalencyTest) { // Create the testing protos unittest::TestAllTypes msg1; unittest::TestAllTypes msg2; TestUtil::SetAllFields(&msg1); TestUtil::SetAllFields(&msg2); msg1.set_optional_int32(-1); // Compare util::MessageDifferencer differencer; differencer.set_message_field_comparison( util::MessageDifferencer::EQUIVALENT); differencer.set_scope(util::MessageDifferencer::PARTIAL); EXPECT_FALSE(differencer.Compare(msg1, msg2)); } TEST(MessageDifferencerTest, BasicPartialEquivalencyNonSetTest) { // Create the testing protos unittest::TestAllTypes msg1; unittest::TestAllTypes msg2; // Compare util::MessageDifferencer differencer; differencer.set_message_field_comparison( util::MessageDifferencer::EQUIVALENT); differencer.set_scope(util::MessageDifferencer::PARTIAL); EXPECT_TRUE(differencer.Compare(msg1, msg2)); } TEST(MessageDifferencerTest, BasicPartialInequivalencyNonSetTest) { // Create the testing protos unittest::TestAllTypes msg1; unittest::TestAllTypes msg2; msg1.set_optional_int32(-1); // Compare util::MessageDifferencer differencer; differencer.set_message_field_comparison( util::MessageDifferencer::EQUIVALENT); differencer.set_scope(util::MessageDifferencer::PARTIAL); EXPECT_FALSE(differencer.Compare(msg1, msg2)); } TEST(MessageDifferencerTest, ApproximateEqualityTest) { // Create the testing protos unittest::TestAllTypes msg1; unittest::TestAllTypes msg2; TestUtil::SetAllFields(&msg1); TestUtil::SetAllFields(&msg2); // Compare EXPECT_TRUE(util::MessageDifferencer::ApproximatelyEquals(msg1, msg2)); } TEST(MessageDifferencerTest, ApproximateModifiedEqualityTest) { // Create the testing protos unittest::TestAllTypes msg1; unittest::TestAllTypes msg2; TestUtil::SetAllFields(&msg1); TestUtil::SetAllFields(&msg2); const float v1 = 2.300005f; const float v2 = 2.300006f; msg1.set_optional_float(v1); msg2.set_optional_float(v2); // Compare ASSERT_NE(v1, v2) << "Should not be the same: " << v1 << ", " << v2; ASSERT_FLOAT_EQ(v1, v2) << "Should be approx. equal: " << v1 << ", " << v2; EXPECT_FALSE(util::MessageDifferencer::Equals(msg1, msg2)); EXPECT_TRUE(util::MessageDifferencer::ApproximatelyEquals(msg1, msg2)); } TEST(MessageDifferencerTest, ApproximateEquivalencyTest) { // Create the testing protos unittest::TestAllTypes msg1; unittest::TestAllTypes msg2; TestUtil::SetAllFields(&msg1); TestUtil::SetAllFields(&msg2); // Compare EXPECT_TRUE(util::MessageDifferencer::ApproximatelyEquivalent(msg1, msg2)); } TEST(MessageDifferencerTest, ApproximateModifiedEquivalencyTest) { // Create the testing protos unittest::TestAllTypes msg1; unittest::TestAllTypes msg2; TestUtil::SetAllFields(&msg1); TestUtil::SetAllFields(&msg2); // Modify the approximateness requirement const float v1 = 2.300005f; const float v2 = 2.300006f; msg1.set_optional_float(v1); msg2.set_optional_float(v2); // Compare ASSERT_NE(v1, v2) << "Should not be the same: " << v1 << ", " << v2; ASSERT_FLOAT_EQ(v1, v2) << "Should be approx. equal: " << v1 << ", " << v2; EXPECT_FALSE(util::MessageDifferencer::Equals(msg1, msg2)); EXPECT_TRUE(util::MessageDifferencer::ApproximatelyEquivalent(msg1, msg2)); // Modify the equivalency requirement too msg1.clear_optional_int32(); msg2.set_optional_int32(0); // Compare. Now should only pass on ApproximatelyEquivalent EXPECT_FALSE(util::MessageDifferencer::Equals(msg1, msg2)); EXPECT_FALSE(util::MessageDifferencer::Equivalent(msg1, msg2)); EXPECT_FALSE(util::MessageDifferencer::ApproximatelyEquals(msg1, msg2)); EXPECT_TRUE(util::MessageDifferencer::ApproximatelyEquivalent(msg1, msg2)); } TEST(MessageDifferencerTest, ApproximateInequivalencyTest) { // Create the testing protos unittest::TestAllTypes msg1; unittest::TestAllTypes msg2; TestUtil::SetAllFields(&msg1); TestUtil::SetAllFields(&msg2); // Should fail on equivalency msg1.set_optional_int32(-1); EXPECT_FALSE(util::MessageDifferencer::ApproximatelyEquivalent(msg1, msg2)); // Make these fields the same again. msg1.set_optional_int32(0); msg2.set_optional_int32(0); EXPECT_TRUE(util::MessageDifferencer::ApproximatelyEquivalent(msg1, msg2)); // Should fail on approximate equality check const float v1 = 2.3f; const float v2 = 9.3f; msg1.set_optional_float(v1); msg2.set_optional_float(v2); EXPECT_FALSE(util::MessageDifferencer::ApproximatelyEquivalent(msg1, msg2)); } TEST(MessageDifferencerTest, WithinFractionOrMarginFloatTest) { // Create the testing protos unittest::TestAllTypes msg1; unittest::TestAllTypes msg2; TestUtil::SetAllFields(&msg1); TestUtil::SetAllFields(&msg2); // Should fail on approximate equality check const float v1 = 100.0f; const float v2 = 109.9f; msg1.set_optional_float(v1); msg2.set_optional_float(v2); // Compare util::MessageDifferencer differencer; EXPECT_FALSE(differencer.Compare(msg1, msg2)); const FieldDescriptor* fd = msg1.GetDescriptor()->FindFieldByName("optional_float"); // Set float comparison to exact, margin and fraction value should not matter. differencer.set_float_comparison(util::MessageDifferencer::EXACT); // Set margin for float comparison. differencer.SetFractionAndMargin(fd, 0.0, 10.0); EXPECT_FALSE(differencer.Compare(msg1, msg2)); // Margin and fraction float comparison is activated when float comparison is // set to approximate. differencer.set_float_comparison(util::MessageDifferencer::APPROXIMATE); EXPECT_TRUE(differencer.Compare(msg1, msg2)); // Test out float comparison with fraction. differencer.SetFractionAndMargin(fd, 0.2, 0.0); EXPECT_TRUE(differencer.Compare(msg1, msg2)); // Should fail since the fraction is smaller than error. differencer.SetFractionAndMargin(fd, 0.01, 0.0); EXPECT_FALSE(differencer.Compare(msg1, msg2)); // Should pass if either fraction or margin are satisfied. differencer.SetFractionAndMargin(fd, 0.01, 10.0); EXPECT_TRUE(differencer.Compare(msg1, msg2)); // Make sure that the margin and fraction only affects the field that it was // set for. msg1.set_default_float(v1); msg2.set_default_float(v2); EXPECT_FALSE(differencer.Compare(msg1, msg2)); msg1.set_default_float(v1); msg2.set_default_float(v1); EXPECT_TRUE(differencer.Compare(msg1, msg2)); } TEST(MessageDifferencerTest, WithinFractionOrMarginDoubleTest) { // Create the testing protos unittest::TestAllTypes msg1; unittest::TestAllTypes msg2; TestUtil::SetAllFields(&msg1); TestUtil::SetAllFields(&msg2); // Should fail on approximate equality check const double v1 = 100.0; const double v2 = 109.9; msg1.set_optional_double(v1); msg2.set_optional_double(v2); // Compare util::MessageDifferencer differencer; EXPECT_FALSE(differencer.Compare(msg1, msg2)); // Set comparison to exact, margin and fraction value should not matter. differencer.set_float_comparison(util::MessageDifferencer::EXACT); // Set margin for float comparison. const FieldDescriptor* fd = msg1.GetDescriptor()->FindFieldByName("optional_double"); differencer.SetFractionAndMargin(fd, 0.0, 10.0); EXPECT_FALSE(differencer.Compare(msg1, msg2)); // Margin and fraction comparison is activated when float comparison is // set to approximate. differencer.set_float_comparison(util::MessageDifferencer::APPROXIMATE); EXPECT_TRUE(differencer.Compare(msg1, msg2)); // Test out comparison with fraction. differencer.SetFractionAndMargin(fd, 0.2, 0.0); EXPECT_TRUE(differencer.Compare(msg1, msg2)); // Should fail since the fraction is smaller than error. differencer.SetFractionAndMargin(fd, 0.01, 0.0); EXPECT_FALSE(differencer.Compare(msg1, msg2)); // Should pass if either fraction or margin are satisfied. differencer.SetFractionAndMargin(fd, 0.01, 10.0); EXPECT_TRUE(differencer.Compare(msg1, msg2)); // Make sure that the margin and fraction only affects the field that it was // set for. msg1.set_default_double(v1); msg2.set_default_double(v2); EXPECT_FALSE(differencer.Compare(msg1, msg2)); msg1.set_default_double(v1); msg2.set_default_double(v1); EXPECT_TRUE(differencer.Compare(msg1, msg2)); } TEST(MessageDifferencerTest, WithinDefaultFractionOrMarginDoubleTest) { // Create the testing protos unittest::TestAllTypes msg1; unittest::TestAllTypes msg2; TestUtil::SetAllFields(&msg1); TestUtil::SetAllFields(&msg2); // Should fail on approximate equality check const double v1 = 100.0; const double v2 = 109.9; msg1.set_optional_double(v1); msg2.set_optional_double(v2); util::MessageDifferencer differencer; // Compare EXPECT_FALSE(differencer.Compare(msg1, msg2)); // Set up a custom field comparitor, with a default fraction and margin for // float and double comparison. util::DefaultFieldComparator field_comparitor; field_comparitor.SetDefaultFractionAndMargin(0.0, 10.0); differencer.set_field_comparator(&field_comparitor); // Set comparison to exact, margin and fraction value should not matter. field_comparitor.set_float_comparison(util::DefaultFieldComparator::EXACT); EXPECT_FALSE(differencer.Compare(msg1, msg2)); // Margin and fraction comparison is activated when float comparison is // set to approximate. field_comparitor.set_float_comparison( util::DefaultFieldComparator::APPROXIMATE); EXPECT_TRUE(differencer.Compare(msg1, msg2)); // Test out comparison with fraction. field_comparitor.SetDefaultFractionAndMargin(0.2, 0.0); EXPECT_TRUE(differencer.Compare(msg1, msg2)); // Should fail since the fraction is smaller than error. field_comparitor.SetDefaultFractionAndMargin(0.01, 0.0); EXPECT_FALSE(differencer.Compare(msg1, msg2)); // Should pass if either fraction or margin are satisfied. field_comparitor.SetDefaultFractionAndMargin(0.01, 10.0); EXPECT_TRUE(differencer.Compare(msg1, msg2)); // Make sure that the default margin and fraction affects all fields msg1.set_default_double(v1); msg2.set_default_double(v2); EXPECT_TRUE(differencer.Compare(msg1, msg2)); } TEST(MessageDifferencerTest, BasicFieldOrderingsTest) { // Create the testing protos unittest::TestFieldOrderings msg1; unittest::TestFieldOrderings msg2; TestUtil::SetAllFieldsAndExtensions(&msg1); TestUtil::SetAllFieldsAndExtensions(&msg2); // Compare EXPECT_TRUE(util::MessageDifferencer::Equals(msg1, msg2)); } TEST(MessageDifferencerTest, BasicFieldOrderingInequalityTest) { // Create the testing protos unittest::TestFieldOrderings msg1; unittest::TestFieldOrderings msg2; TestUtil::SetAllFieldsAndExtensions(&msg1); TestUtil::SetAllFieldsAndExtensions(&msg2); msg1.set_my_float(15.00); msg2.set_my_float(16.00); // Compare EXPECT_FALSE(util::MessageDifferencer::Equals(msg1, msg2)); } TEST(MessageDifferencerTest, BasicExtensionTest) { // Create the testing protos unittest::TestAllExtensions msg1; unittest::TestAllExtensions msg2; TestUtil::SetAllExtensions(&msg1); TestUtil::SetAllExtensions(&msg2); // Compare EXPECT_TRUE(util::MessageDifferencer::Equals(msg1, msg2)); } TEST(MessageDifferencerTest, BasicExtensionInequalityTest) { // Create the testing protos unittest::TestAllExtensions msg1; unittest::TestAllExtensions msg2; TestUtil::SetAllExtensions(&msg1); TestUtil::SetAllExtensions(&msg2); msg1.SetExtension(unittest::optional_int32_extension, 101); msg2.SetExtension(unittest::optional_int32_extension, 102); // Compare EXPECT_FALSE(util::MessageDifferencer::Equals(msg1, msg2)); } TEST(MessageDifferencerTest, OneofTest) { // Create the testing protos unittest::TestOneof2 msg1; unittest::TestOneof2 msg2; TestUtil::SetOneof1(&msg1); TestUtil::SetOneof1(&msg2); // Compare EXPECT_TRUE(util::MessageDifferencer::Equals(msg1, msg2)); } TEST(MessageDifferencerTest, OneofInequalityTest) { // Create the testing protos unittest::TestOneof2 msg1; unittest::TestOneof2 msg2; TestUtil::SetOneof1(&msg1); TestUtil::SetOneof2(&msg2); // Compare EXPECT_FALSE(util::MessageDifferencer::Equals(msg1, msg2)); } TEST(MessageDifferencerTest, UnknownFieldPartialEqualTest) { unittest::TestEmptyMessage empty1; unittest::TestEmptyMessage empty2; UnknownFieldSet* unknown1 = empty1.mutable_unknown_fields(); UnknownFieldSet* unknown2 = empty2.mutable_unknown_fields(); unknown1->AddVarint(243, 122); unknown1->AddLengthDelimited(245, "abc"); unknown1->AddGroup(246)->AddFixed32(248, 1); unknown1->mutable_field(2)->mutable_group()->AddFixed32(248, 2); unknown2->AddVarint(243, 122); unknown2->AddLengthDelimited(245, "abc"); unknown2->AddGroup(246)->AddFixed32(248, 1); unknown2->mutable_field(2)->mutable_group()->AddFixed32(248, 2); util::MessageDifferencer differencer; differencer.set_scope(util::MessageDifferencer::PARTIAL); EXPECT_TRUE(differencer.Compare(empty1, empty2)); } TEST(MessageDifferencerTest, SpecifiedFieldsEqualityAllTest) { unittest::TestAllTypes msg1; unittest::TestAllTypes msg2; TestUtil::SetAllFields(&msg1); TestUtil::SetAllFields(&msg2); std::vector fields1; std::vector fields2; msg1.GetReflection()->ListFields(msg1, &fields1); msg2.GetReflection()->ListFields(msg2, &fields2); util::MessageDifferencer differencer; EXPECT_TRUE(differencer.CompareWithFields(msg1, msg2, fields1, fields2)); } TEST(MessageDifferencerTest, SpecifiedFieldsInequalityAllTest) { unittest::TestAllTypes msg1; unittest::TestAllTypes msg2; TestUtil::SetAllFields(&msg1); std::vector fields1; std::vector fields2; msg1.GetReflection()->ListFields(msg1, &fields1); msg2.GetReflection()->ListFields(msg2, &fields2); util::MessageDifferencer differencer; EXPECT_FALSE(differencer.CompareWithFields(msg1, msg2, fields1, fields2)); } TEST(MessageDifferencerTest, SpecifiedFieldsEmptyListAlwaysSucceeds) { unittest::TestAllTypes msg1; unittest::TestAllTypes msg2; TestUtil::SetAllFields(&msg1); std::vector empty_fields; util::MessageDifferencer differencer; EXPECT_TRUE(differencer.CompareWithFields(msg1, msg2, empty_fields, empty_fields)); TestUtil::SetAllFields(&msg2); EXPECT_TRUE(differencer.CompareWithFields(msg1, msg2, empty_fields, empty_fields)); } TEST(MessageDifferencerTest, SpecifiedFieldsCompareWithSelf) { unittest::TestAllTypes msg1; TestUtil::SetAllFields(&msg1); std::vector fields; msg1.GetReflection()->ListFields(msg1, &fields); util::MessageDifferencer differencer; EXPECT_TRUE(differencer.CompareWithFields(msg1, msg1, fields, fields)); { // Compare with a subset of fields. std::vector compare_fields; for (int i = 0; i < fields.size(); ++i) { if (i % 2 == 0) { compare_fields.push_back(fields[i]); } } EXPECT_TRUE(differencer.CompareWithFields(msg1, msg1, compare_fields, compare_fields)); } { // Specify a different set of fields to compare, even though we're using the // same message. This should fail, since we are explicitly saying that the // set of fields are different. std::vector compare_fields1; std::vector compare_fields2; for (int i = 0; i < fields.size(); ++i) { if (i % 2 == 0) { compare_fields1.push_back(fields[i]); } else { compare_fields2.push_back(fields[i]); } } EXPECT_FALSE(differencer.CompareWithFields( msg1, msg1, compare_fields1, compare_fields2)); } } TEST(MessageDifferencerTest, SpecifiedFieldsEqualityAllShuffledTest) { // This is a public function, so make sure there are no assumptions about the // list of fields. Randomly shuffle them to make sure that they are properly // ordered for comparison. unittest::TestAllTypes msg1; unittest::TestAllTypes msg2; TestUtil::SetAllFields(&msg1); TestUtil::SetAllFields(&msg2); std::vector fields1; std::vector fields2; msg1.GetReflection()->ListFields(msg1, &fields1); msg2.GetReflection()->ListFields(msg2, &fields2); std::random_shuffle(fields1.begin(), fields1.end()); std::random_shuffle(fields2.begin(), fields2.end()); util::MessageDifferencer differencer; EXPECT_TRUE(differencer.CompareWithFields(msg1, msg2, fields1, fields2)); } TEST(MessageDifferencerTest, SpecifiedFieldsSubsetEqualityTest) { // Specify a set of fields to compare. All the fields are equal. unittest::TestAllTypes msg1; unittest::TestAllTypes msg2; TestUtil::SetAllFields(&msg1); TestUtil::SetAllFields(&msg2); std::vector fields1; msg1.GetReflection()->ListFields(msg1, &fields1); std::vector compare_fields; // Only compare the field descriptors with even indices. for (int i = 0; i < fields1.size(); ++i) { if (i % 2 == 0) { compare_fields.push_back(fields1[i]); } } util::MessageDifferencer differencer; EXPECT_TRUE(differencer.CompareWithFields(msg1, msg2, compare_fields, compare_fields)); } TEST(MessageDifferencerTest, SpecifiedFieldsSubsetIgnoresOtherFieldDifferencesTest) { // Specify a set of fields to compare, but clear all the other fields in one // of the messages. This should fail a regular compare, but CompareWithFields // should succeed. unittest::TestAllTypes msg1; unittest::TestAllTypes msg2; TestUtil::SetAllFields(&msg1); TestUtil::SetAllFields(&msg2); std::vector fields1; const Reflection* reflection = msg1.GetReflection(); reflection->ListFields(msg1, &fields1); std::vector compare_fields; // Only compare the field descriptors with even indices. for (int i = 0; i < fields1.size(); ++i) { if (i % 2 == 0) { compare_fields.push_back(fields1[i]); } else { reflection->ClearField(&msg2, fields1[i]); } } util::MessageDifferencer differencer; EXPECT_FALSE(differencer.Compare(msg1, msg2)); EXPECT_TRUE(differencer.CompareWithFields(msg1, msg2, compare_fields, compare_fields)); } TEST(MessageDifferencerTest, SpecifiedFieldsDetectsDifferencesTest) { // Change all of the repeated fields in one of the messages, and use only // those fields for comparison. unittest::TestAllTypes msg1; unittest::TestAllTypes msg2; TestUtil::SetAllFields(&msg1); TestUtil::SetAllFields(&msg2); TestUtil::ModifyRepeatedFields(&msg2); std::vector fields1; msg1.GetReflection()->ListFields(msg1, &fields1); std::vector compare_fields; // Only compare the repeated field descriptors. for (int i = 0; i < fields1.size(); ++i) { if (fields1[i]->is_repeated()) { compare_fields.push_back(fields1[i]); } } util::MessageDifferencer differencer; EXPECT_FALSE(differencer.CompareWithFields(msg1, msg2, compare_fields, compare_fields)); } TEST(MessageDifferencerTest, SpecifiedFieldsEquivalenceAllTest) { unittest::TestAllTypes msg1; unittest::TestAllTypes msg2; TestUtil::SetAllFields(&msg1); TestUtil::SetAllFields(&msg2); std::vector fields1; std::vector fields2; msg1.GetReflection()->ListFields(msg1, &fields1); msg2.GetReflection()->ListFields(msg2, &fields2); util::MessageDifferencer differencer; differencer.set_message_field_comparison( util::MessageDifferencer::EQUIVALENT); EXPECT_TRUE(differencer.CompareWithFields(msg1, msg2, fields1, fields2)); } TEST(MessageDifferencerTest, SpecifiedFieldsEquivalenceIgnoresOtherFieldDifferencesTest) { unittest::TestAllTypes msg1; unittest::TestAllTypes msg2; const Descriptor* desc = msg1.GetDescriptor(); const FieldDescriptor* optional_int32_desc = desc->FindFieldByName("optional_int32"); const FieldDescriptor* optional_int64_desc = desc->FindFieldByName("optional_int64"); const FieldDescriptor* default_int64_desc = desc->FindFieldByName("default_int64"); ASSERT_TRUE(optional_int32_desc != NULL); ASSERT_TRUE(optional_int64_desc != NULL); ASSERT_TRUE(default_int64_desc != NULL); msg1.set_optional_int32(0); msg2.set_optional_int64(0); msg1.set_default_int64(default_int64_desc->default_value_int64()); // Set a field to a non-default value so we know that field selection is // actually doing something. msg2.set_optional_uint64(23); std::vector fields1; std::vector fields2; fields1.push_back(optional_int32_desc); fields1.push_back(default_int64_desc); fields2.push_back(optional_int64_desc); util::MessageDifferencer differencer; EXPECT_FALSE(differencer.CompareWithFields(msg1, msg2, fields1, fields2)); differencer.set_message_field_comparison( util::MessageDifferencer::EQUIVALENT); EXPECT_FALSE(differencer.Compare(msg1, msg2)); EXPECT_TRUE(differencer.CompareWithFields(msg1, msg2, fields1, fields2)); } TEST(MessageDifferencerTest, RepeatedFieldSetTest_SetOfSet) { // Create the testing protos protobuf_unittest::TestDiffMessage msg1; protobuf_unittest::TestDiffMessage msg2; protobuf_unittest::TestDiffMessage::Item* item = msg1.add_item(); item->add_ra(1); item->add_ra(2); item->add_ra(3); item = msg1.add_item(); item->add_ra(5); item->add_ra(6); item = msg1.add_item(); item->add_ra(1); item->add_ra(3); item = msg1.add_item(); item->add_ra(6); item->add_ra(7); item->add_ra(8); item = msg2.add_item(); item->add_ra(6); item->add_ra(5); item = msg2.add_item(); item->add_ra(6); item->add_ra(8); item->add_ra(7); item = msg2.add_item(); item->add_ra(1); item->add_ra(3); item = msg2.add_item(); item->add_ra(3); item->add_ra(2); item->add_ra(1); // Compare util::MessageDifferencer differencer; differencer.set_repeated_field_comparison(util::MessageDifferencer::AS_SET); EXPECT_TRUE(differencer.Compare(msg1, msg2)); } TEST(MessageDifferencerTest, RepeatedFieldSetTest_Combination) { // Create the testing protos protobuf_unittest::TestDiffMessage msg1; protobuf_unittest::TestDiffMessage msg2; // Treat "item" as Map, with key = "a" // Treat "item.ra" also as Set // Treat "rv" as Set // Treat "rw" as List protobuf_unittest::TestDiffMessage::Item* item = msg1.add_item(); item->set_a(3); item->add_ra(1); item->add_ra(2); item->add_ra(3); item = msg1.add_item(); item->set_a(4); item->add_ra(5); item->add_ra(6); item = msg1.add_item(); item->set_a(1); item->add_ra(1); item->add_ra(3); item = msg1.add_item(); item->set_a(2); item->add_ra(6); item->add_ra(7); item->add_ra(8); item = msg2.add_item(); item->set_a(4); item->add_ra(6); item->add_ra(5); item = msg2.add_item(); item->set_a(2); item->add_ra(6); item->add_ra(8); item->add_ra(7); item = msg2.add_item(); item->set_a(1); item->add_ra(1); item->add_ra(3); item = msg2.add_item(); item->set_a(3); item->add_ra(3); item->add_ra(2); item->add_ra(1); msg1.add_rv(3); msg1.add_rv(4); msg1.add_rv(7); msg1.add_rv(0); msg2.add_rv(4); msg2.add_rv(3); msg2.add_rv(0); msg2.add_rv(7); msg1.add_rw("nothing"); msg2.add_rw("nothing"); msg1.add_rw("should"); msg2.add_rw("should"); msg1.add_rw("change"); msg2.add_rw("change"); // Compare util::MessageDifferencer differencer1; differencer1.TreatAsMap(msg1.GetDescriptor()->FindFieldByName("item"), item->GetDescriptor()->FindFieldByName("a")); differencer1.TreatAsSet(msg1.GetDescriptor()->FindFieldByName("rv")); differencer1.TreatAsSet(item->GetDescriptor()->FindFieldByName("ra")); EXPECT_TRUE(differencer1.Compare(msg1, msg2)); util::MessageDifferencer differencer2; differencer2.TreatAsMap(msg1.GetDescriptor()->FindFieldByName("item"), item->GetDescriptor()->FindFieldByName("a")); differencer2.set_repeated_field_comparison(util::MessageDifferencer::AS_SET); differencer2.TreatAsList(msg1.GetDescriptor()->FindFieldByName("rw")); EXPECT_TRUE(differencer2.Compare(msg1, msg2)); } TEST(MessageDifferencerTest, RepeatedFieldMapTest_Partial) { protobuf_unittest::TestDiffMessage msg1; // message msg1 { // item { a: 1; b: "11" } // } protobuf_unittest::TestDiffMessage::Item* item = msg1.add_item(); item->set_a(1); item->set_b("11"); protobuf_unittest::TestDiffMessage msg2; // message msg2 { // item { a: 2; b: "22" } // item { a: 1; b: "11" } // } item = msg2.add_item(); item->set_a(2); item->set_b("22"); item = msg2.add_item(); item->set_a(1); item->set_b("11"); // Compare util::MessageDifferencer differencer; differencer.TreatAsMap(GetFieldDescriptor(msg1, "item"), GetFieldDescriptor(msg1, "item.a")); differencer.set_scope(util::MessageDifferencer::PARTIAL); EXPECT_TRUE(differencer.Compare(msg1, msg2)); } TEST(MessageDifferencerTest, RepeatedFieldSetTest_Duplicates) { protobuf_unittest::TestDiffMessage a, b, c; // message a: { // rv: 0 // rv: 1 // rv: 0 // } a.add_rv(0); a.add_rv(1); a.add_rv(0); // message b: { // rv: 0 // rv: 0 // rv: 1 // } b.add_rv(0); b.add_rv(0); b.add_rv(1); // message c: { // rv: 0 // rv: 1 // } c.add_rv(0); c.add_rv(1); util::MessageDifferencer differencer; differencer.TreatAsSet(GetFieldDescriptor(a, "rv")); EXPECT_TRUE(differencer.Compare(b, a)); EXPECT_FALSE(differencer.Compare(c, a)); util::MessageDifferencer differencer1; differencer1.set_repeated_field_comparison(util::MessageDifferencer::AS_SET); EXPECT_TRUE(differencer1.Compare(b, a)); EXPECT_FALSE(differencer1.Compare(c, a)); } TEST(MessageDifferencerTest, RepeatedFieldSetTest_PartialSimple) { protobuf_unittest::TestDiffMessage a, b, c; // message a: { // rm { c: 1 } // rm { c: 0 } // } a.add_rm()->set_c(1); a.add_rm()->set_c(0); // message b: { // rm { c: 1 } // rm {} // } b.add_rm()->set_c(1); b.add_rm(); // message c: { // rm {} // rm { c: 1 } // } c.add_rm(); c.add_rm()->set_c(1); util::MessageDifferencer differencer; differencer.set_scope(util::MessageDifferencer::PARTIAL); differencer.TreatAsSet(GetFieldDescriptor(a, "rm")); EXPECT_TRUE(differencer.Compare(b, a)); EXPECT_TRUE(differencer.Compare(c, a)); } TEST(MessageDifferencerTest, RepeatedFieldSetTest_Partial) { protobuf_unittest::TestDiffMessage msg1, msg2; // message msg1: { // rm { a: 1 } // rm { b: 2 } // rm { c: 3 } // } msg1.add_rm()->set_a(1); msg1.add_rm()->set_b(2); msg1.add_rm()->set_c(3); // message msg2: { // rm { a: 1; c: 3 } // rm { b: 2; c: 3 } // rm { b: 2 } // } protobuf_unittest::TestField* field = msg2.add_rm(); field->set_a(1); field->set_c(3); field = msg2.add_rm(); field->set_b(2); field->set_c(3); field = msg2.add_rm(); field->set_b(2); util::MessageDifferencer differencer; differencer.set_scope(util::MessageDifferencer::PARTIAL); differencer.TreatAsSet(GetFieldDescriptor(msg1, "rm")); EXPECT_TRUE(differencer.Compare(msg1, msg2)); } TEST(MessageDifferencerTest, RepeatedFieldMapTest_MultipleFieldsAsKey) { protobuf_unittest::TestDiffMessage msg1; protobuf_unittest::TestDiffMessage msg2; // Treat "item" as Map, with key = ("a", "ra") // Treat "item.ra" as Set protobuf_unittest::TestDiffMessage::Item* item = msg1.add_item(); // key => value: (1, {2, 3}) => "a" item->set_a(1); item->add_ra(2); item->add_ra(3); item->set_b("a"); item = msg1.add_item(); // key => value: (2, {1, 3}) => "b" item->set_a(2); item->add_ra(1); item->add_ra(3); item->set_b("b"); item = msg1.add_item(); // key => value: (1, {1, 3}) => "c" item->set_a(1); item->add_ra(1); item->add_ra(3); item->set_b("c"); item = msg2.add_item(); // key => value: (1, {1, 3}) => "c" item->set_a(1); item->add_ra(3); item->add_ra(1); item->set_b("c"); item = msg2.add_item(); // key => value: (1, {2, 3}) => "a" item->set_a(1); item->add_ra(3); item->add_ra(2); item->set_b("a"); item = msg2.add_item(); // key => value: (2, {1, 3}) => "b" item->set_a(2); item->add_ra(3); item->add_ra(1); item->set_b("b"); // Compare util::MessageDifferencer differencer; differencer.TreatAsSet(GetFieldDescriptor(msg1, "item.ra")); EXPECT_FALSE(differencer.Compare(msg1, msg2)); std::vector key_fields; key_fields.push_back(GetFieldDescriptor(msg1, "item.a")); key_fields.push_back(GetFieldDescriptor(msg1, "item.ra")); differencer.TreatAsMapWithMultipleFieldsAsKey( GetFieldDescriptor(msg1, "item"), key_fields); EXPECT_TRUE(differencer.Compare(msg1, msg2)); // Introduce some differences. msg1.clear_item(); msg2.clear_item(); item = msg1.add_item(); item->set_a(4); item->add_ra(5); item->add_ra(6); item->set_b("hello"); item = msg2.add_item(); item->set_a(4); item->add_ra(6); item->add_ra(5); item->set_b("world"); string output; differencer.ReportDifferencesToString(&output); EXPECT_FALSE(differencer.Compare(msg1, msg2)); EXPECT_EQ( "moved: item[0].ra[0] -> item[0].ra[1] : 5\n" "moved: item[0].ra[1] -> item[0].ra[0] : 6\n" "modified: item[0].b: \"hello\" -> \"world\"\n", output); } TEST(MessageDifferencerTest, RepeatedFieldMapTest_MultipleFieldPathsAsKey) { protobuf_unittest::TestDiffMessage msg1; protobuf_unittest::TestDiffMessage msg2; // Treat "item" as Map, with key = ("m.a", "m.rc") // Treat "item.m.rc" as Set protobuf_unittest::TestDiffMessage::Item* item = msg1.add_item(); // key => value: (1, {2, 3}) => "a" item->mutable_m()->set_a(1); item->mutable_m()->add_rc(2); item->mutable_m()->add_rc(3); item->set_b("a"); item = msg1.add_item(); // key => value: (2, {1, 3}) => "b" item->mutable_m()->set_a(2); item->mutable_m()->add_rc(1); item->mutable_m()->add_rc(3); item->set_b("b"); item = msg1.add_item(); // key => value: (1, {1, 3}) => "c" item->mutable_m()->set_a(1); item->mutable_m()->add_rc(1); item->mutable_m()->add_rc(3); item->set_b("c"); item = msg2.add_item(); // key => value: (1, {1, 3}) => "c" item->mutable_m()->set_a(1); item->mutable_m()->add_rc(3); item->mutable_m()->add_rc(1); item->set_b("c"); item = msg2.add_item(); // key => value: (1, {2, 3}) => "a" item->mutable_m()->set_a(1); item->mutable_m()->add_rc(3); item->mutable_m()->add_rc(2); item->set_b("a"); item = msg2.add_item(); // key => value: (2, {1, 3}) => "b" item->mutable_m()->set_a(2); item->mutable_m()->add_rc(3); item->mutable_m()->add_rc(1); item->set_b("b"); // Compare util::MessageDifferencer differencer; differencer.TreatAsSet(GetFieldDescriptor(msg1, "item.m.rc")); EXPECT_FALSE(differencer.Compare(msg1, msg2)); std::vector > key_field_paths; std::vector key_field_path1; key_field_path1.push_back(GetFieldDescriptor(msg1, "item.m")); key_field_path1.push_back(GetFieldDescriptor(msg1, "item.m.a")); std::vector key_field_path2; key_field_path2.push_back(GetFieldDescriptor(msg1, "item.m")); key_field_path2.push_back(GetFieldDescriptor(msg1, "item.m.rc")); key_field_paths.push_back(key_field_path1); key_field_paths.push_back(key_field_path2); differencer.TreatAsMapWithMultipleFieldPathsAsKey( GetFieldDescriptor(msg1, "item"), key_field_paths); EXPECT_TRUE(differencer.Compare(msg1, msg2)); // Introduce some differences. msg1.clear_item(); msg2.clear_item(); item = msg1.add_item(); item->mutable_m()->set_a(4); item->mutable_m()->add_rc(5); item->mutable_m()->add_rc(6); item->set_b("hello"); item = msg2.add_item(); item->mutable_m()->set_a(4); item->mutable_m()->add_rc(6); item->mutable_m()->add_rc(5); item->set_b("world"); string output; differencer.ReportDifferencesToString(&output); EXPECT_FALSE(differencer.Compare(msg1, msg2)); EXPECT_EQ( "modified: item[0].b: \"hello\" -> \"world\"\n" "moved: item[0].m.rc[0] -> item[0].m.rc[1] : 5\n" "moved: item[0].m.rc[1] -> item[0].m.rc[0] : 6\n", output); } TEST(MessageDifferencerTest, RepeatedFieldMapTest_IgnoredKeyFields) { protobuf_unittest::TestDiffMessage msg1; protobuf_unittest::TestDiffMessage msg2; // Treat "item" as Map, with key = ("a", "ra") protobuf_unittest::TestDiffMessage::Item* item = msg1.add_item(); item->set_a(1); item->add_ra(2); item->set_b("hello"); item = msg2.add_item(); item->set_a(1); item->add_ra(3); item->set_b("world"); // Compare util::MessageDifferencer differencer; std::vector key_fields; key_fields.push_back(GetFieldDescriptor(msg1, "item.a")); key_fields.push_back(GetFieldDescriptor(msg1, "item.ra")); differencer.TreatAsMapWithMultipleFieldsAsKey( GetFieldDescriptor(msg1, "item"), key_fields); string output; differencer.ReportDifferencesToString(&output); EXPECT_FALSE(differencer.Compare(msg1, msg2)); EXPECT_EQ( "added: item[0]: { a: 1 ra: 3 b: \"world\" }\n" "deleted: item[0]: { a: 1 ra: 2 b: \"hello\" }\n", output); // Ignored fields that are listed as parts of the key are still used // in key comparison, but they're not used in value comparison. differencer.IgnoreField(GetFieldDescriptor(msg1, "item.ra")); output.clear(); EXPECT_FALSE(differencer.Compare(msg1, msg2)); EXPECT_EQ( "added: item[0]: { a: 1 ra: 3 b: \"world\" }\n" "deleted: item[0]: { a: 1 ra: 2 b: \"hello\" }\n", output); // Ignoring a field in the key is different from treating the left fields // as key. That is: // (key = ("a", "ra") && ignore "ra") != (key = ("a") && ignore "ra") util::MessageDifferencer differencer2; differencer2.TreatAsMap(GetFieldDescriptor(msg1, "item"), GetFieldDescriptor(msg1, "item.a")); differencer2.IgnoreField(GetFieldDescriptor(msg1, "item.ra")); output.clear(); differencer2.ReportDifferencesToString(&output); EXPECT_FALSE(differencer2.Compare(msg1, msg2)); EXPECT_EQ( "ignored: item[0].ra\n" "modified: item[0].b: \"hello\" -> \"world\"\n", output); } static const char* const kIgnoredFields[] = {"rm.b", "rm.m.b"}; class TestIgnorer : public util::MessageDifferencer::IgnoreCriteria { public: virtual bool IsIgnored( const Message& message1, const Message& message2, const FieldDescriptor* field, const std::vector& parent_fields) { string name = ""; for (int i = 0; i < parent_fields.size(); ++i) { name += parent_fields[i].field->name() + "."; } name += field->name(); for (int i = 0; i < GOOGLE_ARRAYSIZE(kIgnoredFields); ++i) { if (name.compare(kIgnoredFields[i]) == 0) { return true; } } return false; } }; TEST(MessageDifferencerTest, TreatRepeatedFieldAsSetWithIgnoredFields) { protobuf_unittest::TestDiffMessage msg1; protobuf_unittest::TestDiffMessage msg2; TextFormat::MergeFromString("rm { a: 11\n b: 12 }", &msg1); TextFormat::MergeFromString("rm { a: 11\n b: 13 }", &msg2); util::MessageDifferencer differ; differ.TreatAsSet(GetFieldDescriptor(msg1, "rm")); differ.AddIgnoreCriteria(new TestIgnorer); EXPECT_TRUE(differ.Compare(msg1, msg2)); } TEST(MessageDifferencerTest, TreatRepeatedFieldAsMapWithIgnoredKeyFields) { protobuf_unittest::TestDiffMessage msg1; protobuf_unittest::TestDiffMessage msg2; TextFormat::MergeFromString("rm { a: 11\n m { a: 12\n b: 13\n } }", &msg1); TextFormat::MergeFromString("rm { a: 11\n m { a: 12\n b: 14\n } }", &msg2); util::MessageDifferencer differ; differ.TreatAsMap(GetFieldDescriptor(msg1, "rm"), GetFieldDescriptor(msg1, "rm.m")); differ.AddIgnoreCriteria(new TestIgnorer); EXPECT_TRUE(differ.Compare(msg1, msg2)); } // Takes the product of all elements of item.ra as the key for key comparison. class ValueProductMapKeyComparator : public util::MessageDifferencer::MapKeyComparator { public: typedef util::MessageDifferencer::SpecificField SpecificField; virtual bool IsMatch( const Message &message1, const Message &message2, const std::vector& parent_fields) const { const Reflection* reflection1 = message1.GetReflection(); const Reflection* reflection2 = message2.GetReflection(); // FieldDescriptor for item.ra const FieldDescriptor* ra_field = message1.GetDescriptor()->FindFieldByName("ra"); // Get the product of all elements in item.ra int result1 = 1, result2 = 1; for (int i = 0; i < reflection1->FieldSize(message1, ra_field); ++i) { result1 *= reflection1->GetRepeatedInt32(message1, ra_field, i); } for (int i = 0; i < reflection2->FieldSize(message2, ra_field); ++i) { result2 *= reflection2->GetRepeatedInt32(message2, ra_field, i); } return result1 == result2; } }; TEST(MessageDifferencerTest, RepeatedFieldMapTest_CustomMapKeyComparator) { protobuf_unittest::TestDiffMessage msg1; protobuf_unittest::TestDiffMessage msg2; // Treat "item" as Map, using custom key comparator to determine if two // elements have the same key. protobuf_unittest::TestDiffMessage::Item* item = msg1.add_item(); item->add_ra(6); item->add_ra(35); item->set_b("hello"); item = msg2.add_item(); item->add_ra(10); item->add_ra(21); item->set_b("hello"); util::MessageDifferencer differencer; ValueProductMapKeyComparator key_comparator; differencer.TreatAsMapUsingKeyComparator( GetFieldDescriptor(msg1, "item"), &key_comparator); string output; differencer.ReportDifferencesToString(&output); // Though the above two messages have different values for item.ra, they // are regarded as having the same key because 6 * 35 == 10 * 21. That's // how the key comparator determines if the two have the same key. // However, in value comparison, all fields of the message are taken into // consideration, so they are different because their item.ra fields have // different values using normal value comparison. EXPECT_FALSE(differencer.Compare(msg1, msg2)); EXPECT_EQ( "modified: item[0].ra[0]: 6 -> 10\n" "modified: item[0].ra[1]: 35 -> 21\n", output); differencer.IgnoreField(GetFieldDescriptor(msg1, "item.ra")); output.clear(); // item.ra is ignored in value comparison, so the two messages equal. EXPECT_TRUE(differencer.Compare(msg1, msg2)); EXPECT_EQ("ignored: item[0].ra\n", output); } TEST(MessageDifferencerTest, RepeatedFieldSetTest_Subset) { protobuf_unittest::TestDiffMessage msg1; protobuf_unittest::TestDiffMessage msg2; msg1.add_rv(3); msg1.add_rv(8); msg1.add_rv(2); msg2.add_rv(2); msg2.add_rv(3); msg2.add_rv(5); msg2.add_rv(8); util::MessageDifferencer differencer; // Fail with only partial scope set. differencer.set_scope(util::MessageDifferencer::PARTIAL); differencer.set_repeated_field_comparison(util::MessageDifferencer::AS_LIST); EXPECT_FALSE(differencer.Compare(msg1, msg2)); // Fail with only set-like comparison set. differencer.set_scope(util::MessageDifferencer::FULL); differencer.set_repeated_field_comparison(util::MessageDifferencer::AS_SET); EXPECT_FALSE(differencer.Compare(msg1, msg2)); // Succeed with scope and repeated field comparison set properly. differencer.set_scope(util::MessageDifferencer::PARTIAL); differencer.set_repeated_field_comparison(util::MessageDifferencer::AS_SET); EXPECT_TRUE(differencer.Compare(msg1, msg2)); } TEST(MessageDifferencerTest, IgnoreField_Single) { protobuf_unittest::TestField msg1; protobuf_unittest::TestField msg2; msg1.set_c(3); msg1.add_rc(1); msg2.set_c(5); msg2.add_rc(1); util::MessageDifferencer differencer; differencer.IgnoreField(GetFieldDescriptor(msg1, "c")); ExpectEqualsWithDifferencer(&differencer, msg1, msg2); } TEST(MessageDifferencerTest, IgnoreField_Repeated) { protobuf_unittest::TestField msg1; protobuf_unittest::TestField msg2; msg1.set_c(3); msg1.add_rc(1); msg1.add_rc(2); msg2.set_c(3); msg2.add_rc(1); msg2.add_rc(3); util::MessageDifferencer differencer; differencer.IgnoreField(GetFieldDescriptor(msg1, "rc")); ExpectEqualsWithDifferencer(&differencer, msg1, msg2); } TEST(MessageDifferencerTest, IgnoreField_Message) { protobuf_unittest::TestDiffMessage msg1; protobuf_unittest::TestDiffMessage msg2; protobuf_unittest::TestField* field; field = msg1.add_rm(); field->set_c(3); field = msg2.add_rm(); field->set_c(4); util::MessageDifferencer differencer; differencer.IgnoreField(GetFieldDescriptor(msg1, "rm")); ExpectEqualsWithDifferencer(&differencer, msg1, msg2); } TEST(MessageDifferencerTest, IgnoreField_Group) { protobuf_unittest::TestDiffMessage msg1; protobuf_unittest::TestDiffMessage msg2; protobuf_unittest::TestDiffMessage::Item* item; item = msg1.add_item(); item->set_a(3); item = msg2.add_item(); item->set_a(4); util::MessageDifferencer differencer; differencer.IgnoreField(GetFieldDescriptor(msg1, "item")); ExpectEqualsWithDifferencer(&differencer, msg1, msg2); } TEST(MessageDifferencerTest, IgnoreField_Missing) { protobuf_unittest::TestField msg1; protobuf_unittest::TestField msg2; msg1.set_c(3); msg1.add_rc(1); msg2.add_rc(1); util::MessageDifferencer differencer; differencer.IgnoreField(GetFieldDescriptor(msg1, "c")); ExpectEqualsWithDifferencer(&differencer, msg1, msg2); ExpectEqualsWithDifferencer(&differencer, msg2, msg1); } TEST(MessageDifferencerTest, IgnoreField_Multiple) { protobuf_unittest::TestField msg1; protobuf_unittest::TestField msg2; msg1.set_c(3); msg1.add_rc(1); msg1.add_rc(2); msg2.set_c(5); msg2.add_rc(1); msg2.add_rc(3); const FieldDescriptor* c = GetFieldDescriptor(msg1, "c"); const FieldDescriptor* rc = GetFieldDescriptor(msg1, "rc"); { // Ignore c util::MessageDifferencer differencer; differencer.IgnoreField(c); EXPECT_FALSE(differencer.Compare(msg1, msg2)); } { // Ignore rc util::MessageDifferencer differencer; differencer.IgnoreField(rc); EXPECT_FALSE(differencer.Compare(msg1, msg2)); } { // Ignore both util::MessageDifferencer differencer; differencer.IgnoreField(c); differencer.IgnoreField(rc); ExpectEqualsWithDifferencer(&differencer, msg1, msg2); } } TEST(MessageDifferencerTest, IgnoreField_NestedMessage) { protobuf_unittest::TestDiffMessage msg1; protobuf_unittest::TestDiffMessage msg2; protobuf_unittest::TestField* field; field = msg1.add_rm(); field->set_c(3); field->add_rc(1); field = msg2.add_rm(); field->set_c(4); field->add_rc(1); util::MessageDifferencer differencer; differencer.IgnoreField(GetFieldDescriptor(msg1, "rm.c")); ExpectEqualsWithDifferencer(&differencer, msg1, msg2); } TEST(MessageDifferencerTest, IgnoreField_NestedGroup) { protobuf_unittest::TestDiffMessage msg1; protobuf_unittest::TestDiffMessage msg2; protobuf_unittest::TestDiffMessage::Item* item; item = msg1.add_item(); item->set_a(3); item->set_b("foo"); item = msg2.add_item(); item->set_a(4); item->set_b("foo"); util::MessageDifferencer differencer; differencer.IgnoreField(GetFieldDescriptor(msg1, "item.a")); ExpectEqualsWithDifferencer(&differencer, msg1, msg2); } TEST(MessageDifferencerTest, IgnoreField_InsideSet) { protobuf_unittest::TestDiffMessage msg1; protobuf_unittest::TestDiffMessage msg2; protobuf_unittest::TestDiffMessage::Item* item; item = msg1.add_item(); item->set_a(1); item->set_b("foo"); item->add_ra(1); item = msg1.add_item(); item->set_a(2); item->set_b("bar"); item->add_ra(2); item = msg2.add_item(); item->set_a(2); item->set_b("bar"); item->add_ra(2); item = msg2.add_item(); item->set_a(1); item->set_b("baz"); item->add_ra(1); const FieldDescriptor* item_desc = GetFieldDescriptor(msg1, "item"); const FieldDescriptor* b = GetFieldDescriptor(msg1, "item.b"); util::MessageDifferencer differencer; differencer.IgnoreField(b); differencer.TreatAsSet(item_desc); ExpectEqualsWithDifferencer(&differencer, msg1, msg2); } TEST(MessageDifferencerTest, IgnoreField_InsideMap) { protobuf_unittest::TestDiffMessage msg1; protobuf_unittest::TestDiffMessage msg2; protobuf_unittest::TestDiffMessage::Item* item; item = msg1.add_item(); item->set_a(1); item->set_b("foo"); item->add_ra(1); item = msg1.add_item(); item->set_a(2); item->set_b("bar"); item->add_ra(2); item = msg2.add_item(); item->set_a(2); item->set_b("bar"); item->add_ra(2); item = msg2.add_item(); item->set_a(1); item->set_b("baz"); item->add_ra(1); const FieldDescriptor* item_desc = GetFieldDescriptor(msg1, "item"); const FieldDescriptor* a = GetFieldDescriptor(msg1, "item.a"); const FieldDescriptor* b = GetFieldDescriptor(msg1, "item.b"); util::MessageDifferencer differencer; differencer.IgnoreField(b); differencer.TreatAsMap(item_desc, a); ExpectEqualsWithDifferencer(&differencer, msg1, msg2); } TEST(MessageDifferencerTest, IgnoreField_DoesNotIgnoreKey) { protobuf_unittest::TestDiffMessage msg1; protobuf_unittest::TestDiffMessage msg2; protobuf_unittest::TestDiffMessage::Item* item; item = msg1.add_item(); item->set_a(1); item->set_b("foo"); item->add_ra(1); item = msg2.add_item(); item->set_a(2); item->set_b("foo"); item->add_ra(1); const FieldDescriptor* item_desc = GetFieldDescriptor(msg1, "item"); const FieldDescriptor* a = GetFieldDescriptor(msg1, "item.a"); util::MessageDifferencer differencer; differencer.IgnoreField(a); differencer.TreatAsMap(item_desc, a); EXPECT_FALSE(differencer.Compare(msg1, msg2)); } TEST(MessageDifferencerTest, IgnoreField_TrumpsCompareWithFields) { protobuf_unittest::TestField msg1; protobuf_unittest::TestField msg2; msg1.set_c(3); msg1.add_rc(1); msg1.add_rc(2); msg2.set_c(3); msg2.add_rc(1); msg2.add_rc(3); const FieldDescriptor* c = GetFieldDescriptor(msg1, "c"); const FieldDescriptor* rc = GetFieldDescriptor(msg1, "rc"); std::vector fields; fields.push_back(c); fields.push_back(rc); util::MessageDifferencer differencer; differencer.IgnoreField(rc); differencer.set_scope(util::MessageDifferencer::FULL); EXPECT_TRUE(differencer.CompareWithFields(msg1, msg2, fields, fields)); differencer.set_scope(util::MessageDifferencer::PARTIAL); EXPECT_TRUE(differencer.CompareWithFields(msg1, msg2, fields, fields)); } // Test class to save a copy of the last field_context.parent_fields() vector // passed to the comparison function. class ParentSavingFieldComparator : public util::FieldComparator { public: ParentSavingFieldComparator() {} virtual ComparisonResult Compare( const google::protobuf::Message& message_1, const google::protobuf::Message& message_2, const google::protobuf::FieldDescriptor* field, int index_1, int index_2, const google::protobuf::util::FieldContext* field_context) { if (field_context) parent_fields_ = *(field_context->parent_fields()); if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { return RECURSE; } else { return SAME; } } std::vector parent_fields() { return parent_fields_; } private: std::vector parent_fields_; }; // Tests if MessageDifferencer sends the parent fields in the FieldContext // parameter. TEST(MessageDifferencerTest, FieldContextParentFieldsTest) { protobuf_unittest::TestDiffMessage msg1; msg1.add_rm()->set_c(1); protobuf_unittest::TestDiffMessage msg2; msg2.add_rm()->set_c(1); ParentSavingFieldComparator field_comparator; util::MessageDifferencer differencer; differencer.set_field_comparator(&field_comparator); differencer.Compare(msg1, msg2); // We want only one parent with the name "rm" ASSERT_EQ(1, field_comparator.parent_fields().size()); EXPECT_EQ("rm", field_comparator.parent_fields()[0].field->name()); } class ComparisonTest : public testing::Test { protected: ComparisonTest() : use_equivalency_(false), repeated_field_as_set_(false) { // Setup the test. TestUtil::SetAllFields(&proto1_); TestUtil::SetAllFields(&proto2_); TestUtil::SetAllExtensions(&proto1ex_); TestUtil::SetAllExtensions(&proto2ex_); TestUtil::SetAllFieldsAndExtensions(&orderings_proto1_); TestUtil::SetAllFieldsAndExtensions(&orderings_proto2_); unknown1_ = empty1_.mutable_unknown_fields(); unknown2_ = empty2_.mutable_unknown_fields(); } ~ComparisonTest() { } void SetSpecialFieldOption(const Message& message, util::MessageDifferencer* d) { if (!ignored_field_.empty()) { d->IgnoreField(GetFieldDescriptor(message, ignored_field_)); } if (repeated_field_as_set_) { d->set_repeated_field_comparison(util::MessageDifferencer::AS_SET); } if (!set_field_.empty()) { d->TreatAsSet(GetFieldDescriptor(message, set_field_)); } if (!map_field_.empty() && !map_key_.empty()) { d->TreatAsMap(GetFieldDescriptor(message, map_field_), GetFieldDescriptor(message, map_field_ + "." + map_key_)); } } string Run(const Message& msg1, const Message& msg2) { string output; // Setup the comparison. util::MessageDifferencer differencer; differencer.ReportDifferencesToString(&output); if (use_equivalency_) { differencer.set_message_field_comparison( util::MessageDifferencer::EQUIVALENT); } SetSpecialFieldOption(msg1, &differencer); // Conduct the comparison. EXPECT_FALSE(differencer.Compare(msg1, msg2)); return output; } string Run() { return Run(proto1_, proto2_); } string RunOrder() { return Run(orderings_proto1_, orderings_proto2_); } string RunEx() { return Run(proto1ex_, proto2ex_); } string RunDiff() { return Run(proto1diff_, proto2diff_); } string RunUn() { return Run(empty1_, empty2_); } void use_equivalency() { use_equivalency_ = true; } void repeated_field_as_set() { repeated_field_as_set_ = true; } void field_as_set(const string& field) { set_field_ = field; } void field_as_map(const string& field, const string& key) { map_field_ = field; map_key_ = key; } void ignore_field(const string& field) { ignored_field_ = field; } unittest::TestAllTypes proto1_; unittest::TestAllTypes proto2_; unittest::TestFieldOrderings orderings_proto1_; unittest::TestFieldOrderings orderings_proto2_; unittest::TestAllExtensions proto1ex_; unittest::TestAllExtensions proto2ex_; unittest::TestDiffMessage proto1diff_; unittest::TestDiffMessage proto2diff_; unittest::TestEmptyMessage empty1_; unittest::TestEmptyMessage empty2_; UnknownFieldSet* unknown1_; UnknownFieldSet* unknown2_; bool use_equivalency_; bool repeated_field_as_set_; string set_field_; string map_field_; string map_key_; string ignored_field_; }; // Basic tests. TEST_F(ComparisonTest, AdditionTest) { proto1_.clear_optional_int32(); EXPECT_EQ("added: optional_int32: 101\n", Run()); } TEST_F(ComparisonTest, Addition_OrderTest) { orderings_proto1_.clear_my_int(); EXPECT_EQ("added: my_int: 1\n", RunOrder()); } TEST_F(ComparisonTest, DeletionTest) { proto2_.clear_optional_int32(); EXPECT_EQ("deleted: optional_int32: 101\n", Run()); } TEST_F(ComparisonTest, Deletion_OrderTest) { orderings_proto2_.clear_my_string(); EXPECT_EQ("deleted: my_string: \"foo\"\n", RunOrder()); } TEST_F(ComparisonTest, RepeatedDeletionTest) { proto2_.clear_repeated_int32(); EXPECT_EQ("deleted: repeated_int32[0]: 201\n" "deleted: repeated_int32[1]: 301\n", Run()); } TEST_F(ComparisonTest, ModificationTest) { proto1_.set_optional_int32(-1); EXPECT_EQ("modified: optional_int32: -1 -> 101\n", Run()); } // Basic equivalency tests. TEST_F(ComparisonTest, EquivalencyAdditionTest) { use_equivalency(); proto1_.clear_optional_int32(); EXPECT_EQ("modified: optional_int32: 0 -> 101\n", Run()); } TEST_F(ComparisonTest, EquivalencyDeletionTest) { use_equivalency(); proto2_.clear_optional_int32(); EXPECT_EQ("modified: optional_int32: 101 -> 0\n", Run()); } // Group tests. TEST_F(ComparisonTest, GroupAdditionTest) { proto1_.mutable_optionalgroup()->clear_a(); EXPECT_EQ("added: optionalgroup.a: 117\n", Run()); } TEST_F(ComparisonTest, GroupDeletionTest) { proto2_.mutable_optionalgroup()->clear_a(); EXPECT_EQ("deleted: optionalgroup.a: 117\n", Run()); } TEST_F(ComparisonTest, GroupModificationTest) { proto1_.mutable_optionalgroup()->set_a(2); EXPECT_EQ("modified: optionalgroup.a: 2 -> 117\n", Run()); } TEST_F(ComparisonTest, GroupFullAdditionTest) { proto1_.clear_optionalgroup(); // Note the difference in the output between this and GroupAdditionTest. EXPECT_EQ("added: optionalgroup: { a: 117 }\n", Run()); } TEST_F(ComparisonTest, GroupFullDeletionTest) { proto2_.clear_optionalgroup(); EXPECT_EQ("deleted: optionalgroup: { a: 117 }\n", Run()); } TEST_F(ComparisonTest, RepeatedSetOptionTest) { repeated_field_as_set(); proto2_.clear_repeatedgroup(); proto1_.clear_repeatedgroup(); proto1_.add_repeatedgroup()->set_a(317); proto2_.add_repeatedgroup()->set_a(909); proto2_.add_repeatedgroup()->set_a(907); proto1_.add_repeatedgroup()->set_a(904); proto1_.add_repeatedgroup()->set_a(907); proto1_.add_repeatedgroup()->set_a(909); EXPECT_EQ("moved: repeatedgroup[2] -> repeatedgroup[1] : { a: 907 }\n" "moved: repeatedgroup[3] -> repeatedgroup[0] : { a: 909 }\n" "deleted: repeatedgroup[0]: { a: 317 }\n" "deleted: repeatedgroup[1]: { a: 904 }\n", Run()); } TEST_F(ComparisonTest, RepeatedSetOptionTest_Ex) { repeated_field_as_set(); proto1ex_.ClearExtension(protobuf_unittest::repeated_nested_message_extension); proto2ex_.ClearExtension(protobuf_unittest::repeated_nested_message_extension); proto2ex_.AddExtension(protobuf_unittest::repeated_nested_message_extension) ->set_bb(909); proto2ex_.AddExtension(protobuf_unittest::repeated_nested_message_extension) ->set_bb(907); proto1ex_.AddExtension(protobuf_unittest::repeated_nested_message_extension) ->set_bb(904); proto1ex_.AddExtension(protobuf_unittest::repeated_nested_message_extension) ->set_bb(907); proto1ex_.AddExtension(protobuf_unittest::repeated_nested_message_extension) ->set_bb(909); EXPECT_EQ("moved: (protobuf_unittest.repeated_nested_message_extension)[2] ->" " (protobuf_unittest.repeated_nested_message_extension)[0] :" " { bb: 909 }\n" "deleted: (protobuf_unittest.repeated_nested_message_extension)[0]:" " { bb: 904 }\n", RunEx()); } TEST_F(ComparisonTest, RepeatedMapFieldTest_Group) { field_as_map("repeatedgroup", "a"); proto1_.clear_repeatedgroup(); proto2_.clear_repeatedgroup(); proto1_.add_repeatedgroup()->set_a(317); // deleted proto1_.add_repeatedgroup()->set_a(904); // deleted proto1_.add_repeatedgroup()->set_a(907); // moved from proto1_.add_repeatedgroup()->set_a(909); // moved from proto2_.add_repeatedgroup()->set_a(909); // moved to proto2_.add_repeatedgroup()->set_a(318); // added proto2_.add_repeatedgroup()->set_a(907); // moved to EXPECT_EQ("moved: repeatedgroup[3] -> repeatedgroup[0] : { a: 909 }\n" "added: repeatedgroup[1]: { a: 318 }\n" "deleted: repeatedgroup[0]: { a: 317 }\n" "deleted: repeatedgroup[1]: { a: 904 }\n", Run()); } TEST_F(ComparisonTest, RepeatedMapFieldTest_MessageKey) { // Use m as key, but use b as value. field_as_map("item", "m"); protobuf_unittest::TestDiffMessage msg1; protobuf_unittest::TestDiffMessage msg2; protobuf_unittest::TestDiffMessage::Item* item = msg1.add_item(); // The following code creates one deletion, one addition and two moved fields // on the messages. item->mutable_m()->set_c(0); item->set_b("first"); item = msg1.add_item(); item->mutable_m()->set_c(2); item->set_b("second"); item = msg1.add_item(); item->set_b("null"); // empty key moved item = msg1.add_item(); item->mutable_m()->set_c(3); item->set_b("third"); // deletion item = msg1.add_item(); item->mutable_m()->set_c(2); item->set_b("second"); // duplicated key ( deletion ) item = msg2.add_item(); item->mutable_m()->set_c(2); item->set_b("second"); // modification item = msg2.add_item(); item->mutable_m()->set_c(4); item->set_b("fourth"); // addition item = msg2.add_item(); item->mutable_m()->set_c(0); item->set_b("fist"); // move with change item = msg2.add_item(); item->set_b("null"); EXPECT_EQ( "modified: item[0].b -> item[2].b: \"first\" -> \"fist\"\n" "moved: item[1] -> item[0] : { b: \"second\" m { c: 2 } }\n" "moved: item[2] -> item[3] : { b: \"null\" }\n" "added: item[1]: { b: \"fourth\" m { c: 4 } }\n" "deleted: item[3]: { b: \"third\" m { c: 3 } }\n" "deleted: item[4]: { b: \"second\" m { c: 2 } }\n", Run(msg1, msg2)); } TEST_F(ComparisonTest, RepeatedFieldSetTest_SetOfSet) { repeated_field_as_set(); // Create the testing protos protobuf_unittest::TestDiffMessage msg1; protobuf_unittest::TestDiffMessage msg2; protobuf_unittest::TestDiffMessage::Item* item = msg1.add_item(); item->add_ra(1); item->add_ra(2); item->add_ra(3); item = msg1.add_item(); item->add_ra(5); item->add_ra(6); item = msg1.add_item(); item->add_ra(1); item->add_ra(3); item = msg1.add_item(); item->add_ra(6); item->add_ra(7); item->add_ra(8); item = msg2.add_item(); item->add_ra(6); item->add_ra(5); item = msg2.add_item(); item->add_ra(6); item->add_ra(8); item = msg2.add_item(); item->add_ra(1); item->add_ra(3); item = msg2.add_item(); item->add_ra(3); item->add_ra(2); item->add_ra(1); // Compare EXPECT_EQ("moved: item[0].ra[0] -> item[3].ra[2] : 1\n" "moved: item[0].ra[2] -> item[3].ra[0] : 3\n" "moved: item[0] -> item[3] : { ra: 1 ra: 2 ra: 3 }\n" "moved: item[1].ra[0] -> item[0].ra[1] : 5\n" "moved: item[1].ra[1] -> item[0].ra[0] : 6\n" "moved: item[1] -> item[0] : { ra: 5 ra: 6 }\n" "added: item[1]: { ra: 6 ra: 8 }\n" "deleted: item[3]: { ra: 6 ra: 7 ra: 8 }\n", Run(msg1, msg2)); } TEST_F(ComparisonTest, RepeatedMapFieldTest_RepeatedKey) { // used rb as a key, but b is the value. repeated_field_as_set(); field_as_map("item", "rb"); protobuf_unittest::TestDiffMessage msg1; protobuf_unittest::TestDiffMessage msg2; protobuf_unittest::TestDiffMessage::Item* item = msg1.add_item(); item->add_rb("a"); item->add_rb("b"); item->set_b("first"); item = msg2.add_item(); item->add_rb("c"); item->set_b("second"); item = msg2.add_item(); item->add_rb("b"); item->add_rb("a"); item->set_b("fist"); EXPECT_EQ("modified: item[0].b -> item[1].b: \"first\" -> \"fist\"\n" "moved: item[0].rb[0] -> item[1].rb[1] : \"a\"\n" "moved: item[0].rb[1] -> item[1].rb[0] : \"b\"\n" "added: item[0]: { b: \"second\" rb: \"c\" }\n", Run(msg1, msg2)); } TEST_F(ComparisonTest, RepeatedMapFieldTest_RepeatedMessageKey) { field_as_map("item", "rm"); protobuf_unittest::TestDiffMessage msg1; protobuf_unittest::TestDiffMessage msg2; protobuf_unittest::TestDiffMessage::Item* item = msg1.add_item(); protobuf_unittest::TestField* key = item->add_rm(); key->set_c(2); key->add_rc(10); key->add_rc(10); item = msg1.add_item(); key = item->add_rm(); key->set_c(0); key->add_rc(1); key->add_rc(2); key = item->add_rm(); key->set_c(0); item->add_rb("first"); item = msg2.add_item(); item->CopyFrom(msg1.item(1)); item->add_rb("second"); EXPECT_EQ("added: item[0].rb[1]: \"second\"\n" "deleted: item[0]: { rm { c: 2 rc: 10 rc: 10 } }\n", Run(msg1, msg2)); } TEST_F(ComparisonTest, RepeatedSetOptionTest_Unknown) { // Currently, as_set option doesn't have affects on unknown field. // If needed, this feature will be added by request. repeated_field_as_set(); unknown1_->AddGroup(245)->AddFixed32(248, 1); unknown2_->AddGroup(245)->AddFixed32(248, 3); unknown2_->AddGroup(245)->AddFixed32(248, 1); // We expect it behaves the same as normal comparison. EXPECT_EQ("modified: 245[0].248[0]: 0x00000001 -> 0x00000003\n" "added: 245[1]: { ... }\n", RunUn()); } TEST_F(ComparisonTest, Matching_Unknown) { unknown1_->AddGroup(245)->AddFixed32(248, 1); unknown2_->AddGroup(245)->AddFixed32(248, 1); unknown1_->AddGroup(245)->AddFixed32(248, 3); unknown2_->AddGroup(245)->AddFixed32(248, 3); unknown2_->AddLengthDelimited(242, "cat"); unknown2_->AddGroup(246)->AddFixed32(248, 4); // report_match is false so only added/modified fields are expected. EXPECT_EQ("added: 242[0]: \"cat\"\n" "added: 246[0]: { ... }\n", RunUn()); } TEST_F(ComparisonTest, RepeatedSetFieldTest) { field_as_set("repeatedgroup"); proto1_.clear_repeatedgroup(); proto2_.clear_repeatedgroup(); proto2_.add_repeatedgroup()->set_a(909); proto2_.add_repeatedgroup()->set_a(907); proto1_.add_repeatedgroup()->set_a(317); proto1_.add_repeatedgroup()->set_a(904); proto1_.add_repeatedgroup()->set_a(907); proto1_.add_repeatedgroup()->set_a(909); EXPECT_EQ("moved: repeatedgroup[2] -> repeatedgroup[1] : { a: 907 }\n" "moved: repeatedgroup[3] -> repeatedgroup[0] : { a: 909 }\n" "deleted: repeatedgroup[0]: { a: 317 }\n" "deleted: repeatedgroup[1]: { a: 904 }\n", Run()); } // Embedded message tests. TEST_F(ComparisonTest, EmbeddedAdditionTest) { proto1_.mutable_optional_nested_message()->clear_bb(); EXPECT_EQ("added: optional_nested_message.bb: 118\n", Run()); } TEST_F(ComparisonTest, EmbeddedDeletionTest) { proto2_.mutable_optional_nested_message()->clear_bb(); EXPECT_EQ("deleted: optional_nested_message.bb: 118\n", Run()); } TEST_F(ComparisonTest, EmbeddedModificationTest) { proto1_.mutable_optional_nested_message()->set_bb(2); EXPECT_EQ("modified: optional_nested_message.bb: 2 -> 118\n", Run()); } TEST_F(ComparisonTest, EmbeddedFullAdditionTest) { proto1_.clear_optional_nested_message(); EXPECT_EQ("added: optional_nested_message: { bb: 118 }\n", Run()); } TEST_F(ComparisonTest, EmbeddedPartialAdditionTest) { proto1_.clear_optional_nested_message(); proto2_.mutable_optional_nested_message()->clear_bb(); EXPECT_EQ("added: optional_nested_message: { }\n", Run()); } TEST_F(ComparisonTest, EmbeddedFullDeletionTest) { proto2_.clear_optional_nested_message(); EXPECT_EQ("deleted: optional_nested_message: { bb: 118 }\n", Run()); } // Repeated element tests. TEST_F(ComparisonTest, BasicRepeatedTest) { proto1_.clear_repeated_int32(); proto2_.clear_repeated_int32(); proto1_.add_repeated_int32(500); proto1_.add_repeated_int32(501); proto1_.add_repeated_int32(502); proto1_.add_repeated_int32(503); proto1_.add_repeated_int32(500); proto2_.add_repeated_int32(500); proto2_.add_repeated_int32(509); proto2_.add_repeated_int32(502); proto2_.add_repeated_int32(504); EXPECT_EQ("modified: repeated_int32[1]: 501 -> 509\n" "modified: repeated_int32[3]: 503 -> 504\n" "deleted: repeated_int32[4]: 500\n", Run()); } TEST_F(ComparisonTest, BasicRepeatedTest_SetOption) { repeated_field_as_set(); proto1_.clear_repeated_int32(); proto2_.clear_repeated_int32(); proto1_.add_repeated_int32(501); proto1_.add_repeated_int32(502); proto1_.add_repeated_int32(503); proto1_.add_repeated_int32(500); proto1_.add_repeated_int32(500); proto2_.add_repeated_int32(500); proto2_.add_repeated_int32(509); proto2_.add_repeated_int32(503); proto2_.add_repeated_int32(502); proto2_.add_repeated_int32(504); EXPECT_EQ("moved: repeated_int32[1] -> repeated_int32[3] : 502\n" "moved: repeated_int32[3] -> repeated_int32[0] : 500\n" "added: repeated_int32[1]: 509\n" "added: repeated_int32[4]: 504\n" "deleted: repeated_int32[0]: 501\n" "deleted: repeated_int32[4]: 500\n", Run()); } TEST_F(ComparisonTest, BasicRepeatedTest_SetField) { field_as_set("repeated_int32"); proto1_.clear_repeated_int32(); proto2_.clear_repeated_int32(); proto1_.add_repeated_int32(501); proto1_.add_repeated_int32(502); proto1_.add_repeated_int32(503); proto1_.add_repeated_int32(500); proto1_.add_repeated_int32(500); proto2_.add_repeated_int32(500); proto2_.add_repeated_int32(509); proto2_.add_repeated_int32(503); proto2_.add_repeated_int32(502); proto2_.add_repeated_int32(504); EXPECT_EQ("moved: repeated_int32[1] -> repeated_int32[3] : 502\n" "moved: repeated_int32[3] -> repeated_int32[0] : 500\n" "added: repeated_int32[1]: 509\n" "added: repeated_int32[4]: 504\n" "deleted: repeated_int32[0]: 501\n" "deleted: repeated_int32[4]: 500\n", Run()); } // Multiple action tests. TEST_F(ComparisonTest, AddDeleteTest) { proto1_.clear_optional_int32(); proto2_.clear_optional_int64(); EXPECT_EQ("added: optional_int32: 101\n" "deleted: optional_int64: 102\n", Run()); } TEST_F(ComparisonTest, AddDelete_FieldOrderingTest) { orderings_proto1_.ClearExtension(unittest::my_extension_string); orderings_proto2_.clear_my_int(); EXPECT_EQ("deleted: my_int: 1\n" "added: (protobuf_unittest.my_extension_string): \"bar\"\n", RunOrder()); } TEST_F(ComparisonTest, AllThreeTest) { proto1_.clear_optional_int32(); proto2_.clear_optional_float(); proto2_.set_optional_string("hello world!"); EXPECT_EQ("added: optional_int32: 101\n" "deleted: optional_float: 111\n" "modified: optional_string: \"115\" -> \"hello world!\"\n", Run()); } TEST_F(ComparisonTest, SandwhichTest) { proto1_.clear_optional_int64(); proto1_.clear_optional_uint32(); proto2_.clear_optional_uint64(); EXPECT_EQ("added: optional_int64: 102\n" "added: optional_uint32: 103\n" "deleted: optional_uint64: 104\n", Run()); } TEST_F(ComparisonTest, IgnoredNoChangeTest) { proto1diff_.set_v(3); proto2diff_.set_v(3); proto2diff_.set_w("foo"); ignore_field("v"); EXPECT_EQ("ignored: v\n" "added: w: \"foo\"\n", RunDiff()); } TEST_F(ComparisonTest, IgnoredAddTest) { proto2diff_.set_v(3); proto2diff_.set_w("foo"); ignore_field("v"); EXPECT_EQ("ignored: v\n" "added: w: \"foo\"\n", RunDiff()); } TEST_F(ComparisonTest, IgnoredDeleteTest) { proto1diff_.set_v(3); proto2diff_.set_w("foo"); ignore_field("v"); EXPECT_EQ("ignored: v\n" "added: w: \"foo\"\n", RunDiff()); } TEST_F(ComparisonTest, IgnoredModifyTest) { proto1diff_.set_v(3); proto2diff_.set_v(4); proto2diff_.set_w("foo"); ignore_field("v"); EXPECT_EQ("ignored: v\n" "added: w: \"foo\"\n", RunDiff()); } TEST_F(ComparisonTest, IgnoredRepeatedAddTest) { proto1diff_.add_rv(3); proto1diff_.add_rv(4); proto2diff_.add_rv(3); proto2diff_.add_rv(4); proto2diff_.add_rv(5); proto2diff_.set_w("foo"); ignore_field("rv"); EXPECT_EQ("ignored: rv\n" "added: w: \"foo\"\n", RunDiff()); } TEST_F(ComparisonTest, IgnoredRepeatedDeleteTest) { proto1diff_.add_rv(3); proto1diff_.add_rv(4); proto1diff_.add_rv(5); proto2diff_.add_rv(3); proto2diff_.add_rv(4); proto2diff_.set_w("foo"); ignore_field("rv"); EXPECT_EQ("ignored: rv\n" "added: w: \"foo\"\n", RunDiff()); } TEST_F(ComparisonTest, IgnoredRepeatedModifyTest) { proto1diff_.add_rv(3); proto1diff_.add_rv(4); proto2diff_.add_rv(3); proto2diff_.add_rv(5); proto2diff_.set_w("foo"); ignore_field("rv"); EXPECT_EQ("ignored: rv\n" "added: w: \"foo\"\n", RunDiff()); } TEST_F(ComparisonTest, IgnoredWholeNestedMessage) { proto1diff_.mutable_m()->set_c(3); proto2diff_.mutable_m()->set_c(4); proto2diff_.set_w("foo"); ignore_field("m"); EXPECT_EQ("added: w: \"foo\"\n" "ignored: m\n", RunDiff()); } TEST_F(ComparisonTest, IgnoredNestedField) { proto1diff_.mutable_m()->set_c(3); proto2diff_.mutable_m()->set_c(4); proto2diff_.set_w("foo"); ignore_field("m.c"); EXPECT_EQ("added: w: \"foo\"\n" "ignored: m.c\n", RunDiff()); } TEST_F(ComparisonTest, IgnoredRepeatedNested) { proto1diff_.add_rm()->set_c(0); proto1diff_.add_rm()->set_c(1); proto2diff_.add_rm()->set_c(2); proto2diff_.add_rm()->set_c(3); proto2diff_.set_w("foo"); ignore_field("rm.c"); EXPECT_EQ("ignored: rm[0].c\n" "ignored: rm[1].c\n" "added: w: \"foo\"\n", RunDiff()); } TEST_F(ComparisonTest, IgnoredNestedRepeated) { proto1diff_.mutable_m()->add_rc(23); proto1diff_.mutable_m()->add_rc(24); proto2diff_.mutable_m()->add_rc(25); proto2diff_.set_w("foo"); ignore_field("m.rc"); EXPECT_EQ("added: w: \"foo\"\n" "ignored: m.rc\n", RunDiff()); } TEST_F(ComparisonTest, ExtensionTest) { proto1ex_.SetExtension(unittest::optional_int32_extension, 401); proto2ex_.SetExtension(unittest::optional_int32_extension, 402); proto1ex_.ClearExtension(unittest::optional_int64_extension); proto2ex_.SetExtension(unittest::optional_int64_extension, 403); EXPECT_EQ( "modified: (protobuf_unittest.optional_int32_extension): 401 -> 402\n" "added: (protobuf_unittest.optional_int64_extension): 403\n", RunEx()); } TEST_F(ComparisonTest, MatchedUnknownFieldTagTest) { unknown1_->AddVarint(240, 122); unknown2_->AddVarint(240, 121); unknown1_->AddFixed32(241, 1); unknown2_->AddFixed64(241, 2); unknown1_->AddLengthDelimited(242, "cat"); unknown2_->AddLengthDelimited(242, "dog"); EXPECT_EQ( "modified: 240[0]: 122 -> 121\n" "deleted: 241[0]: 0x00000001\n" "added: 241[0]: 0x0000000000000002\n" "modified: 242[0]: \"cat\" -> \"dog\"\n", RunUn()); } TEST_F(ComparisonTest, UnmatchedUnknownFieldTagTest) { unknown1_->AddFixed32(243, 1); unknown2_->AddVarint(244, 2); unknown2_->AddVarint(244, 4); EXPECT_EQ( "deleted: 243[0]: 0x00000001\n" "added: 244[0]: 2\n" "added: 244[1]: 4\n", RunUn()); } TEST_F(ComparisonTest, DifferentSizedUnknownFieldTest) { unknown1_->AddVarint(240, 1); unknown1_->AddVarint(240, 3); unknown1_->AddVarint(240, 4); unknown2_->AddVarint(240, 2); unknown2_->AddVarint(240, 3); unknown2_->AddVarint(240, 2); unknown2_->AddVarint(240, 5); EXPECT_EQ( "modified: 240[0]: 1 -> 2\n" "modified: 240[2]: 4 -> 2\n" "added: 240[3]: 5\n", RunUn()); } TEST_F(ComparisonTest, UnknownFieldsAll) { unknown1_->AddVarint(243, 122); unknown1_->AddFixed64(244, 0x0172356); unknown1_->AddFixed64(244, 0x098); unknown1_->AddGroup(245)->AddFixed32(248, 1); unknown1_->mutable_field(3)->mutable_group()->AddFixed32(248, 2); unknown1_->AddGroup(249)->AddFixed64(250, 1); unknown2_->AddVarint(243, 121); unknown2_->AddLengthDelimited(73882, "test 123"); unknown2_->AddGroup(245)->AddFixed32(248, 3); unknown2_->AddGroup(247); EXPECT_EQ( "modified: 243[0]: 122 -> 121\n" "deleted: 244[0]: 0x0000000000172356\n" "deleted: 244[1]: 0x0000000000000098\n" "modified: 245[0].248[0]: 0x00000001 -> 0x00000003\n" "deleted: 245[0].248[1]: 0x00000002\n" "added: 247[0]: { ... }\n" "deleted: 249[0]: { ... }\n" "added: 73882[0]: \"test 123\"\n", RunUn()); } TEST_F(ComparisonTest, EquivalentIgnoresUnknown) { unittest::ForeignMessage message1, message2; message1.set_c(5); message1.mutable_unknown_fields()->AddVarint(123, 456); message2.set_c(5); message2.mutable_unknown_fields()->AddVarint(321, 654); EXPECT_FALSE(util::MessageDifferencer::Equals(message1, message2)); EXPECT_TRUE(util::MessageDifferencer::Equivalent(message1, message2)); } class MatchingTest : public testing::Test { public: typedef util::MessageDifferencer MessageDifferencer; protected: MatchingTest() { } ~MatchingTest() { } string RunWithResult(MessageDifferencer* differencer, const Message& msg1, const Message& msg2, bool result) { string output; { // Before we return the "output" string, we must make sure the // StreamReporter is destructored because its destructor will // flush the stream. io::StringOutputStream output_stream(&output); MessageDifferencer::StreamReporter reporter(&output_stream); reporter.set_report_modified_aggregates(true); differencer->set_report_matches(true); differencer->ReportDifferencesTo(&reporter); if (result) { EXPECT_TRUE(differencer->Compare(msg1, msg2)); } else { EXPECT_FALSE(differencer->Compare(msg1, msg2)); } } return output; } private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MatchingTest); }; TEST_F(MatchingTest, StreamReporterMatching) { protobuf_unittest::TestField msg1, msg2; msg1.set_c(72); msg2.set_c(72); msg1.add_rc(13); msg2.add_rc(13); msg1.add_rc(17); msg2.add_rc(17); string output; MessageDifferencer differencer; differencer.set_report_matches(true); differencer.ReportDifferencesToString(&output); EXPECT_TRUE(differencer.Compare(msg1, msg2)); EXPECT_EQ( "matched: c : 72\n" "matched: rc[0] : 13\n" "matched: rc[1] : 17\n", output); } TEST_F(MatchingTest, DontReportMatchedWhenIgnoring) { protobuf_unittest::TestField msg1, msg2; msg1.set_c(72); msg2.set_c(72); msg1.add_rc(13); msg2.add_rc(13); msg1.add_rc(17); msg2.add_rc(17); string output; MessageDifferencer differencer; differencer.set_report_matches(true); differencer.ReportDifferencesToString(&output); differencer.IgnoreField(msg1.GetDescriptor()->FindFieldByName("c")); EXPECT_TRUE(differencer.Compare(msg1, msg2)); EXPECT_EQ( "ignored: c\n" "matched: rc[0] : 13\n" "matched: rc[1] : 17\n", output); } TEST_F(MatchingTest, ReportMatchedForMovedFields) { protobuf_unittest::TestDiffMessage msg1, msg2; protobuf_unittest::TestDiffMessage::Item* item = msg1.add_item(); item->set_a(53); item->set_b("hello"); item = msg2.add_item(); item->set_a(27); item = msg2.add_item(); item->set_a(53); item->set_b("hello"); item = msg1.add_item(); item->set_a(27); MessageDifferencer differencer; const FieldDescriptor* desc; desc = msg1.GetDescriptor()->FindFieldByName("item"); differencer.TreatAsSet(desc); EXPECT_EQ( "matched: item[0].a -> item[1].a : 53\n" "matched: item[0].b -> item[1].b : \"hello\"\n" "moved: item[0] -> item[1] : { a: 53 b: \"hello\" }\n" "matched: item[1].a -> item[0].a : 27\n" "moved: item[1] -> item[0] : { a: 27 }\n", RunWithResult(&differencer, msg1, msg2, true)); } TEST_F(MatchingTest, MatchesAppearInPostTraversalOrderForMovedFields) { protobuf_unittest::TestDiffMessage msg1, msg2; protobuf_unittest::TestDiffMessage::Item* item; protobuf_unittest::TestField* field; const FieldDescriptor* desc; const FieldDescriptor* nested_desc; const FieldDescriptor* double_nested_desc; desc = msg1.GetDescriptor()->FindFieldByName("item"); nested_desc = desc->message_type()->FindFieldByName("rm"); double_nested_desc = nested_desc->message_type()->FindFieldByName("rc"); MessageDifferencer differencer; differencer.TreatAsSet(desc); differencer.TreatAsSet(nested_desc); differencer.TreatAsSet(double_nested_desc); item = msg1.add_item(); field = item->add_rm(); field->set_c(1); field->add_rc(2); field->add_rc(3); field = item->add_rm(); field->set_c(4); field->add_rc(5); field->add_rc(6); field->add_rc(7); item = msg2.add_item(); field = item->add_rm(); field->set_c(4); field->add_rc(7); field->add_rc(6); field->add_rc(5); field = item->add_rm(); field->set_c(1); field->add_rc(3); field->add_rc(2); item = msg1.add_item(); field = item->add_rm(); field->set_c(8); field->add_rc(10); field->add_rc(11); field->add_rc(9); item = msg2.add_item(); field = item->add_rm(); field->set_c(8); field->add_rc(9); field->add_rc(10); field->add_rc(11); EXPECT_EQ( "matched: item[0].rm[0].c -> item[0].rm[1].c : 1\n" "moved: item[0].rm[0].rc[0] -> item[0].rm[1].rc[1] : 2\n" "moved: item[0].rm[0].rc[1] -> item[0].rm[1].rc[0] : 3\n" "moved: item[0].rm[0] -> item[0].rm[1] : { c: 1 rc: 2 rc: 3 }\n" "matched: item[0].rm[1].c -> item[0].rm[0].c : 4\n" "moved: item[0].rm[1].rc[0] -> item[0].rm[0].rc[2] : 5\n" "matched: item[0].rm[1].rc[1] -> item[0].rm[0].rc[1] : 6\n" "moved: item[0].rm[1].rc[2] -> item[0].rm[0].rc[0] : 7\n" "moved: item[0].rm[1] -> item[0].rm[0] : { c: 4 rc: 5 rc: 6 rc: 7 }\n" "matched: item[0] : { rm { c: 1 rc: 2 rc: 3 }" " rm { c: 4 rc: 5 rc: 6 rc: 7 } }\n" "matched: item[1].rm[0].c : 8\n" "moved: item[1].rm[0].rc[0] -> item[1].rm[0].rc[1] : 10\n" "moved: item[1].rm[0].rc[1] -> item[1].rm[0].rc[2] : 11\n" "moved: item[1].rm[0].rc[2] -> item[1].rm[0].rc[0] : 9\n" "matched: item[1].rm[0] : { c: 8 rc: 10 rc: 11 rc: 9 }\n" "matched: item[1] : { rm { c: 8 rc: 10 rc: 11 rc: 9 } }\n", RunWithResult(&differencer, msg1, msg2, true)); } TEST_F(MatchingTest, MatchAndModifiedInterleaveProperly) { protobuf_unittest::TestDiffMessage msg1, msg2; protobuf_unittest::TestDiffMessage::Item* item; protobuf_unittest::TestField* field; const FieldDescriptor* desc; const FieldDescriptor* nested_key; const FieldDescriptor* nested_desc; const FieldDescriptor* double_nested_key; const FieldDescriptor* double_nested_desc; desc = msg1.GetDescriptor()->FindFieldByName("item"); nested_key = desc->message_type()->FindFieldByName("a"); nested_desc = desc->message_type()->FindFieldByName("rm"); double_nested_key = nested_desc->message_type()->FindFieldByName("c"); double_nested_desc = nested_desc->message_type()->FindFieldByName("rc"); MessageDifferencer differencer; differencer.TreatAsMap(desc, nested_key); differencer.TreatAsMap(nested_desc, double_nested_key); differencer.TreatAsSet(double_nested_desc); item = msg1.add_item(); item->set_a(1); field = item->add_rm(); field->set_c(2); field->add_rc(3); field->add_rc(4); field = item->add_rm(); field->set_c(5); field->add_rc(6); field->add_rc(7); field->add_rc(8); item = msg1.add_item(); item->set_a(9); field = item->add_rm(); field->set_c(10); field->add_rc(11); field->add_rc(12); field = item->add_rm(); field->set_c(13); item = msg2.add_item(); item->set_a(1); field = item->add_rm(); field->set_c(5); field->add_rc(8); field->add_rc(8); field->add_rc(6); field = item->add_rm(); field->set_c(3); field->add_rc(2); field->add_rc(4); item = msg2.add_item(); item->set_a(9); field = item->add_rm(); field->set_c(10); field->add_rc(12); field->add_rc(11); field = item->add_rm(); field->set_c(13); EXPECT_EQ( "matched: item[0].a : 1\n" "matched: item[0].rm[1].c -> item[0].rm[0].c : 5\n" "moved: item[0].rm[1].rc[0] -> item[0].rm[0].rc[2] : 6\n" "moved: item[0].rm[1].rc[2] -> item[0].rm[0].rc[0] : 8\n" "added: item[0].rm[0].rc[1]: 8\n" "deleted: item[0].rm[1].rc[1]: 7\n" "modified: item[0].rm[1] -> item[0].rm[0]: { c: 5 rc: 6 rc: 7 rc: 8 } ->" " { c: 5 rc: 8 rc: 8 rc: 6 }\n" "added: item[0].rm[1]: { c: 3 rc: 2 rc: 4 }\n" "deleted: item[0].rm[0]: { c: 2 rc: 3 rc: 4 }\n" "modified: item[0]: { a: 1 rm { c: 2 rc: 3 rc: 4 }" " rm { c: 5 rc: 6 rc: 7 rc: 8 } } ->" " { a: 1 rm { c: 5 rc: 8 rc: 8 rc: 6 }" " rm { c: 3 rc: 2 rc: 4 } }\n" "matched: item[1].a : 9\n" "matched: item[1].rm[0].c : 10\n" "moved: item[1].rm[0].rc[0] -> item[1].rm[0].rc[1] : 11\n" "moved: item[1].rm[0].rc[1] -> item[1].rm[0].rc[0] : 12\n" "matched: item[1].rm[0] : { c: 10 rc: 11 rc: 12 }\n" "matched: item[1].rm[1].c : 13\n" "matched: item[1].rm[1] : { c: 13 }\n" "matched: item[1] : { a: 9 rm { c: 10 rc: 11 rc: 12 } rm { c: 13 } }\n", RunWithResult(&differencer, msg1, msg2, false)); } TEST_F(MatchingTest, MatchingWorksWithExtensions) { protobuf_unittest::TestAllExtensions msg1, msg2; protobuf_unittest::TestAllTypes::NestedMessage* nested; using protobuf_unittest::repeated_nested_message_extension; const FileDescriptor* descriptor; const FieldDescriptor* desc; const FieldDescriptor* nested_key; descriptor = msg1.GetDescriptor()->file(); desc = descriptor->FindExtensionByName("repeated_nested_message_extension"); ASSERT_FALSE(desc == NULL); nested_key = desc->message_type()->FindFieldByName("bb"); MessageDifferencer differencer; differencer.TreatAsMap(desc, nested_key); nested = msg1.AddExtension(repeated_nested_message_extension); nested->set_bb(7); nested = msg1.AddExtension(repeated_nested_message_extension); nested->set_bb(13); nested = msg1.AddExtension(repeated_nested_message_extension); nested->set_bb(11); nested = msg2.AddExtension(repeated_nested_message_extension); nested->set_bb(11); nested = msg2.AddExtension(repeated_nested_message_extension); nested->set_bb(13); nested = msg2.AddExtension(repeated_nested_message_extension); nested->set_bb(7); EXPECT_EQ( "matched: (protobuf_unittest.repeated_nested_message_extension)[0].bb ->" " (protobuf_unittest.repeated_nested_message_extension)[2].bb : 7\n" "moved: (protobuf_unittest.repeated_nested_message_extension)[0] ->" " (protobuf_unittest.repeated_nested_message_extension)[2] :" " { bb: 7 }\n" "matched: (protobuf_unittest.repeated_nested_message_extension)[1].bb :" " 13\n" "matched: (protobuf_unittest.repeated_nested_message_extension)[1] :" " { bb: 13 }\n" "matched: (protobuf_unittest.repeated_nested_message_extension)[2].bb ->" " (protobuf_unittest.repeated_nested_message_extension)[0].bb :" " 11\n" "moved: (protobuf_unittest.repeated_nested_message_extension)[2] ->" " (protobuf_unittest.repeated_nested_message_extension)[0] :" " { bb: 11 }\n", RunWithResult(&differencer, msg1, msg2, true)); } TEST(AnyTest, Simple) { protobuf_unittest::TestField value1, value2; value1.set_a(20); value2.set_a(21); protobuf_unittest::TestAny m1, m2; m1.mutable_any_value()->PackFrom(value1); m2.mutable_any_value()->PackFrom(value2); util::MessageDifferencer message_differencer; string difference_string; message_differencer.ReportDifferencesToString(&difference_string); EXPECT_FALSE(message_differencer.Compare(m1, m2)); EXPECT_EQ("modified: any_value.a: 20 -> 21\n", difference_string); } TEST(Anytest, TreatAsSet) { protobuf_unittest::TestField value1, value2; value1.set_a(20); value1.set_b(30); value2.set_a(20); value2.set_b(31); protobuf_unittest::TestAny m1, m2; m1.add_repeated_any_value()->PackFrom(value1); m1.add_repeated_any_value()->PackFrom(value2); m2.add_repeated_any_value()->PackFrom(value2); m2.add_repeated_any_value()->PackFrom(value1); util::MessageDifferencer message_differencer; message_differencer.TreatAsSet(GetFieldDescriptor(m1, "repeated_any_value")); EXPECT_TRUE(message_differencer.Compare(m1, m2)); } } // namespace } // namespace protobuf } // namespace google