use super::*;
fn build(fns: &[&str], tag: &str) -> String {
let loc = myflat_loc();
let mut items: Vec<(syn::Item, SourceLocation)> = vec![
(
syn::Item::Struct(syn::parse_quote!(
pub struct ZThing {
_p: u8,
}
)),
loc.clone(),
),
(
syn::Item::Struct(syn::parse_quote!(
pub struct ZOther {
_p: u8,
}
)),
loc.clone(),
),
];
let mut decls = crate::package!("ops")
.class(crate::ptr_class!(ZThing))
.class(crate::ptr_class!(ZOther));
for src in fns {
let f: syn::ItemFn = syn::parse_str(src).expect("test fn");
let id = f.sig.ident.clone();
decls = decls.fun(crate::FunctionDecl::new(id));
items.push((syn::Item::Fn(f), loc.clone()));
}
let registry = crate::test_util::reg_from_items(declare_referenced(items)).expect("index");
let jni = JniGenBuilder::new()
.set_package_prefix("io.test.jni")
.package(decls);
super::flatten::write_all(jni.build_with(registry).expect("resolve"), tag)
}
#[test]
fn preflight_is_emitted_exactly_for_the_predicate() {
for (src, want, tag) in [
(
"pub fn z_op(a: ZThing, b: ZThing) -> i64 { unimplemented!() }",
true,
"jni_alias_cc",
),
(
"pub fn z_op(a: ZThing, b: &ZThing) -> i64 { unimplemented!() }",
true,
"jni_alias_cb",
),
(
"pub fn z_op(a: &ZThing, b: &ZThing) -> i64 { unimplemented!() }",
false,
"jni_alias_bb",
),
(
"pub fn z_op(a: ZThing, b: i64) -> i64 { unimplemented!() }",
false,
"jni_alias_one",
),
(
"pub fn z_op(a: ZThing, b: ZOther) -> i64 { unimplemented!() }",
false,
"jni_alias_xtype",
),
] {
let out = build(&[src], tag);
assert_eq!(
out.contains("Aliasing arguments"),
want,
"preflight emission wrong for `{src}`:\n{out}"
);
}
}
#[test]
fn option_and_bare_share_a_resource_domain() {
let out = build(
&["pub fn z_op(a: ZThing, b: Option<ZThing>) -> i64 { unimplemented!() }"],
"jni_alias_option",
);
let all: String = out.split_whitespace().collect();
assert!(out.contains("Aliasing arguments"), "{out}");
assert!(all.contains("a.ptr!=0L&&a.ptr==(b?.ptr?:0L)"), "{out}");
}
#[test]
fn preflight_precedes_the_lock_and_the_call() {
let all = build(
&["pub fn z_op(a: ZThing, b: ZThing) -> i64 { unimplemented!() }"],
"jni_alias_order",
);
let start = all.find("public fun zOp(").expect("wrapper emitted");
let out = &all[start..];
let alias_at = out.find("Aliasing arguments").expect("preflight emitted");
let lock_at = out
.find("withSortedHandleLocks")
.expect("lock scaffold emitted");
assert!(
alias_at < lock_at,
"preflight must precede the lock:\n{out}"
);
let call_at = out.find("markConsumed").expect("consume emitted");
assert!(
alias_at < call_at,
"preflight must precede the consume:\n{out}"
);
}