1 #![cfg(feature = "invocation")]
2
3 use std::{sync::Arc, thread::spawn};
4
5 use jni::{
6 errors::{Error, JniError},
7 Executor, JavaVM,
8 };
9
10 mod util;
11 use util::jvm;
12
13 /// Checks if nested attaches are working properly and threads detach themselves
14 /// on exit.
15 #[test]
nested_attach()16 fn nested_attach() {
17 let executor = Executor::new(jvm().clone());
18
19 assert_eq!(jvm().threads_attached(), 0);
20 let thread = spawn(|| {
21 assert_eq!(jvm().threads_attached(), 0);
22 check_nested_attach(jvm(), executor);
23 assert_eq!(jvm().threads_attached(), 1);
24 });
25 thread.join().unwrap();
26 assert_eq!(jvm().threads_attached(), 0);
27 }
28
29 /// Checks if nested `with_attached` calls does not detach the thread before the outer-most
30 /// call is finished.
check_nested_attach(vm: &Arc<JavaVM>, executor: Executor)31 fn check_nested_attach(vm: &Arc<JavaVM>, executor: Executor) {
32 check_detached(vm);
33 executor
34 .with_attached(|_| {
35 check_attached(vm);
36 executor.with_attached(|_| {
37 check_attached(vm);
38 Ok(())
39 })?;
40 check_attached(vm);
41 Ok(())
42 })
43 .unwrap();
44 }
45
check_attached(vm: &JavaVM)46 fn check_attached(vm: &JavaVM) {
47 assert!(is_attached(vm));
48 }
49
check_detached(vm: &JavaVM)50 fn check_detached(vm: &JavaVM) {
51 assert!(!is_attached(vm));
52 }
53
is_attached(vm: &JavaVM) -> bool54 fn is_attached(vm: &JavaVM) -> bool {
55 vm.get_env()
56 .map(|_| true)
57 .or_else(|jni_err| match jni_err {
58 Error::JniCall(JniError::ThreadDetached) => Ok(false),
59 _ => Err(jni_err),
60 })
61 .expect("An unexpected JNI error occurred")
62 }
63