use super::*;
fn const_items() -> Vec<(syn::Item, prebindgen::SourceLocation)> {
let loc = myflat_loc();
vec![
(
syn::Item::Const(syn::parse_quote!(
pub const MAX_LEN: i64 = 42;
)),
loc.clone(),
),
(
syn::Item::Const(syn::parse_quote!(
pub const GREETING: &str = "hi";
)),
loc.clone(),
),
]
}
#[test]
fn declared_consts_emit_getter_and_val() {
let registry =
crate::test_util::reg_from_items(declare_referenced(const_items())).expect("index items");
let jni = JniGenBuilder::new()
.set_package_prefix("io.test.jni")
.package(
crate::package!("cfg")
.constant(crate::constant!(MAX_LEN))
.constant(crate::constant!(GREETING).name("HELLO")),
);
let dir = unique_test_dir("jnigen_consts_basic");
let _ = std::fs::remove_dir_all(&dir);
std::fs::create_dir_all(&dir).unwrap();
let gen = jni.build_with(registry).expect("resolve");
let rust_path = gen.write_rust(dir.join("gen.rs")).expect("write_rust");
let rust = std::fs::read_to_string(&rust_path).unwrap();
let rc: String = rust.split_whitespace().collect();
assert!(
rc.contains("pubconstMAX_LEN:i64=myflat::MAX_LEN;"),
"{rust}"
);
assert!(
rc.contains("pubconstGREETING:&str=myflat::GREETING;"),
"{rust}"
);
assert!(
!rc.contains("=42"),
"initializer must not be copied: {rust}"
);
assert!(
rust.contains("Java_io_test_jni_JNINative_constGetMaxLen"),
"{rust}"
);
assert!(
rust.contains("Java_io_test_jni_JNINative_constGetGreeting"),
"{rust}"
);
assert!(rust.contains("myflat::MAX_LEN"), "{rust}");
let kdir = dir.join("kotlin");
let paths = gen.write_kotlin(&kdir).expect("write_kotlin");
let pkg = paths
.iter()
.find(|p| p.ends_with("io/test/jni/cfg.kt"))
.map(|p| std::fs::read_to_string(p).unwrap())
.expect("cfg package file");
let pc: String = pkg.split_whitespace().collect();
assert!(
pc.contains("valMAX_LEN:Longbylazy{constGetMaxLen("),
"{pkg}"
);
assert!(
pc.contains("valHELLO:Stringbylazy{constGetGreeting("),
"{pkg}"
);
assert!(!pc.contains("=constGet"), "{pkg}");
assert!(pc.contains("privatefunconstGetMaxLen("), "{pkg}");
let native = paths
.iter()
.find(|p| p.ends_with("io/test/jni.kt"))
.map(|p| std::fs::read_to_string(p).unwrap())
.expect("base package file");
let nc: String = native.split_whitespace().collect();
assert!(nc.contains("externalfunconstGetMaxLen("), "{native}");
assert!(nc.contains("externalfunconstGetGreeting("), "{native}");
}
#[test]
fn unsigned_const_uses_ulong_surface() {
let registry = crate::test_util::reg_from_items(declare_referenced(vec![(
syn::Item::Const(syn::parse_quote!(
pub const MAX_UNSIGNED: u64 = u64::MAX;
)),
myflat_loc(),
)]))
.expect("index items");
let jni = JniGenBuilder::new()
.set_package_prefix("io.test.jni")
.package(crate::package!("cfg").constant(crate::constant!(MAX_UNSIGNED)));
let dir = unique_test_dir("jnigen_consts_unsigned");
let _ = std::fs::remove_dir_all(&dir);
std::fs::create_dir_all(&dir).unwrap();
let gen = jni.build_with(registry).expect("resolve");
gen.write_rust(dir.join("gen.rs")).expect("write_rust");
let paths = gen.write_kotlin(&dir.join("kotlin")).expect("write_kotlin");
let kotlin = paths
.iter()
.map(|p| std::fs::read_to_string(p).unwrap())
.collect::<Vec<_>>()
.join("\n");
let kc: String = kotlin.split_whitespace().collect();
assert!(kc.contains("valMAX_UNSIGNED:ULongbylazy"), "{kotlin}");
assert!(kc.contains("privatefunconstGetMaxUnsigned("), "{kotlin}");
assert!(kc.contains("):ULong"), "{kotlin}");
assert!(kc.contains("externalfunconstGetMaxUnsigned("), "{kotlin}");
assert!(kc.contains("):Long"), "{kotlin}");
assert!(kc.contains(".toULong()"), "{kotlin}");
}
#[test]
fn undeclared_const_not_emitted() {
let registry =
crate::test_util::reg_from_items(declare_referenced(const_items())).expect("index items");
let jni = JniGenBuilder::new()
.set_package_prefix("io.test.jni")
.package(crate::package!("cfg").constant(crate::constant!(MAX_LEN)))
.ignore(crate::constant!(GREETING));
let dir = unique_test_dir("jnigen_consts_undeclared");
let _ = std::fs::remove_dir_all(&dir);
std::fs::create_dir_all(&dir).unwrap();
let gen = jni.build_with(registry).expect("resolve");
let rust_path = gen.write_rust(dir.join("gen.rs")).expect("write_rust");
let rust = std::fs::read_to_string(&rust_path).unwrap();
assert!(rust.contains("pub const MAX_LEN"), "{rust}");
assert!(!rust.contains("GREETING"), "{rust}");
let kdir = dir.join("kotlin");
let paths = gen.write_kotlin(&kdir).expect("write_kotlin");
let all: String = paths
.iter()
.map(|p| std::fs::read_to_string(p).unwrap())
.collect();
assert!(!all.contains("GREETING"), "{all}");
}
#[test]
fn constant_fun_source_emits_val_over_ordinary_wrapper() {
let loc = myflat_loc();
let items: Vec<(syn::Item, prebindgen::SourceLocation)> = vec![(
syn::Item::Fn(syn::parse_quote!(
pub fn tag() -> String {
unimplemented!()
}
)),
loc.clone(),
)];
let registry =
crate::test_util::reg_from_items(declare_referenced(items)).expect("index items");
let jni = JniGenBuilder::new()
.set_package_prefix("io.test.jni")
.package(
crate::package!("cfg")
.constant(crate::constant!(THE_TAG).fun(prebindgen_registry::fun!(tag))),
);
let dir = unique_test_dir("jnigen_constant_fun_basic");
let _ = std::fs::remove_dir_all(&dir);
std::fs::create_dir_all(&dir).unwrap();
let gen = jni.build_with(registry).expect("resolve");
let rust_path = gen.write_rust(dir.join("gen.rs")).expect("write_rust");
let rust = std::fs::read_to_string(&rust_path).unwrap();
assert!(rust.contains("Java_io_test_jni_JNINative_tag"), "{rust}");
assert!(rust.contains("myflat::tag()"), "{rust}");
let kdir = dir.join("kotlin");
let paths = gen.write_kotlin(&kdir).expect("write_kotlin");
let pkg = paths
.iter()
.find(|p| p.ends_with("io/test/jni/cfg.kt"))
.map(|p| std::fs::read_to_string(p).unwrap())
.expect("cfg package file");
let pc: String = pkg.split_whitespace().collect();
assert!(pc.contains("valTHE_TAG:Stringbylazy{tag("), "{pkg}");
assert!(pc.contains("privatefuntag("), "{pkg}");
assert!(!pc.contains("publicfuntag("), "{pkg}");
let native = paths
.iter()
.find(|p| p.ends_with("io/test/jni.kt"))
.map(|p| std::fs::read_to_string(p).unwrap())
.expect("base package file");
let nc: String = native.split_whitespace().collect();
assert!(nc.contains("externalfuntag("), "{native}");
}
#[test]
#[should_panic(expected = "must be nullary")]
fn constant_fun_source_non_nullary_rejected() {
let loc = myflat_loc();
let items: Vec<(syn::Item, prebindgen::SourceLocation)> = vec![(
syn::Item::Fn(syn::parse_quote!(
pub fn scaled(factor: i64) -> i64 {
unimplemented!()
}
)),
loc.clone(),
)];
let registry =
crate::test_util::reg_from_items(declare_referenced(items)).expect("index items");
let jni = JniGenBuilder::new()
.set_package_prefix("io.test.jni")
.package(
crate::package!("cfg")
.constant(crate::constant!(SCALED).fun(prebindgen_registry::fun!(scaled))),
);
let dir = unique_test_dir("jnigen_constant_fun_arity_reject");
let _ = std::fs::remove_dir_all(&dir);
std::fs::create_dir_all(&dir).unwrap();
let gen = jni.build_with(registry).expect("resolve");
gen.write_rust(dir.join("gen.rs")).expect("write_rust");
let _ = gen.write_kotlin(&dir.join("kotlin"));
}
#[test]
#[should_panic(expected = "declared opaque handle")]
fn constant_fun_source_handle_return_rejected() {
let loc = myflat_loc();
let items: Vec<(syn::Item, prebindgen::SourceLocation)> = vec![
(
syn::Item::Struct(syn::parse_quote!(
pub struct ZThing {
_p: u8,
}
)),
loc.clone(),
),
(
syn::Item::Fn(syn::parse_quote!(
pub fn default_thing() -> ZThing {
unimplemented!()
}
)),
loc.clone(),
),
];
let registry =
crate::test_util::reg_from_items(declare_referenced(items)).expect("index items");
let jni = JniGenBuilder::new()
.set_package_prefix("io.test.jni")
.package(
crate::package!("things")
.class(crate::ptr_class!(ZThing))
.constant(
crate::constant!(DEFAULT_THING).fun(prebindgen_registry::fun!(default_thing)),
),
);
let dir = unique_test_dir("jnigen_constant_fun_handle_reject");
let _ = std::fs::remove_dir_all(&dir);
std::fs::create_dir_all(&dir).unwrap();
let gen = jni.build_with(registry).expect("resolve");
gen.write_rust(dir.join("gen.rs")).expect("write_rust");
let _ = gen.write_kotlin(&dir.join("kotlin"));
}
#[test]
fn constant_expr_emits_getter_and_val() {
let loc = myflat_loc();
let items: Vec<(syn::Item, prebindgen::SourceLocation)> = vec![(
syn::Item::Fn(syn::parse_quote!(
pub fn tag_of(n: i64) -> String {
unimplemented!()
}
)),
loc.clone(),
)];
let registry =
crate::test_util::reg_from_items(declare_referenced(items)).expect("index items");
let jni = JniGenBuilder::new()
.set_package_prefix("io.test.jni")
.package(
crate::package!("cfg")
.fun(prebindgen_registry::fun!(tag_of))
.constant(crate::constant!(DEFAULT_TAG).expr(
prebindgen_registry::ty!(String),
prebindgen_registry::expr!(tag_of(7)),
)),
);
let dir = unique_test_dir("jnigen_constant_expr_basic");
let _ = std::fs::remove_dir_all(&dir);
std::fs::create_dir_all(&dir).unwrap();
let gen = jni.build_with(registry).expect("resolve");
let rust_path = gen.write_rust(dir.join("gen.rs")).expect("write_rust");
let rust = std::fs::read_to_string(&rust_path).unwrap();
let rc: String = rust.split_whitespace().collect();
assert!(
rust.contains("Java_io_test_jni_JNINative_constGetDefaultTag"),
"{rust}"
);
assert!(rc.contains("usemyflat::*;"), "{rust}");
assert!(rc.contains("tag_of(7)"), "{rust}");
let kdir = dir.join("kotlin");
let paths = gen.write_kotlin(&kdir).expect("write_kotlin");
let pkg = paths
.iter()
.find(|p| p.ends_with("io/test/jni/cfg.kt"))
.map(|p| std::fs::read_to_string(p).unwrap())
.expect("cfg package file");
let pc: String = pkg.split_whitespace().collect();
assert!(
pc.contains("valDEFAULT_TAG:Stringbylazy{constGetDefaultTag("),
"{pkg}"
);
assert!(pc.contains("privatefunconstGetDefaultTag("), "{pkg}");
let native = paths
.iter()
.find(|p| p.ends_with("io/test/jni.kt"))
.map(|p| std::fs::read_to_string(p).unwrap())
.expect("base package file");
let nc: String = native.split_whitespace().collect();
assert!(nc.contains("externalfunconstGetDefaultTag("), "{native}");
}
#[test]
#[should_panic(expected = "declared opaque handle")]
fn constant_expr_handle_type_rejected() {
let loc = myflat_loc();
let items: Vec<(syn::Item, prebindgen::SourceLocation)> = vec![
(
syn::Item::Struct(syn::parse_quote!(
pub struct ZThing {
_p: u8,
}
)),
loc.clone(),
),
(
syn::Item::Fn(syn::parse_quote!(
pub fn thing_new() -> ZThing {
unimplemented!()
}
)),
loc.clone(),
),
];
let registry =
crate::test_util::reg_from_items(declare_referenced(items)).expect("index items");
let jni = JniGenBuilder::new()
.set_package_prefix("io.test.jni")
.package(
crate::package!("things")
.class(crate::ptr_class!(ZThing))
.fun(prebindgen_registry::fun!(thing_new))
.constant(crate::constant!(DEFAULT_THING).expr(
prebindgen_registry::ty!(ZThing),
prebindgen_registry::expr!(thing_new()),
)),
);
let dir = unique_test_dir("jnigen_constant_expr_handle_reject");
let _ = std::fs::remove_dir_all(&dir);
std::fs::create_dir_all(&dir).unwrap();
let _ = jni
.build_with(registry)
.and_then(|gen| gen.write_rust(dir.join("gen.rs")));
}
#[test]
#[should_panic(expected = "declared opaque handle")]
fn handle_const_rejected() {
let loc = myflat_loc();
let items: Vec<(syn::Item, prebindgen::SourceLocation)> = vec![
(
syn::Item::Struct(syn::parse_quote!(
pub struct ZThing {
_p: u8,
}
)),
loc.clone(),
),
(
syn::Item::Const(syn::parse_quote!(
pub const DEFAULT_THING: ZThing = ZThing { _p: 0 };
)),
loc.clone(),
),
(
syn::Item::Fn(syn::parse_quote!(
pub fn thing_new() -> ZThing {
unimplemented!()
}
)),
loc.clone(),
),
];
let registry =
crate::test_util::reg_from_items(declare_referenced(items)).expect("index items");
let jni = JniGenBuilder::new()
.set_package_prefix("io.test.jni")
.package(
crate::package!("things")
.class(crate::ptr_class!(ZThing))
.fun(prebindgen_registry::fun!(thing_new))
.constant(crate::constant!(DEFAULT_THING)),
);
let dir = unique_test_dir("jnigen_consts_handle_reject");
let _ = std::fs::remove_dir_all(&dir);
std::fs::create_dir_all(&dir).unwrap();
let _ = jni
.build_with(registry)
.and_then(|gen| gen.write_rust(dir.join("gen.rs")));
}
#[test]
fn constant_with_source_calls_path_verbatim() {
let loc = myflat_loc();
let items: Vec<(syn::Item, prebindgen::SourceLocation)> = vec![(
syn::Item::Fn(syn::parse_quote!(
pub fn unrelated() -> i64 {
unimplemented!()
}
)),
loc.clone(),
)];
let registry =
crate::test_util::reg_from_items(declare_referenced(items)).expect("index items");
let jni = JniGenBuilder::new()
.set_package_prefix("io.test.jni")
.package(
crate::package!("cfg")
.fun(prebindgen_registry::fun!(unrelated))
.constant(crate::constant!(COVER_VERSION).with(
prebindgen_registry::ty!(String),
prebindgen_registry::path!(crate::cover_version),
)),
);
let dir = unique_test_dir("jnigen_constant_with_basic");
let _ = std::fs::remove_dir_all(&dir);
std::fs::create_dir_all(&dir).unwrap();
let gen = jni.build_with(registry).expect("resolve");
let rust_path = gen.write_rust(dir.join("gen.rs")).expect("write_rust");
let rust = std::fs::read_to_string(&rust_path).unwrap();
let rc: String = rust.split_whitespace().collect();
assert!(
rust.contains("Java_io_test_jni_JNINative_constGetCoverVersion"),
"{rust}"
);
assert!(rc.contains("crate::cover_version()"), "{rust}");
assert!(!rc.contains("myflat::cover_version"), "{rust}");
let kdir = dir.join("kotlin");
let paths = gen.write_kotlin(&kdir).expect("write_kotlin");
let pkg = paths
.iter()
.find(|p| p.ends_with("io/test/jni/cfg.kt"))
.map(|p| std::fs::read_to_string(p).unwrap())
.expect("cfg package file");
let pc: String = pkg.split_whitespace().collect();
assert!(
pc.contains("valCOVER_VERSION:Stringbylazy{constGetCoverVersion("),
"{pkg}"
);
}
#[test]
#[should_panic(expected = "value source already set")]
fn constant_second_source_rejected() {
let _ = crate::constant!(X)
.expr(
prebindgen_registry::ty!(i64),
prebindgen_registry::expr!(1 + 1),
)
.with(
prebindgen_registry::ty!(i64),
prebindgen_registry::path!(crate::f),
);
}
#[test]
fn constant_named_runtime_form_matches_macro() {
let a = crate::ConstDecl::named(format!("ENCODING_{}", "ZENOH_BYTES")).expr(
prebindgen_registry::ty!(String),
prebindgen_registry::expr!(enc()),
);
let b = crate::constant!(ENCODING_ZENOH_BYTES).expr(
prebindgen_registry::ty!(String),
prebindgen_registry::expr!(enc()),
);
assert_eq!(a.val_name(), b.val_name());
assert_eq!(a.rust_ident, b.rust_ident);
}
#[test]
#[should_panic(expected = "not a valid identifier")]
fn constant_named_invalid_ident_rejected() {
let _ = crate::ConstDecl::named("NOT AN IDENT");
}