diff --git a/.circleci/config.yml b/.circleci/config.yml index 31c3b62..b7d9f5a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -137,6 +137,9 @@ jobs: - run: name: Cargo test (use integers for enums) command: cargo test --workspace --features use-integers-for-enums + - run: + name: Cargo test (preserve proto field names) + command: cargo test --workspace --features preserve-proto-field-names - cache_save workflows: diff --git a/pbjson-build/src/generator/message.rs b/pbjson-build/src/generator/message.rs index f5fc404..1fa58dd 100644 --- a/pbjson-build/src/generator/message.rs +++ b/pbjson-build/src/generator/message.rs @@ -40,12 +40,20 @@ pub fn generate_message( ignore_unknown_fields: bool, btree_map_paths: &[String], emit_fields: bool, + preserve_proto_field_names: bool, ) -> Result<()> { let rust_type = resolver.rust_type(&message.path); // Generate Serialize write_serialize_start(0, &rust_type, writer)?; - write_message_serialize(resolver, 2, message, writer, emit_fields)?; + write_message_serialize( + resolver, + 2, + message, + writer, + emit_fields, + preserve_proto_field_names, + )?; write_serialize_end(0, writer)?; // Generate Deserialize @@ -106,15 +114,23 @@ fn write_message_serialize( message: &Message, writer: &mut W, emit_fields: bool, + preserve_proto_field_names: bool, ) -> Result<()> { write_struct_serialize_start(indent, message, writer, emit_fields)?; for field in &message.fields { - write_serialize_field(resolver, indent, field, writer, emit_fields)?; + write_serialize_field( + resolver, + indent, + field, + writer, + emit_fields, + preserve_proto_field_names, + )?; } for one_of in &message.one_ofs { - write_serialize_one_of(indent, resolver, one_of, writer)?; + write_serialize_one_of(indent, resolver, one_of, writer, preserve_proto_field_names)?; } write_struct_serialize_end(indent, writer) @@ -218,14 +234,21 @@ fn write_serialize_variable( field: &Field, variable: Variable<'_>, writer: &mut W, + preserve_proto_field_names: bool, ) -> Result<()> { + let json_name = field.json_name(); + let field_name = if preserve_proto_field_names { + field.name.as_str() + } else { + json_name.as_str() + }; match &field.field_type { FieldType::Scalar(scalar) => write_serialize_scalar_variable( indent, *scalar, field.field_modifier, variable, - field.json_name(), + field_name, writer, ), FieldType::Enum(path) => { @@ -250,7 +273,7 @@ fn write_serialize_variable( writer, "{}struct_ser.serialize_field(\"{}\", &v)?;", Indent(indent), - field.json_name() + field_name, ) } FieldType::Map(_, value_type) @@ -302,7 +325,7 @@ fn write_serialize_variable( writer, "{}struct_ser.serialize_field(\"{}\", &v)?;", Indent(indent), - field.json_name() + field_name, ) } _ => { @@ -310,7 +333,7 @@ fn write_serialize_variable( writer, "{}struct_ser.serialize_field(\"{}\", {})?;", Indent(indent), - field.json_name(), + field_name, variable.as_ref ) } @@ -322,7 +345,7 @@ fn write_serialize_scalar_variable( scalar: ScalarType, field_modifier: FieldModifier, variable: Variable<'_>, - json_name: String, + field_name: &str, writer: &mut W, ) -> Result<()> { let conversion = match scalar { @@ -333,7 +356,7 @@ fn write_serialize_scalar_variable( writer, "{}struct_ser.serialize_field(\"{}\", {})?;", Indent(indent), - json_name, + field_name, variable.as_ref ) } @@ -345,7 +368,7 @@ fn write_serialize_scalar_variable( writer, "{}struct_ser.serialize_field(\"{}\", &{}.iter().map({}).collect::>())?;", Indent(indent), - json_name, + field_name, variable.raw, conversion ) @@ -355,7 +378,7 @@ fn write_serialize_scalar_variable( writer, "{}struct_ser.serialize_field(\"{}\", {}(&{}).as_str())?;", Indent(indent), - json_name, + field_name, conversion, variable.raw, ) @@ -369,6 +392,7 @@ fn write_serialize_field( field: &Field, writer: &mut W, emit_fields: bool, + preserve_proto_field_names: bool, ) -> Result<()> { let as_ref = format!("&self.{}", field.rust_field_name()); let variable = Variable { @@ -379,7 +403,14 @@ fn write_serialize_field( match &field.field_modifier { FieldModifier::Required => { - write_serialize_variable(resolver, indent, field, variable, writer)?; + write_serialize_variable( + resolver, + indent, + field, + variable, + writer, + preserve_proto_field_names, + )?; } FieldModifier::Optional => { writeln!( @@ -393,14 +424,28 @@ fn write_serialize_field( as_unref: "*v", raw: "v", }; - write_serialize_variable(resolver, indent + 1, field, variable, writer)?; + write_serialize_variable( + resolver, + indent + 1, + field, + variable, + writer, + preserve_proto_field_names, + )?; writeln!(writer, "{}}}", Indent(indent))?; } FieldModifier::Repeated | FieldModifier::UseDefault => { write!(writer, "{}if ", Indent(indent))?; write_field_empty_predicate(field, writer, emit_fields)?; writeln!(writer, " {{")?; - write_serialize_variable(resolver, indent + 1, field, variable, writer)?; + write_serialize_variable( + resolver, + indent + 1, + field, + variable, + writer, + preserve_proto_field_names, + )?; writeln!(writer, "{}}}", Indent(indent))?; } } @@ -412,6 +457,7 @@ fn write_serialize_one_of( resolver: &Resolver<'_>, one_of: &OneOf, writer: &mut W, + preserve_proto_field_names: bool, ) -> Result<()> { writeln!( writer, @@ -434,7 +480,14 @@ fn write_serialize_one_of( as_unref: "*v", raw: "v", }; - write_serialize_variable(resolver, indent + 3, field, variable, writer)?; + write_serialize_variable( + resolver, + indent + 3, + field, + variable, + writer, + preserve_proto_field_names, + )?; writeln!(writer, "{}}}", Indent(indent + 2))?; } diff --git a/pbjson-build/src/lib.rs b/pbjson-build/src/lib.rs index 2b52e4d..eaee816 100644 --- a/pbjson-build/src/lib.rs +++ b/pbjson-build/src/lib.rs @@ -107,6 +107,7 @@ pub struct Builder { btree_map_paths: Vec, emit_fields: bool, use_integers_for_enums: bool, + preserve_proto_field_names: bool, } impl Builder { @@ -191,6 +192,13 @@ impl Builder { self } + /// Output fields with their original names as defined in their proto schemas, instead of + /// lowerCamelCase + pub fn preserve_proto_field_names(&mut self) -> &mut Self { + self.preserve_proto_field_names = true; + self + } + /// Generates code for all registered types where `prefixes` contains a prefix of /// the fully-qualified path of the type pub fn build>(&mut self, prefixes: &[S]) -> Result<()> { @@ -279,6 +287,7 @@ impl Builder { self.ignore_unknown_fields, &self.btree_map_paths, self.emit_fields, + self.preserve_proto_field_names, )? } } diff --git a/pbjson-test/Cargo.toml b/pbjson-test/Cargo.toml index 4d006af..230cabd 100644 --- a/pbjson-test/Cargo.toml +++ b/pbjson-test/Cargo.toml @@ -17,6 +17,7 @@ ignore-unknown-fields = [] btree = [] emit-fields = [] use-integers-for-enums = [] +preserve-proto-field-names = [] [dev-dependencies] chrono = "0.4" diff --git a/pbjson-test/build.rs b/pbjson-test/build.rs index ce22277..02bd410 100644 --- a/pbjson-test/build.rs +++ b/pbjson-test/build.rs @@ -59,6 +59,10 @@ fn main() -> Result<()> { builder.use_integers_for_enums(); } + if cfg!(feature = "preserve-proto-field-names") { + builder.preserve_proto_field_names(); + } + builder.build(&[".test"])?; Ok(()) diff --git a/pbjson-test/src/lib.rs b/pbjson-test/src/lib.rs index 4e8d18a..49b7a55 100644 --- a/pbjson-test/src/lib.rs +++ b/pbjson-test/src/lib.rs @@ -58,24 +58,82 @@ mod tests { use pbjson_types::{Duration, Timestamp}; use test::syntax3::*; - fn verify_encode(decoded: &KitchenSink, expected: &str) { + /// A struct holding the expected json-encoded representation of a test step. + /// + /// The json can come in two forms: fields with lowerCamelCase (typical expected) or with the + /// original name defined in the `.proto` schema. When decoding json, both forms must be + /// accepted by the parser. When encoding json, the form will be chosen based on the builder's + /// `preserve_proto_field_names` option, which during testing is toggled with a feature flag + #[derive(Debug, Clone, Copy)] + struct EncodedStrings { + expected: &'static str, + + /// the proto-preserving encoding; None if equal to the standard encoding + expected_preserved_proto: Option<&'static str>, + } + + impl From<&'static str> for EncodedStrings { + fn from(expected: &'static str) -> Self { + EncodedStrings { + expected, + expected_preserved_proto: None, + } + } + } + impl From<(&'static str, &'static str)> for EncodedStrings { + fn from((expected, expected_preserved_proto): (&'static str, &'static str)) -> Self { + EncodedStrings { + expected, + expected_preserved_proto: Some(expected_preserved_proto), + } + } + } + + fn verify_encode(decoded: &KitchenSink, expected: impl Into) { + let encoded = expected.into(); + + // the proto-preserved encoding is only used if the flag is set and the alternate form was + // actually provided + let expected = match ( + cfg!(feature = "preserve-proto-field-names"), + encoded.expected_preserved_proto, + ) { + (true, Some(preserved_proto)) => preserved_proto, + _ => encoded.expected, + }; + assert_eq!(serde_json::to_string(&decoded).unwrap().as_str(), expected); } - fn verify_decode(decoded: &KitchenSink, expected: &str) { + fn verify_decode(decoded: &KitchenSink, expected: impl Into) { + let encoded = expected.into(); + // Decode from a string first - assert_eq!(decoded, &serde_json::from_str(expected).unwrap()); + assert_eq!(decoded, &serde_json::from_str(encoded.expected).unwrap()); // Then, try decoding from a Reader: this can catch issues when trying to borrow data // from the input, which is not possible when deserializing from a Reader (e.g. an opened // file). assert_eq!( decoded, - &serde_json::from_reader(expected.as_bytes()).unwrap() + &serde_json::from_reader(encoded.expected.as_bytes()).unwrap() ); + + //both the lowerCamelCase and proto-preserved encodings must be accepted during decode + if let Some(expected_preserved_proto) = encoded.expected_preserved_proto { + assert_eq!( + decoded, + &serde_json::from_str(expected_preserved_proto).unwrap() + ); + assert_eq!( + decoded, + &serde_json::from_reader(expected_preserved_proto.as_bytes()).unwrap() + ); + } } - fn verify(decoded: &KitchenSink, expected: &str) { + fn verify(decoded: &KitchenSink, expected: impl Into) { + let expected = expected.into(); verify_encode(decoded, expected); verify_decode(decoded, expected); } @@ -151,14 +209,16 @@ mod tests { // Explicit optional fields can distinguish between no value and default value decoded.optional_i32 = Some(2); - verify(&decoded, r#"{"optionalI32":2}"#); + verify(&decoded, (r#"{"optionalI32":2}"#, r#"{"optional_i32":2}"#)); decoded.optional_i32 = Some(0); - verify(&decoded, r#"{"optionalI32":0}"#); + verify(&decoded, (r#"{"optionalI32":0}"#, r#"{"optional_i32":0}"#)); // Can also decode from string - verify_decode(&decoded, r#"{"optionalI32":"0"}"#); - verify_decode(&decoded, r#"{"optional_i32":"0"}"#); + verify_decode( + &decoded, + (r#"{"optionalI32":"0"}"#, r#"{"optional_i32":"0"}"#), + ); decoded.optional_i32 = None; verify_decode(&decoded, "{}"); @@ -171,14 +231,19 @@ mod tests { verify_decode(&decoded, "{}"); decoded.optional_i64 = Some(532); - verify(&decoded, r#"{"optionalI64":"532"}"#); + verify( + &decoded, + (r#"{"optionalI64":"532"}"#, r#"{"optional_i64":"532"}"#), + ); decoded.optional_i64 = Some(0); - verify(&decoded, r#"{"optionalI64":"0"}"#); + verify( + &decoded, + (r#"{"optionalI64":"0"}"#, r#"{"optional_i64":"0"}"#), + ); // Can also decode from non-string - verify_decode(&decoded, r#"{"optionalI64":0}"#); - verify_decode(&decoded, r#"{"optional_i64":0}"#); + verify_decode(&decoded, (r#"{"optionalI64":0}"#, r#"{"optional_i64":0}"#)); decoded.optional_i64 = None; verify_decode(&decoded, "{}"); @@ -189,7 +254,10 @@ mod tests { decoded.optional_u64 = Some(3); verify( &decoded, - r#"{"u32":567094456,"optionalU32":0,"u64":"34346","optionalU64":"3"}"#, + ( + r#"{"u32":567094456,"optionalU32":0,"u64":"34346","optionalU64":"3"}"#, + r#"{"u32":567094456,"optional_u32":0,"u64":"34346","optional_u64":"3"}"#, + ), ); decoded.u64 = 0; @@ -199,19 +267,41 @@ mod tests { verify_decode(&decoded, "{}"); decoded.repeated_i32 = vec![0, 23, 5, 6, 2, 34]; - verify(&decoded, r#"{"repeatedI32":[0,23,5,6,2,34]}"#); + verify( + &decoded, + ( + r#"{"repeatedI32":[0,23,5,6,2,34]}"#, + r#"{"repeated_i32":[0,23,5,6,2,34]}"#, + ), + ); // Can also mix in some strings - verify_decode(&decoded, r#"{"repeatedI32":[0,"23",5,6,"2",34]}"#); - verify_decode(&decoded, r#"{"repeated_i32":[0,"23",5,6,"2",34]}"#); + verify_decode( + &decoded, + ( + r#"{"repeatedI32":[0,"23",5,6,"2",34]}"#, + r#"{"repeated_i32":[0,"23",5,6,"2",34]}"#, + ), + ); decoded.repeated_i32 = vec![]; verify_decode(&decoded, "{}"); decoded.repeated_u64 = vec![0, 532, 2]; - verify(&decoded, r#"{"repeatedU64":["0","532","2"]}"#); + verify( + &decoded, + ( + r#"{"repeatedU64":["0","532","2"]}"#, + r#"{"repeated_u64":["0","532","2"]}"#, + ), + ); // Can also mix in some non-strings - verify_decode(&decoded, r#"{"repeatedU64":["0",532,"2"]}"#); - verify_decode(&decoded, r#"{"repeated_u64":["0",532,"2"]}"#); + verify_decode( + &decoded, + ( + r#"{"repeatedU64":["0",532,"2"]}"#, + r#"{"repeated_u64":["0",532,"2"]}"#, + ), + ); decoded.repeated_u64 = vec![]; verify_decode(&decoded, "{}"); @@ -227,11 +317,19 @@ mod tests { verify_decode(&decoded, "{}"); decoded.optional_value = Some(kitchen_sink::Value::Unknown as i32); - verify(&decoded, r#"{"optionalValue":"VALUE_UNKNOWN"}"#); + verify( + &decoded, + ( + r#"{"optionalValue":"VALUE_UNKNOWN"}"#, + r#"{"optional_value":"VALUE_UNKNOWN"}"#, + ), + ); // Can also use variant number - verify_decode(&decoded, r#"{"optionalValue":0}"#); - verify_decode(&decoded, r#"{"optional_value":0}"#); + verify_decode( + &decoded, + (r#"{"optionalValue":0}"#, r#"{"optional_value":0}"#), + ); decoded.optional_value = None; verify_decode(&decoded, "{}"); @@ -239,7 +337,13 @@ mod tests { decoded .string_dict .insert("foo".to_string(), "bar".to_string()); - verify(&decoded, r#"{"stringDict":{"foo":"bar"}}"#); + verify( + &decoded, + ( + r#"{"stringDict":{"foo":"bar"}}"#, + r#"{"string_dict":{"foo":"bar"}}"#, + ), + ); decoded.string_dict = Default::default(); verify_decode(&decoded, "{}"); @@ -249,46 +353,78 @@ mod tests { .insert(343, kitchen_sink::Prefix::A as i32); // Dictionary keys should always be strings // Enum dictionary values should be encoded as strings - verify(&decoded, r#"{"int32Dict":{"343":"A"}}"#); + verify( + &decoded, + ( + r#"{"int32Dict":{"343":"A"}}"#, + r#"{"int32_dict":{"343":"A"}}"#, + ), + ); // Enum dictionary values can be decoded from integers - verify_decode(&decoded, r#"{"int32Dict":{"343":66}}"#); - verify_decode(&decoded, r#"{"int32_dict":{"343":66}}"#); + verify_decode( + &decoded, + ( + r#"{"int32Dict":{"343":66}}"#, + r#"{"int32_dict":{"343":66}}"#, + ), + ); decoded.int32_dict = Default::default(); verify_decode(&decoded, "{}"); // 64-bit dictionary values should be encoded as strings decoded.integer_dict.insert(12, 13); - verify(&decoded, r#"{"integerDict":{"12":"13"}}"#); + verify( + &decoded, + ( + r#"{"integerDict":{"12":"13"}}"#, + r#"{"integer_dict":{"12":"13"}}"#, + ), + ); // 64-bit dictionary values can be decoded from numeric types - verify_decode(&decoded, r#"{"integerDict":{"12":13}}"#); - verify_decode(&decoded, r#"{"integer_dict":{"12":13}}"#); + verify_decode( + &decoded, + ( + r#"{"integerDict":{"12":13}}"#, + r#"{"integer_dict":{"12":13}}"#, + ), + ); decoded.integer_dict = Default::default(); verify_decode(&decoded, "{}"); decoded.one_of = Some(kitchen_sink::OneOf::OneOfI32(0)); - verify(&decoded, r#"{"oneOfI32":0}"#); + verify(&decoded, (r#"{"oneOfI32":0}"#, r#"{"one_of_i32":0}"#)); // Can also specify string - verify_decode(&decoded, r#"{"oneOfI32":"0"}"#); - verify_decode(&decoded, r#"{"one_of_i32":"0"}"#); + verify_decode(&decoded, (r#"{"oneOfI32":"0"}"#, r#"{"one_of_i32":"0"}"#)); decoded.one_of = Some(kitchen_sink::OneOf::OneOfI32(12)); - verify(&decoded, r#"{"oneOfI32":12}"#); + verify(&decoded, (r#"{"oneOfI32":12}"#, r#"{"one_of_i32":12}"#)); decoded.one_of = Some(kitchen_sink::OneOf::OneOfBool(false)); - verify(&decoded, r#"{"oneOfBool":false}"#); + verify( + &decoded, + (r#"{"oneOfBool":false}"#, r#"{"one_of_bool":false}"#), + ); decoded.one_of = Some(kitchen_sink::OneOf::OneOfBool(true)); - verify(&decoded, r#"{"oneOfBool":true}"#); + verify( + &decoded, + (r#"{"oneOfBool":true}"#, r#"{"one_of_bool":true}"#), + ); decoded.one_of = Some(kitchen_sink::OneOf::OneOfValue( kitchen_sink::Value::B as i32, )); - verify(&decoded, r#"{"oneOfValue":"VALUE_B"}"#); + verify( + &decoded, + ( + r#"{"oneOfValue":"VALUE_B"}"#, + r#"{"one_of_value":"VALUE_B"}"#, + ), + ); // Can also specify enum variant - verify_decode(&decoded, r#"{"oneOfValue":63}"#); - verify_decode(&decoded, r#"{"one_of_value":63}"#); + verify_decode(&decoded, (r#"{"oneOfValue":63}"#, r#"{"one_of_value":63}"#)); decoded.one_of = None; verify_decode(&decoded, "{}"); @@ -300,10 +436,18 @@ mod tests { ]; verify( &decoded, - r#"{"repeatedValue":["VALUE_B","VALUE_B","VALUE_A"]}"#, + ( + r#"{"repeatedValue":["VALUE_B","VALUE_B","VALUE_A"]}"#, + r#"{"repeated_value":["VALUE_B","VALUE_B","VALUE_A"]}"#, + ), + ); + verify_decode( + &decoded, + ( + r#"{"repeatedValue":[63,"VALUE_B","VALUE_A"]}"#, + r#"{"repeated_value":[63,"VALUE_B","VALUE_A"]}"#, + ), ); - verify_decode(&decoded, r#"{"repeatedValue":[63,"VALUE_B","VALUE_A"]}"#); - verify_decode(&decoded, r#"{"repeated_value":[63,"VALUE_B","VALUE_A"]}"#); decoded.repeated_value = Default::default(); verify_decode(&decoded, "{}"); @@ -315,10 +459,19 @@ mod tests { verify_decode(&decoded, "{}"); decoded.optional_bytes = Some(prost::bytes::Bytes::from_static(b"kjkjkj")); - verify(&decoded, r#"{"optionalBytes":"a2pramtq"}"#); + verify( + &decoded, + ( + r#"{"optionalBytes":"a2pramtq"}"#, + r#"{"optional_bytes":"a2pramtq"}"#, + ), + ); decoded.optional_bytes = Some(Default::default()); - verify(&decoded, r#"{"optionalBytes":""}"#); + verify( + &decoded, + (r#"{"optionalBytes":""}"#, r#"{"optional_bytes":""}"#), + ); decoded.optional_bytes = None; verify_decode(&decoded, "{}"); @@ -327,7 +480,13 @@ mod tests { prost::bytes::Bytes::from_static(b"sdfsd"), prost::bytes::Bytes::from_static(b"fghfg"), ]; - verify(&decoded, r#"{"repeatedBytes":["c2Rmc2Q=","ZmdoZmc="]}"#); + verify( + &decoded, + ( + r#"{"repeatedBytes":["c2Rmc2Q=","ZmdoZmc="]}"#, + r#"{"repeated_bytes":["c2Rmc2Q=","ZmdoZmc="]}"#, + ), + ); decoded.repeated_bytes = Default::default(); verify_decode(&decoded, "{}"); @@ -336,7 +495,13 @@ mod tests { "test".to_string(), prost::bytes::Bytes::from_static(b"asdf"), ); - verify(&decoded, r#"{"stringBytesDict":{"test":"YXNkZg=="}}"#); + verify( + &decoded, + ( + r#"{"stringBytesDict":{"test":"YXNkZg=="}}"#, + r#"{"string_bytes_dict":{"test":"YXNkZg=="}}"#, + ), + ); decoded.string_bytes_dict = Default::default(); verify_decode(&decoded, "{}"); @@ -344,7 +509,13 @@ mod tests { decoded .int_bytes_dict .insert(43, prost::bytes::Bytes::from_static(b"343dfgd")); - verify(&decoded, r#"{"intBytesDict":{"43":"MzQzZGZnZA=="}}"#); + verify( + &decoded, + ( + r#"{"intBytesDict":{"43":"MzQzZGZnZA=="}}"#, + r#"{"int_bytes_dict":{"43":"MzQzZGZnZA=="}}"#, + ), + ); decoded.int_bytes_dict = Default::default(); verify_decode(&decoded, "{}"); @@ -356,7 +527,10 @@ mod tests { verify_decode(&decoded, "{}"); decoded.optional_string = Some(String::new()); - verify(&decoded, r#"{"optionalString":""}"#); + verify( + &decoded, + (r#"{"optionalString":""}"#, r#"{"optional_string":""}"#), + ); decoded.optional_string = None; verify_decode(&decoded, "{}"); @@ -382,67 +556,109 @@ mod tests { verify_decode(&decoded, "{}"); decoded.mixed_case = MixedCase::MixedCasea as _; - verify(&decoded, r#"{"mixedCase":"MixedCASEA"}"#); + verify( + &decoded, + ( + r#"{"mixedCase":"MixedCASEA"}"#, + r#"{"mixed_case":"MixedCASEA"}"#, + ), + ); decoded.mixed_case = MixedCase::MixEdCaseB as _; - verify(&decoded, r#"{"mixedCase":"MixEdCaseB"}"#); + verify( + &decoded, + ( + r#"{"mixedCase":"MixEdCaseB"}"#, + r#"{"mixed_case":"MixEdCaseB"}"#, + ), + ); decoded.mixed_case = MixedCase::C as _; - verify(&decoded, r#"{"mixedCase":"c"}"#); + verify(&decoded, (r#"{"mixedCase":"c"}"#, r#"{"mixed_case":"c"}"#)); decoded.mixed_case = MixedCase::Unknown as _; verify(&decoded, r#"{}"#); decoded.bool_value = Some(true.into()); - verify(&decoded, r#"{"boolValue":true}"#); + verify( + &decoded, + (r#"{"boolValue":true}"#, r#"{"bool_value":true}"#), + ); decoded.bool_value = Some(false.into()); - verify(&decoded, r#"{"boolValue":false}"#); + verify( + &decoded, + (r#"{"boolValue":false}"#, r#"{"bool_value":false}"#), + ); decoded.bool_value = None; verify(&decoded, r#"{}"#); decoded.bytes_value = Some(prost::bytes::Bytes::from_static(b"kjkjkj").into()); - verify(&decoded, r#"{"bytesValue":"a2pramtq"}"#); + verify( + &decoded, + ( + r#"{"bytesValue":"a2pramtq"}"#, + r#"{"bytes_value":"a2pramtq"}"#, + ), + ); decoded.bytes_value = Some(prost::bytes::Bytes::new().into()); - verify(&decoded, r#"{"bytesValue":""}"#); + verify(&decoded, (r#"{"bytesValue":""}"#, r#"{"bytes_value":""}"#)); decoded.bytes_value = None; verify(&decoded, r#"{}"#); decoded.double_value = Some(1.1.into()); - verify(&decoded, r#"{"doubleValue":1.1}"#); + verify( + &decoded, + (r#"{"doubleValue":1.1}"#, r#"{"double_value":1.1}"#), + ); decoded.double_value = Some(0.0.into()); - verify(&decoded, r#"{"doubleValue":0.0}"#); + verify( + &decoded, + (r#"{"doubleValue":0.0}"#, r#"{"double_value":0.0}"#), + ); decoded.double_value = None; verify(&decoded, r#"{}"#); decoded.uint32_value = Some(1.into()); - verify(&decoded, r#"{"uint32Value":1}"#); + verify(&decoded, (r#"{"uint32Value":1}"#, r#"{"uint32_value":1}"#)); decoded.uint32_value = Some(0.into()); - verify(&decoded, r#"{"uint32Value":0}"#); + verify(&decoded, (r#"{"uint32Value":0}"#, r#"{"uint32_value":0}"#)); decoded.uint32_value = None; verify(&decoded, r#"{}"#); decoded.uint64_value = Some(1.into()); - verify(&decoded, r#"{"uint64Value":"1"}"#); + verify( + &decoded, + (r#"{"uint64Value":"1"}"#, r#"{"uint64_value":"1"}"#), + ); decoded.uint64_value = Some(0.into()); - verify(&decoded, r#"{"uint64Value":"0"}"#); + verify( + &decoded, + (r#"{"uint64Value":"0"}"#, r#"{"uint64_value":"0"}"#), + ); decoded.uint64_value = None; verify(&decoded, r#"{}"#); decoded.string_value = Some(String::from("1").into()); - verify(&decoded, r#"{"stringValue":"1"}"#); + verify( + &decoded, + (r#"{"stringValue":"1"}"#, r#"{"string_value":"1"}"#), + ); decoded.string_value = Some(String::new().into()); - verify(&decoded, r#"{"stringValue":""}"#); + verify( + &decoded, + (r#"{"stringValue":""}"#, r#"{"string_value":""}"#), + ); decoded.string_value = None; verify(&decoded, r#"{}"#);