1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc. All rights reserved.
3 // https://developers.google.com/protocol-buffers/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 // * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 // * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 // * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31 // Author: jschorr@google.com (Joseph Schorr)
32 // Based on original Protocol Buffers design by
33 // Sanjay Ghemawat, Jeff Dean, and others.
34
35 #include <google/protobuf/util/message_differencer.h>
36
37 #include <algorithm>
38 #include <functional>
39 #include <memory>
40 #include <utility>
41
42 #include <google/protobuf/stubs/logging.h>
43 #include <google/protobuf/stubs/common.h>
44 #include <google/protobuf/stubs/stringprintf.h>
45 #include <google/protobuf/io/printer.h>
46 #include <google/protobuf/io/zero_copy_stream.h>
47 #include <google/protobuf/io/zero_copy_stream_impl.h>
48 #include <google/protobuf/descriptor.pb.h>
49 #include <google/protobuf/dynamic_message.h>
50 #include <google/protobuf/text_format.h>
51 #include <google/protobuf/util/field_comparator.h>
52 #include <google/protobuf/stubs/strutil.h>
53
54 // Always include as last one, otherwise it can break compilation
55 #include <google/protobuf/port_def.inc>
56
57 namespace google {
58 namespace protobuf {
59
60 namespace util {
61
62 // A reporter to report the total number of diffs.
63 // TODO(ykzhu): we can improve this to take into account the value differencers.
64 class NumDiffsReporter : public google::protobuf::util::MessageDifferencer::Reporter {
65 public:
NumDiffsReporter()66 NumDiffsReporter() : num_diffs_(0) {}
67
68 // Returns the total number of diffs.
GetNumDiffs() const69 int32 GetNumDiffs() const { return num_diffs_; }
Reset()70 void Reset() { num_diffs_ = 0; }
71
72 // Report that a field has been added into Message2.
ReportAdded(const google::protobuf::Message & message1,const google::protobuf::Message & message2,const std::vector<google::protobuf::util::MessageDifferencer::SpecificField> & field_path)73 void ReportAdded(
74 const google::protobuf::Message& message1, const google::protobuf::Message& message2,
75 const std::vector<google::protobuf::util::MessageDifferencer::SpecificField>&
76 field_path) override {
77 ++num_diffs_;
78 }
79
80 // Report that a field has been deleted from Message1.
ReportDeleted(const google::protobuf::Message & message1,const google::protobuf::Message & message2,const std::vector<google::protobuf::util::MessageDifferencer::SpecificField> & field_path)81 void ReportDeleted(
82 const google::protobuf::Message& message1, const google::protobuf::Message& message2,
83 const std::vector<google::protobuf::util::MessageDifferencer::SpecificField>&
84 field_path) override {
85 ++num_diffs_;
86 }
87
88 // Report that the value of a field has been modified.
ReportModified(const google::protobuf::Message & message1,const google::protobuf::Message & message2,const std::vector<google::protobuf::util::MessageDifferencer::SpecificField> & field_path)89 void ReportModified(
90 const google::protobuf::Message& message1, const google::protobuf::Message& message2,
91 const std::vector<google::protobuf::util::MessageDifferencer::SpecificField>&
92 field_path) override {
93 ++num_diffs_;
94 }
95
96 private:
97 int32 num_diffs_;
98 };
99
100 // When comparing a repeated field as map, MultipleFieldMapKeyComparator can
101 // be used to specify multiple fields as key for key comparison.
102 // Two elements of a repeated field will be regarded as having the same key
103 // iff they have the same value for every specified key field.
104 // Note that you can also specify only one field as key.
105 class MessageDifferencer::MultipleFieldsMapKeyComparator
106 : public MessageDifferencer::MapKeyComparator {
107 public:
MultipleFieldsMapKeyComparator(MessageDifferencer * message_differencer,const std::vector<std::vector<const FieldDescriptor * >> & key_field_paths)108 MultipleFieldsMapKeyComparator(
109 MessageDifferencer* message_differencer,
110 const std::vector<std::vector<const FieldDescriptor*> >& key_field_paths)
111 : message_differencer_(message_differencer),
112 key_field_paths_(key_field_paths) {
113 GOOGLE_CHECK(!key_field_paths_.empty());
114 for (int i = 0; i < key_field_paths_.size(); ++i) {
115 GOOGLE_CHECK(!key_field_paths_[i].empty());
116 }
117 }
MultipleFieldsMapKeyComparator(MessageDifferencer * message_differencer,const FieldDescriptor * key)118 MultipleFieldsMapKeyComparator(MessageDifferencer* message_differencer,
119 const FieldDescriptor* key)
120 : message_differencer_(message_differencer) {
121 std::vector<const FieldDescriptor*> key_field_path;
122 key_field_path.push_back(key);
123 key_field_paths_.push_back(key_field_path);
124 }
IsMatch(const Message & message1,const Message & message2,const std::vector<SpecificField> & parent_fields) const125 bool IsMatch(const Message& message1, const Message& message2,
126 const std::vector<SpecificField>& parent_fields) const override {
127 for (int i = 0; i < key_field_paths_.size(); ++i) {
128 if (!IsMatchInternal(message1, message2, parent_fields,
129 key_field_paths_[i], 0)) {
130 return false;
131 }
132 }
133 return true;
134 }
135
136 private:
IsMatchInternal(const Message & message1,const Message & message2,const std::vector<SpecificField> & parent_fields,const std::vector<const FieldDescriptor * > & key_field_path,int path_index) const137 bool IsMatchInternal(
138 const Message& message1, const Message& message2,
139 const std::vector<SpecificField>& parent_fields,
140 const std::vector<const FieldDescriptor*>& key_field_path,
141 int path_index) const {
142 const FieldDescriptor* field = key_field_path[path_index];
143 std::vector<SpecificField> current_parent_fields(parent_fields);
144 if (path_index == key_field_path.size() - 1) {
145 if (field->is_repeated()) {
146 if (!message_differencer_->CompareRepeatedField(
147 message1, message2, field, ¤t_parent_fields)) {
148 return false;
149 }
150 } else {
151 if (!message_differencer_->CompareFieldValueUsingParentFields(
152 message1, message2, field, -1, -1, ¤t_parent_fields)) {
153 return false;
154 }
155 }
156 return true;
157 } else {
158 const Reflection* reflection1 = message1.GetReflection();
159 const Reflection* reflection2 = message2.GetReflection();
160 bool has_field1 = reflection1->HasField(message1, field);
161 bool has_field2 = reflection2->HasField(message2, field);
162 if (!has_field1 && !has_field2) {
163 return true;
164 }
165 if (has_field1 != has_field2) {
166 return false;
167 }
168 SpecificField specific_field;
169 specific_field.field = field;
170 current_parent_fields.push_back(specific_field);
171 return IsMatchInternal(reflection1->GetMessage(message1, field),
172 reflection2->GetMessage(message2, field),
173 current_parent_fields, key_field_path,
174 path_index + 1);
175 }
176 }
177 MessageDifferencer* message_differencer_;
178 std::vector<std::vector<const FieldDescriptor*> > key_field_paths_;
179 GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MultipleFieldsMapKeyComparator);
180 };
181
182 // Preserve the order when treating repeated field as SMART_LIST. The current
183 // implementation is to find the longest matching sequence from the first
184 // element. The optimal solution requires to use //util/diff/lcs.h, which is
185 // not open sourced yet. Overwrite this method if you want to have that.
186 // TODO(ykzhu): change to use LCS once it is open sourced.
MatchIndicesPostProcessorForSmartList(std::vector<int> * match_list1,std::vector<int> * match_list2)187 void MatchIndicesPostProcessorForSmartList(
188 std::vector<int>* match_list1, std::vector<int>* match_list2) {
189 int last_matched_index = -1;
190 for (int i = 0; i < match_list1->size(); ++i) {
191 if (match_list1->at(i) < 0) {
192 continue;
193 }
194 if (last_matched_index < 0 || match_list1->at(i) > last_matched_index) {
195 last_matched_index = match_list1->at(i);
196 } else {
197 match_list2->at(match_list1->at(i)) = -1;
198 match_list1->at(i) = -1;
199 }
200 }
201 }
202
MapEntryKeyComparator(MessageDifferencer * message_differencer)203 MessageDifferencer::MapEntryKeyComparator::MapEntryKeyComparator(
204 MessageDifferencer* message_differencer)
205 : message_differencer_(message_differencer) {}
206
IsMatch(const Message & message1,const Message & message2,const std::vector<SpecificField> & parent_fields) const207 bool MessageDifferencer::MapEntryKeyComparator::IsMatch(
208 const Message& message1, const Message& message2,
209 const std::vector<SpecificField>& parent_fields) const {
210 // Map entry has its key in the field with tag 1. See the comment for
211 // map_entry in MessageOptions.
212 const FieldDescriptor* key = message1.GetDescriptor()->FindFieldByNumber(1);
213 // If key is not present in message1 and we're doing partial comparison or if
214 // map key is explicitly ignored treat the field as set instead,
215 const bool treat_as_set =
216 (message_differencer_->scope() == PARTIAL &&
217 !message1.GetReflection()->HasField(message1, key)) ||
218 message_differencer_->IsIgnored(message1, message2, key, parent_fields);
219
220 std::vector<SpecificField> current_parent_fields(parent_fields);
221 if (treat_as_set) {
222 return message_differencer_->Compare(message1, message2,
223 ¤t_parent_fields);
224 }
225 return message_differencer_->CompareFieldValueUsingParentFields(
226 message1, message2, key, -1, -1, ¤t_parent_fields);
227 }
228
Equals(const Message & message1,const Message & message2)229 bool MessageDifferencer::Equals(const Message& message1,
230 const Message& message2) {
231 MessageDifferencer differencer;
232
233 return differencer.Compare(message1, message2);
234 }
235
Equivalent(const Message & message1,const Message & message2)236 bool MessageDifferencer::Equivalent(const Message& message1,
237 const Message& message2) {
238 MessageDifferencer differencer;
239 differencer.set_message_field_comparison(MessageDifferencer::EQUIVALENT);
240
241 return differencer.Compare(message1, message2);
242 }
243
ApproximatelyEquals(const Message & message1,const Message & message2)244 bool MessageDifferencer::ApproximatelyEquals(const Message& message1,
245 const Message& message2) {
246 MessageDifferencer differencer;
247 differencer.set_float_comparison(MessageDifferencer::APPROXIMATE);
248
249 return differencer.Compare(message1, message2);
250 }
251
ApproximatelyEquivalent(const Message & message1,const Message & message2)252 bool MessageDifferencer::ApproximatelyEquivalent(const Message& message1,
253 const Message& message2) {
254 MessageDifferencer differencer;
255 differencer.set_message_field_comparison(MessageDifferencer::EQUIVALENT);
256 differencer.set_float_comparison(MessageDifferencer::APPROXIMATE);
257
258 return differencer.Compare(message1, message2);
259 }
260
261 // ===========================================================================
262
MessageDifferencer()263 MessageDifferencer::MessageDifferencer()
264 : reporter_(NULL),
265 field_comparator_(NULL),
266 message_field_comparison_(EQUAL),
267 scope_(FULL),
268 repeated_field_comparison_(AS_LIST),
269 map_entry_key_comparator_(this),
270 report_matches_(false),
271 report_moves_(true),
272 report_ignores_(true),
273 output_string_(nullptr),
274 match_indices_for_smart_list_callback_(
275 MatchIndicesPostProcessorForSmartList) {}
276
~MessageDifferencer()277 MessageDifferencer::~MessageDifferencer() {
278 for (int i = 0; i < owned_key_comparators_.size(); ++i) {
279 delete owned_key_comparators_[i];
280 }
281 for (int i = 0; i < ignore_criteria_.size(); ++i) {
282 delete ignore_criteria_[i];
283 }
284 }
285
set_field_comparator(FieldComparator * comparator)286 void MessageDifferencer::set_field_comparator(FieldComparator* comparator) {
287 GOOGLE_CHECK(comparator) << "Field comparator can't be NULL.";
288 field_comparator_ = comparator;
289 }
290
set_message_field_comparison(MessageFieldComparison comparison)291 void MessageDifferencer::set_message_field_comparison(
292 MessageFieldComparison comparison) {
293 message_field_comparison_ = comparison;
294 }
295
set_scope(Scope scope)296 void MessageDifferencer::set_scope(Scope scope) { scope_ = scope; }
297
scope()298 MessageDifferencer::Scope MessageDifferencer::scope() { return scope_; }
299
set_float_comparison(FloatComparison comparison)300 void MessageDifferencer::set_float_comparison(FloatComparison comparison) {
301 default_field_comparator_.set_float_comparison(
302 comparison == EXACT ? DefaultFieldComparator::EXACT
303 : DefaultFieldComparator::APPROXIMATE);
304 }
305
set_repeated_field_comparison(RepeatedFieldComparison comparison)306 void MessageDifferencer::set_repeated_field_comparison(
307 RepeatedFieldComparison comparison) {
308 repeated_field_comparison_ = comparison;
309 }
310
311 MessageDifferencer::RepeatedFieldComparison
repeated_field_comparison()312 MessageDifferencer::repeated_field_comparison() {
313 return repeated_field_comparison_;
314 }
315
CheckRepeatedFieldComparisons(const FieldDescriptor * field,const RepeatedFieldComparison & new_comparison)316 void MessageDifferencer::CheckRepeatedFieldComparisons(
317 const FieldDescriptor* field,
318 const RepeatedFieldComparison& new_comparison) {
319 GOOGLE_CHECK(field->is_repeated())
320 << "Field must be repeated: " << field->full_name();
321 const MapKeyComparator* key_comparator = GetMapKeyComparator(field);
322 GOOGLE_CHECK(key_comparator == NULL)
323 << "Cannot treat this repeated field as both MAP and " << new_comparison
324 << " for"
325 << " comparison. Field name is: " << field->full_name();
326 GOOGLE_CHECK(repeated_field_comparisons_.find(field) ==
327 repeated_field_comparisons_.end() ||
328 repeated_field_comparisons_[field] == new_comparison)
329 << "Cannot treat the same field as both "
330 << repeated_field_comparisons_[field] << " and " << new_comparison
331 << ". Field name is: " << field->full_name();
332 }
333
TreatAsSet(const FieldDescriptor * field)334 void MessageDifferencer::TreatAsSet(const FieldDescriptor* field) {
335 CheckRepeatedFieldComparisons(field, AS_SET);
336 repeated_field_comparisons_[field] = AS_SET;
337 }
338
TreatAsSmartSet(const FieldDescriptor * field)339 void MessageDifferencer::TreatAsSmartSet(const FieldDescriptor* field) {
340 CheckRepeatedFieldComparisons(field, AS_SMART_SET);
341 repeated_field_comparisons_[field] = AS_SMART_SET;
342 }
343
SetMatchIndicesForSmartListCallback(std::function<void (std::vector<int> *,std::vector<int> *)> callback)344 void MessageDifferencer::SetMatchIndicesForSmartListCallback(
345 std::function<void(std::vector<int>*, std::vector<int>*)> callback) {
346 match_indices_for_smart_list_callback_ = callback;
347 }
348
TreatAsList(const FieldDescriptor * field)349 void MessageDifferencer::TreatAsList(const FieldDescriptor* field) {
350 CheckRepeatedFieldComparisons(field, AS_LIST);
351 repeated_field_comparisons_[field] = AS_LIST;
352 }
353
TreatAsSmartList(const FieldDescriptor * field)354 void MessageDifferencer::TreatAsSmartList(const FieldDescriptor* field) {
355 CheckRepeatedFieldComparisons(field, AS_SMART_LIST);
356 repeated_field_comparisons_[field] = AS_SMART_LIST;
357 }
358
TreatAsMap(const FieldDescriptor * field,const FieldDescriptor * key)359 void MessageDifferencer::TreatAsMap(const FieldDescriptor* field,
360 const FieldDescriptor* key) {
361 GOOGLE_CHECK_EQ(FieldDescriptor::CPPTYPE_MESSAGE, field->cpp_type())
362 << "Field has to be message type. Field name is: " << field->full_name();
363 GOOGLE_CHECK(key->containing_type() == field->message_type())
364 << key->full_name()
365 << " must be a direct subfield within the repeated field "
366 << field->full_name() << ", not " << key->containing_type()->full_name();
367 GOOGLE_CHECK(repeated_field_comparisons_.find(field) ==
368 repeated_field_comparisons_.end())
369 << "Cannot treat the same field as both "
370 << repeated_field_comparisons_[field]
371 << " and MAP. Field name is: " << field->full_name();
372 MapKeyComparator* key_comparator =
373 new MultipleFieldsMapKeyComparator(this, key);
374 owned_key_comparators_.push_back(key_comparator);
375 map_field_key_comparator_[field] = key_comparator;
376 }
377
TreatAsMapWithMultipleFieldsAsKey(const FieldDescriptor * field,const std::vector<const FieldDescriptor * > & key_fields)378 void MessageDifferencer::TreatAsMapWithMultipleFieldsAsKey(
379 const FieldDescriptor* field,
380 const std::vector<const FieldDescriptor*>& key_fields) {
381 std::vector<std::vector<const FieldDescriptor*> > key_field_paths;
382 for (int i = 0; i < key_fields.size(); ++i) {
383 std::vector<const FieldDescriptor*> key_field_path;
384 key_field_path.push_back(key_fields[i]);
385 key_field_paths.push_back(key_field_path);
386 }
387 TreatAsMapWithMultipleFieldPathsAsKey(field, key_field_paths);
388 }
389
TreatAsMapWithMultipleFieldPathsAsKey(const FieldDescriptor * field,const std::vector<std::vector<const FieldDescriptor * >> & key_field_paths)390 void MessageDifferencer::TreatAsMapWithMultipleFieldPathsAsKey(
391 const FieldDescriptor* field,
392 const std::vector<std::vector<const FieldDescriptor*> >& key_field_paths) {
393 GOOGLE_CHECK(field->is_repeated())
394 << "Field must be repeated: " << field->full_name();
395 GOOGLE_CHECK_EQ(FieldDescriptor::CPPTYPE_MESSAGE, field->cpp_type())
396 << "Field has to be message type. Field name is: " << field->full_name();
397 for (int i = 0; i < key_field_paths.size(); ++i) {
398 const std::vector<const FieldDescriptor*>& key_field_path =
399 key_field_paths[i];
400 for (int j = 0; j < key_field_path.size(); ++j) {
401 const FieldDescriptor* parent_field =
402 j == 0 ? field : key_field_path[j - 1];
403 const FieldDescriptor* child_field = key_field_path[j];
404 GOOGLE_CHECK(child_field->containing_type() == parent_field->message_type())
405 << child_field->full_name()
406 << " must be a direct subfield within the field: "
407 << parent_field->full_name();
408 if (j != 0) {
409 GOOGLE_CHECK_EQ(FieldDescriptor::CPPTYPE_MESSAGE, parent_field->cpp_type())
410 << parent_field->full_name() << " has to be of type message.";
411 GOOGLE_CHECK(!parent_field->is_repeated())
412 << parent_field->full_name() << " cannot be a repeated field.";
413 }
414 }
415 }
416 GOOGLE_CHECK(repeated_field_comparisons_.find(field) ==
417 repeated_field_comparisons_.end())
418 << "Cannot treat the same field as both "
419 << repeated_field_comparisons_[field]
420 << " and MAP. Field name is: " << field->full_name();
421 MapKeyComparator* key_comparator =
422 new MultipleFieldsMapKeyComparator(this, key_field_paths);
423 owned_key_comparators_.push_back(key_comparator);
424 map_field_key_comparator_[field] = key_comparator;
425 }
426
TreatAsMapUsingKeyComparator(const FieldDescriptor * field,const MapKeyComparator * key_comparator)427 void MessageDifferencer::TreatAsMapUsingKeyComparator(
428 const FieldDescriptor* field, const MapKeyComparator* key_comparator) {
429 GOOGLE_CHECK(field->is_repeated())
430 << "Field must be repeated: " << field->full_name();
431 GOOGLE_CHECK(repeated_field_comparisons_.find(field) ==
432 repeated_field_comparisons_.end())
433 << "Cannot treat the same field as both "
434 << repeated_field_comparisons_[field]
435 << " and MAP. Field name is: " << field->full_name();
436 map_field_key_comparator_[field] = key_comparator;
437 }
438
AddIgnoreCriteria(IgnoreCriteria * ignore_criteria)439 void MessageDifferencer::AddIgnoreCriteria(IgnoreCriteria* ignore_criteria) {
440 ignore_criteria_.push_back(ignore_criteria);
441 }
442
IgnoreField(const FieldDescriptor * field)443 void MessageDifferencer::IgnoreField(const FieldDescriptor* field) {
444 ignored_fields_.insert(field);
445 }
446
SetFractionAndMargin(const FieldDescriptor * field,double fraction,double margin)447 void MessageDifferencer::SetFractionAndMargin(const FieldDescriptor* field,
448 double fraction, double margin) {
449 default_field_comparator_.SetFractionAndMargin(field, fraction, margin);
450 }
451
ReportDifferencesToString(std::string * output)452 void MessageDifferencer::ReportDifferencesToString(std::string* output) {
453 GOOGLE_DCHECK(output) << "Specified output string was NULL";
454
455 output_string_ = output;
456 output_string_->clear();
457 }
458
ReportDifferencesTo(Reporter * reporter)459 void MessageDifferencer::ReportDifferencesTo(Reporter* reporter) {
460 // If an output string is set, clear it to prevent
461 // it superseding the specified reporter.
462 if (output_string_) {
463 output_string_ = NULL;
464 }
465
466 reporter_ = reporter;
467 }
468
FieldBefore(const FieldDescriptor * field1,const FieldDescriptor * field2)469 bool MessageDifferencer::FieldBefore(const FieldDescriptor* field1,
470 const FieldDescriptor* field2) {
471 // Handle sentinel values (i.e. make sure NULLs are always ordered
472 // at the end of the list).
473 if (field1 == NULL) {
474 return false;
475 }
476
477 if (field2 == NULL) {
478 return true;
479 }
480
481 // Always order fields by their tag number
482 return (field1->number() < field2->number());
483 }
484
Compare(const Message & message1,const Message & message2)485 bool MessageDifferencer::Compare(const Message& message1,
486 const Message& message2) {
487 std::vector<SpecificField> parent_fields;
488
489 bool result = false;
490
491 // Setup the internal reporter if need be.
492 if (output_string_) {
493 io::StringOutputStream output_stream(output_string_);
494 StreamReporter reporter(&output_stream);
495 reporter_ = &reporter;
496 result = Compare(message1, message2, &parent_fields);
497 reporter_ = NULL;
498 } else {
499 result = Compare(message1, message2, &parent_fields);
500 }
501
502 return result;
503 }
504
CompareWithFields(const Message & message1,const Message & message2,const std::vector<const FieldDescriptor * > & message1_fields_arg,const std::vector<const FieldDescriptor * > & message2_fields_arg)505 bool MessageDifferencer::CompareWithFields(
506 const Message& message1, const Message& message2,
507 const std::vector<const FieldDescriptor*>& message1_fields_arg,
508 const std::vector<const FieldDescriptor*>& message2_fields_arg) {
509 if (message1.GetDescriptor() != message2.GetDescriptor()) {
510 GOOGLE_LOG(DFATAL) << "Comparison between two messages with different "
511 << "descriptors.";
512 return false;
513 }
514
515 std::vector<SpecificField> parent_fields;
516
517 bool result = false;
518
519 FieldDescriptorArray message1_fields(message1_fields_arg.size() + 1);
520 FieldDescriptorArray message2_fields(message2_fields_arg.size() + 1);
521
522 std::copy(message1_fields_arg.cbegin(), message1_fields_arg.cend(),
523 message1_fields.begin());
524 std::copy(message2_fields_arg.cbegin(), message2_fields_arg.cend(),
525 message2_fields.begin());
526
527 // Append sentinel values.
528 message1_fields[message1_fields_arg.size()] = nullptr;
529 message2_fields[message2_fields_arg.size()] = nullptr;
530
531 std::sort(message1_fields.begin(), message1_fields.end(), FieldBefore);
532 std::sort(message2_fields.begin(), message2_fields.end(), FieldBefore);
533
534 // Setup the internal reporter if need be.
535 if (output_string_) {
536 io::StringOutputStream output_stream(output_string_);
537 StreamReporter reporter(&output_stream);
538 reporter_ = &reporter;
539 result = CompareRequestedFieldsUsingSettings(
540 message1, message2, message1_fields, message2_fields, &parent_fields);
541 reporter_ = NULL;
542 } else {
543 result = CompareRequestedFieldsUsingSettings(
544 message1, message2, message1_fields, message2_fields, &parent_fields);
545 }
546
547 return result;
548 }
549
Compare(const Message & message1,const Message & message2,std::vector<SpecificField> * parent_fields)550 bool MessageDifferencer::Compare(const Message& message1,
551 const Message& message2,
552 std::vector<SpecificField>* parent_fields) {
553 const Descriptor* descriptor1 = message1.GetDescriptor();
554 const Descriptor* descriptor2 = message2.GetDescriptor();
555 if (descriptor1 != descriptor2) {
556 GOOGLE_LOG(DFATAL) << "Comparison between two messages with different "
557 << "descriptors. " << descriptor1->full_name() << " vs "
558 << descriptor2->full_name();
559 return false;
560 }
561 // Expand google.protobuf.Any payload if possible.
562 if (descriptor1->full_name() == internal::kAnyFullTypeName) {
563 std::unique_ptr<Message> data1;
564 std::unique_ptr<Message> data2;
565 if (UnpackAny(message1, &data1) && UnpackAny(message2, &data2)) {
566 // Avoid DFATAL for different descriptors in google.protobuf.Any payloads.
567 if (data1->GetDescriptor() != data2->GetDescriptor()) {
568 return false;
569 }
570 return Compare(*data1, *data2, parent_fields);
571 }
572 }
573 const Reflection* reflection1 = message1.GetReflection();
574 const Reflection* reflection2 = message2.GetReflection();
575
576 bool unknown_compare_result = true;
577 // Ignore unknown fields in EQUIVALENT mode
578 if (message_field_comparison_ != EQUIVALENT) {
579 const UnknownFieldSet& unknown_field_set1 =
580 reflection1->GetUnknownFields(message1);
581 const UnknownFieldSet& unknown_field_set2 =
582 reflection2->GetUnknownFields(message2);
583 if (!CompareUnknownFields(message1, message2, unknown_field_set1,
584 unknown_field_set2, parent_fields)) {
585 if (reporter_ == NULL) {
586 return false;
587 }
588 unknown_compare_result = false;
589 }
590 }
591
592 FieldDescriptorArray message1_fields = RetrieveFields(message1, true);
593 FieldDescriptorArray message2_fields = RetrieveFields(message2, false);
594
595 return CompareRequestedFieldsUsingSettings(
596 message1, message2,
597 message1_fields, message2_fields,
598 parent_fields) && unknown_compare_result;
599 }
600
RetrieveFields(const Message & message,bool base_message)601 FieldDescriptorArray MessageDifferencer::RetrieveFields(const Message& message,
602 bool base_message) {
603 const Descriptor* descriptor = message.GetDescriptor();
604
605 tmp_message_fields_.clear();
606 tmp_message_fields_.reserve(descriptor->field_count() + 1);
607
608 const Reflection* reflection = message.GetReflection();
609 if (descriptor->options().map_entry()) {
610 if (this->scope_ == PARTIAL && base_message) {
611 reflection->ListFields(message, &tmp_message_fields_);
612 } else {
613 // Map entry fields are always considered present.
614 for (int i = 0; i < descriptor->field_count(); i++) {
615 tmp_message_fields_.push_back(descriptor->field(i));
616 }
617 }
618 } else {
619 reflection->ListFields(message, &tmp_message_fields_);
620 }
621 // Add sentinel values to deal with the
622 // case where the number of the fields in
623 // each list are different.
624 tmp_message_fields_.push_back(nullptr);
625
626 FieldDescriptorArray message_fields(tmp_message_fields_.begin(),
627 tmp_message_fields_.end());
628
629 return message_fields;
630 }
631
CompareRequestedFieldsUsingSettings(const Message & message1,const Message & message2,const FieldDescriptorArray & message1_fields,const FieldDescriptorArray & message2_fields,std::vector<SpecificField> * parent_fields)632 bool MessageDifferencer::CompareRequestedFieldsUsingSettings(
633 const Message& message1, const Message& message2,
634 const FieldDescriptorArray& message1_fields,
635 const FieldDescriptorArray& message2_fields,
636 std::vector<SpecificField>* parent_fields) {
637 if (scope_ == FULL) {
638 if (message_field_comparison_ == EQUIVALENT) {
639 // We need to merge the field lists of both messages (i.e.
640 // we are merely checking for a difference in field values,
641 // rather than the addition or deletion of fields).
642 FieldDescriptorArray fields_union =
643 CombineFields(message1_fields, FULL, message2_fields, FULL);
644 return CompareWithFieldsInternal(message1, message2, fields_union,
645 fields_union, parent_fields);
646 } else {
647 // Simple equality comparison, use the unaltered field lists.
648 return CompareWithFieldsInternal(message1, message2, message1_fields,
649 message2_fields, parent_fields);
650 }
651 } else {
652 if (message_field_comparison_ == EQUIVALENT) {
653 // We use the list of fields for message1 for both messages when
654 // comparing. This way, extra fields in message2 are ignored,
655 // and missing fields in message2 use their default value.
656 return CompareWithFieldsInternal(message1, message2, message1_fields,
657 message1_fields, parent_fields);
658 } else {
659 // We need to consider the full list of fields for message1
660 // but only the intersection for message2. This way, any fields
661 // only present in message2 will be ignored, but any fields only
662 // present in message1 will be marked as a difference.
663 FieldDescriptorArray fields_intersection =
664 CombineFields(message1_fields, PARTIAL, message2_fields, PARTIAL);
665 return CompareWithFieldsInternal(message1, message2, message1_fields,
666 fields_intersection, parent_fields);
667 }
668 }
669 }
670
CombineFields(const FieldDescriptorArray & fields1,Scope fields1_scope,const FieldDescriptorArray & fields2,Scope fields2_scope)671 FieldDescriptorArray MessageDifferencer::CombineFields(
672 const FieldDescriptorArray& fields1, Scope fields1_scope,
673 const FieldDescriptorArray& fields2, Scope fields2_scope) {
674 int index1 = 0;
675 int index2 = 0;
676
677 tmp_message_fields_.clear();
678
679 while (index1 < fields1.size() && index2 < fields2.size()) {
680 const FieldDescriptor* field1 = fields1[index1];
681 const FieldDescriptor* field2 = fields2[index2];
682
683 if (FieldBefore(field1, field2)) {
684 if (fields1_scope == FULL) {
685 tmp_message_fields_.push_back(fields1[index1]);
686 }
687 ++index1;
688 } else if (FieldBefore(field2, field1)) {
689 if (fields2_scope == FULL) {
690 tmp_message_fields_.push_back(fields2[index2]);
691 }
692 ++index2;
693 } else {
694 tmp_message_fields_.push_back(fields1[index1]);
695 ++index1;
696 ++index2;
697 }
698 }
699
700 tmp_message_fields_.push_back(nullptr);
701
702 FieldDescriptorArray combined_fields(tmp_message_fields_.begin(),
703 tmp_message_fields_.end());
704
705 return combined_fields;
706 }
707
CompareWithFieldsInternal(const Message & message1,const Message & message2,const FieldDescriptorArray & message1_fields,const FieldDescriptorArray & message2_fields,std::vector<SpecificField> * parent_fields)708 bool MessageDifferencer::CompareWithFieldsInternal(
709 const Message& message1, const Message& message2,
710 const FieldDescriptorArray& message1_fields,
711 const FieldDescriptorArray& message2_fields,
712 std::vector<SpecificField>* parent_fields) {
713 bool isDifferent = false;
714 int field_index1 = 0;
715 int field_index2 = 0;
716
717 const Reflection* reflection1 = message1.GetReflection();
718 const Reflection* reflection2 = message2.GetReflection();
719
720 while (true) {
721 const FieldDescriptor* field1 = message1_fields[field_index1];
722 const FieldDescriptor* field2 = message2_fields[field_index2];
723
724 // Once we have reached sentinel values, we are done the comparison.
725 if (field1 == NULL && field2 == NULL) {
726 break;
727 }
728
729 // Check for differences in the field itself.
730 if (FieldBefore(field1, field2)) {
731 // Field 1 is not in the field list for message 2.
732 if (IsIgnored(message1, message2, field1, *parent_fields)) {
733 // We are ignoring field1. Report the ignore and move on to
734 // the next field in message1_fields.
735 if (reporter_ != NULL) {
736 SpecificField specific_field;
737 specific_field.field = field1;
738
739 parent_fields->push_back(specific_field);
740 if (report_ignores_) {
741 reporter_->ReportIgnored(message1, message2, *parent_fields);
742 }
743 parent_fields->pop_back();
744 }
745 ++field_index1;
746 continue;
747 }
748
749 if (reporter_ != NULL) {
750 assert(field1 != NULL);
751 int count = field1->is_repeated()
752 ? reflection1->FieldSize(message1, field1)
753 : 1;
754
755 for (int i = 0; i < count; ++i) {
756 SpecificField specific_field;
757 specific_field.field = field1;
758 specific_field.index = field1->is_repeated() ? i : -1;
759
760 parent_fields->push_back(specific_field);
761 reporter_->ReportDeleted(message1, message2, *parent_fields);
762 parent_fields->pop_back();
763 }
764
765 isDifferent = true;
766 } else {
767 return false;
768 }
769
770 ++field_index1;
771 continue;
772 } else if (FieldBefore(field2, field1)) {
773 // Field 2 is not in the field list for message 1.
774 if (IsIgnored(message1, message2, field2, *parent_fields)) {
775 // We are ignoring field2. Report the ignore and move on to
776 // the next field in message2_fields.
777 if (reporter_ != NULL) {
778 SpecificField specific_field;
779 specific_field.field = field2;
780
781 parent_fields->push_back(specific_field);
782 if (report_ignores_) {
783 reporter_->ReportIgnored(message1, message2, *parent_fields);
784 }
785 parent_fields->pop_back();
786 }
787 ++field_index2;
788 continue;
789 }
790
791 if (reporter_ != NULL) {
792 int count = field2->is_repeated()
793 ? reflection2->FieldSize(message2, field2)
794 : 1;
795
796 for (int i = 0; i < count; ++i) {
797 SpecificField specific_field;
798 specific_field.field = field2;
799 specific_field.index = field2->is_repeated() ? i : -1;
800 specific_field.new_index = specific_field.index;
801
802 parent_fields->push_back(specific_field);
803 reporter_->ReportAdded(message1, message2, *parent_fields);
804 parent_fields->pop_back();
805 }
806
807 isDifferent = true;
808 } else {
809 return false;
810 }
811
812 ++field_index2;
813 continue;
814 }
815
816 // By this point, field1 and field2 are guaranteed to point to the same
817 // field, so we can now compare the values.
818 if (IsIgnored(message1, message2, field1, *parent_fields)) {
819 // Ignore this field. Report and move on.
820 if (reporter_ != NULL) {
821 SpecificField specific_field;
822 specific_field.field = field1;
823
824 parent_fields->push_back(specific_field);
825 if (report_ignores_) {
826 reporter_->ReportIgnored(message1, message2, *parent_fields);
827 }
828 parent_fields->pop_back();
829 }
830
831 ++field_index1;
832 ++field_index2;
833 continue;
834 }
835
836 bool fieldDifferent = false;
837 assert(field1 != NULL);
838 if (field1->is_repeated()) {
839 fieldDifferent =
840 !CompareRepeatedField(message1, message2, field1, parent_fields);
841 if (fieldDifferent) {
842 if (reporter_ == NULL) return false;
843 isDifferent = true;
844 }
845 } else {
846 fieldDifferent = !CompareFieldValueUsingParentFields(
847 message1, message2, field1, -1, -1, parent_fields);
848
849 // If we have found differences, either report them or terminate if
850 // no reporter is present.
851 if (fieldDifferent && reporter_ == NULL) {
852 return false;
853 }
854
855 if (reporter_ != NULL) {
856 SpecificField specific_field;
857 specific_field.field = field1;
858 parent_fields->push_back(specific_field);
859 if (fieldDifferent) {
860 reporter_->ReportModified(message1, message2, *parent_fields);
861 isDifferent = true;
862 } else if (report_matches_) {
863 reporter_->ReportMatched(message1, message2, *parent_fields);
864 }
865 parent_fields->pop_back();
866 }
867 }
868 // Increment the field indices.
869 ++field_index1;
870 ++field_index2;
871 }
872
873 return !isDifferent;
874 }
875
IsMatch(const FieldDescriptor * repeated_field,const MapKeyComparator * key_comparator,const Message * message1,const Message * message2,const std::vector<SpecificField> & parent_fields,Reporter * reporter,int index1,int index2)876 bool MessageDifferencer::IsMatch(
877 const FieldDescriptor* repeated_field,
878 const MapKeyComparator* key_comparator, const Message* message1,
879 const Message* message2, const std::vector<SpecificField>& parent_fields,
880 Reporter* reporter, int index1, int index2) {
881 std::vector<SpecificField> current_parent_fields(parent_fields);
882 if (repeated_field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
883 return CompareFieldValueUsingParentFields(*message1, *message2,
884 repeated_field, index1, index2,
885 ¤t_parent_fields);
886 }
887 // Back up the Reporter and output_string_. They will be reset in the
888 // following code.
889 Reporter* backup_reporter = reporter_;
890 std::string* output_string = output_string_;
891 reporter_ = reporter;
892 output_string_ = NULL;
893 bool match;
894
895 if (key_comparator == NULL) {
896 match = CompareFieldValueUsingParentFields(*message1, *message2,
897 repeated_field, index1, index2,
898 ¤t_parent_fields);
899 } else {
900 const Reflection* reflection1 = message1->GetReflection();
901 const Reflection* reflection2 = message2->GetReflection();
902 const Message& m1 =
903 reflection1->GetRepeatedMessage(*message1, repeated_field, index1);
904 const Message& m2 =
905 reflection2->GetRepeatedMessage(*message2, repeated_field, index2);
906 SpecificField specific_field;
907 specific_field.field = repeated_field;
908 specific_field.index = index1;
909 specific_field.new_index = index2;
910 current_parent_fields.push_back(specific_field);
911 match = key_comparator->IsMatch(m1, m2, current_parent_fields);
912 }
913
914 reporter_ = backup_reporter;
915 output_string_ = output_string;
916 return match;
917 }
918
CompareRepeatedField(const Message & message1,const Message & message2,const FieldDescriptor * repeated_field,std::vector<SpecificField> * parent_fields)919 bool MessageDifferencer::CompareRepeatedField(
920 const Message& message1, const Message& message2,
921 const FieldDescriptor* repeated_field,
922 std::vector<SpecificField>* parent_fields) {
923 // the input FieldDescriptor is guaranteed to be repeated field.
924 const Reflection* reflection1 = message1.GetReflection();
925 const Reflection* reflection2 = message2.GetReflection();
926 const int count1 = reflection1->FieldSize(message1, repeated_field);
927 const int count2 = reflection2->FieldSize(message2, repeated_field);
928 const bool treated_as_subset = IsTreatedAsSubset(repeated_field);
929
930 // If the field is not treated as subset and no detailed reports is needed,
931 // we do a quick check on the number of the elements to avoid unnecessary
932 // comparison.
933 if (count1 != count2 && reporter_ == NULL && !treated_as_subset) {
934 return false;
935 }
936 // A match can never be found if message1 has more items than message2.
937 if (count1 > count2 && reporter_ == NULL) {
938 return false;
939 }
940
941 // These two list are used for store the index of the correspondent
942 // element in peer repeated field.
943 std::vector<int> match_list1;
944 std::vector<int> match_list2;
945
946 const MapKeyComparator* key_comparator = GetMapKeyComparator(repeated_field);
947 bool smart_list = IsTreatedAsSmartList(repeated_field);
948 bool simple_list = key_comparator == nullptr &&
949 !IsTreatedAsSet(repeated_field) &&
950 !IsTreatedAsSmartSet(repeated_field) && !smart_list;
951
952 // For simple lists, we avoid matching repeated field indices, saving the
953 // memory allocations that would otherwise be needed for match_list1 and
954 // match_list2.
955 if (!simple_list) {
956 // Try to match indices of the repeated fields. Return false if match fails.
957 if (!MatchRepeatedFieldIndices(message1, message2, repeated_field,
958 key_comparator, *parent_fields, &match_list1,
959 &match_list2) &&
960 reporter_ == nullptr) {
961 return false;
962 }
963 }
964
965 bool fieldDifferent = false;
966 SpecificField specific_field;
967 specific_field.field = repeated_field;
968
969 // At this point, we have already matched pairs of fields (with the reporting
970 // to be done later). Now to check if the paired elements are different.
971 int next_unmatched_index = 0;
972 for (int i = 0; i < count1; i++) {
973 if (simple_list && i >= count2) {
974 break;
975 }
976 if (!simple_list && match_list1[i] == -1) {
977 if (smart_list) {
978 if (reporter_ == nullptr) return false;
979 specific_field.index = i;
980 parent_fields->push_back(specific_field);
981 reporter_->ReportDeleted(message1, message2, *parent_fields);
982 parent_fields->pop_back();
983 fieldDifferent = true;
984 // Use -2 to mark this element has been reported.
985 match_list1[i] = -2;
986 }
987 continue;
988 }
989 if (smart_list) {
990 for (int j = next_unmatched_index; j < match_list1[i]; ++j) {
991 GOOGLE_CHECK_LE(0, j);
992 if (reporter_ == nullptr) return false;
993 specific_field.index = j;
994 specific_field.new_index = j;
995 parent_fields->push_back(specific_field);
996 reporter_->ReportAdded(message1, message2, *parent_fields);
997 parent_fields->pop_back();
998 fieldDifferent = true;
999 // Use -2 to mark this element has been reported.
1000 match_list2[j] = -2;
1001 }
1002 }
1003 specific_field.index = i;
1004 if (simple_list) {
1005 specific_field.new_index = i;
1006 } else {
1007 specific_field.new_index = match_list1[i];
1008 next_unmatched_index = match_list1[i] + 1;
1009 }
1010
1011 const bool result = CompareFieldValueUsingParentFields(
1012 message1, message2, repeated_field, i, specific_field.new_index,
1013 parent_fields);
1014
1015 // If we have found differences, either report them or terminate if
1016 // no reporter is present. Note that ReportModified, ReportMoved, and
1017 // ReportMatched are all mutually exclusive.
1018 if (!result) {
1019 if (reporter_ == NULL) return false;
1020 parent_fields->push_back(specific_field);
1021 reporter_->ReportModified(message1, message2, *parent_fields);
1022 parent_fields->pop_back();
1023 fieldDifferent = true;
1024 } else if (reporter_ != NULL &&
1025 specific_field.index != specific_field.new_index &&
1026 !specific_field.field->is_map() && report_moves_) {
1027 parent_fields->push_back(specific_field);
1028 reporter_->ReportMoved(message1, message2, *parent_fields);
1029 parent_fields->pop_back();
1030 } else if (report_matches_ && reporter_ != NULL) {
1031 parent_fields->push_back(specific_field);
1032 reporter_->ReportMatched(message1, message2, *parent_fields);
1033 parent_fields->pop_back();
1034 }
1035 }
1036
1037 // Report any remaining additions or deletions.
1038 for (int i = 0; i < count2; ++i) {
1039 if (!simple_list && match_list2[i] != -1) continue;
1040 if (simple_list && i < count1) continue;
1041 if (!treated_as_subset) {
1042 fieldDifferent = true;
1043 }
1044
1045 if (reporter_ == NULL) continue;
1046 specific_field.index = i;
1047 specific_field.new_index = i;
1048 parent_fields->push_back(specific_field);
1049 reporter_->ReportAdded(message1, message2, *parent_fields);
1050 parent_fields->pop_back();
1051 }
1052
1053 for (int i = 0; i < count1; ++i) {
1054 if (!simple_list && match_list1[i] != -1) continue;
1055 if (simple_list && i < count2) continue;
1056 assert(reporter_ != NULL);
1057 specific_field.index = i;
1058 parent_fields->push_back(specific_field);
1059 reporter_->ReportDeleted(message1, message2, *parent_fields);
1060 parent_fields->pop_back();
1061 fieldDifferent = true;
1062 }
1063 return !fieldDifferent;
1064 }
1065
CompareFieldValue(const Message & message1,const Message & message2,const FieldDescriptor * field,int index1,int index2)1066 bool MessageDifferencer::CompareFieldValue(const Message& message1,
1067 const Message& message2,
1068 const FieldDescriptor* field,
1069 int index1, int index2) {
1070 return CompareFieldValueUsingParentFields(message1, message2, field, index1,
1071 index2, NULL);
1072 }
1073
CompareFieldValueUsingParentFields(const Message & message1,const Message & message2,const FieldDescriptor * field,int index1,int index2,std::vector<SpecificField> * parent_fields)1074 bool MessageDifferencer::CompareFieldValueUsingParentFields(
1075 const Message& message1, const Message& message2,
1076 const FieldDescriptor* field, int index1, int index2,
1077 std::vector<SpecificField>* parent_fields) {
1078 FieldContext field_context(parent_fields);
1079 FieldComparator::ComparisonResult result = GetFieldComparisonResult(
1080 message1, message2, field, index1, index2, &field_context);
1081
1082 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
1083 result == FieldComparator::RECURSE) {
1084 // Get the nested messages and compare them using one of the Compare
1085 // methods.
1086 const Reflection* reflection1 = message1.GetReflection();
1087 const Reflection* reflection2 = message2.GetReflection();
1088 const Message& m1 =
1089 field->is_repeated()
1090 ? reflection1->GetRepeatedMessage(message1, field, index1)
1091 : reflection1->GetMessage(message1, field);
1092 const Message& m2 =
1093 field->is_repeated()
1094 ? reflection2->GetRepeatedMessage(message2, field, index2)
1095 : reflection2->GetMessage(message2, field);
1096
1097 // parent_fields is used in calls to Reporter methods.
1098 if (parent_fields != NULL) {
1099 // Append currently compared field to the end of parent_fields.
1100 SpecificField specific_field;
1101 specific_field.field = field;
1102 specific_field.index = index1;
1103 specific_field.new_index = index2;
1104 parent_fields->push_back(specific_field);
1105 const bool compare_result = Compare(m1, m2, parent_fields);
1106 parent_fields->pop_back();
1107 return compare_result;
1108 } else {
1109 // Recreates parent_fields as if m1 and m2 had no parents.
1110 return Compare(m1, m2);
1111 }
1112 } else {
1113 return (result == FieldComparator::SAME);
1114 }
1115 }
1116
CheckPathChanged(const std::vector<SpecificField> & field_path)1117 bool MessageDifferencer::CheckPathChanged(
1118 const std::vector<SpecificField>& field_path) {
1119 for (int i = 0; i < field_path.size(); ++i) {
1120 // Don't check indexes for map entries -- maps are unordered.
1121 if (field_path[i].field != NULL && field_path[i].field->is_map()) continue;
1122 if (field_path[i].index != field_path[i].new_index) return true;
1123 }
1124 return false;
1125 }
1126
IsTreatedAsSet(const FieldDescriptor * field)1127 bool MessageDifferencer::IsTreatedAsSet(const FieldDescriptor* field) {
1128 if (!field->is_repeated()) return false;
1129 if (repeated_field_comparisons_.find(field) !=
1130 repeated_field_comparisons_.end()) {
1131 return repeated_field_comparisons_[field] == AS_SET;
1132 }
1133 return repeated_field_comparison_ == AS_SET;
1134 }
1135
IsTreatedAsSmartSet(const FieldDescriptor * field)1136 bool MessageDifferencer::IsTreatedAsSmartSet(const FieldDescriptor* field) {
1137 if (!field->is_repeated()) return false;
1138 if (repeated_field_comparisons_.find(field) !=
1139 repeated_field_comparisons_.end()) {
1140 return repeated_field_comparisons_[field] == AS_SMART_SET;
1141 }
1142 return repeated_field_comparison_ == AS_SMART_SET;
1143 }
1144
IsTreatedAsSmartList(const FieldDescriptor * field)1145 bool MessageDifferencer::IsTreatedAsSmartList(const FieldDescriptor* field) {
1146 if (!field->is_repeated()) return false;
1147 if (repeated_field_comparisons_.find(field) !=
1148 repeated_field_comparisons_.end()) {
1149 return repeated_field_comparisons_[field] == AS_SMART_LIST;
1150 }
1151 return repeated_field_comparison_ == AS_SMART_LIST;
1152 }
1153
IsTreatedAsSubset(const FieldDescriptor * field)1154 bool MessageDifferencer::IsTreatedAsSubset(const FieldDescriptor* field) {
1155 return scope_ == PARTIAL &&
1156 (IsTreatedAsSet(field) || GetMapKeyComparator(field) != NULL);
1157 }
1158
IsIgnored(const Message & message1,const Message & message2,const FieldDescriptor * field,const std::vector<SpecificField> & parent_fields)1159 bool MessageDifferencer::IsIgnored(
1160 const Message& message1, const Message& message2,
1161 const FieldDescriptor* field,
1162 const std::vector<SpecificField>& parent_fields) {
1163 if (ignored_fields_.find(field) != ignored_fields_.end()) {
1164 return true;
1165 }
1166 for (int i = 0; i < ignore_criteria_.size(); ++i) {
1167 if (ignore_criteria_[i]->IsIgnored(message1, message2, field,
1168 parent_fields)) {
1169 return true;
1170 }
1171 }
1172 return false;
1173 }
1174
IsUnknownFieldIgnored(const Message & message1,const Message & message2,const SpecificField & field,const std::vector<SpecificField> & parent_fields)1175 bool MessageDifferencer::IsUnknownFieldIgnored(
1176 const Message& message1, const Message& message2,
1177 const SpecificField& field,
1178 const std::vector<SpecificField>& parent_fields) {
1179 for (int i = 0; i < ignore_criteria_.size(); ++i) {
1180 if (ignore_criteria_[i]->IsUnknownFieldIgnored(message1, message2, field,
1181 parent_fields)) {
1182 return true;
1183 }
1184 }
1185 return false;
1186 }
1187
1188 const MessageDifferencer::MapKeyComparator*
GetMapKeyComparator(const FieldDescriptor * field) const1189 MessageDifferencer ::GetMapKeyComparator(const FieldDescriptor* field) const {
1190 if (!field->is_repeated()) return NULL;
1191 FieldKeyComparatorMap::const_iterator it =
1192 map_field_key_comparator_.find(field);
1193 if (it != map_field_key_comparator_.end()) {
1194 return it->second;
1195 }
1196 if (field->is_map()) {
1197 // field cannot already be treated as list or set since TreatAsList() and
1198 // TreatAsSet() call GetMapKeyComparator() and fail if it returns non-NULL.
1199 return &map_entry_key_comparator_;
1200 }
1201 return NULL;
1202 }
1203
1204 namespace {
1205
1206 typedef std::pair<int, const UnknownField*> IndexUnknownFieldPair;
1207
1208 struct UnknownFieldOrdering {
operator ()google::protobuf::util::__anond1c7de470111::UnknownFieldOrdering1209 inline bool operator()(const IndexUnknownFieldPair& a,
1210 const IndexUnknownFieldPair& b) const {
1211 if (a.second->number() < b.second->number()) return true;
1212 if (a.second->number() > b.second->number()) return false;
1213 return a.second->type() < b.second->type();
1214 }
1215 };
1216
1217 } // namespace
1218
UnpackAny(const Message & any,std::unique_ptr<Message> * data)1219 bool MessageDifferencer::UnpackAny(const Message& any,
1220 std::unique_ptr<Message>* data) {
1221 const Reflection* reflection = any.GetReflection();
1222 const FieldDescriptor* type_url_field;
1223 const FieldDescriptor* value_field;
1224 if (!internal::GetAnyFieldDescriptors(any, &type_url_field, &value_field)) {
1225 return false;
1226 }
1227 const std::string& type_url = reflection->GetString(any, type_url_field);
1228 std::string full_type_name;
1229 if (!internal::ParseAnyTypeUrl(type_url, &full_type_name)) {
1230 return false;
1231 }
1232
1233 const Descriptor* desc =
1234 any.GetDescriptor()->file()->pool()->FindMessageTypeByName(
1235 full_type_name);
1236 if (desc == NULL) {
1237 GOOGLE_DLOG(ERROR) << "Proto type '" << full_type_name << "' not found";
1238 return false;
1239 }
1240
1241 if (dynamic_message_factory_ == NULL) {
1242 dynamic_message_factory_.reset(new DynamicMessageFactory());
1243 }
1244 data->reset(dynamic_message_factory_->GetPrototype(desc)->New());
1245 std::string serialized_value = reflection->GetString(any, value_field);
1246 if (!(*data)->ParsePartialFromString(serialized_value)) {
1247 GOOGLE_DLOG(ERROR) << "Failed to parse value for " << full_type_name;
1248 return false;
1249 }
1250 return true;
1251 }
1252
CompareUnknownFields(const Message & message1,const Message & message2,const UnknownFieldSet & unknown_field_set1,const UnknownFieldSet & unknown_field_set2,std::vector<SpecificField> * parent_field)1253 bool MessageDifferencer::CompareUnknownFields(
1254 const Message& message1, const Message& message2,
1255 const UnknownFieldSet& unknown_field_set1,
1256 const UnknownFieldSet& unknown_field_set2,
1257 std::vector<SpecificField>* parent_field) {
1258 // Ignore unknown fields in EQUIVALENT mode.
1259 if (message_field_comparison_ == EQUIVALENT) return true;
1260
1261 if (unknown_field_set1.empty() && unknown_field_set2.empty()) {
1262 return true;
1263 }
1264
1265 bool is_different = false;
1266
1267 // We first sort the unknown fields by field number and type (in other words,
1268 // in tag order), making sure to preserve ordering of values with the same
1269 // tag. This allows us to report only meaningful differences between the
1270 // two sets -- that is, differing values for the same tag. We use
1271 // IndexUnknownFieldPairs to keep track of the field's original index for
1272 // reporting purposes.
1273 std::vector<IndexUnknownFieldPair> fields1; // unknown_field_set1, sorted
1274 std::vector<IndexUnknownFieldPair> fields2; // unknown_field_set2, sorted
1275 fields1.reserve(unknown_field_set1.field_count());
1276 fields2.reserve(unknown_field_set2.field_count());
1277
1278 for (int i = 0; i < unknown_field_set1.field_count(); i++) {
1279 fields1.push_back(std::make_pair(i, &unknown_field_set1.field(i)));
1280 }
1281 for (int i = 0; i < unknown_field_set2.field_count(); i++) {
1282 fields2.push_back(std::make_pair(i, &unknown_field_set2.field(i)));
1283 }
1284
1285 UnknownFieldOrdering is_before;
1286 std::stable_sort(fields1.begin(), fields1.end(), is_before);
1287 std::stable_sort(fields2.begin(), fields2.end(), is_before);
1288
1289 // In order to fill in SpecificField::index, we have to keep track of how
1290 // many values we've seen with the same field number and type.
1291 // current_repeated points at the first field in this range, and
1292 // current_repeated_start{1,2} are the indexes of the first field in the
1293 // range within fields1 and fields2.
1294 const UnknownField* current_repeated = NULL;
1295 int current_repeated_start1 = 0;
1296 int current_repeated_start2 = 0;
1297
1298 // Now that we have two sorted lists, we can detect fields which appear only
1299 // in one list or the other by traversing them simultaneously.
1300 int index1 = 0;
1301 int index2 = 0;
1302 while (index1 < fields1.size() || index2 < fields2.size()) {
1303 enum {
1304 ADDITION,
1305 DELETION,
1306 MODIFICATION,
1307 COMPARE_GROUPS,
1308 NO_CHANGE
1309 } change_type;
1310
1311 // focus_field is the field we're currently reporting on. (In the case
1312 // of a modification, it's the field on the left side.)
1313 const UnknownField* focus_field;
1314 bool match = false;
1315
1316 if (index2 == fields2.size() ||
1317 (index1 < fields1.size() &&
1318 is_before(fields1[index1], fields2[index2]))) {
1319 // fields1[index1] is not present in fields2.
1320 change_type = DELETION;
1321 focus_field = fields1[index1].second;
1322 } else if (index1 == fields1.size() ||
1323 is_before(fields2[index2], fields1[index1])) {
1324 // fields2[index2] is not present in fields1.
1325 if (scope_ == PARTIAL) {
1326 // Ignore.
1327 ++index2;
1328 continue;
1329 }
1330 change_type = ADDITION;
1331 focus_field = fields2[index2].second;
1332 } else {
1333 // Field type and number are the same. See if the values differ.
1334 change_type = MODIFICATION;
1335 focus_field = fields1[index1].second;
1336
1337 switch (focus_field->type()) {
1338 case UnknownField::TYPE_VARINT:
1339 match = fields1[index1].second->varint() ==
1340 fields2[index2].second->varint();
1341 break;
1342 case UnknownField::TYPE_FIXED32:
1343 match = fields1[index1].second->fixed32() ==
1344 fields2[index2].second->fixed32();
1345 break;
1346 case UnknownField::TYPE_FIXED64:
1347 match = fields1[index1].second->fixed64() ==
1348 fields2[index2].second->fixed64();
1349 break;
1350 case UnknownField::TYPE_LENGTH_DELIMITED:
1351 match = fields1[index1].second->length_delimited() ==
1352 fields2[index2].second->length_delimited();
1353 break;
1354 case UnknownField::TYPE_GROUP:
1355 // We must deal with this later, after building the SpecificField.
1356 change_type = COMPARE_GROUPS;
1357 break;
1358 }
1359 if (match && change_type != COMPARE_GROUPS) {
1360 change_type = NO_CHANGE;
1361 }
1362 }
1363
1364 if (current_repeated == NULL ||
1365 focus_field->number() != current_repeated->number() ||
1366 focus_field->type() != current_repeated->type()) {
1367 // We've started a new repeated field.
1368 current_repeated = focus_field;
1369 current_repeated_start1 = index1;
1370 current_repeated_start2 = index2;
1371 }
1372
1373 if (change_type == NO_CHANGE && reporter_ == NULL) {
1374 // Fields were already compared and matched and we have no reporter.
1375 ++index1;
1376 ++index2;
1377 continue;
1378 }
1379
1380 // Build the SpecificField. This is slightly complicated.
1381 SpecificField specific_field;
1382 specific_field.unknown_field_number = focus_field->number();
1383 specific_field.unknown_field_type = focus_field->type();
1384
1385 specific_field.unknown_field_set1 = &unknown_field_set1;
1386 specific_field.unknown_field_set2 = &unknown_field_set2;
1387
1388 if (change_type != ADDITION) {
1389 specific_field.unknown_field_index1 = fields1[index1].first;
1390 }
1391 if (change_type != DELETION) {
1392 specific_field.unknown_field_index2 = fields2[index2].first;
1393 }
1394
1395 // Calculate the field index.
1396 if (change_type == ADDITION) {
1397 specific_field.index = index2 - current_repeated_start2;
1398 specific_field.new_index = index2 - current_repeated_start2;
1399 } else {
1400 specific_field.index = index1 - current_repeated_start1;
1401 specific_field.new_index = index2 - current_repeated_start2;
1402 }
1403
1404 if (IsUnknownFieldIgnored(message1, message2, specific_field,
1405 *parent_field)) {
1406 if (reporter_ != NULL) {
1407 parent_field->push_back(specific_field);
1408 reporter_->ReportUnknownFieldIgnored(message1, message2, *parent_field);
1409 parent_field->pop_back();
1410 }
1411 return true;
1412 }
1413
1414 if (change_type == ADDITION || change_type == DELETION ||
1415 change_type == MODIFICATION) {
1416 if (reporter_ == NULL) {
1417 // We found a difference and we have no reporter.
1418 return false;
1419 }
1420 is_different = true;
1421 }
1422
1423 parent_field->push_back(specific_field);
1424
1425 switch (change_type) {
1426 case ADDITION:
1427 reporter_->ReportAdded(message1, message2, *parent_field);
1428 ++index2;
1429 break;
1430 case DELETION:
1431 reporter_->ReportDeleted(message1, message2, *parent_field);
1432 ++index1;
1433 break;
1434 case MODIFICATION:
1435 reporter_->ReportModified(message1, message2, *parent_field);
1436 ++index1;
1437 ++index2;
1438 break;
1439 case COMPARE_GROUPS:
1440 if (!CompareUnknownFields(
1441 message1, message2, fields1[index1].second->group(),
1442 fields2[index2].second->group(), parent_field)) {
1443 if (reporter_ == NULL) return false;
1444 is_different = true;
1445 reporter_->ReportModified(message1, message2, *parent_field);
1446 }
1447 ++index1;
1448 ++index2;
1449 break;
1450 case NO_CHANGE:
1451 ++index1;
1452 ++index2;
1453 if (report_matches_) {
1454 reporter_->ReportMatched(message1, message2, *parent_field);
1455 }
1456 }
1457
1458 parent_field->pop_back();
1459 }
1460
1461 return !is_different;
1462 }
1463
1464 namespace {
1465
1466 // Find maximum bipartite matching using the argumenting path algorithm.
1467 class MaximumMatcher {
1468 public:
1469 typedef std::function<bool(int, int)> NodeMatchCallback;
1470 // MaximumMatcher takes ownership of the passed in callback and uses it to
1471 // determine whether a node on the left side of the bipartial graph matches
1472 // a node on the right side. count1 is the number of nodes on the left side
1473 // of the graph and count2 to is the number of nodes on the right side.
1474 // Every node is referred to using 0-based indices.
1475 // If a maximum match is found, the result will be stored in match_list1 and
1476 // match_list2. match_list1[i] == j means the i-th node on the left side is
1477 // matched to the j-th node on the right side and match_list2[x] == y means
1478 // the x-th node on the right side is matched to y-th node on the left side.
1479 // match_list1[i] == -1 means the node is not matched. Same with match_list2.
1480 MaximumMatcher(int count1, int count2, NodeMatchCallback callback,
1481 std::vector<int>* match_list1, std::vector<int>* match_list2);
1482 // Find a maximum match and return the number of matched node pairs.
1483 // If early_return is true, this method will return 0 immediately when it
1484 // finds that not all nodes on the left side can be matched.
1485 int FindMaximumMatch(bool early_return);
1486
1487 private:
1488 // Determines whether the node on the left side of the bipartial graph
1489 // matches the one on the right side.
1490 bool Match(int left, int right);
1491 // Find an argumenting path starting from the node v on the left side. If a
1492 // path can be found, update match_list2_ to reflect the path and return
1493 // true.
1494 bool FindArgumentPathDFS(int v, std::vector<bool>* visited);
1495
1496 int count1_;
1497 int count2_;
1498 NodeMatchCallback match_callback_;
1499 std::map<std::pair<int, int>, bool> cached_match_results_;
1500 std::vector<int>* match_list1_;
1501 std::vector<int>* match_list2_;
1502 GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MaximumMatcher);
1503 };
1504
MaximumMatcher(int count1,int count2,NodeMatchCallback callback,std::vector<int> * match_list1,std::vector<int> * match_list2)1505 MaximumMatcher::MaximumMatcher(int count1, int count2,
1506 NodeMatchCallback callback,
1507 std::vector<int>* match_list1,
1508 std::vector<int>* match_list2)
1509 : count1_(count1),
1510 count2_(count2),
1511 match_callback_(std::move(callback)),
1512 match_list1_(match_list1),
1513 match_list2_(match_list2) {
1514 match_list1_->assign(count1, -1);
1515 match_list2_->assign(count2, -1);
1516 }
1517
FindMaximumMatch(bool early_return)1518 int MaximumMatcher::FindMaximumMatch(bool early_return) {
1519 int result = 0;
1520 for (int i = 0; i < count1_; ++i) {
1521 std::vector<bool> visited(count1_);
1522 if (FindArgumentPathDFS(i, &visited)) {
1523 ++result;
1524 } else if (early_return) {
1525 return 0;
1526 }
1527 }
1528 // Backfill match_list1_ as we only filled match_list2_ when finding
1529 // argumenting pathes.
1530 for (int i = 0; i < count2_; ++i) {
1531 if ((*match_list2_)[i] != -1) {
1532 (*match_list1_)[(*match_list2_)[i]] = i;
1533 }
1534 }
1535 return result;
1536 }
1537
Match(int left,int right)1538 bool MaximumMatcher::Match(int left, int right) {
1539 std::pair<int, int> p(left, right);
1540 std::map<std::pair<int, int>, bool>::iterator it =
1541 cached_match_results_.find(p);
1542 if (it != cached_match_results_.end()) {
1543 return it->second;
1544 }
1545 cached_match_results_[p] = match_callback_(left, right);
1546 return cached_match_results_[p];
1547 }
1548
FindArgumentPathDFS(int v,std::vector<bool> * visited)1549 bool MaximumMatcher::FindArgumentPathDFS(int v, std::vector<bool>* visited) {
1550 (*visited)[v] = true;
1551 // We try to match those un-matched nodes on the right side first. This is
1552 // the step that the naive greedy matching algorithm uses. In the best cases
1553 // where the greedy algorithm can find a maximum matching, we will always
1554 // find a match in this step and the performance will be identical to the
1555 // greedy algorithm.
1556 for (int i = 0; i < count2_; ++i) {
1557 int matched = (*match_list2_)[i];
1558 if (matched == -1 && Match(v, i)) {
1559 (*match_list2_)[i] = v;
1560 return true;
1561 }
1562 }
1563 // Then we try those already matched nodes and see if we can find an
1564 // alternative match for the node matched to them.
1565 // The greedy algorithm will stop before this and fail to produce the
1566 // correct result.
1567 for (int i = 0; i < count2_; ++i) {
1568 int matched = (*match_list2_)[i];
1569 if (matched != -1 && Match(v, i)) {
1570 if (!(*visited)[matched] && FindArgumentPathDFS(matched, visited)) {
1571 (*match_list2_)[i] = v;
1572 return true;
1573 }
1574 }
1575 }
1576 return false;
1577 }
1578
1579 } // namespace
1580
MatchRepeatedFieldIndices(const Message & message1,const Message & message2,const FieldDescriptor * repeated_field,const MapKeyComparator * key_comparator,const std::vector<SpecificField> & parent_fields,std::vector<int> * match_list1,std::vector<int> * match_list2)1581 bool MessageDifferencer::MatchRepeatedFieldIndices(
1582 const Message& message1, const Message& message2,
1583 const FieldDescriptor* repeated_field,
1584 const MapKeyComparator* key_comparator,
1585 const std::vector<SpecificField>& parent_fields,
1586 std::vector<int>* match_list1, std::vector<int>* match_list2) {
1587 const int count1 =
1588 message1.GetReflection()->FieldSize(message1, repeated_field);
1589 const int count2 =
1590 message2.GetReflection()->FieldSize(message2, repeated_field);
1591 const bool is_treated_as_smart_set = IsTreatedAsSmartSet(repeated_field);
1592
1593 match_list1->assign(count1, -1);
1594 match_list2->assign(count2, -1);
1595 // Ensure that we don't report differences during the matching process. Since
1596 // field comparators could potentially use this message differencer object to
1597 // perform further comparisons, turn off reporting here and re-enable it
1598 // before returning.
1599 Reporter* reporter = reporter_;
1600 reporter_ = NULL;
1601 NumDiffsReporter num_diffs_reporter;
1602 std::vector<int32> num_diffs_list1;
1603 if (is_treated_as_smart_set) {
1604 num_diffs_list1.assign(count1, kint32max);
1605 }
1606
1607 bool success = true;
1608 // Find potential match if this is a special repeated field.
1609 if (scope_ == PARTIAL) {
1610 // When partial matching is enabled, Compare(a, b) && Compare(a, c)
1611 // doesn't necessarily imply Compare(b, c). Therefore a naive greedy
1612 // algorithm will fail to find a maximum matching.
1613 // Here we use the augmenting path algorithm.
1614 auto callback = [&](int i1, int i2) {
1615 return IsMatch(repeated_field, key_comparator, &message1, &message2,
1616 parent_fields, nullptr, i1, i2);
1617 };
1618 MaximumMatcher matcher(count1, count2, std::move(callback), match_list1,
1619 match_list2);
1620 // If diff info is not needed, we should end the matching process as
1621 // soon as possible if not all items can be matched.
1622 bool early_return = (reporter == nullptr);
1623 int match_count = matcher.FindMaximumMatch(early_return);
1624 if (match_count != count1 && early_return) return false;
1625 success = success && (match_count == count1);
1626 } else {
1627 int start_offset = 0;
1628 // If the two repeated fields are treated as sets, optimize for the case
1629 // where both start with same items stored in the same order.
1630 if (IsTreatedAsSet(repeated_field) || is_treated_as_smart_set ||
1631 IsTreatedAsSmartList(repeated_field)) {
1632 start_offset = std::min(count1, count2);
1633 for (int i = 0; i < count1 && i < count2; i++) {
1634 if (IsMatch(repeated_field, key_comparator, &message1, &message2,
1635 parent_fields, nullptr, i, i)) {
1636 match_list1->at(i) = i;
1637 match_list2->at(i) = i;
1638 } else {
1639 start_offset = i;
1640 break;
1641 }
1642 }
1643 }
1644 for (int i = start_offset; i < count1; ++i) {
1645 // Indicates any matched elements for this repeated field.
1646 bool match = false;
1647 int matched_j = -1;
1648
1649 for (int j = start_offset; j < count2; j++) {
1650 if (match_list2->at(j) != -1) {
1651 if (!is_treated_as_smart_set || num_diffs_list1[i] == 0 ||
1652 num_diffs_list1[match_list2->at(j)] == 0) {
1653 continue;
1654 }
1655 }
1656
1657 if (is_treated_as_smart_set) {
1658 num_diffs_reporter.Reset();
1659 match = IsMatch(repeated_field, key_comparator, &message1, &message2,
1660 parent_fields, &num_diffs_reporter, i, j);
1661 } else {
1662 match = IsMatch(repeated_field, key_comparator, &message1, &message2,
1663 parent_fields, nullptr, i, j);
1664 }
1665
1666 if (is_treated_as_smart_set) {
1667 if (match) {
1668 num_diffs_list1[i] = 0;
1669 } else if (repeated_field->cpp_type() ==
1670 FieldDescriptor::CPPTYPE_MESSAGE) {
1671 // Replace with the one with fewer diffs.
1672 const int32 num_diffs = num_diffs_reporter.GetNumDiffs();
1673 if (num_diffs < num_diffs_list1[i]) {
1674 // If j has been already matched to some element, ensure the
1675 // current num_diffs is smaller.
1676 if (match_list2->at(j) == -1 ||
1677 num_diffs < num_diffs_list1[match_list2->at(j)]) {
1678 num_diffs_list1[i] = num_diffs;
1679 match = true;
1680 }
1681 }
1682 }
1683 }
1684
1685 if (match) {
1686 matched_j = j;
1687 if (!is_treated_as_smart_set || num_diffs_list1[i] == 0) {
1688 break;
1689 }
1690 }
1691 }
1692
1693 match = (matched_j != -1);
1694 if (match) {
1695 if (is_treated_as_smart_set && match_list2->at(matched_j) != -1) {
1696 // This is to revert the previously matched index in list2.
1697 match_list1->at(match_list2->at(matched_j)) = -1;
1698 match = false;
1699 }
1700 match_list1->at(i) = matched_j;
1701 match_list2->at(matched_j) = i;
1702 }
1703 if (!match && reporter == nullptr) return false;
1704 success = success && match;
1705 }
1706 }
1707
1708 if (IsTreatedAsSmartList(repeated_field)) {
1709 match_indices_for_smart_list_callback_(match_list1, match_list2);
1710 }
1711
1712 reporter_ = reporter;
1713
1714 return success;
1715 }
1716
GetFieldComparisonResult(const Message & message1,const Message & message2,const FieldDescriptor * field,int index1,int index2,const FieldContext * field_context)1717 FieldComparator::ComparisonResult MessageDifferencer::GetFieldComparisonResult(
1718 const Message& message1, const Message& message2,
1719 const FieldDescriptor* field, int index1, int index2,
1720 const FieldContext* field_context) {
1721 FieldComparator* comparator = field_comparator_ != NULL
1722 ? field_comparator_
1723 : &default_field_comparator_;
1724 return comparator->Compare(message1, message2, field, index1, index2,
1725 field_context);
1726 }
1727
1728 // ===========================================================================
1729
Reporter()1730 MessageDifferencer::Reporter::Reporter() {}
~Reporter()1731 MessageDifferencer::Reporter::~Reporter() {}
1732
1733 // ===========================================================================
1734
MapKeyComparator()1735 MessageDifferencer::MapKeyComparator::MapKeyComparator() {}
~MapKeyComparator()1736 MessageDifferencer::MapKeyComparator::~MapKeyComparator() {}
1737
1738 // ===========================================================================
1739
IgnoreCriteria()1740 MessageDifferencer::IgnoreCriteria::IgnoreCriteria() {}
~IgnoreCriteria()1741 MessageDifferencer::IgnoreCriteria::~IgnoreCriteria() {}
1742
1743 // ===========================================================================
1744
1745 // Note that the printer's delimiter is not used, because if we are given a
1746 // printer, we don't know its delimiter.
StreamReporter(io::ZeroCopyOutputStream * output)1747 MessageDifferencer::StreamReporter::StreamReporter(
1748 io::ZeroCopyOutputStream* output)
1749 : printer_(new io::Printer(output, '$')),
1750 delete_printer_(true),
1751 report_modified_aggregates_(false) {}
1752
StreamReporter(io::Printer * printer)1753 MessageDifferencer::StreamReporter::StreamReporter(io::Printer* printer)
1754 : printer_(printer),
1755 delete_printer_(false),
1756 report_modified_aggregates_(false) {}
1757
~StreamReporter()1758 MessageDifferencer::StreamReporter::~StreamReporter() {
1759 if (delete_printer_) delete printer_;
1760 }
1761
PrintPath(const std::vector<SpecificField> & field_path,bool left_side)1762 void MessageDifferencer::StreamReporter::PrintPath(
1763 const std::vector<SpecificField>& field_path, bool left_side) {
1764 for (int i = 0; i < field_path.size(); ++i) {
1765 if (i > 0) {
1766 printer_->Print(".");
1767 }
1768
1769 SpecificField specific_field = field_path[i];
1770
1771 if (specific_field.field != NULL) {
1772 if (specific_field.field->is_extension()) {
1773 printer_->Print("($name$)", "name", specific_field.field->full_name());
1774 } else {
1775 printer_->PrintRaw(specific_field.field->name());
1776 }
1777 if (specific_field.field->is_map()) {
1778 // Don't print index in a map field; they are semantically unordered.
1779 continue;
1780 }
1781 } else {
1782 printer_->PrintRaw(StrCat(specific_field.unknown_field_number));
1783 }
1784 if (left_side && specific_field.index >= 0) {
1785 printer_->Print("[$name$]", "name", StrCat(specific_field.index));
1786 }
1787 if (!left_side && specific_field.new_index >= 0) {
1788 printer_->Print("[$name$]", "name",
1789 StrCat(specific_field.new_index));
1790 }
1791 }
1792 }
1793
PrintPath(const std::vector<SpecificField> & field_path,bool left_side,const Message & message)1794 void MessageDifferencer::StreamReporter::PrintPath(
1795 const std::vector<SpecificField>& field_path, bool left_side,
1796 const Message& message) {
1797 PrintPath(field_path, left_side);
1798 }
1799
PrintValue(const Message & message,const std::vector<SpecificField> & field_path,bool left_side)1800 void MessageDifferencer::StreamReporter::PrintValue(
1801 const Message& message, const std::vector<SpecificField>& field_path,
1802 bool left_side) {
1803 const SpecificField& specific_field = field_path.back();
1804 const FieldDescriptor* field = specific_field.field;
1805 if (field != NULL) {
1806 std::string output;
1807 int index = left_side ? specific_field.index : specific_field.new_index;
1808 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
1809 const Reflection* reflection = message.GetReflection();
1810 const Message& field_message =
1811 field->is_repeated()
1812 ? reflection->GetRepeatedMessage(message, field, index)
1813 : reflection->GetMessage(message, field);
1814 output = field_message.ShortDebugString();
1815 if (output.empty()) {
1816 printer_->Print("{ }");
1817 } else {
1818 printer_->Print("{ $name$ }", "name", output);
1819 }
1820 } else {
1821 TextFormat::PrintFieldValueToString(message, field, index, &output);
1822 printer_->PrintRaw(output);
1823 }
1824 } else {
1825 const UnknownFieldSet* unknown_fields =
1826 (left_side ? specific_field.unknown_field_set1
1827 : specific_field.unknown_field_set2);
1828 const UnknownField* unknown_field =
1829 &unknown_fields->field(left_side ? specific_field.unknown_field_index1
1830 : specific_field.unknown_field_index2);
1831 PrintUnknownFieldValue(unknown_field);
1832 }
1833 }
1834
PrintUnknownFieldValue(const UnknownField * unknown_field)1835 void MessageDifferencer::StreamReporter::PrintUnknownFieldValue(
1836 const UnknownField* unknown_field) {
1837 GOOGLE_CHECK(unknown_field != NULL) << " Cannot print NULL unknown_field.";
1838
1839 std::string output;
1840 switch (unknown_field->type()) {
1841 case UnknownField::TYPE_VARINT:
1842 output = StrCat(unknown_field->varint());
1843 break;
1844 case UnknownField::TYPE_FIXED32:
1845 output = StrCat(
1846 "0x", strings::Hex(unknown_field->fixed32(), strings::ZERO_PAD_8));
1847 break;
1848 case UnknownField::TYPE_FIXED64:
1849 output = StrCat(
1850 "0x", strings::Hex(unknown_field->fixed64(), strings::ZERO_PAD_16));
1851 break;
1852 case UnknownField::TYPE_LENGTH_DELIMITED:
1853 output = StringPrintf(
1854 "\"%s\"", CEscape(unknown_field->length_delimited()).c_str());
1855 break;
1856 case UnknownField::TYPE_GROUP:
1857 // TODO(kenton): Print the contents of the group like we do for
1858 // messages. Requires an equivalent of ShortDebugString() for
1859 // UnknownFieldSet.
1860 output = "{ ... }";
1861 break;
1862 }
1863 printer_->PrintRaw(output);
1864 }
1865
Print(const std::string & str)1866 void MessageDifferencer::StreamReporter::Print(const std::string& str) {
1867 printer_->Print(str.c_str());
1868 }
1869
ReportAdded(const Message & message1,const Message & message2,const std::vector<SpecificField> & field_path)1870 void MessageDifferencer::StreamReporter::ReportAdded(
1871 const Message& message1, const Message& message2,
1872 const std::vector<SpecificField>& field_path) {
1873 printer_->Print("added: ");
1874 PrintPath(field_path, false, message2);
1875 printer_->Print(": ");
1876 PrintValue(message2, field_path, false);
1877 printer_->Print("\n"); // Print for newlines.
1878 }
1879
ReportDeleted(const Message & message1,const Message & message2,const std::vector<SpecificField> & field_path)1880 void MessageDifferencer::StreamReporter::ReportDeleted(
1881 const Message& message1, const Message& message2,
1882 const std::vector<SpecificField>& field_path) {
1883 printer_->Print("deleted: ");
1884 PrintPath(field_path, true, message1);
1885 printer_->Print(": ");
1886 PrintValue(message1, field_path, true);
1887 printer_->Print("\n"); // Print for newlines
1888 }
1889
ReportModified(const Message & message1,const Message & message2,const std::vector<SpecificField> & field_path)1890 void MessageDifferencer::StreamReporter::ReportModified(
1891 const Message& message1, const Message& message2,
1892 const std::vector<SpecificField>& field_path) {
1893 if (!report_modified_aggregates_ && field_path.back().field == NULL) {
1894 if (field_path.back().unknown_field_type == UnknownField::TYPE_GROUP) {
1895 // Any changes to the subfields have already been printed.
1896 return;
1897 }
1898 } else if (!report_modified_aggregates_) {
1899 if (field_path.back().field->cpp_type() ==
1900 FieldDescriptor::CPPTYPE_MESSAGE) {
1901 // Any changes to the subfields have already been printed.
1902 return;
1903 }
1904 }
1905
1906 printer_->Print("modified: ");
1907 PrintPath(field_path, true, message1);
1908 if (CheckPathChanged(field_path)) {
1909 printer_->Print(" -> ");
1910 PrintPath(field_path, false, message2);
1911 }
1912 printer_->Print(": ");
1913 PrintValue(message1, field_path, true);
1914 printer_->Print(" -> ");
1915 PrintValue(message2, field_path, false);
1916 printer_->Print("\n"); // Print for newlines.
1917 }
1918
ReportMoved(const Message & message1,const Message & message2,const std::vector<SpecificField> & field_path)1919 void MessageDifferencer::StreamReporter::ReportMoved(
1920 const Message& message1, const Message& message2,
1921 const std::vector<SpecificField>& field_path) {
1922 printer_->Print("moved: ");
1923 PrintPath(field_path, true, message1);
1924 printer_->Print(" -> ");
1925 PrintPath(field_path, false, message2);
1926 printer_->Print(" : ");
1927 PrintValue(message1, field_path, true);
1928 printer_->Print("\n"); // Print for newlines.
1929 }
1930
ReportMatched(const Message & message1,const Message & message2,const std::vector<SpecificField> & field_path)1931 void MessageDifferencer::StreamReporter::ReportMatched(
1932 const Message& message1, const Message& message2,
1933 const std::vector<SpecificField>& field_path) {
1934 printer_->Print("matched: ");
1935 PrintPath(field_path, true, message1);
1936 if (CheckPathChanged(field_path)) {
1937 printer_->Print(" -> ");
1938 PrintPath(field_path, false, message2);
1939 }
1940 printer_->Print(" : ");
1941 PrintValue(message1, field_path, true);
1942 printer_->Print("\n"); // Print for newlines.
1943 }
1944
ReportIgnored(const Message & message1,const Message & message2,const std::vector<SpecificField> & field_path)1945 void MessageDifferencer::StreamReporter::ReportIgnored(
1946 const Message& message1, const Message& message2,
1947 const std::vector<SpecificField>& field_path) {
1948 printer_->Print("ignored: ");
1949 PrintPath(field_path, true, message1);
1950 if (CheckPathChanged(field_path)) {
1951 printer_->Print(" -> ");
1952 PrintPath(field_path, false, message2);
1953 }
1954 printer_->Print("\n"); // Print for newlines.
1955 }
1956
ReportUnknownFieldIgnored(const Message & message1,const Message & message2,const std::vector<SpecificField> & field_path)1957 void MessageDifferencer::StreamReporter::ReportUnknownFieldIgnored(
1958 const Message& message1, const Message& message2,
1959 const std::vector<SpecificField>& field_path) {
1960 printer_->Print("ignored: ");
1961 PrintPath(field_path, true, message1);
1962 if (CheckPathChanged(field_path)) {
1963 printer_->Print(" -> ");
1964 PrintPath(field_path, false, message2);
1965 }
1966 printer_->Print("\n"); // Print for newlines.
1967 }
1968
1969 MessageDifferencer::MapKeyComparator*
CreateMultipleFieldsMapKeyComparator(const std::vector<std::vector<const FieldDescriptor * >> & key_field_paths)1970 MessageDifferencer::CreateMultipleFieldsMapKeyComparator(
1971 const std::vector<std::vector<const FieldDescriptor*> >& key_field_paths) {
1972 return new MultipleFieldsMapKeyComparator(this, key_field_paths);
1973 }
1974
1975 } // namespace util
1976 } // namespace protobuf
1977 } // namespace google
1978