use super::*;
#[test]
fn test_view_explicit_presence_scalar_is_option() {
let mut file = proto3_file("opt_scalar.proto");
file.message_type.push(DescriptorProto {
name: Some("Msg".to_string()),
field: vec![FieldDescriptorProto {
name: Some("value".to_string()),
number: Some(1),
label: Some(Label::LABEL_OPTIONAL),
r#type: Some(Type::TYPE_INT32),
proto3_optional: Some(true),
oneof_index: Some(0),
..Default::default()
}],
oneof_decl: vec![OneofDescriptorProto {
name: Some("_value".to_string()),
..Default::default()
}],
..Default::default()
});
let files = generate(
&[file],
&["opt_scalar.proto".to_string()],
&CodeGenConfig::default(),
)
.expect("should generate");
let content = &joined(&files);
assert!(
content.contains("pub value: ::core::option::Option<i32>"),
"view field for proto3 optional i32 must be ::core::option::Option<i32>: {content}"
);
assert!(
!content.contains("pub enum ValueView"),
"synthetic oneof must not produce a view enum: {content}"
);
}
#[test]
fn test_view_repeated_message_field() {
let mut file = proto3_file("rep_msg.proto");
file.message_type.push(DescriptorProto {
name: Some("Item".to_string()),
field: vec![make_field(
"val",
1,
Label::LABEL_OPTIONAL,
Type::TYPE_INT32,
)],
..Default::default()
});
file.message_type.push(DescriptorProto {
name: Some("Container".to_string()),
field: vec![FieldDescriptorProto {
name: Some("items".to_string()),
number: Some(1),
label: Some(Label::LABEL_REPEATED),
r#type: Some(Type::TYPE_MESSAGE),
type_name: Some(".Item".to_string()),
..Default::default()
}],
..Default::default()
});
let files = generate(
&[file],
&["rep_msg.proto".to_string()],
&CodeGenConfig::default(),
)
.expect("should generate");
let content = &joined(&files);
assert!(
content.contains("pub struct ItemView"),
"missing ItemView: {content}"
);
assert!(
content.contains("pub struct ContainerView"),
"missing ContainerView: {content}"
);
assert!(
content.contains("RepeatedView") && content.contains("ItemView"),
"ContainerView.items must be RepeatedView<ItemView>: {content}"
);
assert!(
content.contains("fn _decode_depth"),
"missing _decode_depth impl: {content}"
);
}
#[test]
fn test_view_packed_scalar_reserves_capacity() {
let mut file = proto3_file("packed_view.proto");
file.message_type.push(DescriptorProto {
name: Some("PackedView".to_string()),
field: vec![
make_field("ids", 1, Label::LABEL_REPEATED, Type::TYPE_UINT32),
make_field("flags", 2, Label::LABEL_REPEATED, Type::TYPE_BOOL),
make_field("ratios", 3, Label::LABEL_REPEATED, Type::TYPE_FLOAT),
make_field("hashes", 4, Label::LABEL_REPEATED, Type::TYPE_FIXED32),
make_field("scores", 5, Label::LABEL_REPEATED, Type::TYPE_DOUBLE),
make_field("offsets", 6, Label::LABEL_REPEATED, Type::TYPE_SFIXED64),
make_field("names", 7, Label::LABEL_REPEATED, Type::TYPE_STRING),
],
..Default::default()
});
let files = generate(
&[file],
&["packed_view.proto".to_string()],
&CodeGenConfig::default(),
)
.expect("should generate");
let content = &joined(&files);
assert!(
content.contains("view.ids.reserve(payload.len());"),
"varint packed view must reserve using the payload length: {content}"
);
assert!(
content.contains("view.flags.reserve(payload.len());"),
"bool packed view must reserve using the payload length: {content}"
);
assert!(
content.contains("view.ratios.reserve(payload.len() / 4usize);"),
"float packed view must reserve the exact element count: {content}"
);
assert!(
content.contains("view.hashes.reserve(payload.len() / 4usize);"),
"fixed32 packed view must reserve the exact element count: {content}"
);
assert!(
content.contains("view.scores.reserve(payload.len() / 8usize);"),
"double packed view must reserve the exact element count: {content}"
);
assert!(
content.contains("view.offsets.reserve(payload.len() / 8usize);"),
"sfixed64 packed view must reserve the exact element count: {content}"
);
assert!(
!content.contains("view.names.reserve("),
"string repeated view must not emit a packed-reserve call: {content}"
);
}
#[test]
fn test_view_oneof_with_message_variant() {
let mut file = proto3_file("oneof_msg.proto");
file.message_type.push(DescriptorProto {
name: Some("Body".to_string()),
field: vec![make_field(
"data",
1,
Label::LABEL_OPTIONAL,
Type::TYPE_INT32,
)],
..Default::default()
});
file.message_type.push(DescriptorProto {
name: Some("Request".to_string()),
field: vec![
FieldDescriptorProto {
name: Some("count".to_string()),
number: Some(1),
label: Some(Label::LABEL_OPTIONAL),
r#type: Some(Type::TYPE_INT32),
oneof_index: Some(0),
..Default::default()
},
FieldDescriptorProto {
name: Some("body".to_string()),
number: Some(2),
label: Some(Label::LABEL_OPTIONAL),
r#type: Some(Type::TYPE_MESSAGE),
type_name: Some(".Body".to_string()),
oneof_index: Some(0),
..Default::default()
},
],
oneof_decl: vec![OneofDescriptorProto {
name: Some("payload".to_string()),
..Default::default()
}],
..Default::default()
});
let files = generate(
&[file],
&["oneof_msg.proto".to_string()],
&CodeGenConfig::default(),
)
.expect("should generate");
let content = &joined(&files);
assert!(
content.contains("__buffa::view::oneof::request::Payload"),
"RequestView must reference __buffa::view::oneof::request::Payload: {content}"
);
assert!(
content.contains("Count(i32)"),
"Payload view must have Count(i32): {content}"
);
assert!(
content.contains("BodyView") && content.contains("::buffa::alloc::boxed::Box<"),
"Payload view must have boxed BodyView variant: {content}"
);
assert!(
content.contains("RecursionLimitExceeded"),
"message-type oneof variant must check recursion depth: {content}"
);
}