use super::*;
#[test]
fn test_has_serde_via_derive_still_detected() {
let source = r#"
#[derive(Clone, serde::Serialize, serde::Deserialize)]
pub struct Config {
pub name: String,
pub timeout: u64,
}
"#;
let surface = extract_from_source(source);
assert_eq!(surface.types.len(), 1);
assert!(surface.types[0].has_serde, "derive-based serde must still be detected");
}
#[test]
fn test_has_serde_via_manual_impls_detected() {
let source = r#"
#[derive(Clone, Debug)]
pub struct NodeContext {
pub tag_name: String,
pub depth: usize,
}
impl serde::Serialize for NodeContext {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
unimplemented!()
}
}
impl<'de> serde::Deserialize<'de> for NodeContext {
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
unimplemented!()
}
}
"#;
let surface = extract_from_source(source);
assert_eq!(surface.types.len(), 1);
assert!(
surface.types[0].has_serde,
"manual impl Serialize + impl Deserialize must set has_serde=true"
);
}
#[test]
fn test_has_serde_with_lifetime_parameterised_manual_impls() {
let source = r#"
#[derive(Clone, Debug)]
pub struct Foo {
pub value: String,
}
impl serde::Serialize for Foo {
fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
unimplemented!()
}
}
impl<'de> serde::Deserialize<'de> for Foo {
fn deserialize<D: serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
unimplemented!()
}
}
"#;
let surface = extract_from_source(source);
assert_eq!(surface.types.len(), 1);
assert!(
surface.types[0].has_serde,
"lifetime-parameterised manual serde impls must set has_serde=true"
);
}
#[test]
fn test_has_serde_only_serialize_not_set() {
let source = r#"
#[derive(Clone, Debug)]
pub struct Foo {
pub value: String,
}
impl serde::Serialize for Foo {
fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
unimplemented!()
}
}
"#;
let surface = extract_from_source(source);
assert_eq!(surface.types.len(), 1);
assert!(
!surface.types[0].has_serde,
"only Serialize without Deserialize must not set has_serde"
);
}
#[test]
fn test_enum_rename_all_under_cfg_attr_any_is_honoured() {
let source = r#"
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[cfg_attr(any(feature = "serde", feature = "metadata"), derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(any(feature = "serde", feature = "metadata"), serde(rename_all = "snake_case"))]
pub enum TierStrategy {
#[default]
Auto,
Tier2,
}
"#;
let surface = extract_from_source(source);
assert_eq!(surface.enums.len(), 1);
let enum_def = &surface.enums[0];
assert!(
enum_def.has_serde,
"cfg_attr-gated derive(Serialize, Deserialize) must set has_serde"
);
assert_eq!(
enum_def.serde_rename_all.as_deref(),
Some("snake_case"),
"rename_all nested inside cfg_attr(any(...), ...) must be extracted"
);
let auto_variant = enum_def
.variants
.iter()
.find(|v| v.name == "Auto")
.expect("Auto variant present");
let wire_name = crate::backends::java::gen_bindings::helpers::java_apply_rename_all(
&auto_variant.name,
enum_def.serde_rename_all.as_deref(),
);
assert_eq!(
wire_name, "auto",
"Java wire name must honour the cfg_attr-gated rename_all"
);
}
#[test]
fn test_extract_function_since_annotation_is_populated() {
let source = r#"
#[alef(since = "1.0.0")]
pub fn new_api() {}
"#;
let surface = extract_from_source(source);
assert_eq!(surface.functions.len(), 1);
assert_eq!(surface.functions[0].version.since.as_deref(), Some("1.0.0"));
assert!(surface.functions[0].version.deprecated.is_none());
}