diff options
author | Feng Xiao <xfxyjwf@gmail.com> | 2015-06-17 13:12:11 -0700 |
---|---|---|
committer | Feng Xiao <xfxyjwf@gmail.com> | 2015-06-17 13:12:11 -0700 |
commit | e9a122eb19ec54dbca15da80355ed0c17cada9b1 (patch) | |
tree | fac37489873ccf47777b2e652db580f9315d7bc7 /src/google/protobuf/util/message_differencer_unittest.cc | |
parent | b36395b2bac88f70070544c325bc09234cb1f1a6 (diff) | |
parent | 818c5eee08840355d70d2f3bdf1a2f17986a5e70 (diff) | |
download | protobuf-e9a122eb19ec54dbca15da80355ed0c17cada9b1.tar.gz protobuf-e9a122eb19ec54dbca15da80355ed0c17cada9b1.tar.bz2 protobuf-e9a122eb19ec54dbca15da80355ed0c17cada9b1.zip |
Merge pull request #501 from xfxyjwf/down
Down-integrate from internal code base.
Diffstat (limited to 'src/google/protobuf/util/message_differencer_unittest.cc')
-rwxr-xr-x | src/google/protobuf/util/message_differencer_unittest.cc | 3132 |
1 files changed, 3132 insertions, 0 deletions
diff --git a/src/google/protobuf/util/message_differencer_unittest.cc b/src/google/protobuf/util/message_differencer_unittest.cc new file mode 100755 index 00000000..bd19f695 --- /dev/null +++ b/src/google/protobuf/util/message_differencer_unittest.cc @@ -0,0 +1,3132 @@ +// 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 <algorithm> +#include <string> +#include <vector> + + +#include <google/protobuf/util/field_comparator.h> +#include <google/protobuf/util/message_differencer.h> +#include <google/protobuf/util/message_differencer_unittest.pb.h> +#include <google/protobuf/text_format.h> +#include <google/protobuf/wire_format.h> +#include <google/protobuf/io/zero_copy_stream_impl.h> +#include <google/protobuf/io/coded_stream.h> +#include <google/protobuf/any_test.pb.h> +#include <google/protobuf/map_unittest.pb.h> +#include <google/protobuf/unittest.pb.h> +#include <google/protobuf/map_test_util.h> +#include <google/protobuf/test_util.h> + +#include <google/protobuf/stubs/common.h> +#include <google/protobuf/stubs/strutil.h> +#include <google/protobuf/testing/googletest.h> +#include <gtest/gtest.h> + +namespace google { +namespace protobuf { + +namespace { + + +const FieldDescriptor* GetFieldDescriptor( + const Message& message, const string& field_name) { + vector<string> 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; + + MapTestUtil::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); + + vector<const FieldDescriptor*> fields1; + vector<const FieldDescriptor*> 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); + + vector<const FieldDescriptor*> fields1; + vector<const FieldDescriptor*> 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); + + vector<const FieldDescriptor*> 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); + + vector<const FieldDescriptor*> fields; + msg1.GetReflection()->ListFields(msg1, &fields); + + util::MessageDifferencer differencer; + EXPECT_TRUE(differencer.CompareWithFields(msg1, msg1, fields, fields)); + + { + // Compare with a subset of fields. + vector<const FieldDescriptor*> 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. + vector<const FieldDescriptor*> compare_fields1; + vector<const FieldDescriptor*> 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); + + vector<const FieldDescriptor*> fields1; + vector<const FieldDescriptor*> 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); + + vector<const FieldDescriptor*> fields1; + msg1.GetReflection()->ListFields(msg1, &fields1); + + vector<const FieldDescriptor*> 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); + + vector<const FieldDescriptor*> fields1; + const Reflection* reflection = msg1.GetReflection(); + reflection->ListFields(msg1, &fields1); + + vector<const FieldDescriptor*> 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); + + vector<const FieldDescriptor*> fields1; + msg1.GetReflection()->ListFields(msg1, &fields1); + + vector<const FieldDescriptor*> 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); + + vector<const FieldDescriptor*> fields1; + vector<const FieldDescriptor*> 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); + + vector<const FieldDescriptor*> fields1; + vector<const FieldDescriptor*> 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 differencer; + differencer.TreatAsMap(msg1.GetDescriptor()->FindFieldByName("item"), + item->GetDescriptor()->FindFieldByName("a")); + differencer.TreatAsSet(msg1.GetDescriptor()->FindFieldByName("rv")); + differencer.TreatAsSet(item->GetDescriptor()->FindFieldByName("ra")); + EXPECT_TRUE(differencer.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)); +} + +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)); + vector<const FieldDescriptor*> 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)); + vector<vector<const FieldDescriptor*> > key_field_paths; + vector<const FieldDescriptor*> key_field_path1; + key_field_path1.push_back(GetFieldDescriptor(msg1, "item.m")); + key_field_path1.push_back(GetFieldDescriptor(msg1, "item.m.a")); + vector<const FieldDescriptor*> 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; + vector<const FieldDescriptor*> 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: + bool IsIgnored( + const Message& message1, const Message& message2, + const FieldDescriptor* field, + const vector<util::MessageDifferencer::SpecificField>& parent_fields) + override { + 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: + virtual bool IsMatch(const Message &message1, + const Message &message2) 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"); + + vector<const FieldDescriptor*> 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; + } + } + + vector<google::protobuf::util::MessageDifferencer::SpecificField> parent_fields() { + return parent_fields_; + } + + private: + vector<google::protobuf::util::MessageDifferencer::SpecificField> 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 doens'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; + 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 |