use super::*;
fn event_file() -> FileDescriptorProto {
let msg = DescriptorProto {
name: Some("Event".to_string()),
nested_type: vec![DescriptorProto {
name: Some("Detail".to_string()),
..Default::default()
}],
oneof_decl: vec![OneofDescriptorProto {
name: Some("payload".to_string()),
..Default::default()
}],
field: vec![{
let mut f = make_field("data", 1, Label::LABEL_OPTIONAL, Type::TYPE_STRING);
f.oneof_index = Some(0);
f
}],
..Default::default()
};
let mut file = proto3_file("test.proto");
file.package = Some("pkg".to_string());
file.message_type = vec![msg];
file
}
fn gen_str(files: Vec<FileDescriptorProto>) -> String {
let config = CodeGenConfig::default();
let names: Vec<String> = files
.iter()
.map(|f| f.name.clone().unwrap_or_default())
.collect();
let out = generate(&files, &names, &config).expect("codegen should succeed");
joined(&out)
}
#[test]
fn natural_reexports_for_oneof_view_and_nested() {
let content = gen_str(vec![event_file()]);
assert!(
content.contains("pub use self::__buffa::view::EventView;"),
"missing top-level view re-export: {content}"
);
assert!(
content.contains("pub use super::__buffa::oneof::event::Payload;"),
"missing oneof re-export: {content}"
);
assert!(
content.contains("pub use super::__buffa::view::oneof::event::Payload as PayloadView;"),
"missing view-of-oneof re-export: {content}"
);
assert!(
content.contains("pub use super::__buffa::view::event::DetailView;"),
"missing nested view re-export: {content}"
);
}
#[test]
fn nested_reexport_path_depth_matches_nesting() {
let inner = DescriptorProto {
name: Some("Inner".to_string()),
oneof_decl: vec![OneofDescriptorProto {
name: Some("kind".to_string()),
..Default::default()
}],
field: vec![{
let mut f = make_field("a", 1, Label::LABEL_OPTIONAL, Type::TYPE_INT32);
f.oneof_index = Some(0);
f
}],
..Default::default()
};
let middle = DescriptorProto {
name: Some("Middle".to_string()),
nested_type: vec![inner],
..Default::default()
};
let outer = DescriptorProto {
name: Some("Outer".to_string()),
nested_type: vec![middle],
..Default::default()
};
let mut file = proto3_file("test.proto");
file.package = Some("pkg".to_string());
file.message_type = vec![outer];
let content = gen_str(vec![file]);
assert!(
content
.contains("pub use super::super::super::__buffa::oneof::outer::middle::inner::Kind;"),
"deeply nested oneof re-export missing or wrong depth: {content}"
);
}
#[test]
fn oneof_reexport_skipped_when_nested_message_collides() {
let msg = DescriptorProto {
name: Some("Event".to_string()),
nested_type: vec![DescriptorProto {
name: Some("Payload".to_string()),
..Default::default()
}],
oneof_decl: vec![OneofDescriptorProto {
name: Some("payload".to_string()),
..Default::default()
}],
field: vec![{
let mut f = make_field("a", 1, Label::LABEL_OPTIONAL, Type::TYPE_STRING);
f.oneof_index = Some(0);
f
}],
..Default::default()
};
let mut file = proto3_file("test.proto");
file.package = Some("pkg".to_string());
file.message_type = vec![msg];
let content = gen_str(vec![file]);
assert!(
!content.contains("pub use super::__buffa::oneof::event::Payload;"),
"oneof re-export should be skipped when nested message collides: {content}"
);
assert!(
!content.contains("PayloadView;"),
"PayloadView re-export should be skipped (mutual collision): {content}"
);
assert!(
content.contains("pub enum Payload {"),
"canonical oneof enum should still exist: {content}"
);
}
#[test]
fn oneof_reexport_skipped_when_nested_enum_collides() {
let msg = DescriptorProto {
name: Some("PerkRestrictions".to_string()),
enum_type: vec![EnumDescriptorProto {
name: Some("RegionCodes".to_string()),
value: vec![enum_value("REGION_CODES_UNKNOWN", 0), enum_value("US", 1)],
..Default::default()
}],
oneof_decl: vec![OneofDescriptorProto {
name: Some("region_codes".to_string()),
..Default::default()
}],
field: vec![{
let mut f = make_field("code", 1, Label::LABEL_OPTIONAL, Type::TYPE_STRING);
f.oneof_index = Some(0);
f
}],
..Default::default()
};
let mut file = proto3_file("test.proto");
file.package = Some("pkg".to_string());
file.message_type = vec![msg];
let content = gen_str(vec![file]);
assert!(
!content.contains("pub use super::__buffa::oneof::perk_restrictions::RegionCodes;"),
"oneof re-export should be skipped when nested enum collides: {content}"
);
assert!(
content.contains("RegionCodes as RegionCodesView;"),
"view-of-oneof re-export should survive (no collision): {content}"
);
}
#[test]
fn root_view_reexport_skipped_when_top_level_message_collides() {
let event = DescriptorProto {
name: Some("Event".to_string()),
..Default::default()
};
let event_view = DescriptorProto {
name: Some("EventView".to_string()),
..Default::default()
};
let mut file = proto3_file("test.proto");
file.package = Some("pkg".to_string());
file.message_type = vec![event, event_view];
let content = gen_str(vec![file]);
assert!(
!content.contains("pub use self::__buffa::view::EventView;"),
"view re-export should be skipped when message collides: {content}"
);
assert!(
content.contains("pub use self::__buffa::view::EventViewView;"),
"EventView's own view re-export should survive: {content}"
);
}
#[test]
fn root_view_reexport_skipped_when_collides_across_files() {
let mut a = proto3_file("a.proto");
a.package = Some("pkg".to_string());
a.message_type = vec![DescriptorProto {
name: Some("Event".to_string()),
..Default::default()
}];
let mut b = proto3_file("b.proto");
b.package = Some("pkg".to_string());
b.message_type = vec![DescriptorProto {
name: Some("EventView".to_string()),
..Default::default()
}];
let content = gen_str(vec![a, b]);
assert!(
!content.contains("pub use self::__buffa::view::EventView;"),
"cross-file view collision should drop the re-export: {content}"
);
}
#[test]
fn no_reexports_when_views_disabled_and_no_oneofs() {
let msg = DescriptorProto {
name: Some("Plain".to_string()),
..Default::default()
};
let mut file = proto3_file("test.proto");
file.package = Some("pkg".to_string());
file.message_type = vec![msg];
let config = CodeGenConfig {
generate_views: false,
..Default::default()
};
let out = generate(&[file], &["test.proto".to_string()], &config).unwrap();
let content = joined(&out);
assert!(
!content.contains("pub use"),
"no re-exports expected without views or oneofs: {content}"
);
}
#[test]
fn oneof_reexport_present_when_views_disabled() {
let mut file = event_file();
file.message_type[0].nested_type.clear();
let config = CodeGenConfig {
generate_views: false,
..Default::default()
};
let out = generate(&[file], &["test.proto".to_string()], &config).unwrap();
let content = joined(&out);
assert!(
content.contains("pub use super::__buffa::oneof::event::Payload;"),
"oneof re-export should fire without views: {content}"
);
assert!(
!content.contains("PayloadView"),
"no view-of-oneof re-export without views: {content}"
);
}
#[test]
fn file_level_extension_reexported_at_root() {
let mut file = proto3_file("test.proto");
file.package = Some("pkg".to_string());
file.message_type = vec![DescriptorProto {
name: Some("Target".to_string()),
extension_range: vec![
crate::generated::descriptor::descriptor_proto::ExtensionRange {
start: Some(100),
end: Some(200),
..Default::default()
},
],
..Default::default()
}];
file.extension = vec![{
let mut f = make_field("my_opt", 100, Label::LABEL_OPTIONAL, Type::TYPE_STRING);
f.extendee = Some(".pkg.Target".to_string());
f
}];
let content = gen_str(vec![file]);
assert!(
content.contains("pub use self::__buffa::ext::MY_OPT;"),
"file-level extension re-export missing: {content}"
);
}
#[test]
fn register_types_reexported_at_root() {
let mut file = proto3_file("test.proto");
file.package = Some("pkg".to_string());
file.message_type = vec![DescriptorProto {
name: Some("Target".to_string()),
extension_range: vec![
crate::generated::descriptor::descriptor_proto::ExtensionRange {
start: Some(100),
end: Some(200),
..Default::default()
},
],
..Default::default()
}];
file.extension = vec![{
let mut f = make_field("my_opt", 100, Label::LABEL_OPTIONAL, Type::TYPE_STRING);
f.extendee = Some(".pkg.Target".to_string());
f
}];
let config = CodeGenConfig {
generate_json: true,
..Default::default()
};
let out = generate(&[file], &["test.proto".to_string()], &config).unwrap();
let content = joined(&out);
assert!(
content.contains("pub use self::__buffa::register_types;"),
"register_types re-export missing: {content}"
);
}
#[test]
fn extension_const_collision_with_message_drops_reexport() {
let mut file = proto3_file("test.proto");
file.package = Some("pkg".to_string());
file.message_type = vec![
DescriptorProto {
name: Some("Target".to_string()),
extension_range: vec![
crate::generated::descriptor::descriptor_proto::ExtensionRange {
start: Some(100),
end: Some(200),
..Default::default()
},
],
..Default::default()
},
DescriptorProto {
name: Some("MY_OPT".to_string()),
..Default::default()
},
];
file.extension = vec![{
let mut f = make_field("my_opt", 100, Label::LABEL_OPTIONAL, Type::TYPE_STRING);
f.extendee = Some(".pkg.Target".to_string());
f
}];
let content = gen_str(vec![file]);
assert!(
!content.contains("pub use self::__buffa::ext::MY_OPT;"),
"extension re-export should be dropped on collision: {content}"
);
}
#[test]
fn message_owned_mod_emitted_for_reexports_only() {
let mut file = event_file();
file.message_type[0].nested_type.clear();
let content = gen_str(vec![file]);
assert!(
content.contains("pub mod event {"),
"owned-mod block must be emitted to host the re-exports: {content}"
);
}