use prebindgen_registry::Conversions;
use super::*;
#[test]
fn option_carves_single_niche() {
let mut reg = Registry::empty_for_test();
install_input(
&mut reg,
"TestType",
0,
entry(
syn::parse_quote!(jni::sys::jlong),
"jlong_to_TestType_aaaa",
Niches::one(syn::parse_quote!(0i64), syn::parse_quote!(*v == 0)),
),
);
let inner_ty: syn::Type = syn::parse_quote!(TestType);
let (wire, _body, niches) = option_input(
®.reading_of(&inner_ty).expect("interned"),
®,
&prebindgen_registry::Emit::for_test(),
)
.expect("Option<TestType> resolves");
assert_eq!(
wire.to_token_stream().to_string(),
"jni :: sys :: jlong",
"wire stays jlong (no JObject widening)"
);
assert!(niches.is_empty(), "single niche fully consumed");
}
#[test]
fn option_cascades_through_multi_niche() {
let mut reg = Registry::empty_for_test();
install_input(
&mut reg,
"TestType",
0,
entry(
syn::parse_quote!(jni::sys::jint),
"jint_to_TestType_aaaa",
Niches::from_slots([
NicheSlot {
value: syn::parse_quote!(jni::sys::jint::MIN),
matches: syn::parse_quote!(*v == jni::sys::jint::MIN),
},
NicheSlot {
value: syn::parse_quote!(jni::sys::jint::MAX),
matches: syn::parse_quote!(*v == jni::sys::jint::MAX),
},
]),
),
);
let layer1_ty: syn::Type = syn::parse_quote!(TestType);
let (w1, _, n1) = option_input(
®.reading_of(&layer1_ty).expect("interned"),
®,
&prebindgen_registry::Emit::for_test(),
)
.expect("layer 1 resolves");
assert_eq!(w1.to_token_stream().to_string(), "jni :: sys :: jint");
assert_eq!(n1.len(), 1, "first carve leaves one niche");
install_input(
&mut reg,
"Option < TestType >",
1,
entry(w1.clone(), "jint_to_OptionTestType_bbbb", n1),
);
let layer2_ty: syn::Type = syn::parse_quote!(Option<TestType>);
let (w2, _, n2) = option_input(
®.reading_of(&layer2_ty).expect("interned"),
®,
&prebindgen_registry::Emit::for_test(),
)
.expect("layer 2 resolves");
assert_eq!(
w2.to_token_stream().to_string(),
"jni :: sys :: jint",
"wire still jint at layer 2 — no widening"
);
assert!(n2.is_empty(), "second carve consumes the last niche");
install_input(
&mut reg,
"Option < Option < TestType > >",
1,
entry(w2.clone(), "jint_to_OptionOptionTestType_cccc", n2),
);
let layer3_ty: syn::Type = syn::parse_quote!(Option<Option<TestType>>);
let (w3, _, n3) = option_input(
®.reading_of(&layer3_ty).expect("interned"),
®,
&prebindgen_registry::Emit::for_test(),
)
.expect("layer 3 resolves via box fallback");
assert_eq!(
w3.to_token_stream().to_string(),
"jni :: objects :: JObject",
"layer 3 widens to JObject (box fallback)"
);
assert!(
n3.is_empty(),
"boxed wrapper exposes no further niches — every JObject carries meaning"
);
}
#[test]
fn option_output_cascades_through_multi_niche() {
let mut reg = Registry::empty_for_test();
install_output(
&mut reg,
"TestType",
0,
entry(
syn::parse_quote!(jni::sys::jint),
"TestType_to_jint_aaaa",
Niches::from_slots([
NicheSlot {
value: syn::parse_quote!(-1i32),
matches: syn::parse_quote!(*v == -1),
},
NicheSlot {
value: syn::parse_quote!(-2i32),
matches: syn::parse_quote!(*v == -2),
},
]),
),
);
let inner_ty: syn::Type = syn::parse_quote!(TestType);
let (w1, body1, n1) = option_output(®.reading_of(&inner_ty).expect("interned"), ®)
.expect("Option<TestType> output resolves");
assert_eq!(w1.to_token_stream().to_string(), "jni :: sys :: jint");
assert_eq!(n1.len(), 1, "one slot left after carving the first");
let body_str = body1.to_token_stream().to_string();
assert!(
body_str.contains("None => - 1i32") || body_str.contains("None => -1i32"),
"expected `None => -1i32` in body; got:\n{}",
body_str,
);
install_output(
&mut reg,
"Option < TestType >",
1,
entry(w1.clone(), "OptionTestType_to_jint_bbbb", n1),
);
let layer2_ty: syn::Type = syn::parse_quote!(Option<TestType>);
let (w2, body2, n2) = option_output(®.reading_of(&layer2_ty).expect("interned"), ®)
.expect("Option<Option<TestType>> output resolves");
assert_eq!(w2.to_token_stream().to_string(), "jni :: sys :: jint");
assert!(n2.is_empty());
let body2_str = body2.to_token_stream().to_string();
assert!(
body2_str.contains("None => - 2i32") || body2_str.contains("None => -2i32"),
"second layer must use the second niche (-2); got:\n{}",
body2_str,
);
}
#[test]
fn option_over_jobject_uses_default_null_niche() {
let mut reg = Registry::empty_for_test();
install_input(
&mut reg,
"MyStruct",
0,
entry(
syn::parse_quote!(jni::objects::JObject),
"JObject_to_MyStruct_aaaa",
default_niches_for_wire(&syn::parse_quote!(jni::objects::JObject)),
),
);
let ty: syn::Type = syn::parse_quote!(MyStruct);
let (wire, _, rest) = option_input(
®.reading_of(&ty).expect("interned"),
®,
&prebindgen_registry::Emit::for_test(),
)
.expect("Option<MyStruct> resolves");
assert_eq!(
wire.to_token_stream().to_string(),
"jni :: objects :: JObject"
);
assert!(rest.is_empty(), "JObject's single null niche is consumed");
}
#[test]
fn option_fails_when_no_niche_and_non_primitive_wire() {
let mut reg = Registry::empty_for_test();
install_input(
&mut reg,
"MyStruct",
0,
entry(
syn::parse_quote!(jni::objects::JObject),
"JObject_to_MyStruct_aaaa",
Niches::empty(), ),
);
let ty: syn::Type = syn::parse_quote!(MyStruct);
assert!(option_input(
®.reading_of(&ty).expect("interned"),
®,
&prebindgen_registry::Emit::for_test()
)
.is_none());
}
#[test]
fn option_box_fallback_exposes_no_niches() {
let mut reg = Registry::empty_for_test();
install_input(
&mut reg,
"i64",
0,
entry(
syn::parse_quote!(jni::sys::jlong),
"jlong_to_i64_aaaa",
Niches::empty(), ),
);
let ty: syn::Type = syn::parse_quote!(i64);
let (wire, _, rest) = option_input(
®.reading_of(&ty).expect("interned"),
®,
&prebindgen_registry::Emit::for_test(),
)
.expect("Option<i64> via box fallback");
assert_eq!(
wire.to_token_stream().to_string(),
"jni :: objects :: JObject"
);
assert!(rest.is_empty());
}