use super::{
ConversionConfig, gen_enum_from_binding_to_core, gen_enum_from_binding_to_core_cfg, gen_enum_from_core_to_binding,
gen_enum_from_core_to_binding_cfg,
};
use crate::core::ir::{EnumDef, EnumVariant};
fn simple_enum() -> EnumDef {
EnumDef {
name: "Backend".to_string(),
rust_path: "my_crate::Backend".to_string(),
variants: vec![
EnumVariant {
name: "Cpu".to_string(),
..Default::default()
},
EnumVariant {
name: "Gpu".to_string(),
..Default::default()
},
],
..Default::default()
}
}
#[test]
fn host_cfg_variant_keeps_its_arm_and_gains_a_cfg_guard_in_both_directions() {
let mut enum_def = simple_enum();
enum_def.variants[1].cfg = Some(r#"feature = "gpu-accel""#.to_string());
let core_to_binding = gen_enum_from_core_to_binding(&enum_def, "my_crate");
assert!(
core_to_binding.contains("my_crate::Backend::Gpu => Self::Gpu"),
"host-owned variant's From<CoreType> arm must still be emitted, got:\n{core_to_binding}"
);
assert_eq!(
core_to_binding.matches("#[cfg(feature = \"gpu-accel\")]").count(),
1,
"the From<CoreType> arm must carry the #[cfg] guard exactly once, got:\n{core_to_binding}"
);
assert!(
!core_to_binding.contains("_ => Default::default()"),
"a host-owned cfg-gated variant must not trigger a catch-all (unreachable pattern under \
-D warnings), got:\n{core_to_binding}"
);
let binding_to_core = gen_enum_from_binding_to_core(&enum_def, "my_crate");
assert!(
binding_to_core.contains("Backend::Gpu => Self::Gpu"),
"host-owned variant's From<BindingEnum> arm must still be emitted, got:\n{binding_to_core}"
);
assert_eq!(
binding_to_core.matches("#[cfg(feature = \"gpu-accel\")]").count(),
1,
"the From<BindingEnum> arm must carry the #[cfg] guard exactly once, got:\n{binding_to_core}"
);
assert!(
!binding_to_core.contains("_ => Default::default()"),
"a host-owned cfg-gated variant must not trigger a catch-all (unreachable pattern under \
-D warnings), got:\n{binding_to_core}"
);
}
#[test]
fn foreign_cfg_variant_arm_is_dropped_not_gated_in_both_directions() {
let mut enum_def = simple_enum();
enum_def.rust_path = "dep_crate::Backend".to_string();
enum_def.variants[1].cfg = Some(r#"feature = "testkit""#.to_string());
let core_to_binding = gen_enum_from_core_to_binding(&enum_def, "my_crate");
assert!(
!core_to_binding.contains("#[cfg(feature = \"testkit\")]"),
"no invalid #[cfg] naming an undeclared feature may be emitted, got:\n{core_to_binding}"
);
assert!(
!core_to_binding.contains("dep_crate::Backend::Gpu =>"),
"a foreign-crate cfg-gated variant must not be referenced in the From<CoreType> match, got:\n{core_to_binding}"
);
assert!(
core_to_binding.contains("_ => Default::default()"),
"dropping the arm must still leave the match exhaustive via the catch-all, got:\n{core_to_binding}"
);
let binding_to_core = gen_enum_from_binding_to_core(&enum_def, "my_crate");
assert!(
!binding_to_core.contains("#[cfg(feature = \"testkit\")]"),
"no invalid #[cfg] naming an undeclared feature may be emitted, got:\n{binding_to_core}"
);
assert!(
!binding_to_core.contains("Backend::Gpu => Self::Gpu"),
"a foreign-crate cfg-gated variant must not be referenced in the From<BindingEnum> match, got:\n{binding_to_core}"
);
assert!(
binding_to_core.contains("_ => Default::default()"),
"dropping the arm must still leave the From<BindingEnum> match exhaustive via the \
catch-all, got:\n{binding_to_core}"
);
}
#[test]
fn ungated_enum_emits_no_cfg_in_either_direction() {
let enum_def = simple_enum();
let core_to_binding = gen_enum_from_core_to_binding(&enum_def, "my_crate");
assert!(
!core_to_binding.contains("#[cfg("),
"ungated enum must not emit #[cfg(...)] in From<CoreType> impl, got:\n{core_to_binding}"
);
let binding_to_core = gen_enum_from_binding_to_core(&enum_def, "my_crate");
assert!(
!binding_to_core.contains("#[cfg("),
"ungated enum must not emit #[cfg(...)] in From<BindingEnum> impl, got:\n{binding_to_core}"
);
}
#[test]
fn foreign_cfg_variant_proven_disabled_needs_no_catch_all() {
let mut enum_def = simple_enum();
enum_def.rust_path = "dep_crate::Backend".to_string();
enum_def.variants[1].cfg = Some(r#"feature = "gpu-accel""#.to_string());
let configured = vec!["other-feature".to_string()];
let config = ConversionConfig {
configured_features: Some(configured.as_slice()),
..Default::default()
};
let core_to_binding = gen_enum_from_core_to_binding_cfg(&enum_def, "my_crate", &config);
assert!(
!core_to_binding.contains("_ => Default::default()"),
"a foreign variant proven unreachable by the binding's own configured features must not \
trigger a catch-all (unreachable pattern under -D warnings), got:\n{core_to_binding}"
);
assert!(
!core_to_binding.contains("Backend::Gpu"),
"the proven-unreachable variant must not be referenced at all, got:\n{core_to_binding}"
);
assert!(
core_to_binding.contains("Backend::Cpu => Self::Cpu"),
"the still-reachable variant must still convert, got:\n{core_to_binding}"
);
let binding_to_core = gen_enum_from_binding_to_core_cfg(&enum_def, "my_crate", &config);
assert!(
!binding_to_core.contains("_ => Default::default()"),
"same proof, opposite direction, got:\n{binding_to_core}"
);
}
#[test]
fn foreign_cfg_variant_not_ruled_out_keeps_conservative_catch_all() {
let mut enum_def = simple_enum();
enum_def.rust_path = "dep_crate::Backend".to_string();
enum_def.variants[1].cfg = Some(r#"feature = "gpu-accel""#.to_string());
let configured = vec!["gpu-accel".to_string()];
let config = ConversionConfig {
configured_features: Some(configured.as_slice()),
..Default::default()
};
let core_to_binding = gen_enum_from_core_to_binding_cfg(&enum_def, "my_crate", &config);
assert!(
core_to_binding.contains("_ => Default::default()"),
"a variant the configured features do not rule out must keep the conservative catch-all, \
got:\n{core_to_binding}"
);
}