Skip to content

Commit

Permalink
fix: Handle google.Structs correctly #71
Browse files Browse the repository at this point in the history
  • Loading branch information
rholshausen committed Aug 13, 2024
1 parent 1e5e5bc commit c3ec0eb
Show file tree
Hide file tree
Showing 5 changed files with 301 additions and 52 deletions.
21 changes: 18 additions & 3 deletions src/matching.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,19 @@ use prost_types::field_descriptor_proto::Type;
use tracing::{debug, instrument, trace, warn};

use crate::message_decoder::{decode_message, ProtobufField, ProtobufFieldData};
use crate::utils::{display_bytes, enum_name, field_data_to_json, find_message_descriptor_for_type, find_message_field_by_name, find_method_descriptor_for_service, find_service_descriptor_for_type, is_map_field, is_repeated_field, last_name, split_service_and_method};
use crate::utils::{
display_bytes,
enum_name,
struct_field_data_to_json,
find_message_descriptor_for_type,
find_message_field_by_name,
find_method_descriptor_for_service,
find_service_descriptor_for_type,
is_map_field,
is_repeated_field,
last_name,
split_service_and_method
};

/// Match a single Protobuf message
///
Expand Down Expand Up @@ -432,7 +444,8 @@ fn compare_field(
}
".google.protobuf.Struct" => {
debug!("Field is a Protobuf Struct, will compare it as JSON");
let expected_json = match field_data_to_json(expected_message, message_descriptor, descriptors) {
trace!("Parsing expected message");
let expected_json = match struct_field_data_to_json(expected_message, message_descriptor, descriptors) {
Ok(j) => j,
Err(err) => {
return vec![
Expand All @@ -445,7 +458,8 @@ fn compare_field(
];
}
};
let actual_json = match field_data_to_json(actual_message, message_descriptor, descriptors) {
trace!("Parsing actual message");
let actual_json = match struct_field_data_to_json(actual_message, message_descriptor, descriptors) {
Ok(j) => j,
Err(err) => {
return vec![
Expand All @@ -459,6 +473,7 @@ fn compare_field(
}
};

trace!(%expected_json, %actual_json, "Comparing JSON");
match compare_json(path, &expected_json, &actual_json, matching_context) {
Ok(_) => vec![],
Err(err) => err.iter().map(CommonMismatch::to_body_mismatch).collect()
Expand Down
2 changes: 1 addition & 1 deletion src/message_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ impl MessageBuilder {
buffer.put_slice(&message_bytes);
}
RType::Struct(s) => {
trace!("Encoding a Protobuf Struct");
trace!(?s, "Encoding a Protobuf Struct");
let mut buffer2 = BytesMut::with_capacity(s.encoded_len());
s.encode(&mut buffer2)?;
encode_key(tag as u32, WireType::LengthDelimited, &mut buffer);
Expand Down
13 changes: 8 additions & 5 deletions src/message_decoder/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -390,9 +390,10 @@ pub fn decode_message<B>(
let (field_num, wire_type) = decode_key(buffer)?;
trace!(field_num, ?wire_type, "read field header, bytes remaining = {}", buffer.remaining());

match find_field_descriptor(field_num as i32, descriptor) {
match &find_field_descriptor(field_num as i32, descriptor) {
Ok(field_descriptor) => {
let field_name = field_descriptor.name.clone().unwrap_or_default();
let field_name = field_descriptor.name();
trace!("field_name = {}", field_name);
let data = match wire_type {
WireType::Varint => {
let varint = decode_varint(buffer)?;
Expand Down Expand Up @@ -438,10 +439,12 @@ pub fn decode_message<B>(
return Err(anyhow!("Insufficient data remaining ({} bytes) to read {} bytes for field {}", buffer.remaining(), data_length, field_num));
};
let t: Type = field_descriptor.r#type();
trace!(field_type = ?t, data_buffer = ?data_buffer);
match t {
Type::String => vec![ (ProtobufFieldData::String(from_utf8(&data_buffer)?.to_string()), wire_type) ],
Type::Message => {
let full_type_name = field_descriptor.type_name.as_deref().unwrap_or_default();
let full_type_name = field_descriptor.type_name();
trace!(%full_type_name, "Embedded message");
// TODO: replace with proper support for nested fields
// this code checks fully qualified name first, if it can find it, this means the type name was a
// valid fully-qualified reference;
Expand Down Expand Up @@ -490,7 +493,7 @@ pub fn decode_message<B>(
for (data, wire_type) in data {
fields.push(ProtobufField {
field_num,
field_name: field_name.clone(),
field_name: field_name.to_string(),
wire_type,
data
});
Expand Down Expand Up @@ -545,7 +548,7 @@ fn decode_enum(
}

fn decode_packed_field(
field: FieldDescriptorProto,
field: &FieldDescriptorProto,
descriptor: &DescriptorProto,
descriptors: &FileDescriptorSet,
data: &mut Bytes
Expand Down
8 changes: 4 additions & 4 deletions src/protobuf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -846,15 +846,15 @@ fn build_proto_value(
Ok(prost_types::Value { kind: Some(prost_types::value::Kind::StringValue(s.clone())) })
}
Value::Array(a) => {
let mut values = a.iter().enumerate().map(|(index, v)| {
let values = a.iter().enumerate().map(|(index, v)| {
let index_path = path.join(index.to_string());
build_proto_value(&index_path, v, matching_rules, generators)
});
if let Some(err) = values.find_map(|v| v.err()) {
}).collect_vec();
if let Some(err) = values.iter().find_map(|v| v.as_ref().err()) {
return Err(anyhow!("Could not construct a Protobuf list value - {}", err))
}
// Unwrap here is safe as the previous statement would catch an error
let list = prost_types::ListValue { values: values.map(|v| v.unwrap()).collect() };
let list = prost_types::ListValue { values: values.iter().map(|v| v.as_ref().unwrap().clone()).collect() };
Ok(prost_types::Value { kind: Some(prost_types::value::Kind::ListValue(list)) })
}
Value::Object(map) => {
Expand Down
Loading

0 comments on commit c3ec0eb

Please sign in to comment.