use super::*;
#[test]
fn bounded_duration_option_is_one_scalar_with_named_niche() {
let loc = SourceLocation::default();
let items: Vec<(syn::Item, SourceLocation)> = [
"#[prebindgen] pub type Duration = std::time::Duration;",
"pub fn duration_from_millis(v: u64) -> Duration { unimplemented!() }",
"pub fn duration_to_millis(v: &Duration) -> u64 { unimplemented!() }",
"pub fn duration_echo(v: Option<Duration>) -> Option<Duration> { unimplemented!() }",
"pub fn duration_nested_echo(v: Option<Option<Duration>>) -> Option<Option<Duration>> { unimplemented!() }",
]
.into_iter()
.map(|source| {
let item: syn::Item = syn::parse_str(source).unwrap();
(item, loc.clone())
})
.collect();
let registry = crate::test_util::reg_from_items(declare_referenced(items)).unwrap();
let cbindgen = CbindgenBuilder::new()
.source_module(syn::parse_quote!(myflat))
.convert(
prebindgen_registry::convert!(Duration)
.input(prebindgen_registry::fun!(duration_from_millis))
.output(prebindgen_registry::fun!(duration_to_millis))
.valid_range(0u64..=1_000_000u64),
)
.base_name("z_duration")
.function(syn::parse_quote!(duration_echo))
.panic()
.function(syn::parse_quote!(duration_nested_echo))
.panic();
let src = write(cbindgen, registry, "bounded_duration");
let compact: String = src.split_whitespace().collect();
assert!(
compact.contains("pubconstZ_DURATION_NICHE_0:u64=18446744073709551615"),
"{src}"
);
assert!(
compact.contains("pubconstZ_DURATION_NICHE_1:u64=18446744073709551614"),
"{src}"
);
assert!(
compact.contains("pubconstZ_DURATION_NONE:u64=18446744073709551615"),
"{src}"
);
assert!(
compact.contains("extern\"C\"fnduration_echo(v:u64)->u64"),
"{src}"
);
assert!(
compact.contains("extern\"C\"fnduration_nested_echo(v:u64)->u64"),
"{src}"
);
assert!(!compact.contains("v:*constu64"), "{src}");
assert!(!compact.contains("_present"), "{src}");
assert!(compact.contains("ifv==18446744073709551615"), "{src}");
}
#[test]
fn bounded_float_option_uses_a_finite_bit_exact_niche() {
let loc = SourceLocation::default();
let items: Vec<(syn::Item, SourceLocation)> = [
"pub fn ratio_from_f64(v: f64) -> Ratio { unimplemented!() }",
"pub fn ratio_to_f64(v: Ratio) -> f64 { unimplemented!() }",
"pub fn ratio_echo(v: Option<Ratio>) -> Option<Ratio> { unimplemented!() }",
]
.into_iter()
.map(|source| {
let item: syn::Item = syn::parse_str(source).unwrap();
(item, loc.clone())
})
.collect();
let registry = crate::test_util::reg_from_items(declare_referenced(items)).unwrap();
let cbindgen = CbindgenBuilder::new()
.source_module(syn::parse_quote!(myflat))
.convert(
prebindgen_registry::convert!(Ratio)
.input(prebindgen_registry::fun!(ratio_from_f64))
.output(prebindgen_registry::fun!(ratio_to_f64))
.valid_range(0.0f64..=1.0f64),
)
.base_name("z_ratio")
.function(syn::parse_quote!(ratio_echo))
.panic();
let src = write(cbindgen, registry, "bounded_float");
let compact: String = src.split_whitespace().collect();
assert!(
compact.contains("pubconstZ_RATIO_NONE:f64=1.7976931348623157e308f64"),
"{src}"
);
assert!(
compact.contains("extern\"C\"fnratio_echo(v:f64)->f64"),
"{src}"
);
assert!(
compact.contains("v.to_bits()==9218868437227405311"),
"{src}"
);
assert!(compact.contains("myflat::ratio_to_f64(v)"), "{src}");
}
#[test]
fn custom_conversion_without_domain_stays_infallible() {
let loc = SourceLocation::default();
let items: Vec<(syn::Item, SourceLocation)> = [
"pub fn ratio_from_f64(v: f64) -> Ratio { unimplemented!() }",
"pub fn ratio_to_f64(v: Ratio) -> f64 { unimplemented!() }",
"pub fn ratio_echo(v: Ratio) -> Ratio { unimplemented!() }",
]
.into_iter()
.map(|source| {
let item: syn::Item = syn::parse_str(source).unwrap();
(item, loc.clone())
})
.collect();
let registry = crate::test_util::reg_from_items(declare_referenced(items)).unwrap();
let cbindgen = CbindgenBuilder::new()
.source_module(syn::parse_quote!(myflat))
.convert(
prebindgen_registry::convert!(Ratio)
.input(prebindgen_registry::fun!(ratio_from_f64))
.output(prebindgen_registry::fun!(ratio_to_f64)),
)
.function(syn::parse_quote!(ratio_echo));
let src = write(cbindgen, registry, "unbounded_conversion");
let compact: String = src.split_whitespace().collect();
assert!(
compact.contains("fn__cbg_in_Ratio(v:f64)->myflat::Ratio"),
"{src}"
);
assert!(
compact.contains("fn__cbg_out_Ratio(v:myflat::Ratio)->f64"),
"{src}"
);
assert!(
compact.contains("extern\"C\"fnratio_echo(v:f64)->f64"),
"{src}"
);
}
#[test]
fn empty_adapter_writes_empty_file() {
let cbindgen = CbindgenBuilder::new();
let registry: RegistryBuilder<()> =
crate::test_util::reg_from_items(Vec::new()).expect("empty");
let src = write(cbindgen, registry, "empty");
assert!(src.trim().is_empty(), "expected empty output, got:\n{src}");
}
#[test]
fn keyexpr_try_from_lowering() {
let loc = SourceLocation::default();
let func: syn::ItemFn = syn::parse_quote!(
pub fn z_keyexpr_try_from(s: String) -> Result<ZKeyExpr, Error> {
unimplemented!()
}
);
let registry = crate::test_util::reg_from_items(declare_referenced([
(syn::Item::Fn(func), loc.clone()),
(syn::Item::Struct(error_struct()), loc.clone()),
]))
.expect("index items");
let cbindgen = CbindgenBuilder::new()
.source_module(syn::parse_quote!(zenoh_flat))
.free_memory_function("z_free")
.opaque_ptr(syn::parse_quote!(ZKeyExpr))
.base_name("z_keyexpr")
.data_struct(syn::parse_quote!(Error))
.base_name("z_error")
.error()
.function(syn::parse_quote!(z_keyexpr_try_from));
let src = write(cbindgen, registry, "keyexpr");
let compact: String = src.split_whitespace().collect();
assert!(compact.contains("extern\"C\"fnz_keyexpr_try_from"), "{src}");
assert!(compact.contains("->*mutz_keyexpr"), "{src}");
assert!(!compact.contains("out:*mut"), "{src}");
assert!(compact.contains("e:*mutz_error"), "{src}");
assert!(compact.contains("structz_keyexpr{_private"), "{src}");
assert!(compact.contains("structz_error"), "{src}");
assert!(
compact.contains("fnz_keyexpr_drop(this_:*mutz_keyexpr"),
"{src}"
);
assert!(
compact.contains("Box::from_raw(this_as*mutzenoh_flat::ZKeyExpr)"),
"{src}"
);
assert!(compact.contains("fnmalloc(size:usize)"), "{src}");
assert!(
compact.contains("fnz_free(p:*mut::core::ffi::c_void)"),
"{src}"
);
assert!(!compact.contains("z_error_drop"), "{src}");
assert!(!compact.contains("cbg_string_t"), "{src}");
assert!(compact.contains("zenoh_flat::z_keyexpr_try_from"), "{src}");
assert!(!compact.contains("__CErr"), "{src}");
assert!(
compact.contains("as::core::convert::From<::std::string::String"),
"{src}"
);
assert!(compact.contains("__cbg_out_Error"), "{src}");
assert!(compact.contains("return::core::ptr::null_mut()"), "{src}");
}
#[test]
fn opaque_error_lowering() {
let loc = SourceLocation::default();
let func: syn::ItemFn = syn::parse_quote!(
pub fn z_keyexpr_try_from(s: String) -> Result<ZKeyExpr, ZError> {
unimplemented!()
}
);
let registry =
crate::test_util::reg_from_items(declare_referenced([(syn::Item::Fn(func), loc.clone())]))
.expect("index items");
let cbindgen = CbindgenBuilder::new()
.source_module(syn::parse_quote!(zenoh_flat))
.free_memory_function("z_free")
.opaque_ptr(syn::parse_quote!(ZKeyExpr))
.base_name("z_keyexpr")
.opaque_error(
syn::parse_quote!(ZError),
syn::parse_quote!(z_error_message),
)
.function(syn::parse_quote!(z_keyexpr_try_from));
let src = write(cbindgen, registry, "opaque_error");
let compact: String = src.split_whitespace().collect();
assert!(compact.contains("extern\"C\"fnz_keyexpr_try_from"), "{src}");
assert!(compact.contains("->*mutz_keyexpr"), "{src}");
assert!(compact.contains("e:*mut*mut::core::ffi::c_char"), "{src}");
assert!(compact.contains("zenoh_flat::z_error_message(&v)"), "{src}");
assert!(compact.contains("__cbg_alloc_cstr"), "{src}");
assert!(!compact.contains("structz_error"), "{src}");
assert!(
compact.contains("as::core::convert::From<::std::string::String"),
"{src}"
);
}