blob: 9842f64c11f2d0801e87d7dcab758e223eeeb922 [file] [log] [blame]
Brian Silverman9c614bc2016-02-15 20:20:02 -05001// 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// This file defines static methods and classes for comparing Protocol
36// Messages (see //google/protobuf/util/message_differencer.h for more
37// information).
38
39#include <google/protobuf/util/message_differencer.h>
40
41#include <algorithm>
42#include <memory>
Brian Silverman9c614bc2016-02-15 20:20:02 -050043#include <utility>
44
45#include <google/protobuf/stubs/callback.h>
46#include <google/protobuf/stubs/common.h>
Austin Schuh40c16522018-10-28 20:27:54 -070047#include <google/protobuf/stubs/logging.h>
Brian Silverman9c614bc2016-02-15 20:20:02 -050048#include <google/protobuf/stubs/stringprintf.h>
49#include <google/protobuf/any.h>
50#include <google/protobuf/io/printer.h>
51#include <google/protobuf/io/zero_copy_stream.h>
52#include <google/protobuf/io/zero_copy_stream_impl.h>
Austin Schuh40c16522018-10-28 20:27:54 -070053#include <google/protobuf/descriptor.pb.h>
Brian Silverman9c614bc2016-02-15 20:20:02 -050054#include <google/protobuf/dynamic_message.h>
55#include <google/protobuf/text_format.h>
56#include <google/protobuf/util/field_comparator.h>
57#include <google/protobuf/stubs/strutil.h>
58
59namespace google {
60namespace protobuf {
61
62namespace util {
63
64// When comparing a repeated field as map, MultipleFieldMapKeyComparator can
65// be used to specify multiple fields as key for key comparison.
66// Two elements of a repeated field will be regarded as having the same key
67// iff they have the same value for every specified key field.
68// Note that you can also specify only one field as key.
69class MessageDifferencer::MultipleFieldsMapKeyComparator
70 : public MessageDifferencer::MapKeyComparator {
71 public:
72 MultipleFieldsMapKeyComparator(
73 MessageDifferencer* message_differencer,
Austin Schuh40c16522018-10-28 20:27:54 -070074 const std::vector<std::vector<const FieldDescriptor*> >& key_field_paths)
Brian Silverman9c614bc2016-02-15 20:20:02 -050075 : message_differencer_(message_differencer),
76 key_field_paths_(key_field_paths) {
77 GOOGLE_CHECK(!key_field_paths_.empty());
78 for (int i = 0; i < key_field_paths_.size(); ++i) {
79 GOOGLE_CHECK(!key_field_paths_[i].empty());
80 }
81 }
82 MultipleFieldsMapKeyComparator(
83 MessageDifferencer* message_differencer,
84 const FieldDescriptor* key)
85 : message_differencer_(message_differencer) {
Austin Schuh40c16522018-10-28 20:27:54 -070086 std::vector<const FieldDescriptor*> key_field_path;
Brian Silverman9c614bc2016-02-15 20:20:02 -050087 key_field_path.push_back(key);
88 key_field_paths_.push_back(key_field_path);
89 }
90 virtual bool IsMatch(
91 const Message& message1,
92 const Message& message2,
Austin Schuh40c16522018-10-28 20:27:54 -070093 const std::vector<SpecificField>& parent_fields) const {
Brian Silverman9c614bc2016-02-15 20:20:02 -050094 for (int i = 0; i < key_field_paths_.size(); ++i) {
95 if (!IsMatchInternal(message1, message2, parent_fields,
96 key_field_paths_[i], 0)) {
97 return false;
98 }
99 }
100 return true;
101 }
102 private:
103 bool IsMatchInternal(
104 const Message& message1,
105 const Message& message2,
Austin Schuh40c16522018-10-28 20:27:54 -0700106 const std::vector<SpecificField>& parent_fields,
107 const std::vector<const FieldDescriptor*>& key_field_path,
Brian Silverman9c614bc2016-02-15 20:20:02 -0500108 int path_index) const {
109 const FieldDescriptor* field = key_field_path[path_index];
Austin Schuh40c16522018-10-28 20:27:54 -0700110 std::vector<SpecificField> current_parent_fields(parent_fields);
Brian Silverman9c614bc2016-02-15 20:20:02 -0500111 if (path_index == key_field_path.size() - 1) {
112 if (field->is_repeated()) {
113 if (!message_differencer_->CompareRepeatedField(
114 message1, message2, field, &current_parent_fields)) {
115 return false;
116 }
117 } else {
118 if (!message_differencer_->CompareFieldValueUsingParentFields(
119 message1, message2, field, -1, -1, &current_parent_fields)) {
120 return false;
121 }
122 }
123 return true;
124 } else {
125 const Reflection* reflection1 = message1.GetReflection();
126 const Reflection* reflection2 = message2.GetReflection();
127 bool has_field1 = reflection1->HasField(message1, field);
128 bool has_field2 = reflection2->HasField(message2, field);
129 if (!has_field1 && !has_field2) {
130 return true;
131 }
132 if (has_field1 != has_field2) {
133 return false;
134 }
135 SpecificField specific_field;
136 specific_field.field = field;
137 current_parent_fields.push_back(specific_field);
138 return IsMatchInternal(
139 reflection1->GetMessage(message1, field),
140 reflection2->GetMessage(message2, field),
141 current_parent_fields,
142 key_field_path,
143 path_index + 1);
144 }
145 }
146 MessageDifferencer* message_differencer_;
Austin Schuh40c16522018-10-28 20:27:54 -0700147 std::vector<std::vector<const FieldDescriptor*> > key_field_paths_;
Brian Silverman9c614bc2016-02-15 20:20:02 -0500148 GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MultipleFieldsMapKeyComparator);
149};
150
Austin Schuh40c16522018-10-28 20:27:54 -0700151MessageDifferencer::MapEntryKeyComparator::MapEntryKeyComparator(
152 MessageDifferencer* message_differencer)
153 : message_differencer_(message_differencer) {}
154
155bool MessageDifferencer::MapEntryKeyComparator::IsMatch(
156 const Message& message1, const Message& message2,
157 const std::vector<SpecificField>& parent_fields) const {
158 // Map entry has its key in the field with tag 1. See the comment for
159 // map_entry in MessageOptions.
160 const FieldDescriptor* key = message1.GetDescriptor()->FindFieldByNumber(1);
161 // If key is not present in message1 and we're doing partial comparison or if
162 // map key is explicitly ignored treat the field as set instead,
163 const bool treat_as_set =
164 (message_differencer_->scope() == PARTIAL &&
165 !message1.GetReflection()->HasField(message1, key)) ||
166 message_differencer_->IsIgnored(message1, message2, key, parent_fields);
167
168 std::vector<SpecificField> current_parent_fields(parent_fields);
169 if (treat_as_set) {
170 return message_differencer_->Compare(message1, message2,
171 &current_parent_fields);
172 }
173 return message_differencer_->CompareFieldValueUsingParentFields(
174 message1, message2, key, -1, -1, &current_parent_fields);
175}
176
Brian Silverman9c614bc2016-02-15 20:20:02 -0500177bool MessageDifferencer::Equals(const Message& message1,
178 const Message& message2) {
179 MessageDifferencer differencer;
180
181 return differencer.Compare(message1, message2);
182}
183
184bool MessageDifferencer::Equivalent(const Message& message1,
185 const Message& message2) {
186 MessageDifferencer differencer;
187 differencer.set_message_field_comparison(MessageDifferencer::EQUIVALENT);
188
189 return differencer.Compare(message1, message2);
190}
191
192bool MessageDifferencer::ApproximatelyEquals(const Message& message1,
193 const Message& message2) {
194 MessageDifferencer differencer;
195 differencer.set_float_comparison(
196 MessageDifferencer::APPROXIMATE);
197
198 return differencer.Compare(message1, message2);
199}
200
201bool MessageDifferencer::ApproximatelyEquivalent(const Message& message1,
202 const Message& message2) {
203 MessageDifferencer differencer;
204 differencer.set_message_field_comparison(MessageDifferencer::EQUIVALENT);
205 differencer.set_float_comparison(MessageDifferencer::APPROXIMATE);
206
207 return differencer.Compare(message1, message2);
208}
209
210// ===========================================================================
211
212MessageDifferencer::MessageDifferencer()
213 : reporter_(NULL),
214 field_comparator_(NULL),
215 message_field_comparison_(EQUAL),
216 scope_(FULL),
217 repeated_field_comparison_(AS_LIST),
Austin Schuh40c16522018-10-28 20:27:54 -0700218 map_entry_key_comparator_(this),
Brian Silverman9c614bc2016-02-15 20:20:02 -0500219 report_matches_(false),
Austin Schuh40c16522018-10-28 20:27:54 -0700220 report_moves_(true),
221 output_string_(NULL) {}
Brian Silverman9c614bc2016-02-15 20:20:02 -0500222
223MessageDifferencer::~MessageDifferencer() {
224 for (int i = 0; i < owned_key_comparators_.size(); ++i) {
225 delete owned_key_comparators_[i];
226 }
227 for (int i = 0; i < ignore_criteria_.size(); ++i) {
228 delete ignore_criteria_[i];
229 }
230}
231
232void MessageDifferencer::set_field_comparator(FieldComparator* comparator) {
233 GOOGLE_CHECK(comparator) << "Field comparator can't be NULL.";
234 field_comparator_ = comparator;
235}
236
237void MessageDifferencer::set_message_field_comparison(
238 MessageFieldComparison comparison) {
239 message_field_comparison_ = comparison;
240}
241
242void MessageDifferencer::set_scope(Scope scope) {
243 scope_ = scope;
244}
245
246MessageDifferencer::Scope MessageDifferencer::scope() {
247 return scope_;
248}
249
250void MessageDifferencer::set_float_comparison(FloatComparison comparison) {
251 default_field_comparator_.set_float_comparison(
252 comparison == EXACT ?
253 DefaultFieldComparator::EXACT : DefaultFieldComparator::APPROXIMATE);
254}
255
256void MessageDifferencer::set_repeated_field_comparison(
257 RepeatedFieldComparison comparison) {
258 repeated_field_comparison_ = comparison;
259}
260
261void MessageDifferencer::TreatAsSet(const FieldDescriptor* field) {
262 GOOGLE_CHECK(field->is_repeated()) << "Field must be repeated: "
263 << field->full_name();
264 const MapKeyComparator* key_comparator = GetMapKeyComparator(field);
265 GOOGLE_CHECK(key_comparator == NULL)
266 << "Cannot treat this repeated field as both Map and Set for"
267 << " comparison. Field name is: " << field->full_name();
268 GOOGLE_CHECK(list_fields_.find(field) == list_fields_.end())
269 << "Cannot treat the same field as both SET and LIST. Field name is: "
270 << field->full_name();
271 set_fields_.insert(field);
272}
273
274void MessageDifferencer::TreatAsList(const FieldDescriptor* field) {
275 GOOGLE_CHECK(field->is_repeated()) << "Field must be repeated: "
276 << field->full_name();
277 const MapKeyComparator* key_comparator = GetMapKeyComparator(field);
278 GOOGLE_CHECK(key_comparator == NULL)
279 << "Cannot treat this repeated field as both Map and Set for"
280 << " comparison. Field name is: " << field->full_name();
281 GOOGLE_CHECK(set_fields_.find(field) == set_fields_.end())
282 << "Cannot treat the same field as both SET and LIST. Field name is: "
283 << field->full_name();
284 list_fields_.insert(field);
285}
286
287void MessageDifferencer::TreatAsMap(const FieldDescriptor* field,
288 const FieldDescriptor* key) {
289 GOOGLE_CHECK(field->is_repeated()) << "Field must be repeated: "
290 << field->full_name();
291 GOOGLE_CHECK_EQ(FieldDescriptor::CPPTYPE_MESSAGE, field->cpp_type())
292 << "Field has to be message type. Field name is: "
293 << field->full_name();
294 GOOGLE_CHECK(key->containing_type() == field->message_type())
295 << key->full_name()
296 << " must be a direct subfield within the repeated field "
297 << field->full_name() << ", not " << key->containing_type()->full_name();
298 GOOGLE_CHECK(set_fields_.find(field) == set_fields_.end())
299 << "Cannot treat this repeated field as both Map and Set for "
300 << "comparison.";
301 GOOGLE_CHECK(list_fields_.find(field) == list_fields_.end())
302 << "Cannot treat this repeated field as both Map and List for "
303 << "comparison.";
304 MapKeyComparator* key_comparator =
305 new MultipleFieldsMapKeyComparator(this, key);
306 owned_key_comparators_.push_back(key_comparator);
307 map_field_key_comparator_[field] = key_comparator;
308}
309
310void MessageDifferencer::TreatAsMapWithMultipleFieldsAsKey(
311 const FieldDescriptor* field,
Austin Schuh40c16522018-10-28 20:27:54 -0700312 const std::vector<const FieldDescriptor*>& key_fields) {
313 std::vector<std::vector<const FieldDescriptor*> > key_field_paths;
Brian Silverman9c614bc2016-02-15 20:20:02 -0500314 for (int i = 0; i < key_fields.size(); ++i) {
Austin Schuh40c16522018-10-28 20:27:54 -0700315 std::vector<const FieldDescriptor*> key_field_path;
Brian Silverman9c614bc2016-02-15 20:20:02 -0500316 key_field_path.push_back(key_fields[i]);
317 key_field_paths.push_back(key_field_path);
318 }
319 TreatAsMapWithMultipleFieldPathsAsKey(field, key_field_paths);
320}
321
322void MessageDifferencer::TreatAsMapWithMultipleFieldPathsAsKey(
323 const FieldDescriptor* field,
Austin Schuh40c16522018-10-28 20:27:54 -0700324 const std::vector<std::vector<const FieldDescriptor*> >& key_field_paths) {
Brian Silverman9c614bc2016-02-15 20:20:02 -0500325 GOOGLE_CHECK(field->is_repeated()) << "Field must be repeated: "
326 << field->full_name();
327 GOOGLE_CHECK_EQ(FieldDescriptor::CPPTYPE_MESSAGE, field->cpp_type())
328 << "Field has to be message type. Field name is: "
329 << field->full_name();
330 for (int i = 0; i < key_field_paths.size(); ++i) {
Austin Schuh40c16522018-10-28 20:27:54 -0700331 const std::vector<const FieldDescriptor*>& key_field_path =
332 key_field_paths[i];
Brian Silverman9c614bc2016-02-15 20:20:02 -0500333 for (int j = 0; j < key_field_path.size(); ++j) {
334 const FieldDescriptor* parent_field =
335 j == 0 ? field : key_field_path[j - 1];
336 const FieldDescriptor* child_field = key_field_path[j];
337 GOOGLE_CHECK(child_field->containing_type() == parent_field->message_type())
338 << child_field->full_name()
339 << " must be a direct subfield within the field: "
340 << parent_field->full_name();
341 if (j != 0) {
342 GOOGLE_CHECK_EQ(FieldDescriptor::CPPTYPE_MESSAGE, parent_field->cpp_type())
343 << parent_field->full_name() << " has to be of type message.";
344 GOOGLE_CHECK(!parent_field->is_repeated())
345 << parent_field->full_name() << " cannot be a repeated field.";
346 }
347 }
348 }
349 GOOGLE_CHECK(set_fields_.find(field) == set_fields_.end())
350 << "Cannot treat this repeated field as both Map and Set for "
351 << "comparison.";
352 MapKeyComparator* key_comparator =
353 new MultipleFieldsMapKeyComparator(this, key_field_paths);
354 owned_key_comparators_.push_back(key_comparator);
355 map_field_key_comparator_[field] = key_comparator;
356}
357
358void MessageDifferencer::TreatAsMapUsingKeyComparator(
359 const FieldDescriptor* field,
360 const MapKeyComparator* key_comparator) {
361 GOOGLE_CHECK(field->is_repeated()) << "Field must be repeated: "
362 << field->full_name();
Brian Silverman9c614bc2016-02-15 20:20:02 -0500363 GOOGLE_CHECK(set_fields_.find(field) == set_fields_.end())
364 << "Cannot treat this repeated field as both Map and Set for "
365 << "comparison.";
366 map_field_key_comparator_[field] = key_comparator;
367}
368
369void MessageDifferencer::AddIgnoreCriteria(IgnoreCriteria* ignore_criteria) {
370 ignore_criteria_.push_back(ignore_criteria);
371}
372
373void MessageDifferencer::IgnoreField(const FieldDescriptor* field) {
374 ignored_fields_.insert(field);
375}
376
377void MessageDifferencer::SetFractionAndMargin(const FieldDescriptor* field,
378 double fraction, double margin) {
379 default_field_comparator_.SetFractionAndMargin(field, fraction, margin);
380}
381
382void MessageDifferencer::ReportDifferencesToString(string* output) {
383 GOOGLE_DCHECK(output) << "Specified output string was NULL";
384
385 output_string_ = output;
386 output_string_->clear();
387}
388
389void MessageDifferencer::ReportDifferencesTo(Reporter* reporter) {
390 // If an output string is set, clear it to prevent
391 // it superceding the specified reporter.
392 if (output_string_) {
393 output_string_ = NULL;
394 }
395
396 reporter_ = reporter;
397}
398
399bool MessageDifferencer::FieldBefore(const FieldDescriptor* field1,
400 const FieldDescriptor* field2) {
401 // Handle sentinel values (i.e. make sure NULLs are always ordered
402 // at the end of the list).
403 if (field1 == NULL) {
404 return false;
405 }
406
407 if (field2 == NULL) {
408 return true;
409 }
410
411 // Always order fields by their tag number
412 return (field1->number() < field2->number());
413}
414
415bool MessageDifferencer::Compare(const Message& message1,
416 const Message& message2) {
Austin Schuh40c16522018-10-28 20:27:54 -0700417 std::vector<SpecificField> parent_fields;
Brian Silverman9c614bc2016-02-15 20:20:02 -0500418
419 bool result = false;
420
421 // Setup the internal reporter if need be.
422 if (output_string_) {
423 io::StringOutputStream output_stream(output_string_);
424 StreamReporter reporter(&output_stream);
425 reporter_ = &reporter;
426 result = Compare(message1, message2, &parent_fields);
427 reporter_ = NULL;
428 } else {
429 result = Compare(message1, message2, &parent_fields);
430 }
431
432 return result;
433}
434
435bool MessageDifferencer::CompareWithFields(
436 const Message& message1,
437 const Message& message2,
Austin Schuh40c16522018-10-28 20:27:54 -0700438 const std::vector<const FieldDescriptor*>& message1_fields_arg,
439 const std::vector<const FieldDescriptor*>& message2_fields_arg) {
Brian Silverman9c614bc2016-02-15 20:20:02 -0500440 if (message1.GetDescriptor() != message2.GetDescriptor()) {
441 GOOGLE_LOG(DFATAL) << "Comparison between two messages with different "
442 << "descriptors.";
443 return false;
444 }
445
Austin Schuh40c16522018-10-28 20:27:54 -0700446 std::vector<SpecificField> parent_fields;
Brian Silverman9c614bc2016-02-15 20:20:02 -0500447
448 bool result = false;
449
Austin Schuh40c16522018-10-28 20:27:54 -0700450 std::vector<const FieldDescriptor*> message1_fields(message1_fields_arg);
451 std::vector<const FieldDescriptor*> message2_fields(message2_fields_arg);
Brian Silverman9c614bc2016-02-15 20:20:02 -0500452
453 std::sort(message1_fields.begin(), message1_fields.end(), FieldBefore);
454 std::sort(message2_fields.begin(), message2_fields.end(), FieldBefore);
455 // Append NULL sentinel values.
456 message1_fields.push_back(NULL);
457 message2_fields.push_back(NULL);
458
459 // Setup the internal reporter if need be.
460 if (output_string_) {
461 io::StringOutputStream output_stream(output_string_);
462 StreamReporter reporter(&output_stream);
463 reporter_ = &reporter;
464 result = CompareRequestedFieldsUsingSettings(
465 message1, message2, message1_fields, message2_fields, &parent_fields);
466 reporter_ = NULL;
467 } else {
468 result = CompareRequestedFieldsUsingSettings(
469 message1, message2, message1_fields, message2_fields, &parent_fields);
470 }
471
472 return result;
473}
474
475bool MessageDifferencer::Compare(
476 const Message& message1,
477 const Message& message2,
Austin Schuh40c16522018-10-28 20:27:54 -0700478 std::vector<SpecificField>* parent_fields) {
Brian Silverman9c614bc2016-02-15 20:20:02 -0500479 const Descriptor* descriptor1 = message1.GetDescriptor();
480 const Descriptor* descriptor2 = message2.GetDescriptor();
481 if (descriptor1 != descriptor2) {
482 GOOGLE_LOG(DFATAL) << "Comparison between two messages with different "
Austin Schuh40c16522018-10-28 20:27:54 -0700483 << "descriptors. "
484 << descriptor1->full_name() << " vs "
485 << descriptor2->full_name();
Brian Silverman9c614bc2016-02-15 20:20:02 -0500486 return false;
487 }
488 // Expand google.protobuf.Any payload if possible.
489 if (descriptor1->full_name() == internal::kAnyFullTypeName) {
Austin Schuh40c16522018-10-28 20:27:54 -0700490 std::unique_ptr<Message> data1;
491 std::unique_ptr<Message> data2;
Brian Silverman9c614bc2016-02-15 20:20:02 -0500492 if (UnpackAny(message1, &data1) && UnpackAny(message2, &data2)) {
Austin Schuh40c16522018-10-28 20:27:54 -0700493 // Avoid DFATAL for different descriptors in google.protobuf.Any payloads.
494 if (data1->GetDescriptor() != data2->GetDescriptor()) {
495 return false;
496 }
Brian Silverman9c614bc2016-02-15 20:20:02 -0500497 return Compare(*data1, *data2, parent_fields);
498 }
499 }
500 const Reflection* reflection1 = message1.GetReflection();
501 const Reflection* reflection2 = message2.GetReflection();
502
503 // Retrieve all the set fields, including extensions.
Austin Schuh40c16522018-10-28 20:27:54 -0700504 std::vector<const FieldDescriptor*> message1_fields;
505 message1_fields.reserve(1 + message1.GetDescriptor()->field_count());
Brian Silverman9c614bc2016-02-15 20:20:02 -0500506
Austin Schuh40c16522018-10-28 20:27:54 -0700507 std::vector<const FieldDescriptor*> message2_fields;
508 message2_fields.reserve(1 + message2.GetDescriptor()->field_count());
509
510 if (descriptor1->options().map_entry()) {
511 if (scope_ == PARTIAL) {
512 reflection1->ListFields(message1, &message1_fields);
513 } else {
514 // Map entry fields are always considered present.
515 for (int i = 0; i < descriptor1->field_count(); i++) {
516 message1_fields.push_back(descriptor1->field(i));
517 }
518 }
519 for (int i = 0; i < descriptor1->field_count(); i++) {
520 message2_fields.push_back(descriptor1->field(i));
521 }
522 } else {
523 reflection1->ListFields(message1, &message1_fields);
524 reflection2->ListFields(message2, &message2_fields);
525 }
Brian Silverman9c614bc2016-02-15 20:20:02 -0500526
527 // Add sentinel values to deal with the
528 // case where the number of the fields in
529 // each list are different.
530 message1_fields.push_back(NULL);
531 message2_fields.push_back(NULL);
532
533 bool unknown_compare_result = true;
534 // Ignore unknown fields in EQUIVALENT mode
535 if (message_field_comparison_ != EQUIVALENT) {
536 const google::protobuf::UnknownFieldSet* unknown_field_set1 =
537 &reflection1->GetUnknownFields(message1);
538 const google::protobuf::UnknownFieldSet* unknown_field_set2 =
539 &reflection2->GetUnknownFields(message2);
540 if (!CompareUnknownFields(message1, message2,
541 *unknown_field_set1, *unknown_field_set2,
542 parent_fields)) {
543 if (reporter_ == NULL) {
544 return false;
545 };
546 unknown_compare_result = false;
547 }
548 }
549
550 return CompareRequestedFieldsUsingSettings(
551 message1, message2,
552 message1_fields, message2_fields,
553 parent_fields) && unknown_compare_result;
554}
555
556bool MessageDifferencer::CompareRequestedFieldsUsingSettings(
557 const Message& message1,
558 const Message& message2,
Austin Schuh40c16522018-10-28 20:27:54 -0700559 const std::vector<const FieldDescriptor*>& message1_fields,
560 const std::vector<const FieldDescriptor*>& message2_fields,
561 std::vector<SpecificField>* parent_fields) {
Brian Silverman9c614bc2016-02-15 20:20:02 -0500562 if (scope_ == FULL) {
563 if (message_field_comparison_ == EQUIVALENT) {
564 // We need to merge the field lists of both messages (i.e.
565 // we are merely checking for a difference in field values,
566 // rather than the addition or deletion of fields).
Austin Schuh40c16522018-10-28 20:27:54 -0700567 std::vector<const FieldDescriptor*> fields_union;
Brian Silverman9c614bc2016-02-15 20:20:02 -0500568 CombineFields(message1_fields, FULL, message2_fields, FULL,
569 &fields_union);
570 return CompareWithFieldsInternal(message1, message2, fields_union,
571 fields_union, parent_fields);
572 } else {
573 // Simple equality comparison, use the unaltered field lists.
574 return CompareWithFieldsInternal(message1, message2, message1_fields,
575 message2_fields, parent_fields);
576 }
577 } else {
578 if (message_field_comparison_ == EQUIVALENT) {
579 // We use the list of fields for message1 for both messages when
580 // comparing. This way, extra fields in message2 are ignored,
581 // and missing fields in message2 use their default value.
582 return CompareWithFieldsInternal(message1, message2, message1_fields,
583 message1_fields, parent_fields);
584 } else {
585 // We need to consider the full list of fields for message1
586 // but only the intersection for message2. This way, any fields
587 // only present in message2 will be ignored, but any fields only
588 // present in message1 will be marked as a difference.
Austin Schuh40c16522018-10-28 20:27:54 -0700589 std::vector<const FieldDescriptor*> fields_intersection;
Brian Silverman9c614bc2016-02-15 20:20:02 -0500590 CombineFields(message1_fields, PARTIAL, message2_fields, PARTIAL,
591 &fields_intersection);
592 return CompareWithFieldsInternal(message1, message2, message1_fields,
593 fields_intersection, parent_fields);
594 }
595 }
596}
597
598void MessageDifferencer::CombineFields(
Austin Schuh40c16522018-10-28 20:27:54 -0700599 const std::vector<const FieldDescriptor*>& fields1,
Brian Silverman9c614bc2016-02-15 20:20:02 -0500600 Scope fields1_scope,
Austin Schuh40c16522018-10-28 20:27:54 -0700601 const std::vector<const FieldDescriptor*>& fields2,
Brian Silverman9c614bc2016-02-15 20:20:02 -0500602 Scope fields2_scope,
Austin Schuh40c16522018-10-28 20:27:54 -0700603 std::vector<const FieldDescriptor*>* combined_fields) {
Brian Silverman9c614bc2016-02-15 20:20:02 -0500604
605 int index1 = 0;
606 int index2 = 0;
607
608 while (index1 < fields1.size() && index2 < fields2.size()) {
609 const FieldDescriptor* field1 = fields1[index1];
610 const FieldDescriptor* field2 = fields2[index2];
611
612 if (FieldBefore(field1, field2)) {
613 if (fields1_scope == FULL) {
614 combined_fields->push_back(fields1[index1]);
615 }
616 ++index1;
617 } else if (FieldBefore(field2, field1)) {
618 if (fields2_scope == FULL) {
619 combined_fields->push_back(fields2[index2]);
620 }
621 ++index2;
622 } else {
623 combined_fields->push_back(fields1[index1]);
624 ++index1;
625 ++index2;
626 }
627 }
628}
629
630bool MessageDifferencer::CompareWithFieldsInternal(
631 const Message& message1,
632 const Message& message2,
Austin Schuh40c16522018-10-28 20:27:54 -0700633 const std::vector<const FieldDescriptor*>& message1_fields,
634 const std::vector<const FieldDescriptor*>& message2_fields,
635 std::vector<SpecificField>* parent_fields) {
Brian Silverman9c614bc2016-02-15 20:20:02 -0500636 bool isDifferent = false;
637 int field_index1 = 0;
638 int field_index2 = 0;
639
640 const Reflection* reflection1 = message1.GetReflection();
641 const Reflection* reflection2 = message2.GetReflection();
642
643 while (true) {
644 const FieldDescriptor* field1 = message1_fields[field_index1];
645 const FieldDescriptor* field2 = message2_fields[field_index2];
646
647 // Once we have reached sentinel values, we are done the comparison.
648 if (field1 == NULL && field2 == NULL) {
649 break;
650 }
651
652 // Check for differences in the field itself.
653 if (FieldBefore(field1, field2)) {
654 // Field 1 is not in the field list for message 2.
655 if (IsIgnored(message1, message2, field1, *parent_fields)) {
656 // We are ignoring field1. Report the ignore and move on to
657 // the next field in message1_fields.
658 if (reporter_ != NULL) {
659 SpecificField specific_field;
660 specific_field.field = field1;
661
662 parent_fields->push_back(specific_field);
663 reporter_->ReportIgnored(message1, message2, *parent_fields);
664 parent_fields->pop_back();
665 }
666 ++field_index1;
667 continue;
668 }
669
670 if (reporter_ != NULL) {
Austin Schuh40c16522018-10-28 20:27:54 -0700671 assert(field1 != NULL);
Brian Silverman9c614bc2016-02-15 20:20:02 -0500672 int count = field1->is_repeated() ?
673 reflection1->FieldSize(message1, field1) : 1;
674
675 for (int i = 0; i < count; ++i) {
676 SpecificField specific_field;
677 specific_field.field = field1;
678 specific_field.index = field1->is_repeated() ? i : -1;
679
680 parent_fields->push_back(specific_field);
681 reporter_->ReportDeleted(message1, message2, *parent_fields);
682 parent_fields->pop_back();
683 }
684
685 isDifferent = true;
686 } else {
687 return false;
688 }
689
690 ++field_index1;
691 continue;
692 } else if (FieldBefore(field2, field1)) {
693 // Field 2 is not in the field list for message 1.
694 if (IsIgnored(message1, message2, field2, *parent_fields)) {
695 // We are ignoring field2. Report the ignore and move on to
696 // the next field in message2_fields.
697 if (reporter_ != NULL) {
698 SpecificField specific_field;
699 specific_field.field = field2;
700
701 parent_fields->push_back(specific_field);
702 reporter_->ReportIgnored(message1, message2, *parent_fields);
703 parent_fields->pop_back();
704 }
705 ++field_index2;
706 continue;
707 }
708
709 if (reporter_ != NULL) {
710 int count = field2->is_repeated() ?
711 reflection2->FieldSize(message2, field2) : 1;
712
713 for (int i = 0; i < count; ++i) {
714 SpecificField specific_field;
715 specific_field.field = field2;
716 specific_field.index = field2->is_repeated() ? i : -1;
717 specific_field.new_index = specific_field.index;
718
719 parent_fields->push_back(specific_field);
720 reporter_->ReportAdded(message1, message2, *parent_fields);
721 parent_fields->pop_back();
722 }
723
724 isDifferent = true;
725 } else {
726 return false;
727 }
728
729 ++field_index2;
730 continue;
731 }
732
733 // By this point, field1 and field2 are guarenteed to point to the same
734 // field, so we can now compare the values.
735 if (IsIgnored(message1, message2, field1, *parent_fields)) {
736 // Ignore this field. Report and move on.
737 if (reporter_ != NULL) {
738 SpecificField specific_field;
739 specific_field.field = field1;
740
741 parent_fields->push_back(specific_field);
742 reporter_->ReportIgnored(message1, message2, *parent_fields);
743 parent_fields->pop_back();
744 }
745
746 ++field_index1;
747 ++field_index2;
748 continue;
749 }
750
751 bool fieldDifferent = false;
Austin Schuh40c16522018-10-28 20:27:54 -0700752 assert(field1 != NULL);
Brian Silverman9c614bc2016-02-15 20:20:02 -0500753 if (field1->is_repeated()) {
754 fieldDifferent = !CompareRepeatedField(message1, message2, field1,
755 parent_fields);
756 if (fieldDifferent) {
757 if (reporter_ == NULL) return false;
758 isDifferent = true;
759 }
760 } else {
761 fieldDifferent = !CompareFieldValueUsingParentFields(
762 message1, message2, field1, -1, -1, parent_fields);
763
764 // If we have found differences, either report them or terminate if
765 // no reporter is present.
766 if (fieldDifferent && reporter_ == NULL) {
767 return false;
768 }
769
770 if (reporter_ != NULL) {
771 SpecificField specific_field;
772 specific_field.field = field1;
773 parent_fields->push_back(specific_field);
774 if (fieldDifferent) {
775 reporter_->ReportModified(message1, message2, *parent_fields);
776 isDifferent = true;
777 } else if (report_matches_) {
778 reporter_->ReportMatched(message1, message2, *parent_fields);
779 }
780 parent_fields->pop_back();
781 }
782 }
783 // Increment the field indicies.
784 ++field_index1;
785 ++field_index2;
786 }
787
788 return !isDifferent;
789}
790
Austin Schuh40c16522018-10-28 20:27:54 -0700791bool MessageDifferencer::IsMatch(
792 const FieldDescriptor* repeated_field,
793 const MapKeyComparator* key_comparator, const Message* message1,
794 const Message* message2, const std::vector<SpecificField>& parent_fields,
795 int index1, int index2) {
796 std::vector<SpecificField> current_parent_fields(parent_fields);
Brian Silverman9c614bc2016-02-15 20:20:02 -0500797 if (repeated_field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
798 return CompareFieldValueUsingParentFields(
799 *message1, *message2, repeated_field, index1, index2,
800 &current_parent_fields);
801 }
802 // Back up the Reporter and output_string_. They will be reset in the
803 // following code.
804 Reporter* backup_reporter = reporter_;
805 string* output_string = output_string_;
806 reporter_ = NULL;
807 output_string_ = NULL;
808 bool match;
809
810 if (key_comparator == NULL) {
811 match = CompareFieldValueUsingParentFields(
812 *message1, *message2, repeated_field, index1, index2,
813 &current_parent_fields);
814 } else {
815 const Reflection* reflection1 = message1->GetReflection();
816 const Reflection* reflection2 = message2->GetReflection();
817 const Message& m1 =
818 reflection1->GetRepeatedMessage(*message1, repeated_field, index1);
819 const Message& m2 =
820 reflection2->GetRepeatedMessage(*message2, repeated_field, index2);
821 SpecificField specific_field;
822 specific_field.field = repeated_field;
Austin Schuh40c16522018-10-28 20:27:54 -0700823 specific_field.index = index1;
824 specific_field.new_index = index2;
Brian Silverman9c614bc2016-02-15 20:20:02 -0500825 current_parent_fields.push_back(specific_field);
826 match = key_comparator->IsMatch(m1, m2, current_parent_fields);
827 }
828
829 reporter_ = backup_reporter;
830 output_string_ = output_string;
831 return match;
832}
833
834bool MessageDifferencer::CompareRepeatedField(
835 const Message& message1,
836 const Message& message2,
837 const FieldDescriptor* repeated_field,
Austin Schuh40c16522018-10-28 20:27:54 -0700838 std::vector<SpecificField>* parent_fields) {
Brian Silverman9c614bc2016-02-15 20:20:02 -0500839 // the input FieldDescriptor is guaranteed to be repeated field.
840 const Reflection* reflection1 = message1.GetReflection();
841 const Reflection* reflection2 = message2.GetReflection();
842 const int count1 = reflection1->FieldSize(message1, repeated_field);
843 const int count2 = reflection2->FieldSize(message2, repeated_field);
844 const bool treated_as_subset = IsTreatedAsSubset(repeated_field);
845
846 // If the field is not treated as subset and no detailed reports is needed,
847 // we do a quick check on the number of the elements to avoid unnecessary
848 // comparison.
849 if (count1 != count2 && reporter_ == NULL && !treated_as_subset) {
850 return false;
851 }
852 // A match can never be found if message1 has more items than message2.
853 if (count1 > count2 && reporter_ == NULL) {
854 return false;
855 }
856
857 // These two list are used for store the index of the correspondent
858 // element in peer repeated field.
Austin Schuh40c16522018-10-28 20:27:54 -0700859 std::vector<int> match_list1;
860 std::vector<int> match_list2;
Brian Silverman9c614bc2016-02-15 20:20:02 -0500861
862 // Try to match indices of the repeated fields. Return false if match fails
863 // and there's no detailed report needed.
864 if (!MatchRepeatedFieldIndices(message1, message2, repeated_field,
865 *parent_fields, &match_list1, &match_list2) &&
866 reporter_ == NULL) {
867 return false;
868 }
869
870 bool fieldDifferent = false;
871 SpecificField specific_field;
872 specific_field.field = repeated_field;
873
874 // At this point, we have already matched pairs of fields (with the reporting
875 // to be done later). Now to check if the paired elements are different.
876 for (int i = 0; i < count1; i++) {
877 if (match_list1[i] == -1) continue;
878 specific_field.index = i;
879 specific_field.new_index = match_list1[i];
880
881 const bool result = CompareFieldValueUsingParentFields(
882 message1, message2, repeated_field, i, specific_field.new_index,
883 parent_fields);
884
885 // If we have found differences, either report them or terminate if
886 // no reporter is present. Note that ReportModified, ReportMoved, and
887 // ReportMatched are all mutually exclusive.
888 if (!result) {
889 if (reporter_ == NULL) return false;
890 parent_fields->push_back(specific_field);
891 reporter_->ReportModified(message1, message2, *parent_fields);
892 parent_fields->pop_back();
893 fieldDifferent = true;
894 } else if (reporter_ != NULL &&
Austin Schuh40c16522018-10-28 20:27:54 -0700895 specific_field.index != specific_field.new_index &&
896 !specific_field.field->is_map() && report_moves_) {
Brian Silverman9c614bc2016-02-15 20:20:02 -0500897 parent_fields->push_back(specific_field);
898 reporter_->ReportMoved(message1, message2, *parent_fields);
899 parent_fields->pop_back();
900 } else if (report_matches_ && reporter_ != NULL) {
901 parent_fields->push_back(specific_field);
902 reporter_->ReportMatched(message1, message2, *parent_fields);
903 parent_fields->pop_back();
904 }
905 }
906
907 // Report any remaining additions or deletions.
908 for (int i = 0; i < count2; ++i) {
909 if (match_list2[i] != -1) continue;
910 if (!treated_as_subset) {
911 fieldDifferent = true;
912 }
913
914 if (reporter_ == NULL) continue;
915 specific_field.index = i;
916 specific_field.new_index = i;
917 parent_fields->push_back(specific_field);
918 reporter_->ReportAdded(message1, message2, *parent_fields);
919 parent_fields->pop_back();
920 }
921
922 for (int i = 0; i < count1; ++i) {
923 if (match_list1[i] != -1) continue;
Austin Schuh40c16522018-10-28 20:27:54 -0700924 assert(reporter_ != NULL);
Brian Silverman9c614bc2016-02-15 20:20:02 -0500925 specific_field.index = i;
926 parent_fields->push_back(specific_field);
927 reporter_->ReportDeleted(message1, message2, *parent_fields);
928 parent_fields->pop_back();
929 fieldDifferent = true;
930 }
931 return !fieldDifferent;
932}
933
934bool MessageDifferencer::CompareFieldValue(const Message& message1,
935 const Message& message2,
936 const FieldDescriptor* field,
937 int index1,
938 int index2) {
939 return CompareFieldValueUsingParentFields(message1, message2, field, index1,
940 index2, NULL);
941}
942
943bool MessageDifferencer::CompareFieldValueUsingParentFields(
944 const Message& message1, const Message& message2,
945 const FieldDescriptor* field, int index1, int index2,
Austin Schuh40c16522018-10-28 20:27:54 -0700946 std::vector<SpecificField>* parent_fields) {
Brian Silverman9c614bc2016-02-15 20:20:02 -0500947 FieldContext field_context(parent_fields);
948 FieldComparator::ComparisonResult result = GetFieldComparisonResult(
949 message1, message2, field, index1, index2, &field_context);
950
951 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
952 result == FieldComparator::RECURSE) {
953 // Get the nested messages and compare them using one of the Compare
954 // methods.
955 const Reflection* reflection1 = message1.GetReflection();
956 const Reflection* reflection2 = message2.GetReflection();
957 const Message& m1 = field->is_repeated() ?
958 reflection1->GetRepeatedMessage(message1, field, index1) :
959 reflection1->GetMessage(message1, field);
960 const Message& m2 = field->is_repeated() ?
961 reflection2->GetRepeatedMessage(message2, field, index2) :
962 reflection2->GetMessage(message2, field);
963
964 // parent_fields is used in calls to Reporter methods.
965 if (parent_fields != NULL) {
966 // Append currently compared field to the end of parent_fields.
967 SpecificField specific_field;
968 specific_field.field = field;
969 specific_field.index = index1;
970 specific_field.new_index = index2;
971 parent_fields->push_back(specific_field);
972 const bool compare_result = Compare(m1, m2, parent_fields);
973 parent_fields->pop_back();
974 return compare_result;
975 } else {
976 // Recreates parent_fields as if m1 and m2 had no parents.
977 return Compare(m1, m2);
978 }
979 } else {
980 return (result == FieldComparator::SAME);
981 }
982}
983
984bool MessageDifferencer::CheckPathChanged(
Austin Schuh40c16522018-10-28 20:27:54 -0700985 const std::vector<SpecificField>& field_path) {
Brian Silverman9c614bc2016-02-15 20:20:02 -0500986 for (int i = 0; i < field_path.size(); ++i) {
Austin Schuh40c16522018-10-28 20:27:54 -0700987 // Don't check indexes for map entries -- maps are unordered.
988 if (field_path[i].field != NULL && field_path[i].field->is_map()) continue;
Brian Silverman9c614bc2016-02-15 20:20:02 -0500989 if (field_path[i].index != field_path[i].new_index) return true;
990 }
991 return false;
992}
993
994bool MessageDifferencer::IsTreatedAsSet(const FieldDescriptor* field) {
995 if (!field->is_repeated()) return false;
Brian Silverman9c614bc2016-02-15 20:20:02 -0500996 if (repeated_field_comparison_ == AS_SET)
997 return list_fields_.find(field) == list_fields_.end();
998 return (set_fields_.find(field) != set_fields_.end());
999}
1000
1001bool MessageDifferencer::IsTreatedAsSubset(const FieldDescriptor* field) {
1002 return scope_ == PARTIAL &&
1003 (IsTreatedAsSet(field) || GetMapKeyComparator(field) != NULL);
1004}
1005
1006bool MessageDifferencer::IsIgnored(
1007 const Message& message1,
1008 const Message& message2,
1009 const FieldDescriptor* field,
Austin Schuh40c16522018-10-28 20:27:54 -07001010 const std::vector<SpecificField>& parent_fields) {
Brian Silverman9c614bc2016-02-15 20:20:02 -05001011 if (ignored_fields_.find(field) != ignored_fields_.end()) {
1012 return true;
1013 }
1014 for (int i = 0; i < ignore_criteria_.size(); ++i) {
1015 if (ignore_criteria_[i]->IsIgnored(message1, message2, field,
1016 parent_fields)) {
1017 return true;
1018 }
1019 }
1020 return false;
1021}
1022
1023bool MessageDifferencer::IsUnknownFieldIgnored(
1024 const Message& message1, const Message& message2,
Austin Schuh40c16522018-10-28 20:27:54 -07001025 const SpecificField& field,
1026 const std::vector<SpecificField>& parent_fields) {
Brian Silverman9c614bc2016-02-15 20:20:02 -05001027 for (int i = 0; i < ignore_criteria_.size(); ++i) {
1028 if (ignore_criteria_[i]->IsUnknownFieldIgnored(message1, message2, field,
1029 parent_fields)) {
1030 return true;
1031 }
1032 }
1033 return false;
1034}
1035
Austin Schuh40c16522018-10-28 20:27:54 -07001036const MessageDifferencer::MapKeyComparator*
1037MessageDifferencer ::GetMapKeyComparator(const FieldDescriptor* field) const {
Brian Silverman9c614bc2016-02-15 20:20:02 -05001038 if (!field->is_repeated()) return NULL;
Austin Schuh40c16522018-10-28 20:27:54 -07001039 FieldKeyComparatorMap::const_iterator it =
1040 map_field_key_comparator_.find(field);
1041 if (it != map_field_key_comparator_.end()) {
1042 return it->second;
1043 }
1044 if (field->is_map()) {
1045 // field cannot already be treated as list or set since TreatAsList() and
1046 // TreatAsSet() call GetMapKeyComparator() and fail if it returns non-NULL.
1047 return &map_entry_key_comparator_;
Brian Silverman9c614bc2016-02-15 20:20:02 -05001048 }
1049 return NULL;
1050}
1051
1052namespace {
1053
Austin Schuh40c16522018-10-28 20:27:54 -07001054typedef std::pair<int, const UnknownField*> IndexUnknownFieldPair;
Brian Silverman9c614bc2016-02-15 20:20:02 -05001055
1056struct UnknownFieldOrdering {
1057 inline bool operator()(const IndexUnknownFieldPair& a,
1058 const IndexUnknownFieldPair& b) const {
1059 if (a.second->number() < b.second->number()) return true;
1060 if (a.second->number() > b.second->number()) return false;
1061 return a.second->type() < b.second->type();
1062 }
1063};
1064
1065} // namespace
1066
1067bool MessageDifferencer::UnpackAny(const Message& any,
Austin Schuh40c16522018-10-28 20:27:54 -07001068 std::unique_ptr<Message>* data) {
Brian Silverman9c614bc2016-02-15 20:20:02 -05001069 const Reflection* reflection = any.GetReflection();
1070 const FieldDescriptor* type_url_field;
1071 const FieldDescriptor* value_field;
1072 if (!internal::GetAnyFieldDescriptors(any, &type_url_field, &value_field)) {
1073 return false;
1074 }
1075 const string& type_url = reflection->GetString(any, type_url_field);
1076 string full_type_name;
1077 if (!internal::ParseAnyTypeUrl(type_url, &full_type_name)) {
1078 return false;
1079 }
1080
1081 const google::protobuf::Descriptor* desc =
1082 any.GetDescriptor()->file()->pool()->FindMessageTypeByName(
1083 full_type_name);
1084 if (desc == NULL) {
Austin Schuh40c16522018-10-28 20:27:54 -07001085 GOOGLE_DLOG(ERROR) << "Proto type '" << full_type_name << "' not found";
Brian Silverman9c614bc2016-02-15 20:20:02 -05001086 return false;
1087 }
1088
1089 if (dynamic_message_factory_ == NULL) {
1090 dynamic_message_factory_.reset(new DynamicMessageFactory());
1091 }
1092 data->reset(dynamic_message_factory_->GetPrototype(desc)->New());
1093 string serialized_value = reflection->GetString(any, value_field);
1094 if (!(*data)->ParseFromString(serialized_value)) {
Austin Schuh40c16522018-10-28 20:27:54 -07001095 GOOGLE_DLOG(ERROR) << "Failed to parse value for " << full_type_name;
Brian Silverman9c614bc2016-02-15 20:20:02 -05001096 return false;
1097 }
1098 return true;
1099}
1100
1101bool MessageDifferencer::CompareUnknownFields(
1102 const Message& message1, const Message& message2,
1103 const google::protobuf::UnknownFieldSet& unknown_field_set1,
1104 const google::protobuf::UnknownFieldSet& unknown_field_set2,
Austin Schuh40c16522018-10-28 20:27:54 -07001105 std::vector<SpecificField>* parent_field) {
Brian Silverman9c614bc2016-02-15 20:20:02 -05001106 // Ignore unknown fields in EQUIVALENT mode.
1107 if (message_field_comparison_ == EQUIVALENT) return true;
1108
1109 if (unknown_field_set1.empty() && unknown_field_set2.empty()) {
1110 return true;
1111 }
1112
1113 bool is_different = false;
1114
1115 // We first sort the unknown fields by field number and type (in other words,
1116 // in tag order), making sure to preserve ordering of values with the same
1117 // tag. This allows us to report only meaningful differences between the
1118 // two sets -- that is, differing values for the same tag. We use
1119 // IndexUnknownFieldPairs to keep track of the field's original index for
1120 // reporting purposes.
Austin Schuh40c16522018-10-28 20:27:54 -07001121 std::vector<IndexUnknownFieldPair> fields1; // unknown_field_set1, sorted
1122 std::vector<IndexUnknownFieldPair> fields2; // unknown_field_set2, sorted
Brian Silverman9c614bc2016-02-15 20:20:02 -05001123 fields1.reserve(unknown_field_set1.field_count());
1124 fields2.reserve(unknown_field_set2.field_count());
1125
1126 for (int i = 0; i < unknown_field_set1.field_count(); i++) {
1127 fields1.push_back(std::make_pair(i, &unknown_field_set1.field(i)));
1128 }
1129 for (int i = 0; i < unknown_field_set2.field_count(); i++) {
1130 fields2.push_back(std::make_pair(i, &unknown_field_set2.field(i)));
1131 }
1132
1133 UnknownFieldOrdering is_before;
1134 std::stable_sort(fields1.begin(), fields1.end(), is_before);
1135 std::stable_sort(fields2.begin(), fields2.end(), is_before);
1136
1137 // In order to fill in SpecificField::index, we have to keep track of how
1138 // many values we've seen with the same field number and type.
1139 // current_repeated points at the first field in this range, and
1140 // current_repeated_start{1,2} are the indexes of the first field in the
1141 // range within fields1 and fields2.
1142 const UnknownField* current_repeated = NULL;
1143 int current_repeated_start1 = 0;
1144 int current_repeated_start2 = 0;
1145
1146 // Now that we have two sorted lists, we can detect fields which appear only
1147 // in one list or the other by traversing them simultaneously.
1148 int index1 = 0;
1149 int index2 = 0;
1150 while (index1 < fields1.size() || index2 < fields2.size()) {
1151 enum { ADDITION, DELETION, MODIFICATION, COMPARE_GROUPS,
1152 NO_CHANGE } change_type;
1153
1154 // focus_field is the field we're currently reporting on. (In the case
1155 // of a modification, it's the field on the left side.)
1156 const UnknownField* focus_field;
1157 bool match = false;
1158
1159 if (index2 == fields2.size() ||
1160 (index1 < fields1.size() &&
1161 is_before(fields1[index1], fields2[index2]))) {
1162 // fields1[index1] is not present in fields2.
1163 change_type = DELETION;
1164 focus_field = fields1[index1].second;
1165 } else if (index1 == fields1.size() ||
1166 is_before(fields2[index2], fields1[index1])) {
1167 // fields2[index2] is not present in fields1.
1168 if (scope_ == PARTIAL) {
1169 // Ignore.
1170 ++index2;
1171 continue;
1172 }
1173 change_type = ADDITION;
1174 focus_field = fields2[index2].second;
1175 } else {
1176 // Field type and number are the same. See if the values differ.
1177 change_type = MODIFICATION;
1178 focus_field = fields1[index1].second;
1179
1180 switch (focus_field->type()) {
1181 case UnknownField::TYPE_VARINT:
1182 match = fields1[index1].second->varint() ==
1183 fields2[index2].second->varint();
1184 break;
1185 case UnknownField::TYPE_FIXED32:
1186 match = fields1[index1].second->fixed32() ==
1187 fields2[index2].second->fixed32();
1188 break;
1189 case UnknownField::TYPE_FIXED64:
1190 match = fields1[index1].second->fixed64() ==
1191 fields2[index2].second->fixed64();
1192 break;
1193 case UnknownField::TYPE_LENGTH_DELIMITED:
1194 match = fields1[index1].second->length_delimited() ==
1195 fields2[index2].second->length_delimited();
1196 break;
1197 case UnknownField::TYPE_GROUP:
1198 // We must deal with this later, after building the SpecificField.
1199 change_type = COMPARE_GROUPS;
1200 break;
1201 }
1202 if (match && change_type != COMPARE_GROUPS) {
1203 change_type = NO_CHANGE;
1204 }
1205 }
1206
1207 if (current_repeated == NULL ||
1208 focus_field->number() != current_repeated->number() ||
1209 focus_field->type() != current_repeated->type()) {
1210 // We've started a new repeated field.
1211 current_repeated = focus_field;
1212 current_repeated_start1 = index1;
1213 current_repeated_start2 = index2;
1214 }
1215
1216 if (change_type == NO_CHANGE && reporter_ == NULL) {
1217 // Fields were already compared and matched and we have no reporter.
1218 ++index1;
1219 ++index2;
1220 continue;
1221 }
1222
1223 // Build the SpecificField. This is slightly complicated.
1224 SpecificField specific_field;
1225 specific_field.unknown_field_number = focus_field->number();
1226 specific_field.unknown_field_type = focus_field->type();
1227
1228 specific_field.unknown_field_set1 = &unknown_field_set1;
1229 specific_field.unknown_field_set2 = &unknown_field_set2;
1230
1231 if (change_type != ADDITION) {
1232 specific_field.unknown_field_index1 = fields1[index1].first;
1233 }
1234 if (change_type != DELETION) {
1235 specific_field.unknown_field_index2 = fields2[index2].first;
1236 }
1237
1238 // Calculate the field index.
1239 if (change_type == ADDITION) {
1240 specific_field.index = index2 - current_repeated_start2;
1241 specific_field.new_index = index2 - current_repeated_start2;
1242 } else {
1243 specific_field.index = index1 - current_repeated_start1;
1244 specific_field.new_index = index2 - current_repeated_start2;
1245 }
1246
1247 if (IsUnknownFieldIgnored(message1, message2, specific_field,
1248 *parent_field)) {
1249 if (reporter_ != NULL) {
1250 parent_field->push_back(specific_field);
1251 reporter_->ReportUnknownFieldIgnored(message1, message2, *parent_field);
1252 parent_field->pop_back();
1253 }
1254 return true;
1255 }
1256
1257 if (change_type == ADDITION || change_type == DELETION ||
1258 change_type == MODIFICATION) {
1259 if (reporter_ == NULL) {
1260 // We found a difference and we have no reproter.
1261 return false;
1262 }
1263 is_different = true;
1264 }
1265
1266 parent_field->push_back(specific_field);
1267
1268 switch (change_type) {
1269 case ADDITION:
1270 reporter_->ReportAdded(message1, message2, *parent_field);
1271 ++index2;
1272 break;
1273 case DELETION:
1274 reporter_->ReportDeleted(message1, message2, *parent_field);
1275 ++index1;
1276 break;
1277 case MODIFICATION:
1278 reporter_->ReportModified(message1, message2, *parent_field);
1279 ++index1;
1280 ++index2;
1281 break;
1282 case COMPARE_GROUPS:
1283 if (!CompareUnknownFields(message1, message2,
1284 fields1[index1].second->group(),
1285 fields2[index2].second->group(),
1286 parent_field)) {
1287 if (reporter_ == NULL) return false;
1288 is_different = true;
1289 reporter_->ReportModified(message1, message2, *parent_field);
1290 }
1291 ++index1;
1292 ++index2;
1293 break;
1294 case NO_CHANGE:
1295 ++index1;
1296 ++index2;
1297 if (report_matches_) {
1298 reporter_->ReportMatched(message1, message2, *parent_field);
1299 }
1300 }
1301
1302 parent_field->pop_back();
1303 }
1304
1305 return !is_different;
1306}
1307
1308namespace {
1309
1310// Find maximum bipartite matching using the argumenting path algorithm.
1311class MaximumMatcher {
1312 public:
1313 typedef ResultCallback2<bool, int, int> NodeMatchCallback;
1314 // MaximumMatcher takes ownership of the passed in callback and uses it to
1315 // determine whether a node on the left side of the bipartial graph matches
1316 // a node on the right side. count1 is the number of nodes on the left side
1317 // of the graph and count2 to is the number of nodes on the right side.
1318 // Every node is referred to using 0-based indices.
1319 // If a maximum match is found, the result will be stored in match_list1 and
1320 // match_list2. match_list1[i] == j means the i-th node on the left side is
1321 // matched to the j-th node on the right side and match_list2[x] == y means
1322 // the x-th node on the right side is matched to y-th node on the left side.
1323 // match_list1[i] == -1 means the node is not matched. Same with match_list2.
1324 MaximumMatcher(int count1, int count2, NodeMatchCallback* callback,
Austin Schuh40c16522018-10-28 20:27:54 -07001325 std::vector<int>* match_list1, std::vector<int>* match_list2);
Brian Silverman9c614bc2016-02-15 20:20:02 -05001326 // Find a maximum match and return the number of matched node pairs.
1327 // If early_return is true, this method will return 0 immediately when it
1328 // finds that not all nodes on the left side can be matched.
1329 int FindMaximumMatch(bool early_return);
1330 private:
1331 // Determines whether the node on the left side of the bipartial graph
1332 // matches the one on the right side.
1333 bool Match(int left, int right);
1334 // Find an argumenting path starting from the node v on the left side. If a
1335 // path can be found, update match_list2_ to reflect the path and return
1336 // true.
Austin Schuh40c16522018-10-28 20:27:54 -07001337 bool FindArgumentPathDFS(int v, std::vector<bool>* visited);
Brian Silverman9c614bc2016-02-15 20:20:02 -05001338
1339 int count1_;
1340 int count2_;
Austin Schuh40c16522018-10-28 20:27:54 -07001341 std::unique_ptr<NodeMatchCallback> match_callback_;
1342 std::map<std::pair<int, int>, bool> cached_match_results_;
1343 std::vector<int>* match_list1_;
1344 std::vector<int>* match_list2_;
Brian Silverman9c614bc2016-02-15 20:20:02 -05001345 GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MaximumMatcher);
1346};
1347
1348MaximumMatcher::MaximumMatcher(int count1, int count2,
1349 NodeMatchCallback* callback,
Austin Schuh40c16522018-10-28 20:27:54 -07001350 std::vector<int>* match_list1,
1351 std::vector<int>* match_list2)
Brian Silverman9c614bc2016-02-15 20:20:02 -05001352 : count1_(count1), count2_(count2), match_callback_(callback),
1353 match_list1_(match_list1), match_list2_(match_list2) {
1354 match_list1_->assign(count1, -1);
1355 match_list2_->assign(count2, -1);
1356}
1357
1358int MaximumMatcher::FindMaximumMatch(bool early_return) {
1359 int result = 0;
1360 for (int i = 0; i < count1_; ++i) {
Austin Schuh40c16522018-10-28 20:27:54 -07001361 std::vector<bool> visited(count1_);
Brian Silverman9c614bc2016-02-15 20:20:02 -05001362 if (FindArgumentPathDFS(i, &visited)) {
1363 ++result;
1364 } else if (early_return) {
1365 return 0;
1366 }
1367 }
1368 // Backfill match_list1_ as we only filled match_list2_ when finding
1369 // argumenting pathes.
1370 for (int i = 0; i < count2_; ++i) {
1371 if ((*match_list2_)[i] != -1) {
1372 (*match_list1_)[(*match_list2_)[i]] = i;
1373 }
1374 }
1375 return result;
1376}
1377
1378bool MaximumMatcher::Match(int left, int right) {
Austin Schuh40c16522018-10-28 20:27:54 -07001379 std::pair<int, int> p(left, right);
1380 std::map<std::pair<int, int>, bool>::iterator it =
1381 cached_match_results_.find(p);
Brian Silverman9c614bc2016-02-15 20:20:02 -05001382 if (it != cached_match_results_.end()) {
1383 return it->second;
1384 }
1385 cached_match_results_[p] = match_callback_->Run(left, right);
1386 return cached_match_results_[p];
1387}
1388
Austin Schuh40c16522018-10-28 20:27:54 -07001389bool MaximumMatcher::FindArgumentPathDFS(int v, std::vector<bool>* visited) {
Brian Silverman9c614bc2016-02-15 20:20:02 -05001390 (*visited)[v] = true;
1391 // We try to match those un-matched nodes on the right side first. This is
1392 // the step that the navie greedy matching algorithm uses. In the best cases
1393 // where the greedy algorithm can find a maximum matching, we will always
1394 // find a match in this step and the performance will be identical to the
1395 // greedy algorithm.
1396 for (int i = 0; i < count2_; ++i) {
1397 int matched = (*match_list2_)[i];
1398 if (matched == -1 && Match(v, i)) {
1399 (*match_list2_)[i] = v;
1400 return true;
1401 }
1402 }
1403 // Then we try those already matched nodes and see if we can find an
1404 // alternaive match for the node matched to them.
1405 // The greedy algorithm will stop before this and fail to produce the
1406 // correct result.
1407 for (int i = 0; i < count2_; ++i) {
1408 int matched = (*match_list2_)[i];
1409 if (matched != -1 && Match(v, i)) {
1410 if (!(*visited)[matched] && FindArgumentPathDFS(matched, visited)) {
1411 (*match_list2_)[i] = v;
1412 return true;
1413 }
1414 }
1415 }
1416 return false;
1417}
1418
1419} // namespace
1420
1421bool MessageDifferencer::MatchRepeatedFieldIndices(
1422 const Message& message1,
1423 const Message& message2,
1424 const FieldDescriptor* repeated_field,
Austin Schuh40c16522018-10-28 20:27:54 -07001425 const std::vector<SpecificField>& parent_fields,
1426 std::vector<int>* match_list1,
1427 std::vector<int>* match_list2) {
Brian Silverman9c614bc2016-02-15 20:20:02 -05001428 const int count1 =
1429 message1.GetReflection()->FieldSize(message1, repeated_field);
1430 const int count2 =
1431 message2.GetReflection()->FieldSize(message2, repeated_field);
1432 const MapKeyComparator* key_comparator = GetMapKeyComparator(repeated_field);
1433
1434 match_list1->assign(count1, -1);
1435 match_list2->assign(count2, -1);
1436
Brian Silverman9c614bc2016-02-15 20:20:02 -05001437 bool success = true;
1438 // Find potential match if this is a special repeated field.
1439 if (key_comparator != NULL || IsTreatedAsSet(repeated_field)) {
1440 if (scope_ == PARTIAL) {
1441 // When partial matching is enabled, Compare(a, b) && Compare(a, c)
Austin Schuh40c16522018-10-28 20:27:54 -07001442 // doesn't necessarily imply Compare(b, c). Therefore a naive greedy
Brian Silverman9c614bc2016-02-15 20:20:02 -05001443 // algorithm will fail to find a maximum matching.
1444 // Here we use the argumenting path algorithm.
1445 MaximumMatcher::NodeMatchCallback* callback =
Austin Schuh40c16522018-10-28 20:27:54 -07001446 ::google::protobuf::NewPermanentCallback(
Brian Silverman9c614bc2016-02-15 20:20:02 -05001447 this, &MessageDifferencer::IsMatch,
1448 repeated_field, key_comparator,
1449 &message1, &message2, parent_fields);
1450 MaximumMatcher matcher(count1, count2, callback, match_list1,
1451 match_list2);
1452 // If diff info is not needed, we should end the matching process as
1453 // soon as possible if not all items can be matched.
1454 bool early_return = (reporter_ == NULL);
1455 int match_count = matcher.FindMaximumMatch(early_return);
1456 if (match_count != count1 && reporter_ == NULL) return false;
1457 success = success && (match_count == count1);
1458 } else {
Austin Schuh40c16522018-10-28 20:27:54 -07001459 int start_offset = 0;
1460 // If the two repeated fields are treated as sets, optimize for the case
1461 // where both start with same items stored in the same order.
1462 if (IsTreatedAsSet(repeated_field)) {
1463 start_offset = std::min(count1, count2);
1464 for (int i = 0; i < count1 && i < count2; i++) {
1465 if (IsMatch(repeated_field, key_comparator, &message1, &message2,
1466 parent_fields, i, i)) {
1467 match_list1->at(i) = i;
1468 match_list2->at(i) = i;
1469 } else {
1470 start_offset = i;
1471 break;
1472 }
1473 }
1474 }
1475 for (int i = start_offset; i < count1; ++i) {
Brian Silverman9c614bc2016-02-15 20:20:02 -05001476 // Indicates any matched elements for this repeated field.
1477 bool match = false;
1478
Austin Schuh40c16522018-10-28 20:27:54 -07001479 for (int j = start_offset; j < count2; j++) {
Brian Silverman9c614bc2016-02-15 20:20:02 -05001480 if (match_list2->at(j) != -1) continue;
Brian Silverman9c614bc2016-02-15 20:20:02 -05001481
1482 match = IsMatch(repeated_field, key_comparator,
1483 &message1, &message2, parent_fields, i, j);
1484
1485 if (match) {
Austin Schuh40c16522018-10-28 20:27:54 -07001486 match_list1->at(i) = j;
1487 match_list2->at(j) = i;
Brian Silverman9c614bc2016-02-15 20:20:02 -05001488 break;
1489 }
1490 }
1491 if (!match && reporter_ == NULL) return false;
1492 success = success && match;
1493 }
1494 }
1495 } else {
1496 // If this field should be treated as list, just label the match_list.
1497 for (int i = 0; i < count1 && i < count2; i++) {
1498 match_list1->at(i) = i;
1499 match_list2->at(i) = i;
1500 }
1501 }
1502
1503 return success;
1504}
1505
1506FieldComparator::ComparisonResult MessageDifferencer::GetFieldComparisonResult(
1507 const Message& message1, const Message& message2,
1508 const FieldDescriptor* field, int index1, int index2,
1509 const FieldContext* field_context) {
1510 FieldComparator* comparator = field_comparator_ != NULL ?
1511 field_comparator_ : &default_field_comparator_;
1512 return comparator->Compare(message1, message2, field,
1513 index1, index2, field_context);
1514}
1515
1516// ===========================================================================
1517
1518MessageDifferencer::Reporter::Reporter() { }
1519MessageDifferencer::Reporter::~Reporter() {}
1520
1521// ===========================================================================
1522
1523MessageDifferencer::MapKeyComparator::MapKeyComparator() {}
1524MessageDifferencer::MapKeyComparator::~MapKeyComparator() {}
1525
1526// ===========================================================================
1527
1528MessageDifferencer::IgnoreCriteria::IgnoreCriteria() {}
1529MessageDifferencer::IgnoreCriteria::~IgnoreCriteria() {}
1530
1531// ===========================================================================
1532
1533// Note that the printer's delimiter is not used, because if we are given a
1534// printer, we don't know its delimiter.
1535MessageDifferencer::StreamReporter::StreamReporter(
1536 io::ZeroCopyOutputStream* output) : printer_(new io::Printer(output, '$')),
1537 delete_printer_(true),
1538 report_modified_aggregates_(false) { }
1539
1540MessageDifferencer::StreamReporter::StreamReporter(
1541 io::Printer* printer) : printer_(printer),
1542 delete_printer_(false),
1543 report_modified_aggregates_(false) { }
1544
1545MessageDifferencer::StreamReporter::~StreamReporter() {
1546 if (delete_printer_) delete printer_;
1547}
1548
1549void MessageDifferencer::StreamReporter::PrintPath(
Austin Schuh40c16522018-10-28 20:27:54 -07001550 const std::vector<SpecificField>& field_path, bool left_side) {
Brian Silverman9c614bc2016-02-15 20:20:02 -05001551 for (int i = 0; i < field_path.size(); ++i) {
1552 if (i > 0) {
1553 printer_->Print(".");
1554 }
1555
1556 SpecificField specific_field = field_path[i];
1557
1558 if (specific_field.field != NULL) {
1559 if (specific_field.field->is_extension()) {
1560 printer_->Print("($name$)", "name",
1561 specific_field.field->full_name());
1562 } else {
1563 printer_->PrintRaw(specific_field.field->name());
1564 }
Austin Schuh40c16522018-10-28 20:27:54 -07001565 if (specific_field.field->is_map()) {
1566 // Don't print index in a map field; they are semantically unordered.
1567 continue;
1568 }
Brian Silverman9c614bc2016-02-15 20:20:02 -05001569 } else {
1570 printer_->PrintRaw(SimpleItoa(specific_field.unknown_field_number));
1571 }
1572 if (left_side && specific_field.index >= 0) {
1573 printer_->Print("[$name$]", "name", SimpleItoa(specific_field.index));
1574 }
1575 if (!left_side && specific_field.new_index >= 0) {
1576 printer_->Print("[$name$]", "name", SimpleItoa(specific_field.new_index));
1577 }
1578 }
1579}
1580
Austin Schuh40c16522018-10-28 20:27:54 -07001581void MessageDifferencer::StreamReporter::PrintPath(
1582 const std::vector<SpecificField>& field_path, bool left_side,
1583 const Message& message) {
1584 PrintPath(field_path, left_side);
1585}
1586
Brian Silverman9c614bc2016-02-15 20:20:02 -05001587void MessageDifferencer::
1588StreamReporter::PrintValue(const Message& message,
Austin Schuh40c16522018-10-28 20:27:54 -07001589 const std::vector<SpecificField>& field_path,
Brian Silverman9c614bc2016-02-15 20:20:02 -05001590 bool left_side) {
1591 const SpecificField& specific_field = field_path.back();
1592 const FieldDescriptor* field = specific_field.field;
1593 if (field != NULL) {
1594 string output;
1595 int index = left_side ? specific_field.index : specific_field.new_index;
1596 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
1597 const Reflection* reflection = message.GetReflection();
1598 const Message& field_message = field->is_repeated() ?
1599 reflection->GetRepeatedMessage(message, field, index) :
1600 reflection->GetMessage(message, field);
1601 output = field_message.ShortDebugString();
1602 if (output.empty()) {
1603 printer_->Print("{ }");
1604 } else {
1605 printer_->Print("{ $name$ }", "name", output);
1606 }
1607 } else {
1608 TextFormat::PrintFieldValueToString(message, field, index, &output);
1609 printer_->PrintRaw(output);
1610 }
1611 } else {
1612 const UnknownFieldSet* unknown_fields =
1613 (left_side ?
1614 specific_field.unknown_field_set1 :
1615 specific_field.unknown_field_set2);
1616 const UnknownField* unknown_field = &unknown_fields->field(
1617 left_side ?
1618 specific_field.unknown_field_index1 :
1619 specific_field.unknown_field_index2);
1620 PrintUnknownFieldValue(unknown_field);
1621 }
1622}
1623
1624void MessageDifferencer::
1625StreamReporter::PrintUnknownFieldValue(const UnknownField* unknown_field) {
1626 GOOGLE_CHECK(unknown_field != NULL) << " Cannot print NULL unknown_field.";
1627
1628 string output;
1629 switch (unknown_field->type()) {
1630 case UnknownField::TYPE_VARINT:
1631 output = SimpleItoa(unknown_field->varint());
1632 break;
1633 case UnknownField::TYPE_FIXED32:
1634 output = StrCat("0x", strings::Hex(unknown_field->fixed32(),
1635 strings::ZERO_PAD_8));
1636 break;
1637 case UnknownField::TYPE_FIXED64:
1638 output = StrCat("0x", strings::Hex(unknown_field->fixed64(),
1639 strings::ZERO_PAD_16));
1640 break;
1641 case UnknownField::TYPE_LENGTH_DELIMITED:
1642 output = StringPrintf("\"%s\"",
1643 CEscape(unknown_field->length_delimited()).c_str());
1644 break;
1645 case UnknownField::TYPE_GROUP:
1646 // TODO(kenton): Print the contents of the group like we do for
1647 // messages. Requires an equivalent of ShortDebugString() for
1648 // UnknownFieldSet.
1649 output = "{ ... }";
1650 break;
1651 }
1652 printer_->PrintRaw(output);
1653}
1654
1655void MessageDifferencer::StreamReporter::Print(const string& str) {
1656 printer_->Print(str.c_str());
1657}
1658
1659void MessageDifferencer::StreamReporter::ReportAdded(
1660 const Message& message1,
1661 const Message& message2,
Austin Schuh40c16522018-10-28 20:27:54 -07001662 const std::vector<SpecificField>& field_path) {
Brian Silverman9c614bc2016-02-15 20:20:02 -05001663 printer_->Print("added: ");
Austin Schuh40c16522018-10-28 20:27:54 -07001664 PrintPath(field_path, false, message2);
Brian Silverman9c614bc2016-02-15 20:20:02 -05001665 printer_->Print(": ");
1666 PrintValue(message2, field_path, false);
1667 printer_->Print("\n"); // Print for newlines.
1668}
1669
1670void MessageDifferencer::StreamReporter::ReportDeleted(
1671 const Message& message1,
1672 const Message& message2,
Austin Schuh40c16522018-10-28 20:27:54 -07001673 const std::vector<SpecificField>& field_path) {
Brian Silverman9c614bc2016-02-15 20:20:02 -05001674 printer_->Print("deleted: ");
Austin Schuh40c16522018-10-28 20:27:54 -07001675 PrintPath(field_path, true, message1);
Brian Silverman9c614bc2016-02-15 20:20:02 -05001676 printer_->Print(": ");
1677 PrintValue(message1, field_path, true);
1678 printer_->Print("\n"); // Print for newlines
1679}
1680
1681void MessageDifferencer::StreamReporter::ReportModified(
1682 const Message& message1,
1683 const Message& message2,
Austin Schuh40c16522018-10-28 20:27:54 -07001684 const std::vector<SpecificField>& field_path) {
Brian Silverman9c614bc2016-02-15 20:20:02 -05001685 if (!report_modified_aggregates_ && field_path.back().field == NULL) {
1686 if (field_path.back().unknown_field_type == UnknownField::TYPE_GROUP) {
1687 // Any changes to the subfields have already been printed.
1688 return;
1689 }
1690 } else if (!report_modified_aggregates_) {
1691 if (field_path.back().field->cpp_type() ==
1692 FieldDescriptor::CPPTYPE_MESSAGE) {
1693 // Any changes to the subfields have already been printed.
1694 return;
1695 }
1696 }
1697
1698 printer_->Print("modified: ");
Austin Schuh40c16522018-10-28 20:27:54 -07001699 PrintPath(field_path, true, message1);
Brian Silverman9c614bc2016-02-15 20:20:02 -05001700 if (CheckPathChanged(field_path)) {
1701 printer_->Print(" -> ");
Austin Schuh40c16522018-10-28 20:27:54 -07001702 PrintPath(field_path, false, message2);
Brian Silverman9c614bc2016-02-15 20:20:02 -05001703 }
1704 printer_->Print(": ");
1705 PrintValue(message1, field_path, true);
1706 printer_->Print(" -> ");
1707 PrintValue(message2, field_path, false);
1708 printer_->Print("\n"); // Print for newlines.
1709}
1710
1711void MessageDifferencer::StreamReporter::ReportMoved(
1712 const Message& message1,
1713 const Message& message2,
Austin Schuh40c16522018-10-28 20:27:54 -07001714 const std::vector<SpecificField>& field_path) {
Brian Silverman9c614bc2016-02-15 20:20:02 -05001715 printer_->Print("moved: ");
Austin Schuh40c16522018-10-28 20:27:54 -07001716 PrintPath(field_path, true, message1);
Brian Silverman9c614bc2016-02-15 20:20:02 -05001717 printer_->Print(" -> ");
Austin Schuh40c16522018-10-28 20:27:54 -07001718 PrintPath(field_path, false, message2);
Brian Silverman9c614bc2016-02-15 20:20:02 -05001719 printer_->Print(" : ");
1720 PrintValue(message1, field_path, true);
1721 printer_->Print("\n"); // Print for newlines.
1722}
1723
1724void MessageDifferencer::StreamReporter::ReportMatched(
1725 const Message& message1,
1726 const Message& message2,
Austin Schuh40c16522018-10-28 20:27:54 -07001727 const std::vector<SpecificField>& field_path) {
Brian Silverman9c614bc2016-02-15 20:20:02 -05001728 printer_->Print("matched: ");
Austin Schuh40c16522018-10-28 20:27:54 -07001729 PrintPath(field_path, true, message1);
Brian Silverman9c614bc2016-02-15 20:20:02 -05001730 if (CheckPathChanged(field_path)) {
1731 printer_->Print(" -> ");
Austin Schuh40c16522018-10-28 20:27:54 -07001732 PrintPath(field_path, false, message2);
Brian Silverman9c614bc2016-02-15 20:20:02 -05001733 }
1734 printer_->Print(" : ");
1735 PrintValue(message1, field_path, true);
1736 printer_->Print("\n"); // Print for newlines.
1737}
1738
1739void MessageDifferencer::StreamReporter::ReportIgnored(
1740 const Message& message1,
1741 const Message& message2,
Austin Schuh40c16522018-10-28 20:27:54 -07001742 const std::vector<SpecificField>& field_path) {
Brian Silverman9c614bc2016-02-15 20:20:02 -05001743 printer_->Print("ignored: ");
Austin Schuh40c16522018-10-28 20:27:54 -07001744 PrintPath(field_path, true, message1);
Brian Silverman9c614bc2016-02-15 20:20:02 -05001745 if (CheckPathChanged(field_path)) {
1746 printer_->Print(" -> ");
Austin Schuh40c16522018-10-28 20:27:54 -07001747 PrintPath(field_path, false, message2);
Brian Silverman9c614bc2016-02-15 20:20:02 -05001748 }
1749 printer_->Print("\n"); // Print for newlines.
1750}
1751
1752void MessageDifferencer::StreamReporter::ReportUnknownFieldIgnored(
1753 const Message& message1, const Message& message2,
Austin Schuh40c16522018-10-28 20:27:54 -07001754 const std::vector<SpecificField>& field_path) {
Brian Silverman9c614bc2016-02-15 20:20:02 -05001755 printer_->Print("ignored: ");
Austin Schuh40c16522018-10-28 20:27:54 -07001756 PrintPath(field_path, true, message1);
Brian Silverman9c614bc2016-02-15 20:20:02 -05001757 if (CheckPathChanged(field_path)) {
1758 printer_->Print(" -> ");
Austin Schuh40c16522018-10-28 20:27:54 -07001759 PrintPath(field_path, false, message2);
Brian Silverman9c614bc2016-02-15 20:20:02 -05001760 }
1761 printer_->Print("\n"); // Print for newlines.
1762}
1763
Austin Schuh40c16522018-10-28 20:27:54 -07001764MessageDifferencer::MapKeyComparator*
1765MessageDifferencer::CreateMultipleFieldsMapKeyComparator(
1766 const std::vector<std::vector<const FieldDescriptor*> >& key_field_paths) {
1767 return new MultipleFieldsMapKeyComparator(this, key_field_paths);
1768}
1769
1770
Brian Silverman9c614bc2016-02-15 20:20:02 -05001771} // namespace util
1772} // namespace protobuf
1773} // namespace google