|
|
@ -53,6 +53,7 @@ |
|
|
|
#include <google/protobuf/stubs/strutil.h> |
|
|
|
#include <google/protobuf/stubs/strutil.h> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Always include as last one, otherwise it can break compilation
|
|
|
|
#include <google/protobuf/port_def.inc> |
|
|
|
#include <google/protobuf/port_def.inc> |
|
|
|
|
|
|
|
|
|
|
|
namespace google { |
|
|
|
namespace google { |
|
|
@ -512,14 +513,20 @@ bool MessageDifferencer::CompareWithFields( |
|
|
|
|
|
|
|
|
|
|
|
bool result = false; |
|
|
|
bool result = false; |
|
|
|
|
|
|
|
|
|
|
|
std::vector<const FieldDescriptor*> message1_fields(message1_fields_arg); |
|
|
|
FieldDescriptorArray message1_fields(message1_fields_arg.size() + 1); |
|
|
|
std::vector<const FieldDescriptor*> message2_fields(message2_fields_arg); |
|
|
|
FieldDescriptorArray message2_fields(message2_fields_arg.size() + 1); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::copy(message1_fields_arg.cbegin(), message1_fields_arg.cend(), |
|
|
|
|
|
|
|
message1_fields.begin()); |
|
|
|
|
|
|
|
std::copy(message2_fields_arg.cbegin(), message2_fields_arg.cend(), |
|
|
|
|
|
|
|
message2_fields.begin()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Append sentinel values.
|
|
|
|
|
|
|
|
message1_fields[message1_fields_arg.size()] = nullptr; |
|
|
|
|
|
|
|
message2_fields[message2_fields_arg.size()] = nullptr; |
|
|
|
|
|
|
|
|
|
|
|
std::sort(message1_fields.begin(), message1_fields.end(), FieldBefore); |
|
|
|
std::sort(message1_fields.begin(), message1_fields.end(), FieldBefore); |
|
|
|
std::sort(message2_fields.begin(), message2_fields.end(), FieldBefore); |
|
|
|
std::sort(message2_fields.begin(), message2_fields.end(), FieldBefore); |
|
|
|
// Append NULL sentinel values.
|
|
|
|
|
|
|
|
message1_fields.push_back(NULL); |
|
|
|
|
|
|
|
message2_fields.push_back(NULL); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Setup the internal reporter if need be.
|
|
|
|
// Setup the internal reporter if need be.
|
|
|
|
if (output_string_) { |
|
|
|
if (output_string_) { |
|
|
@ -579,10 +586,8 @@ bool MessageDifferencer::Compare(const Message& message1, |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
std::vector<const FieldDescriptor*> message1_fields = |
|
|
|
FieldDescriptorArray message1_fields = RetrieveFields(message1, true); |
|
|
|
RetrieveFields(message1, true); |
|
|
|
FieldDescriptorArray message2_fields = RetrieveFields(message2, false); |
|
|
|
std::vector<const FieldDescriptor*> message2_fields = |
|
|
|
|
|
|
|
RetrieveFields(message2, false); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return CompareRequestedFieldsUsingSettings( |
|
|
|
return CompareRequestedFieldsUsingSettings( |
|
|
|
message1, message2, |
|
|
|
message1, message2, |
|
|
@ -590,48 +595,49 @@ bool MessageDifferencer::Compare(const Message& message1, |
|
|
|
parent_fields) && unknown_compare_result; |
|
|
|
parent_fields) && unknown_compare_result; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
std::vector<const FieldDescriptor*> MessageDifferencer::RetrieveFields( |
|
|
|
FieldDescriptorArray MessageDifferencer::RetrieveFields(const Message& message, |
|
|
|
const Message& message, bool base_message) { |
|
|
|
bool base_message) { |
|
|
|
const Descriptor* descriptor = message.GetDescriptor(); |
|
|
|
const Descriptor* descriptor = message.GetDescriptor(); |
|
|
|
|
|
|
|
|
|
|
|
std::vector<const FieldDescriptor*> message_fields; |
|
|
|
tmp_message_fields_.clear(); |
|
|
|
message_fields.reserve(descriptor->field_count() + 1); |
|
|
|
tmp_message_fields_.reserve(descriptor->field_count() + 1); |
|
|
|
|
|
|
|
|
|
|
|
const Reflection* reflection = message.GetReflection(); |
|
|
|
const Reflection* reflection = message.GetReflection(); |
|
|
|
if (descriptor->options().map_entry()) { |
|
|
|
if (descriptor->options().map_entry()) { |
|
|
|
if (this->scope_ == PARTIAL && base_message) { |
|
|
|
if (this->scope_ == PARTIAL && base_message) { |
|
|
|
reflection->ListFields(message, &message_fields); |
|
|
|
reflection->ListFields(message, &tmp_message_fields_); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
// Map entry fields are always considered present.
|
|
|
|
// Map entry fields are always considered present.
|
|
|
|
for (int i = 0; i < descriptor->field_count(); i++) { |
|
|
|
for (int i = 0; i < descriptor->field_count(); i++) { |
|
|
|
message_fields.push_back(descriptor->field(i)); |
|
|
|
tmp_message_fields_.push_back(descriptor->field(i)); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
reflection->ListFields(message, &message_fields); |
|
|
|
reflection->ListFields(message, &tmp_message_fields_); |
|
|
|
} |
|
|
|
} |
|
|
|
// Add sentinel values to deal with the
|
|
|
|
// Add sentinel values to deal with the
|
|
|
|
// case where the number of the fields in
|
|
|
|
// case where the number of the fields in
|
|
|
|
// each list are different.
|
|
|
|
// each list are different.
|
|
|
|
message_fields.push_back(nullptr); |
|
|
|
tmp_message_fields_.push_back(nullptr); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
FieldDescriptorArray message_fields(tmp_message_fields_.begin(), |
|
|
|
|
|
|
|
tmp_message_fields_.end()); |
|
|
|
|
|
|
|
|
|
|
|
return message_fields; |
|
|
|
return message_fields; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bool MessageDifferencer::CompareRequestedFieldsUsingSettings( |
|
|
|
bool MessageDifferencer::CompareRequestedFieldsUsingSettings( |
|
|
|
const Message& message1, |
|
|
|
const Message& message1, const Message& message2, |
|
|
|
const Message& message2, |
|
|
|
const FieldDescriptorArray& message1_fields, |
|
|
|
const std::vector<const FieldDescriptor*>& message1_fields, |
|
|
|
const FieldDescriptorArray& message2_fields, |
|
|
|
const std::vector<const FieldDescriptor*>& message2_fields, |
|
|
|
|
|
|
|
std::vector<SpecificField>* parent_fields) { |
|
|
|
std::vector<SpecificField>* parent_fields) { |
|
|
|
if (scope_ == FULL) { |
|
|
|
if (scope_ == FULL) { |
|
|
|
if (message_field_comparison_ == EQUIVALENT) { |
|
|
|
if (message_field_comparison_ == EQUIVALENT) { |
|
|
|
// We need to merge the field lists of both messages (i.e.
|
|
|
|
// We need to merge the field lists of both messages (i.e.
|
|
|
|
// we are merely checking for a difference in field values,
|
|
|
|
// we are merely checking for a difference in field values,
|
|
|
|
// rather than the addition or deletion of fields).
|
|
|
|
// rather than the addition or deletion of fields).
|
|
|
|
std::vector<const FieldDescriptor*> fields_union; |
|
|
|
FieldDescriptorArray fields_union = |
|
|
|
CombineFields(message1_fields, FULL, message2_fields, FULL, |
|
|
|
CombineFields(message1_fields, FULL, message2_fields, FULL); |
|
|
|
&fields_union); |
|
|
|
|
|
|
|
return CompareWithFieldsInternal(message1, message2, fields_union, |
|
|
|
return CompareWithFieldsInternal(message1, message2, fields_union, |
|
|
|
fields_union, parent_fields); |
|
|
|
fields_union, parent_fields); |
|
|
|
} else { |
|
|
|
} else { |
|
|
@ -651,52 +657,55 @@ bool MessageDifferencer::CompareRequestedFieldsUsingSettings( |
|
|
|
// but only the intersection for message2. This way, any fields
|
|
|
|
// but only the intersection for message2. This way, any fields
|
|
|
|
// only present in message2 will be ignored, but any fields only
|
|
|
|
// only present in message2 will be ignored, but any fields only
|
|
|
|
// present in message1 will be marked as a difference.
|
|
|
|
// present in message1 will be marked as a difference.
|
|
|
|
std::vector<const FieldDescriptor*> fields_intersection; |
|
|
|
FieldDescriptorArray fields_intersection = |
|
|
|
CombineFields(message1_fields, PARTIAL, message2_fields, PARTIAL, |
|
|
|
CombineFields(message1_fields, PARTIAL, message2_fields, PARTIAL); |
|
|
|
&fields_intersection); |
|
|
|
|
|
|
|
return CompareWithFieldsInternal(message1, message2, message1_fields, |
|
|
|
return CompareWithFieldsInternal(message1, message2, message1_fields, |
|
|
|
fields_intersection, parent_fields); |
|
|
|
fields_intersection, parent_fields); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void MessageDifferencer::CombineFields( |
|
|
|
FieldDescriptorArray MessageDifferencer::CombineFields( |
|
|
|
const std::vector<const FieldDescriptor*>& fields1, |
|
|
|
const FieldDescriptorArray& fields1, Scope fields1_scope, |
|
|
|
Scope fields1_scope, |
|
|
|
const FieldDescriptorArray& fields2, Scope fields2_scope) { |
|
|
|
const std::vector<const FieldDescriptor*>& fields2, |
|
|
|
|
|
|
|
Scope fields2_scope, |
|
|
|
|
|
|
|
std::vector<const FieldDescriptor*>* combined_fields) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int index1 = 0; |
|
|
|
int index1 = 0; |
|
|
|
int index2 = 0; |
|
|
|
int index2 = 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tmp_message_fields_.clear(); |
|
|
|
|
|
|
|
|
|
|
|
while (index1 < fields1.size() && index2 < fields2.size()) { |
|
|
|
while (index1 < fields1.size() && index2 < fields2.size()) { |
|
|
|
const FieldDescriptor* field1 = fields1[index1]; |
|
|
|
const FieldDescriptor* field1 = fields1[index1]; |
|
|
|
const FieldDescriptor* field2 = fields2[index2]; |
|
|
|
const FieldDescriptor* field2 = fields2[index2]; |
|
|
|
|
|
|
|
|
|
|
|
if (FieldBefore(field1, field2)) { |
|
|
|
if (FieldBefore(field1, field2)) { |
|
|
|
if (fields1_scope == FULL) { |
|
|
|
if (fields1_scope == FULL) { |
|
|
|
combined_fields->push_back(fields1[index1]); |
|
|
|
tmp_message_fields_.push_back(fields1[index1]); |
|
|
|
} |
|
|
|
} |
|
|
|
++index1; |
|
|
|
++index1; |
|
|
|
} else if (FieldBefore(field2, field1)) { |
|
|
|
} else if (FieldBefore(field2, field1)) { |
|
|
|
if (fields2_scope == FULL) { |
|
|
|
if (fields2_scope == FULL) { |
|
|
|
combined_fields->push_back(fields2[index2]); |
|
|
|
tmp_message_fields_.push_back(fields2[index2]); |
|
|
|
} |
|
|
|
} |
|
|
|
++index2; |
|
|
|
++index2; |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
combined_fields->push_back(fields1[index1]); |
|
|
|
tmp_message_fields_.push_back(fields1[index1]); |
|
|
|
++index1; |
|
|
|
++index1; |
|
|
|
++index2; |
|
|
|
++index2; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tmp_message_fields_.push_back(nullptr); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
FieldDescriptorArray combined_fields(tmp_message_fields_.begin(), |
|
|
|
|
|
|
|
tmp_message_fields_.end()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return combined_fields; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bool MessageDifferencer::CompareWithFieldsInternal( |
|
|
|
bool MessageDifferencer::CompareWithFieldsInternal( |
|
|
|
const Message& message1, |
|
|
|
const Message& message1, const Message& message2, |
|
|
|
const Message& message2, |
|
|
|
const FieldDescriptorArray& message1_fields, |
|
|
|
const std::vector<const FieldDescriptor*>& message1_fields, |
|
|
|
const FieldDescriptorArray& message2_fields, |
|
|
|
const std::vector<const FieldDescriptor*>& message2_fields, |
|
|
|
|
|
|
|
std::vector<SpecificField>* parent_fields) { |
|
|
|
std::vector<SpecificField>* parent_fields) { |
|
|
|
bool isDifferent = false; |
|
|
|
bool isDifferent = false; |
|
|
|
int field_index1 = 0; |
|
|
|
int field_index1 = 0; |
|
|
|