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 // This file defines static methods and classes for comparing Protocol 36 // Messages. 37 // 38 // Aug. 2008: Added Unknown Fields Comparison for messages. 39 // Aug. 2009: Added different options to compare repeated fields. 40 // Apr. 2010: Moved field comparison to FieldComparator. 41 42 #ifndef GOOGLE_PROTOBUF_UTIL_MESSAGE_DIFFERENCER_H__ 43 #define GOOGLE_PROTOBUF_UTIL_MESSAGE_DIFFERENCER_H__ 44 45 #include <map> 46 #include <set> 47 #include <string> 48 #include <vector> 49 #include <google/protobuf/descriptor.h> // FieldDescriptor 50 #include <google/protobuf/message.h> // Message 51 #include <google/protobuf/unknown_field_set.h> 52 #include <google/protobuf/util/field_comparator.h> 53 54 namespace google { 55 namespace protobuf { 56 57 class DynamicMessageFactory; 58 class FieldDescriptor; 59 60 namespace io { 61 class ZeroCopyOutputStream; 62 class Printer; 63 } 64 65 namespace util { 66 67 class FieldContext; // declared below MessageDifferencer 68 69 // A basic differencer that can be used to determine 70 // the differences between two specified Protocol Messages. If any differences 71 // are found, the Compare method will return false, and any differencer reporter 72 // specified via ReportDifferencesTo will have its reporting methods called (see 73 // below for implementation of the report). Based off of the original 74 // ProtocolDifferencer implementation in //net/proto/protocol-differencer.h 75 // (Thanks Todd!). 76 // 77 // MessageDifferencer REQUIRES that compared messages be the same type, defined 78 // as messages that share the same descriptor. If not, the behavior of this 79 // class is undefined. 80 // 81 // People disagree on what MessageDifferencer should do when asked to compare 82 // messages with different descriptors. Some people think it should always 83 // return false. Others expect it to try to look for similar fields and 84 // compare them anyway -- especially if the descriptors happen to be identical. 85 // If we chose either of these behaviors, some set of people would find it 86 // surprising, and could end up writing code expecting the other behavior 87 // without realizing their error. Therefore, we forbid that usage. 88 // 89 // This class is implemented based on the proto2 reflection. The performance 90 // should be good enough for normal usages. However, for places where the 91 // performance is extremely sensitive, there are several alternatives: 92 // - Comparing serialized string 93 // Downside: false negatives (there are messages that are the same but their 94 // serialized strings are different). 95 // - Equals code generator by compiler plugin (net/proto2/contrib/equals_plugin) 96 // Downside: more generated code; maintenance overhead for the additional rule 97 // (must be in sync with the original proto_library). 98 // 99 // Note on handling of google.protobuf.Any: MessageDifferencer automatically 100 // unpacks Any::value into a Message and compares its individual fields. 101 // Messages encoded in a repeated Any cannot be compared using TreatAsMap. 102 // 103 // 104 // Note on thread-safety: MessageDifferencer is *not* thread-safe. You need to 105 // guard it with a lock to use the same MessageDifferencer instance from 106 // multiple threads. Note that it's fine to call static comparison methods 107 // (like MessageDifferencer::Equals) concurrently. 108 class LIBPROTOBUF_EXPORT MessageDifferencer { 109 public: 110 // Determines whether the supplied messages are equal. Equality is defined as 111 // all fields within the two messages being set to the same value. Primitive 112 // fields and strings are compared by value while embedded messages/groups 113 // are compared as if via a recursive call. Use IgnoreField() and Compare() 114 // if some fields should be ignored in the comparison. 115 // 116 // This method REQUIRES that the two messages have the same 117 // Descriptor (message1.GetDescriptor() == message2.GetDescriptor()). 118 static bool Equals(const Message& message1, const Message& message2); 119 120 // Determines whether the supplied messages are equivalent. Equivalency is 121 // defined as all fields within the two messages having the same value. This 122 // differs from the Equals method above in that fields with default values 123 // are considered set to said value automatically. For details on how default 124 // values are defined for each field type, see http://shortn/_x2Gv6XFrWt. 125 // Also, Equivalent() ignores unknown fields. Use IgnoreField() and Compare() 126 // if some fields should be ignored in the comparison. 127 // 128 // This method REQUIRES that the two messages have the same 129 // Descriptor (message1.GetDescriptor() == message2.GetDescriptor()). 130 static bool Equivalent(const Message& message1, const Message& message2); 131 132 // Determines whether the supplied messages are approximately equal. 133 // Approximate equality is defined as all fields within the two messages 134 // being approximately equal. Primitive (non-float) fields and strings are 135 // compared by value, floats are compared using MathUtil::AlmostEquals() and 136 // embedded messages/groups are compared as if via a recursive call. Use 137 // IgnoreField() and Compare() if some fields should be ignored in the 138 // comparison. 139 // 140 // This method REQUIRES that the two messages have the same 141 // Descriptor (message1.GetDescriptor() == message2.GetDescriptor()). 142 static bool ApproximatelyEquals(const Message& message1, 143 const Message& message2); 144 145 // Determines whether the supplied messages are approximately equivalent. 146 // Approximate equivalency is defined as all fields within the two messages 147 // being approximately equivalent. As in 148 // MessageDifferencer::ApproximatelyEquals, primitive (non-float) fields and 149 // strings are compared by value, floats are compared using 150 // MathUtil::AlmostEquals() and embedded messages/groups are compared as if 151 // via a recursive call. However, fields with default values are considered 152 // set to said value, as per MessageDiffencer::Equivalent. Use IgnoreField() 153 // and Compare() if some fields should be ignored in the comparison. 154 // 155 // This method REQUIRES that the two messages have the same 156 // Descriptor (message1.GetDescriptor() == message2.GetDescriptor()). 157 static bool ApproximatelyEquivalent(const Message& message1, 158 const Message& message2); 159 160 // Identifies an individual field in a message instance. Used for field_path, 161 // below. 162 struct SpecificField { 163 // For known fields, "field" is filled in and "unknown_field_number" is -1. 164 // For unknown fields, "field" is NULL, "unknown_field_number" is the field 165 // number, and "unknown_field_type" is its type. 166 const FieldDescriptor* field; 167 int unknown_field_number; 168 UnknownField::Type unknown_field_type; 169 170 // If this a repeated field, "index" is the index within it. For unknown 171 // fields, this is the index of the field among all unknown fields of the 172 // same field number and type. 173 int index; 174 175 // If "field" is a repeated field which is being treated as a map or 176 // a set (see TreatAsMap() and TreatAsSet(), below), new_index indicates 177 // the index the position to which the element has moved. This only 178 // applies to ReportMoved() and (in the case of TreatAsMap()) 179 // ReportModified(). In all other cases, "new_index" will have the same 180 // value as "index". 181 int new_index; 182 183 // For unknown fields, these are the pointers to the UnknownFieldSet 184 // containing the unknown fields. In certain cases (e.g. proto1's 185 // MessageSet, or nested groups of unknown fields), these may differ from 186 // the messages' internal UnknownFieldSets. 187 const UnknownFieldSet* unknown_field_set1; 188 const UnknownFieldSet* unknown_field_set2; 189 190 // For unknown fields, these are the index of the field within the 191 // UnknownFieldSets. One or the other will be -1 when 192 // reporting an addition or deletion. 193 int unknown_field_index1; 194 int unknown_field_index2; 195 SpecificFieldSpecificField196 SpecificField() 197 : field(NULL), 198 unknown_field_number(-1), 199 index(-1), 200 new_index(-1), 201 unknown_field_set1(NULL), 202 unknown_field_set2(NULL), 203 unknown_field_index1(-1), 204 unknown_field_index2(-1) {} 205 }; 206 207 // Abstract base class from which all MessageDifferencer 208 // reporters derive. The five Report* methods below will be called when 209 // a field has been added, deleted, modified, moved, or matched. The third 210 // argument is a vector of FieldDescriptor pointers which describes the chain 211 // of fields that was taken to find the current field. For example, for a 212 // field found in an embedded message, the vector will contain two 213 // FieldDescriptors. The first will be the field of the embedded message 214 // itself and the second will be the actual field in the embedded message 215 // that was added/deleted/modified. 216 class LIBPROTOBUF_EXPORT Reporter { 217 public: 218 Reporter(); 219 virtual ~Reporter(); 220 221 // Reports that a field has been added into Message2. 222 virtual void ReportAdded( 223 const Message& message1, const Message& message2, 224 const vector<SpecificField>& field_path) = 0; 225 226 // Reports that a field has been deleted from Message1. 227 virtual void ReportDeleted( 228 const Message& message1, 229 const Message& message2, 230 const vector<SpecificField>& field_path) = 0; 231 232 // Reports that the value of a field has been modified. 233 virtual void ReportModified( 234 const Message& message1, 235 const Message& message2, 236 const vector<SpecificField>& field_path) = 0; 237 238 // Reports that a repeated field has been moved to another location. This 239 // only applies when using TreatAsSet or TreatAsMap() -- see below. Also 240 // note that for any given field, ReportModified and ReportMoved are 241 // mutually exclusive. If a field has been both moved and modified, then 242 // only ReportModified will be called. ReportMoved(const Message & message1,const Message & message2,const vector<SpecificField> & field_path)243 virtual void ReportMoved( 244 const Message& message1, 245 const Message& message2, 246 const vector<SpecificField>& field_path) { } 247 248 // Reports that two fields match. Useful for doing side-by-side diffs. 249 // This function is mutually exclusive with ReportModified and ReportMoved. 250 // Note that you must call set_report_matches(true) before calling Compare 251 // to make use of this function. ReportMatched(const Message & message1,const Message & message2,const vector<SpecificField> & field_path)252 virtual void ReportMatched( 253 const Message& message1, 254 const Message& message2, 255 const vector<SpecificField>& field_path) { } 256 257 // Reports that two fields would have been compared, but the 258 // comparison has been skipped because the field was marked as 259 // 'ignored' using IgnoreField(). This function is mutually 260 // exclusive with all the other Report() functions. 261 // 262 // The contract of ReportIgnored is slightly different than the 263 // other Report() functions, in that |field_path.back().index| is 264 // always equal to -1, even if the last field is repeated. This is 265 // because while the other Report() functions indicate where in a 266 // repeated field the action (Addition, Deletion, etc...) 267 // happened, when a repeated field is 'ignored', the differencer 268 // simply calls ReportIgnored on the repeated field as a whole and 269 // moves on without looking at its individual elements. 270 // 271 // Furthermore, ReportIgnored() does not indicate whether the 272 // fields were in fact equal or not, as Compare() does not inspect 273 // these fields at all. It is up to the Reporter to decide whether 274 // the fields are equal or not (perhaps with a second call to 275 // Compare()), if it cares. ReportIgnored(const Message & message1,const Message & message2,const vector<SpecificField> & field_path)276 virtual void ReportIgnored( 277 const Message& message1, 278 const Message& message2, 279 const vector<SpecificField>& field_path) { } 280 281 // Report that an unknown field is ignored. (see comment above). 282 // Note this is a different function since the last SpecificField in field 283 // path has a null field. This could break existing Reporter. ReportUnknownFieldIgnored(const Message & message1,const Message & message2,const vector<SpecificField> & field_path)284 virtual void ReportUnknownFieldIgnored( 285 const Message& message1, const Message& message2, 286 const vector<SpecificField>& field_path) {} 287 288 private: 289 GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Reporter); 290 }; 291 292 // MapKeyComparator is used to determine if two elements have the same key 293 // when comparing elements of a repeated field as a map. 294 class LIBPROTOBUF_EXPORT MapKeyComparator { 295 public: 296 MapKeyComparator(); 297 virtual ~MapKeyComparator(); 298 IsMatch(const Message & message1,const Message & message2,const vector<SpecificField> & parent_fields)299 virtual bool IsMatch(const Message& message1, 300 const Message& message2, 301 const vector<SpecificField>& parent_fields) const { 302 GOOGLE_CHECK(false) << "IsMatch() is not implemented."; 303 return false; 304 } 305 306 private: 307 GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapKeyComparator); 308 }; 309 310 // Abstract base class from which all IgnoreCriteria derive. 311 // By adding IgnoreCriteria more complex ignore logic can be implemented. 312 // IgnoreCriteria are registed with AddIgnoreCriteria. For each compared 313 // field IsIgnored is called on each added IgnoreCriteria until one returns 314 // true or all return false. 315 // IsIgnored is called for fields where at least one side has a value. 316 class LIBPROTOBUF_EXPORT IgnoreCriteria { 317 public: 318 IgnoreCriteria(); 319 virtual ~IgnoreCriteria(); 320 321 // Returns true if the field should be ignored. 322 virtual bool IsIgnored( 323 const Message& message1, 324 const Message& message2, 325 const FieldDescriptor* field, 326 const vector<SpecificField>& parent_fields) = 0; 327 328 // Returns true if the unknown field should be ignored. 329 // Note: This will be called for unknown fields as well in which case 330 // field.field will be null. IsUnknownFieldIgnored(const Message & message1,const Message & message2,const SpecificField & field,const vector<SpecificField> & parent_fields)331 virtual bool IsUnknownFieldIgnored( 332 const Message& message1, const Message& message2, 333 const SpecificField& field, 334 const vector<SpecificField>& parent_fields) { 335 return false; 336 } 337 }; 338 339 // To add a Reporter, construct default here, then use ReportDifferencesTo or 340 // ReportDifferencesToString. 341 explicit MessageDifferencer(); 342 343 ~MessageDifferencer(); 344 345 enum MessageFieldComparison { 346 EQUAL, // Fields must be present in both messages 347 // for the messages to be considered the same. 348 EQUIVALENT, // Fields with default values are considered set 349 // for comparison purposes even if not explicitly 350 // set in the messages themselves. Unknown fields 351 // are ignored. 352 }; 353 354 enum Scope { 355 FULL, // All fields of both messages are considered in the comparison. 356 PARTIAL // Only fields present in the first message are considered; fields 357 // set only in the second message will be skipped during 358 // comparison. 359 }; 360 361 // DEPRECATED. Use FieldComparator::FloatComparison instead. 362 enum FloatComparison { 363 EXACT, // Floats and doubles are compared exactly. 364 APPROXIMATE // Floats and doubles are compared using the 365 // MathUtil::AlmostEquals method. 366 }; 367 368 enum RepeatedFieldComparison { 369 AS_LIST, // Repeated fields are compared in order. Differing values at 370 // the same index are reported using ReportModified(). If the 371 // repeated fields have different numbers of elements, the 372 // unpaired elements are reported using ReportAdded() or 373 // ReportDeleted(). 374 AS_SET, // Treat all the repeated fields as sets by default. 375 // See TreatAsSet(), as below. 376 }; 377 378 // The elements of the given repeated field will be treated as a set for 379 // diffing purposes, so different orderings of the same elements will be 380 // considered equal. Elements which are present on both sides of the 381 // comparison but which have changed position will be reported with 382 // ReportMoved(). Elements which only exist on one side or the other are 383 // reported with ReportAdded() and ReportDeleted() regardless of their 384 // positions. ReportModified() is never used for this repeated field. If 385 // the only differences between the compared messages is that some fields 386 // have been moved, then the comparison returns true. 387 // 388 // If the scope of comparison is set to PARTIAL, then in addition to what's 389 // above, extra values added to repeated fields of the second message will 390 // not cause the comparison to fail. 391 // 392 // Note that set comparison is currently O(k * n^2) (where n is the total 393 // number of elements, and k is the average size of each element). In theory 394 // it could be made O(n * k) with a more complex hashing implementation. Feel 395 // free to contribute one if the current implementation is too slow for you. 396 // If partial matching is also enabled, the time complexity will be O(k * n^2 397 // + n^3) in which n^3 is the time complexity of the maximum matching 398 // algorithm. 399 // 400 // REQUIRES: field->is_repeated() and field not registered with TreatAsList 401 void TreatAsSet(const FieldDescriptor* field); 402 403 // The elements of the given repeated field will be treated as a list for 404 // diffing purposes, so different orderings of the same elements will NOT be 405 // considered equal. 406 // 407 // REQUIRED: field->is_repeated() and field not registered with TreatAsSet 408 void TreatAsList(const FieldDescriptor* field); 409 410 // The elements of the given repeated field will be treated as a map for 411 // diffing purposes, with |key| being the map key. Thus, elements with the 412 // same key will be compared even if they do not appear at the same index. 413 // Differences are reported similarly to TreatAsSet(), except that 414 // ReportModified() is used to report elements with the same key but 415 // different values. Note that if an element is both moved and modified, 416 // only ReportModified() will be called. As with TreatAsSet, if the only 417 // differences between the compared messages is that some fields have been 418 // moved, then the comparison returns true. See TreatAsSet for notes on 419 // performance. 420 // 421 // REQUIRES: field->is_repeated() 422 // REQUIRES: field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE 423 // REQUIRES: key->containing_type() == field->message_type() 424 void TreatAsMap(const FieldDescriptor* field, const FieldDescriptor* key); 425 // Same as TreatAsMap except that this method will use multiple fields as 426 // the key in comparison. All specified fields in 'key_fields' should be 427 // present in the compared elements. Two elements will be treated as having 428 // the same key iff they have the same value for every specified field. There 429 // are two steps in the comparison process. The first one is key matching. 430 // Every element from one message will be compared to every element from 431 // the other message. Only fields in 'key_fields' are compared in this step 432 // to decide if two elements have the same key. The second step is value 433 // comparison. Those pairs of elements with the same key (with equal value 434 // for every field in 'key_fields') will be compared in this step. 435 // Time complexity of the first step is O(s * m * n ^ 2) where s is the 436 // average size of the fields specified in 'key_fields', m is the number of 437 // fields in 'key_fields' and n is the number of elements. If partial 438 // matching is enabled, an extra O(n^3) will be incured by the maximum 439 // matching algorithm. The second step is O(k * n) where k is the average 440 // size of each element. 441 void TreatAsMapWithMultipleFieldsAsKey( 442 const FieldDescriptor* field, 443 const vector<const FieldDescriptor*>& key_fields); 444 // Same as TreatAsMapWithMultipleFieldsAsKey, except that each of the field 445 // do not necessarily need to be a direct subfield. Each element in 446 // key_field_paths indicate a path from the message being compared, listing 447 // successive subfield to reach the key field. 448 // 449 // REQUIRES: 450 // for key_field_path in key_field_paths: 451 // key_field_path[0]->containing_type() == field->message_type() 452 // for i in [0, key_field_path.size() - 1): 453 // key_field_path[i+1]->containing_type() == 454 // key_field_path[i]->message_type() 455 // key_field_path[i]->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE 456 // !key_field_path[i]->is_repeated() 457 void TreatAsMapWithMultipleFieldPathsAsKey( 458 const FieldDescriptor* field, 459 const vector<vector<const FieldDescriptor*> >& key_field_paths); 460 461 // Uses a custom MapKeyComparator to determine if two elements have the same 462 // key when comparing a repeated field as a map. 463 // The caller is responsible to delete the key_comparator. 464 // This method varies from TreatAsMapWithMultipleFieldsAsKey only in the 465 // first key matching step. Rather than comparing some specified fields, it 466 // will invoke the IsMatch method of the given 'key_comparator' to decide if 467 // two elements have the same key. 468 void TreatAsMapUsingKeyComparator( 469 const FieldDescriptor* field, 470 const MapKeyComparator* key_comparator); 471 472 // Add a custom ignore criteria that is evaluated in addition to the 473 // ignored fields added with IgnoreField. 474 // Takes ownership of ignore_criteria. 475 void AddIgnoreCriteria(IgnoreCriteria* ignore_criteria); 476 477 // Indicates that any field with the given descriptor should be 478 // ignored for the purposes of comparing two messages. This applies 479 // to fields nested in the message structure as well as top level 480 // ones. When the MessageDifferencer encounters an ignored field, 481 // ReportIgnored is called on the reporter, if one is specified. 482 // 483 // The only place where the field's 'ignored' status is not applied is when 484 // it is being used as a key in a field passed to TreatAsMap or is one of 485 // the fields passed to TreatAsMapWithMultipleFieldsAsKey. 486 // In this case it is compared in key matching but after that it's ignored 487 // in value comparison. 488 void IgnoreField(const FieldDescriptor* field); 489 490 // Sets the field comparator used to determine differences between protocol 491 // buffer fields. By default it's set to a DefaultFieldComparator instance. 492 // MessageDifferencer doesn't take ownership over the passed object. 493 // Note that this method must be called before Compare for the comparator to 494 // be used. 495 void set_field_comparator(FieldComparator* comparator); 496 497 // DEPRECATED. Pass a DefaultFieldComparator instance instead. 498 // Sets the fraction and margin for the float comparison of a given field. 499 // Uses MathUtil::WithinFractionOrMargin to compare the values. 500 // NOTE: this method does nothing if differencer's field comparator has been 501 // set to a custom object. 502 // 503 // REQUIRES: field->cpp_type == FieldDescriptor::CPPTYPE_DOUBLE or 504 // field->cpp_type == FieldDescriptor::CPPTYPE_FLOAT 505 // REQUIRES: float_comparison_ == APPROXIMATE 506 void SetFractionAndMargin(const FieldDescriptor* field, double fraction, 507 double margin); 508 509 // Sets the type of comparison (as defined in the MessageFieldComparison 510 // enumeration above) that is used by this differencer when determining how 511 // to compare fields in messages. 512 void set_message_field_comparison(MessageFieldComparison comparison); 513 514 // Tells the differencer whether or not to report matches. This method must 515 // be called before Compare. The default for a new differencer is false. set_report_matches(bool report_matches)516 void set_report_matches(bool report_matches) { 517 report_matches_ = report_matches; 518 } 519 520 // Sets the scope of the comparison (as defined in the Scope enumeration 521 // above) that is used by this differencer when determining which fields to 522 // compare between the messages. 523 void set_scope(Scope scope); 524 525 // Returns the current scope used by this differencer. 526 Scope scope(); 527 528 // DEPRECATED. Pass a DefaultFieldComparator instance instead. 529 // Sets the type of comparison (as defined in the FloatComparison enumeration 530 // above) that is used by this differencer when comparing float (and double) 531 // fields in messages. 532 // NOTE: this method does nothing if differencer's field comparator has been 533 // set to a custom object. 534 void set_float_comparison(FloatComparison comparison); 535 536 // Sets the type of comparison for repeated field (as defined in the 537 // RepeatedFieldComparison enumeration above) that is used by this 538 // differencer when compare repeated fields in messages. 539 void set_repeated_field_comparison(RepeatedFieldComparison comparison); 540 541 // Compares the two specified messages, returning true if they are the same, 542 // false otherwise. If this method returns false, any changes between the 543 // two messages will be reported if a Reporter was specified via 544 // ReportDifferencesTo (see also ReportDifferencesToString). 545 // 546 // This method REQUIRES that the two messages have the same 547 // Descriptor (message1.GetDescriptor() == message2.GetDescriptor()). 548 bool Compare(const Message& message1, const Message& message2); 549 550 // Same as above, except comparing only the list of fields specified by the 551 // two vectors of FieldDescriptors. 552 bool CompareWithFields(const Message& message1, const Message& message2, 553 const vector<const FieldDescriptor*>& message1_fields, 554 const vector<const FieldDescriptor*>& message2_fields); 555 556 // Automatically creates a reporter that will output the differences 557 // found (if any) to the specified output string pointer. Note that this 558 // method must be called before Compare. 559 void ReportDifferencesToString(string* output); 560 561 // Tells the MessageDifferencer to report differences via the specified 562 // reporter. Note that this method must be called before Compare for 563 // the reporter to be used. It is the responsibility of the caller to delete 564 // this object. 565 // If the provided pointer equals NULL, the MessageDifferencer stops reporting 566 // differences to any previously set reporters or output strings. 567 void ReportDifferencesTo(Reporter* reporter); 568 569 // An implementation of the MessageDifferencer Reporter that outputs 570 // any differences found in human-readable form to the supplied 571 // ZeroCopyOutputStream or Printer. If a printer is used, the delimiter 572 // *must* be '$'. 573 // 574 // WARNING: this reporter does not necessarily flush its output until it is 575 // destroyed. As a result, it is not safe to assume the output is valid or 576 // complete until after you destroy the reporter. For example, if you use a 577 // StreamReporter to write to a StringOutputStream, the target string may 578 // contain uninitialized data until the reporter is destroyed. 579 class LIBPROTOBUF_EXPORT StreamReporter : public Reporter { 580 public: 581 explicit StreamReporter(io::ZeroCopyOutputStream* output); 582 explicit StreamReporter(io::Printer* printer); // delimiter '$' 583 virtual ~StreamReporter(); 584 585 // When set to true, the stream reporter will also output aggregates nodes 586 // (i.e. messages and groups) whose subfields have been modified. When 587 // false, will only report the individual subfields. Defaults to false. set_report_modified_aggregates(bool report)588 void set_report_modified_aggregates(bool report) { 589 report_modified_aggregates_ = report; 590 } 591 592 // The following are implementations of the methods described above. 593 virtual void ReportAdded(const Message& message1, const Message& message2, 594 const vector<SpecificField>& field_path); 595 596 virtual void ReportDeleted(const Message& message1, 597 const Message& message2, 598 const vector<SpecificField>& field_path); 599 600 virtual void ReportModified(const Message& message1, 601 const Message& message2, 602 const vector<SpecificField>& field_path); 603 604 virtual void ReportMoved(const Message& message1, 605 const Message& message2, 606 const vector<SpecificField>& field_path); 607 608 virtual void ReportMatched(const Message& message1, 609 const Message& message2, 610 const vector<SpecificField>& field_path); 611 612 virtual void ReportIgnored(const Message& message1, 613 const Message& message2, 614 const vector<SpecificField>& field_path); 615 616 virtual void ReportUnknownFieldIgnored( 617 const Message& message1, const Message& message2, 618 const vector<SpecificField>& field_path); 619 620 protected: 621 // Prints the specified path of fields to the buffer. 622 virtual void PrintPath(const vector<SpecificField>& field_path, 623 bool left_side); 624 625 // Prints the value of fields to the buffer. left_side is true if the 626 // given message is from the left side of the comparison, false if it 627 // was the right. This is relevant only to decide whether to follow 628 // unknown_field_index1 or unknown_field_index2 when an unknown field 629 // is encountered in field_path. 630 virtual void PrintValue(const Message& message, 631 const vector<SpecificField>& field_path, 632 bool left_side); 633 634 // Prints the specified path of unknown fields to the buffer. 635 virtual void PrintUnknownFieldValue(const UnknownField* unknown_field); 636 637 // Just print a string 638 void Print(const string& str); 639 640 private: 641 io::Printer* printer_; 642 bool delete_printer_; 643 bool report_modified_aggregates_; 644 645 GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StreamReporter); 646 }; 647 648 private: 649 // A MapKeyComparator to be used in TreatAsMapUsingKeyComparator. 650 // Implementation of this class needs to do field value comparison which 651 // relies on some private methods of MessageDifferencer. That's why this 652 // class is declared as a nested class of MessageDifferencer. 653 class MultipleFieldsMapKeyComparator; 654 // Returns true if field1's number() is less than field2's. 655 static bool FieldBefore(const FieldDescriptor* field1, 656 const FieldDescriptor* field2); 657 658 // Combine the two lists of fields into the combined_fields output vector. 659 // All fields present in both lists will always be included in the combined 660 // list. Fields only present in one of the lists will only appear in the 661 // combined list if the corresponding fields_scope option is set to FULL. 662 void CombineFields(const vector<const FieldDescriptor*>& fields1, 663 Scope fields1_scope, 664 const vector<const FieldDescriptor*>& fields2, 665 Scope fields2_scope, 666 vector<const FieldDescriptor*>* combined_fields); 667 668 // Internal version of the Compare method which performs the actual 669 // comparison. The parent_fields vector is a vector containing field 670 // descriptors of all fields accessed to get to this comparison operation 671 // (i.e. if the current message is an embedded message, the parent_fields 672 // vector will contain the field that has this embedded message). 673 bool Compare(const Message& message1, const Message& message2, 674 vector<SpecificField>* parent_fields); 675 676 // Compares all the unknown fields in two messages. 677 bool CompareUnknownFields(const Message& message1, const Message& message2, 678 const google::protobuf::UnknownFieldSet&, 679 const google::protobuf::UnknownFieldSet&, 680 vector<SpecificField>* parent_fields); 681 682 // Compares the specified messages for the requested field lists. The field 683 // lists are modified depending on comparison settings, and then passed to 684 // CompareWithFieldsInternal. 685 bool CompareRequestedFieldsUsingSettings( 686 const Message& message1, const Message& message2, 687 const vector<const FieldDescriptor*>& message1_fields, 688 const vector<const FieldDescriptor*>& message2_fields, 689 vector<SpecificField>* parent_fields); 690 691 // Compares the specified messages with the specified field lists. 692 bool CompareWithFieldsInternal( 693 const Message& message1, const Message& message2, 694 const vector<const FieldDescriptor*>& message1_fields, 695 const vector<const FieldDescriptor*>& message2_fields, 696 vector<SpecificField>* parent_fields); 697 698 // Compares the repeated fields, and report the error. 699 bool CompareRepeatedField(const Message& message1, const Message& message2, 700 const FieldDescriptor* field, 701 vector<SpecificField>* parent_fields); 702 703 // Shorthand for CompareFieldValueUsingParentFields with NULL parent_fields. 704 bool CompareFieldValue(const Message& message1, 705 const Message& message2, 706 const FieldDescriptor* field, 707 int index1, 708 int index2); 709 710 // Compares the specified field on the two messages, returning 711 // true if they are the same, false otherwise. For repeated fields, 712 // this method only compares the value in the specified index. This method 713 // uses Compare functions to recurse into submessages. 714 // The parent_fields vector is used in calls to a Reporter instance calls. 715 // It can be NULL, in which case the MessageDifferencer will create new 716 // list of parent messages if it needs to recursively compare the given field. 717 // To avoid confusing users you should not set it to NULL unless you modified 718 // Reporter to handle the change of parent_fields correctly. 719 bool CompareFieldValueUsingParentFields(const Message& message1, 720 const Message& message2, 721 const FieldDescriptor* field, 722 int index1, 723 int index2, 724 vector<SpecificField>* parent_fields); 725 726 // Compares the specified field on the two messages, returning comparison 727 // result, as returned by appropriate FieldComparator. 728 FieldComparator::ComparisonResult GetFieldComparisonResult( 729 const Message& message1, const Message& message2, 730 const FieldDescriptor* field, int index1, int index2, 731 const FieldContext* field_context); 732 733 // Check if the two elements in the repeated field are match to each other. 734 // if the key_comprator is NULL, this function returns true when the two 735 // elements are equal. 736 bool IsMatch(const FieldDescriptor* repeated_field, 737 const MapKeyComparator* key_comparator, 738 const Message* message1, const Message* message2, 739 const vector<SpecificField>& parent_fields, 740 int index1, int index2); 741 742 // Returns true when this repeated field has been configured to be treated 743 // as a set. 744 bool IsTreatedAsSet(const FieldDescriptor* field); 745 746 // Returns true when this repeated field is to be compared as a subset, ie. 747 // has been configured to be treated as a set or map and scope is set to 748 // PARTIAL. 749 bool IsTreatedAsSubset(const FieldDescriptor* field); 750 751 // Returns true if this field is to be ignored when this 752 // MessageDifferencer compares messages. 753 bool IsIgnored( 754 const Message& message1, 755 const Message& message2, 756 const FieldDescriptor* field, 757 const vector<SpecificField>& parent_fields); 758 759 // Returns true if this unknown field is to be ignored when this 760 // MessageDifferencer compares messages. 761 bool IsUnknownFieldIgnored(const Message& message1, const Message& message2, 762 const SpecificField& field, 763 const vector<SpecificField>& parent_fields); 764 765 // Returns MapKeyComparator* when this field has been configured to 766 // be treated as a map. If not, returns NULL. 767 const MapKeyComparator* GetMapKeyComparator(const FieldDescriptor* field); 768 769 // Attempts to match indices of a repeated field, so that the contained values 770 // match. Clears output vectors and sets their values to indices of paired 771 // messages, ie. if message1[0] matches message2[1], then match_list1[0] == 1 772 // and match_list2[1] == 0. The unmatched indices are indicated by -1. 773 // This method returns false if the match failed. However, it doesn't mean 774 // that the comparison succeeds when this method returns true (you need to 775 // double-check in this case). 776 bool MatchRepeatedFieldIndices(const Message& message1, 777 const Message& message2, 778 const FieldDescriptor* repeated_field, 779 const vector<SpecificField>& parent_fields, 780 vector<int>* match_list1, 781 vector<int>* match_list2); 782 783 // If "any" is of type google.protobuf.Any, extract its payload using 784 // DynamicMessageFactory and store in "data". 785 bool UnpackAny(const Message& any, google::protobuf::scoped_ptr<Message>* data); 786 787 // Checks if index is equal to new_index in all the specific fields. 788 static bool CheckPathChanged(const vector<SpecificField>& parent_fields); 789 790 // Defines a map between field descriptors and their MapKeyComparators. 791 // Used for repeated fields when they are configured as TreatAsMap. 792 typedef map<const FieldDescriptor*, 793 const MapKeyComparator*> FieldKeyComparatorMap; 794 795 // Defines a set to store field descriptors. Used for repeated fields when 796 // they are configured as TreatAsSet. 797 typedef set<const FieldDescriptor*> FieldSet; 798 799 Reporter* reporter_; 800 DefaultFieldComparator default_field_comparator_; 801 FieldComparator* field_comparator_; 802 MessageFieldComparison message_field_comparison_; 803 Scope scope_; 804 RepeatedFieldComparison repeated_field_comparison_; 805 806 FieldSet set_fields_; 807 FieldSet list_fields_; 808 // Keeps track of MapKeyComparators that are created within 809 // MessageDifferencer. These MapKeyComparators should be deleted 810 // before MessageDifferencer is destroyed. 811 // When TreatAsMap or TreatAsMapWithMultipleFieldsAsKey is called, we don't 812 // store the supplied FieldDescriptors directly. Instead, a new 813 // MapKeyComparator is created for comparison purpose. 814 vector<MapKeyComparator*> owned_key_comparators_; 815 FieldKeyComparatorMap map_field_key_comparator_; 816 vector<IgnoreCriteria*> ignore_criteria_; 817 818 FieldSet ignored_fields_; 819 820 bool compare_unknown_fields_; 821 bool report_matches_; 822 823 string* output_string_; 824 825 google::protobuf::scoped_ptr<DynamicMessageFactory> dynamic_message_factory_; 826 GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageDifferencer); 827 }; 828 829 // This class provides extra information to the FieldComparator::Compare 830 // function. 831 class LIBPROTOBUF_EXPORT FieldContext { 832 public: FieldContext(vector<MessageDifferencer::SpecificField> * parent_fields)833 explicit FieldContext( 834 vector<MessageDifferencer::SpecificField>* parent_fields) 835 : parent_fields_(parent_fields) {} 836 parent_fields()837 vector<MessageDifferencer::SpecificField>* parent_fields() const { 838 return parent_fields_; 839 } 840 841 private: 842 vector<MessageDifferencer::SpecificField>* parent_fields_; 843 }; 844 845 } 846 } 847 848 } // namespace google 849 #endif // GOOGLE_PROTOBUF_UTIL_MESSAGE_DIFFERENCER_H__ 850