use crate::codegen::generators::{gen_pyo3_data_enum, gen_pyo3_data_enum_with_mapper};
use crate::codegen::type_mapper::IdentityMapper;
use crate::core::ir::{EnumDef, EnumVariant, FieldDef, TypeRef};
fn unit_variant(name: &str, cfg: Option<&str>) -> EnumVariant {
EnumVariant {
name: name.to_string(),
cfg: cfg.map(str::to_string),
..Default::default()
}
}
fn named_tuple_variant(name: &str, inner_type: &str, cfg: Option<&str>) -> EnumVariant {
EnumVariant {
name: name.to_string(),
fields: vec![FieldDef {
name: "_0".to_string(),
ty: TypeRef::Named(inner_type.to_string()),
..Default::default()
}],
is_tuple: true,
cfg: cfg.map(str::to_string),
..Default::default()
}
}
fn struct_variant(name: &str, cfg: Option<&str>) -> EnumVariant {
EnumVariant {
name: name.to_string(),
fields: vec![FieldDef {
name: "text".to_string(),
ty: TypeRef::String,
..Default::default()
}],
cfg: cfg.map(str::to_string),
..Default::default()
}
}
fn data_enum(rust_path: &str, variants: Vec<EnumVariant>) -> EnumDef {
EnumDef {
name: "VisitorResult".to_string(),
rust_path: rust_path.to_string(),
variants,
has_serde: true,
serde_tag: Some("type".to_string()),
..Default::default()
}
}
#[test]
fn host_owned_cfg_variant_keeps_accessor_arm_and_gate() {
let def = data_enum(
"mylib::VisitorResult",
vec![
unit_variant("Continue", None),
named_tuple_variant("Thumbnail", "ThumbnailData", Some(r#"feature = "thumbnails""#)),
],
);
let generated = gen_pyo3_data_enum(&def, "mylib");
assert!(
generated.contains("mylib::VisitorResult::Thumbnail(data)"),
"the host-owned variant's accessor arm must still be emitted, got:\n{generated}"
);
assert_eq!(
generated.matches("#[cfg(feature = \"thumbnails\")]").count(),
1,
"the host-owned variant's accessor arm must carry its #[cfg] guard exactly once, got:\n{generated}"
);
}
#[test]
fn foreign_owned_cfg_variant_accessor_arm_is_dropped_not_gated() {
let def = data_enum(
"dep_crate::VisitorResult",
vec![
unit_variant("Continue", None),
named_tuple_variant("Testkit", "TestkitData", Some(r#"feature = "testkit""#)),
],
);
let generated = gen_pyo3_data_enum(&def, "mylib");
assert!(
!generated.contains("#[cfg(feature = \"testkit\")]"),
"no invalid #[cfg] naming an undeclared feature may be emitted, got:\n{generated}"
);
assert!(
!generated.contains("::Testkit(data)"),
"a foreign-crate cfg-gated variant must not be referenced, got:\n{generated}"
);
assert!(
generated.contains("_ => None,"),
"dropping the arm must still leave the match exhaustive via the fallback, got:\n{generated}"
);
}
#[test]
fn ungated_data_enum_emits_no_cfg_in_accessors() {
let def = data_enum(
"mylib::VisitorResult",
vec![
unit_variant("Continue", None),
named_tuple_variant("Thumbnail", "ThumbnailData", None),
],
);
let generated = gen_pyo3_data_enum(&def, "mylib");
assert!(
!generated.contains("#[cfg("),
"ungated enum must not emit #[cfg(...)], got:\n{generated}"
);
}
#[test]
fn host_owned_cfg_variant_keeps_its_factory_and_gate() {
let def = data_enum(
"mylib::VisitorResult",
vec![
unit_variant("Continue", None),
struct_variant("Thumbnail", Some(r#"feature = "thumbnails""#)),
],
);
let generated = gen_pyo3_data_enum_with_mapper(&def, "mylib", Some(&IdentityMapper));
assert!(
generated.contains("_factory_thumbnail"),
"the host-owned variant's factory must still be emitted, got:\n{generated}"
);
assert_eq!(
generated.matches("#[cfg(feature = \"thumbnails\")]").count(),
1,
"the host-owned variant's factory must carry its #[cfg] guard exactly once, got:\n{generated}"
);
}
#[test]
fn foreign_owned_cfg_variant_factory_is_dropped_entirely() {
let def = data_enum(
"dep_crate::VisitorResult",
vec![
unit_variant("Continue", None),
struct_variant("Testkit", Some(r#"feature = "testkit""#)),
],
);
let generated = gen_pyo3_data_enum_with_mapper(&def, "mylib", Some(&IdentityMapper));
assert!(
!generated.contains("_factory_testkit"),
"a foreign-crate cfg-gated variant's factory must not be emitted, got:\n{generated}"
);
assert!(
!generated.contains("#[cfg(feature = \"testkit\")]"),
"no invalid #[cfg] naming an undeclared feature may be emitted, got:\n{generated}"
);
}
#[test]
fn ungated_struct_variant_factory_emits_no_cfg() {
let def = data_enum(
"mylib::VisitorResult",
vec![unit_variant("Continue", None), struct_variant("Thumbnail", None)],
);
let generated = gen_pyo3_data_enum_with_mapper(&def, "mylib", Some(&IdentityMapper));
assert!(
generated.contains("_factory_thumbnail"),
"the ungated variant's factory must be emitted, got:\n{generated}"
);
assert!(
!generated.contains("#[cfg("),
"ungated variant must not emit #[cfg(...)], got:\n{generated}"
);
}