rust_jni/
init_arguments.rs

1use jni::ToJni;
2use jni_sys;
3use raw::*;
4use std::ffi::{CStr, CString};
5use std::marker::PhantomData;
6use std::os::raw::c_void;
7use std::ptr;
8use std::slice;
9use version::{self, JniVersion};
10
11/// Verbose options for starting a Java VM.
12///
13/// [JNI documentation](https://docs.oracle.com/javase/10/docs/specs/jni/invocation.html#jni_createjavavm)
14#[derive(Debug, Clone, PartialEq, Eq)]
15pub enum JvmVerboseOption {
16    /// Verbose class option.
17    ///
18    /// Passed to the JVM as `-verbose:class`.
19    Class,
20    /// Verbose GC option.
21    ///
22    /// Passed to the JVM as `-verbose:gc`.
23    Gc,
24    /// Verbose JNI option.
25    ///
26    /// Passed to the JVM as `-verbose:jni`.
27    Jni,
28}
29
30fn verbose_option_to_string(option: &JvmVerboseOption) -> &'static str {
31    match option {
32        JvmVerboseOption::Class => "class",
33        JvmVerboseOption::Gc => "gc",
34        JvmVerboseOption::Jni => "jni",
35    }
36}
37
38#[cfg(test)]
39mod verbose_option_to_string_tests {
40    use super::*;
41
42    #[test]
43    fn test() {
44        assert_eq!(verbose_option_to_string(&JvmVerboseOption::Class), "class");
45        assert_eq!(verbose_option_to_string(&JvmVerboseOption::Gc), "gc");
46        assert_eq!(verbose_option_to_string(&JvmVerboseOption::Jni), "jni");
47    }
48}
49
50/// Options for starting a Java VM.
51///
52/// [JNI documentation](https://docs.oracle.com/javase/10/docs/specs/jni/invocation.html#jni_createjavavm)
53// TODO(#13): support vfprintf, exit, abort options.
54#[derive(Debug, Clone, PartialEq, Eq)]
55pub enum JvmOption {
56    /// Verbose option.
57    ///
58    /// Passed to the JVM as `-verbose:${verbose_option}`.
59    Verbose(JvmVerboseOption),
60    /// System property option string. Must have a key and a value.
61    ///
62    /// Is formatted as `-D{key}=${value}`.
63    SystemProperty(String, String),
64    /// Enable checking JNI calls.
65    ///
66    /// Passed to the JVM as `-check:jni`.
67    CheckedJni,
68    /// Unknown option.
69    /// Needed for forward compability and to set custom options.
70    /// The string value is passed to the JVM without change.
71    Unknown(String),
72}
73
74impl JvmOption {
75    /// Unsafe because one can pass a non-UTF-8 or non-null-terminated option string.
76    unsafe fn from_raw(option: &jni_sys::JavaVMOption) -> Self {
77        // TODO(#14): support platform encodings other than UTF-8.
78        let option_string = CStr::from_ptr((*option).optionString).to_str().unwrap();
79        let system_property_prefix = "-D";
80        match option_string {
81            "-verbose:gc" => JvmOption::Verbose(JvmVerboseOption::Gc),
82            "-verbose:jni" => JvmOption::Verbose(JvmVerboseOption::Jni),
83            "-verbose:class" => JvmOption::Verbose(JvmVerboseOption::Class),
84            "-Xcheck:jni" => JvmOption::CheckedJni,
85            option if option.starts_with(system_property_prefix) => {
86                let parts: Vec<&str> = option
87                    .split_at(system_property_prefix.len())
88                    .1
89                    .splitn(2, "=")
90                    .collect();
91                if parts.len() != 2 {
92                    JvmOption::Unknown(option.to_owned())
93                } else {
94                    JvmOption::SystemProperty(parts[0].to_owned(), parts[1].to_owned())
95                }
96            }
97            option => JvmOption::Unknown(option.to_owned()),
98        }
99    }
100}
101
102#[cfg(test)]
103mod jvm_option_tests {
104    use super::*;
105
106    #[test]
107    fn from_raw_checked_jni() {
108        let option_string = CStr::from_bytes_with_nul(b"-Xcheck:jni\0").unwrap();
109        let option = &jni_sys::JavaVMOption {
110            optionString: option_string.as_ptr() as *mut i8,
111            extraInfo: ptr::null_mut(),
112        };
113        assert_eq!(
114            unsafe { JvmOption::from_raw(option) },
115            JvmOption::CheckedJni
116        );
117    }
118
119    #[test]
120    fn from_raw_verbose() {
121        let option_string = CStr::from_bytes_with_nul(b"-verbose:jni\0").unwrap();
122        let option = &jni_sys::JavaVMOption {
123            optionString: option_string.as_ptr() as *mut i8,
124            extraInfo: ptr::null_mut(),
125        };
126        assert_eq!(
127            unsafe { JvmOption::from_raw(option) },
128            JvmOption::Verbose(JvmVerboseOption::Jni)
129        );
130
131        let option_string = CStr::from_bytes_with_nul(b"-verbose:gc\0").unwrap();
132        let option = &jni_sys::JavaVMOption {
133            optionString: option_string.as_ptr() as *mut i8,
134            extraInfo: ptr::null_mut(),
135        };
136        assert_eq!(
137            unsafe { JvmOption::from_raw(option) },
138            JvmOption::Verbose(JvmVerboseOption::Gc)
139        );
140
141        let option_string = CStr::from_bytes_with_nul(b"-verbose:class\0").unwrap();
142        let option = &jni_sys::JavaVMOption {
143            optionString: option_string.as_ptr() as *mut i8,
144            extraInfo: ptr::null_mut(),
145        };
146        assert_eq!(
147            unsafe { JvmOption::from_raw(option) },
148            JvmOption::Verbose(JvmVerboseOption::Class)
149        );
150    }
151
152    #[test]
153    fn from_raw_system_property() {
154        let option_string = CStr::from_bytes_with_nul(b"-Dkey=value\0").unwrap();
155        let option = &jni_sys::JavaVMOption {
156            optionString: option_string.as_ptr() as *mut i8,
157            extraInfo: ptr::null_mut(),
158        };
159        assert_eq!(
160            unsafe { JvmOption::from_raw(option) },
161            JvmOption::SystemProperty("key".to_owned(), "value".to_owned())
162        );
163    }
164
165    #[test]
166    fn from_raw_unknown() {
167        let option_string = CStr::from_bytes_with_nul(b"tyhb\0").unwrap();
168        let option = &jni_sys::JavaVMOption {
169            optionString: option_string.as_ptr() as *mut i8,
170            extraInfo: ptr::null_mut(),
171        };
172        assert_eq!(
173            unsafe { JvmOption::from_raw(option) },
174            JvmOption::Unknown("tyhb".to_owned())
175        );
176
177        let option_string = CStr::from_bytes_with_nul(b"-Dkey~value\0").unwrap();
178        let option = &jni_sys::JavaVMOption {
179            optionString: option_string.as_ptr() as *mut i8,
180            extraInfo: ptr::null_mut(),
181        };
182        assert_eq!(
183            unsafe { JvmOption::from_raw(option) },
184            JvmOption::Unknown("-Dkey~value".to_owned())
185        );
186    }
187
188    #[test]
189    fn to_string() {
190        assert_eq!(option_to_string(&JvmOption::CheckedJni), "-Xcheck:jni");
191        assert_eq!(
192            option_to_string(&JvmOption::Verbose(JvmVerboseOption::Gc)),
193            "-verbose:gc"
194        );
195        assert_eq!(
196            option_to_string(&JvmOption::Verbose(JvmVerboseOption::Jni)),
197            "-verbose:jni"
198        );
199        assert_eq!(
200            option_to_string(&JvmOption::Verbose(JvmVerboseOption::Class)),
201            "-verbose:class"
202        );
203        assert_eq!(
204            option_to_string(&JvmOption::SystemProperty(
205                "key".to_owned(),
206                "value".to_owned()
207            )),
208            "-Dkey=value"
209        );
210        assert_eq!(
211            option_to_string(&JvmOption::Unknown("qwer".to_owned())),
212            "qwer"
213        );
214    }
215}
216
217fn option_to_string(option: &JvmOption) -> String {
218    match option {
219        JvmOption::CheckedJni => "-Xcheck:jni".to_owned(),
220        JvmOption::Verbose(option) => format!("-verbose:{}", verbose_option_to_string(option)),
221        JvmOption::SystemProperty(key, value) => format!("-D{}={}", key, value),
222        JvmOption::Unknown(value) => value.clone(),
223    }
224}
225
226#[cfg(test)]
227mod option_to_string_tests {
228    use super::*;
229
230    #[test]
231    fn test() {
232        assert_eq!(option_to_string(&JvmOption::CheckedJni), "-Xcheck:jni");
233        assert_eq!(
234            option_to_string(&JvmOption::Verbose(JvmVerboseOption::Gc)),
235            "-verbose:gc"
236        );
237        assert_eq!(
238            option_to_string(&JvmOption::Verbose(JvmVerboseOption::Jni)),
239            "-verbose:jni"
240        );
241        assert_eq!(
242            option_to_string(&JvmOption::Verbose(JvmVerboseOption::Class)),
243            "-verbose:class"
244        );
245        assert_eq!(
246            option_to_string(&JvmOption::SystemProperty(
247                "key".to_owned(),
248                "value".to_owned()
249            )),
250            "-Dkey=value"
251        );
252        assert_eq!(
253            option_to_string(&JvmOption::Unknown("qwer".to_owned())),
254            "qwer"
255        );
256    }
257}
258
259/// Arguments for creating a Java VM.
260///
261/// [JNI documentation](https://docs.oracle.com/javase/10/docs/specs/jni/invocation.html#jni_createjavavm)
262///
263/// # Example
264/// ```
265/// use rust_jni::{InitArguments, JniVersion, JvmOption, JvmVerboseOption};
266///
267/// let options = InitArguments::get_default(JniVersion::V8).unwrap()
268///     .with_option(JvmOption::Unknown("-Xgc:parallel".to_owned()))
269///     .with_option(JvmOption::Verbose(JvmVerboseOption::Gc));
270///
271/// assert_eq!(options.version(), JniVersion::V8);
272/// ```
273#[derive(Debug, Clone, PartialEq, Eq)]
274pub struct InitArguments {
275    version: JniVersion,
276    options: Vec<JvmOption>,
277    ignore_unrecognized: bool,
278}
279
280impl InitArguments {
281    /// Get default Java VM init arguments for a JNI version.
282    /// If the requested JNI version is not supported, returns
283    /// [`None`](https://doc.rust-lang.org/std/option/enum.Option.html#variant.None).
284    ///
285    /// [JNI documentation](https://docs.oracle.com/javase/10/docs/specs/jni/invocation.html#jni_getdefaultjavavminitargs)
286    pub fn get_default(version: JniVersion) -> Option<Self> {
287        let arguments = Self::get_default_or_closest_supported(version);
288        if arguments.version == version {
289            Some(arguments)
290        } else {
291            None
292        }
293    }
294
295    /// Get default Java VM init arguments for a JNI version.
296    /// If the requested JNI version is not supported, returns default arguments for the closest
297    /// supported JNI version. The new version can be obtained with the
298    /// [`InitArguments::version()`](struct.InitArguments.html#method.version) method.
299    ///
300    /// [JNI documentation](https://docs.oracle.com/javase/10/docs/specs/jni/invocation.html#jni_getdefaultjavavminitargs)
301    pub fn get_default_or_closest_supported(version: JniVersion) -> Self {
302        let mut raw_arguments = jni_sys::JavaVMInitArgs {
303            version: version::to_raw(version),
304            nOptions: 0,
305            options: ptr::null_mut(),
306            ignoreUnrecognized: jni_sys::JNI_FALSE,
307        };
308        // Safe because we pass a pointer to a correct data structure.
309        unsafe {
310            // It is fine if the requested version is not supported, we'll just use
311            // a supported one.
312            JNI_GetDefaultJavaVMInitArgs(
313                &mut raw_arguments as *mut jni_sys::JavaVMInitArgs as *mut c_void,
314            );
315        }
316        // Safe because raw arguments were correctly initialized by the
317        // `JNI_GetDefaultJavaVMInitArgs`.
318        unsafe { Self::from_raw(&raw_arguments).with_option(JvmOption::CheckedJni) }
319    }
320
321    /// Unsafe because one can pass incorrect options.
322    unsafe fn from_raw(raw_arguments: &jni_sys::JavaVMInitArgs) -> InitArguments {
323        let options = slice::from_raw_parts(raw_arguments.options, raw_arguments.nOptions as usize)
324            .iter()
325            .map(|value| JvmOption::from_raw(value))
326            .collect();
327        InitArguments {
328            version: version::from_raw(raw_arguments.version),
329            ignore_unrecognized: to_bool(raw_arguments.ignoreUnrecognized),
330            options,
331        }
332    }
333
334    /// Get default init arguments for the latest supported JNI version.
335    ///
336    /// [JNI documentation](https://docs.oracle.com/javase/10/docs/specs/jni/invocation.html#jni_getdefaultjavavminitargs)
337    pub fn get_latest_default() -> Self {
338        Self::get_default_or_closest_supported(JniVersion::V8)
339    }
340
341    /// Add init options to the Java VM init arguments.
342    ///
343    /// [JNI documentation](https://docs.oracle.com/javase/10/docs/specs/jni/invocation.html#jni_createjavavm)
344    pub fn with_options(mut self, options: &[JvmOption]) -> Self {
345        self.options.extend_from_slice(options);
346        self
347    }
348
349    /// Add an init option to the Java VM init arguments.
350    ///
351    /// [JNI documentation](https://docs.oracle.com/javase/10/docs/specs/jni/invocation.html#jni_createjavavm)
352    pub fn with_option(self, option: JvmOption) -> Self {
353        self.with_options(&[option])
354    }
355
356    /// Disable checking JNI calls for correctness.
357    pub fn unchecked(self) -> Self {
358        InitArguments {
359            version: self.version,
360            ignore_unrecognized: self.ignore_unrecognized,
361            options: self.options
362                .iter()
363                .filter(|&option| *option != JvmOption::CheckedJni)
364                .cloned()
365                .collect(),
366        }
367    }
368
369    /// Enable checking JNI calls for correctness.
370    ///
371    /// This is a default. Only needed to be called if checking JNI calls was explicitly disabled.
372    pub fn checked(self) -> Self {
373        self.with_option(JvmOption::CheckedJni)
374    }
375
376    /// Request for JVM to ignore unrecognized options on startup.
377    ///
378    /// [JNI documentation](https://docs.oracle.com/javase/10/docs/specs/jni/invocation.html#jni_createjavavm)
379    pub fn ignore_unrecognized_options(mut self) -> Self {
380        self.ignore_unrecognized = true;
381        self
382    }
383
384    /// Request for JVM to fail in presence of unrecognized options on startup.
385    ///
386    /// [JNI documentation](https://docs.oracle.com/javase/10/docs/specs/jni/invocation.html#jni_createjavavm)
387    pub fn fail_on_unrecognized_options(mut self) -> Self {
388        self.ignore_unrecognized = false;
389        self
390    }
391
392    /// Return the JNI version these arguments will request when creating a Java VM.
393    ///
394    /// [JNI documentation](https://docs.oracle.com/javase/10/docs/specs/jni/invocation.html#jni_createjavavm)
395    pub fn version(&self) -> JniVersion {
396        self.version
397    }
398}
399
400/// A wrapper around `jni_sys::JavaVMInitArgs` with a lifetime to ensure
401/// there's no access to freed memory.
402pub struct RawInitArguments<'a> {
403    pub raw_arguments: jni_sys::JavaVMInitArgs,
404    _buffer: PhantomData<&'a Vec<CString>>,
405}
406
407pub fn to_raw<'a, 'b, 'c: 'a + 'b>(
408    arguments: &InitArguments,
409    strings_buffer: &'a mut Vec<CString>,
410    options_buffer: &'b mut Vec<jni_sys::JavaVMOption>,
411) -> RawInitArguments<'c> {
412    *strings_buffer = arguments
413        .options
414        .iter()
415        .map(|_| "")
416        .map(CString::new)
417        .map(Result::unwrap)
418        .collect();
419    *options_buffer = arguments
420        .options
421        .iter()
422        .zip(strings_buffer.iter_mut())
423        .map(|(option, ref mut buffer)| {
424            // TODO(#14): support platform encodings other than UTF-8.
425            let buffer: &mut CString = buffer;
426            *buffer = CString::new(option_to_string(option)).unwrap();
427            jni_sys::JavaVMOption {
428                optionString: buffer.as_ptr() as *mut i8,
429                extraInfo: ptr::null_mut(),
430            }
431        })
432        .collect();
433    RawInitArguments {
434        raw_arguments: jni_sys::JavaVMInitArgs {
435            version: version::to_raw(arguments.version),
436            nOptions: options_buffer.len() as i32,
437            options: options_buffer.as_mut_ptr(),
438            // Safe because `bool` conversion is safe internally.
439            ignoreUnrecognized: unsafe { bool::__to_jni(&arguments.ignore_unrecognized) },
440        },
441        _buffer: PhantomData::<&'c Vec<CString>>,
442    }
443}
444
445#[cfg(test)]
446pub unsafe fn from_raw(raw_arguments: &jni_sys::JavaVMInitArgs) -> InitArguments {
447    InitArguments::from_raw(raw_arguments)
448}
449
450#[cfg(test)]
451pub fn test(version: JniVersion) -> InitArguments {
452    InitArguments {
453        version: version,
454        options: vec![],
455        ignore_unrecognized: true,
456    }
457}
458
459#[cfg(test)]
460pub mod tests {
461    use super::*;
462
463    fn default_options() -> Vec<JvmOption> {
464        vec![
465            JvmOption::SystemProperty("key".to_owned(), "value".to_owned()),
466            JvmOption::Unknown("qwer".to_owned()),
467        ]
468    }
469
470    fn resulting_options() -> Vec<JvmOption> {
471        vec![
472            JvmOption::SystemProperty("key".to_owned(), "value".to_owned()),
473            JvmOption::Unknown("qwer".to_owned()),
474            JvmOption::CheckedJni,
475        ]
476    }
477
478    pub fn default_args() -> InitArguments {
479        InitArguments {
480            version: JniVersion::V4,
481            options: default_options(),
482            ignore_unrecognized: false,
483        }
484    }
485
486    fn check_arguments(version: JniVersion) {
487        let actual_arguments = get_default_java_vm_init_args_call_input();
488        assert_eq!(actual_arguments.version, version::to_raw(version));
489        assert_eq!(actual_arguments.nOptions, 0);
490        assert_eq!(actual_arguments.options, ptr::null_mut());
491        assert_eq!(actual_arguments.ignoreUnrecognized, jni_sys::JNI_FALSE);
492    }
493
494    #[test]
495    fn to_raw_test() {
496        let arguments = InitArguments {
497            version: JniVersion::V4,
498            options: default_options(),
499            ignore_unrecognized: false,
500        };
501        let mut strings_buffer = vec![];
502        let mut options_buffer = vec![];
503        let raw_arguments = to_raw(&arguments, &mut strings_buffer, &mut options_buffer);
504        assert_eq!(
505            raw_arguments.raw_arguments.version,
506            version::to_raw(JniVersion::V4)
507        );
508        assert_eq!(raw_arguments.raw_arguments.nOptions, 2);
509        assert_eq!(
510            raw_arguments.raw_arguments.ignoreUnrecognized,
511            jni_sys::JNI_FALSE
512        );
513        let raw_options = unsafe {
514            slice::from_raw_parts(
515                raw_arguments.raw_arguments.options,
516                raw_arguments.raw_arguments.nOptions as usize,
517            )
518        };
519        for (raw_option, option) in raw_options.iter().zip(default_options().into_iter()) {
520            assert_eq!(option, unsafe { JvmOption::from_raw(raw_option) });
521        }
522    }
523
524    #[test]
525    fn get_default_supported() {
526        let mut strings_buffer = vec![];
527        let mut options_buffer = vec![];
528        let mut raw_arguments = to_raw(&default_args(), &mut strings_buffer, &mut options_buffer);
529        let _locked = setup_get_default_java_vm_init_args_call(GetDefaultJavaVMInitArgsCall::new(
530            &mut raw_arguments.raw_arguments as *mut jni_sys::JavaVMInitArgs as *mut c_void,
531        ));
532        assert_eq!(
533            InitArguments::get_default(JniVersion::V4),
534            Some(InitArguments {
535                version: JniVersion::V4,
536                options: resulting_options(),
537                ignore_unrecognized: false
538            })
539        );
540        check_arguments(JniVersion::V4);
541    }
542
543    #[test]
544    fn get_default_unsupported() {
545        let mut strings_buffer = vec![];
546        let mut options_buffer = vec![];
547        let mut raw_arguments = to_raw(&default_args(), &mut strings_buffer, &mut options_buffer);
548        let _locked = setup_get_default_java_vm_init_args_call(GetDefaultJavaVMInitArgsCall::new(
549            &mut raw_arguments.raw_arguments as *mut jni_sys::JavaVMInitArgs as *mut c_void,
550        ));
551        assert_eq!(InitArguments::get_default(JniVersion::V1), None);
552        check_arguments(JniVersion::V1);
553    }
554
555    #[test]
556    fn get_default_or_closest_supported() {
557        let mut strings_buffer = vec![];
558        let mut options_buffer = vec![];
559        let mut raw_arguments = to_raw(&default_args(), &mut strings_buffer, &mut options_buffer);
560        let _locked = setup_get_default_java_vm_init_args_call(GetDefaultJavaVMInitArgsCall::new(
561            &mut raw_arguments.raw_arguments as *mut jni_sys::JavaVMInitArgs as *mut c_void,
562        ));
563        assert_eq!(
564            InitArguments::get_default_or_closest_supported(JniVersion::V1),
565            InitArguments {
566                version: JniVersion::V4,
567                options: resulting_options(),
568                ignore_unrecognized: false
569            }
570        );
571        check_arguments(JniVersion::V1);
572    }
573
574    #[test]
575    fn get_latest_default() {
576        let mut strings_buffer = vec![];
577        let mut options_buffer = vec![];
578        let mut raw_arguments = to_raw(&default_args(), &mut strings_buffer, &mut options_buffer);
579        let _locked = setup_get_default_java_vm_init_args_call(GetDefaultJavaVMInitArgsCall::new(
580            &mut raw_arguments.raw_arguments as *mut jni_sys::JavaVMInitArgs as *mut c_void,
581        ));
582        assert_eq!(
583            InitArguments::get_latest_default(),
584            InitArguments {
585                version: JniVersion::V4,
586                options: resulting_options(),
587                ignore_unrecognized: false
588            }
589        );
590        check_arguments(JniVersion::V8);
591    }
592
593    #[test]
594    fn with_options() {
595        let arguments = InitArguments {
596            version: JniVersion::V4,
597            options: vec![JvmOption::CheckedJni],
598            ignore_unrecognized: false,
599        };
600        assert_eq!(
601            arguments.with_options(&[
602                JvmOption::Verbose(JvmVerboseOption::Gc),
603                JvmOption::Unknown("test".to_owned()),
604            ]),
605            InitArguments {
606                version: JniVersion::V4,
607                options: vec![
608                    JvmOption::CheckedJni,
609                    JvmOption::Verbose(JvmVerboseOption::Gc),
610                    JvmOption::Unknown("test".to_owned()),
611                ],
612                ignore_unrecognized: false,
613            }
614        );
615    }
616
617    #[test]
618    fn with_option() {
619        let arguments = InitArguments {
620            version: JniVersion::V4,
621            options: vec![JvmOption::CheckedJni],
622            ignore_unrecognized: false,
623        };
624        assert_eq!(
625            arguments.with_option(JvmOption::Verbose(JvmVerboseOption::Gc)),
626            InitArguments {
627                version: JniVersion::V4,
628                options: vec![
629                    JvmOption::CheckedJni,
630                    JvmOption::Verbose(JvmVerboseOption::Gc),
631                ],
632                ignore_unrecognized: false,
633            }
634        );
635    }
636
637    #[test]
638    fn unchecked() {
639        let arguments = InitArguments {
640            version: JniVersion::V4,
641            options: vec![
642                JvmOption::Verbose(JvmVerboseOption::Gc),
643                JvmOption::CheckedJni,
644            ],
645            ignore_unrecognized: false,
646        };
647        assert_eq!(
648            arguments.unchecked(),
649            InitArguments {
650                version: JniVersion::V4,
651                options: vec![JvmOption::Verbose(JvmVerboseOption::Gc)],
652                ignore_unrecognized: false,
653            }
654        );
655    }
656
657    #[test]
658    fn checked() {
659        let arguments = InitArguments {
660            version: JniVersion::V4,
661            options: vec![JvmOption::Verbose(JvmVerboseOption::Gc)],
662            ignore_unrecognized: false,
663        };
664        assert_eq!(
665            arguments.checked(),
666            InitArguments {
667                version: JniVersion::V4,
668                options: vec![
669                    JvmOption::Verbose(JvmVerboseOption::Gc),
670                    JvmOption::CheckedJni,
671                ],
672                ignore_unrecognized: false,
673            }
674        );
675    }
676
677    #[test]
678    fn ignore_unrecognized_options() {
679        let arguments = InitArguments {
680            version: JniVersion::V4,
681            options: vec![],
682            ignore_unrecognized: false,
683        };
684        assert_eq!(
685            arguments.ignore_unrecognized_options(),
686            InitArguments {
687                version: JniVersion::V4,
688                options: vec![],
689                ignore_unrecognized: true,
690            }
691        );
692    }
693
694    #[test]
695    fn fail_on_unrecognized_options() {
696        let arguments = InitArguments {
697            version: JniVersion::V4,
698            options: vec![],
699            ignore_unrecognized: true,
700        };
701        assert_eq!(
702            arguments.fail_on_unrecognized_options(),
703            InitArguments {
704                version: JniVersion::V4,
705                options: vec![],
706                ignore_unrecognized: false,
707            }
708        );
709    }
710
711    #[test]
712    fn version() {
713        let arguments = InitArguments {
714            version: JniVersion::V4,
715            options: vec![],
716            ignore_unrecognized: true,
717        };
718        assert_eq!(arguments.version(), JniVersion::V4);
719    }
720}
721
722fn to_bool(value: jni_sys::jboolean) -> bool {
723    match value {
724        jni_sys::JNI_TRUE => true,
725        jni_sys::JNI_FALSE => false,
726        value => panic!("Unexpected jboolean value {}", value),
727    }
728}