diff options
Diffstat (limited to 'tests/napi/src')
-rw-r--r-- | tests/napi/src/array.rs | 73 | ||||
-rw-r--r-- | tests/napi/src/arraybuffer.rs | 52 | ||||
-rw-r--r-- | tests/napi/src/async.rs | 114 | ||||
-rw-r--r-- | tests/napi/src/bigint.rs | 205 | ||||
-rw-r--r-- | tests/napi/src/callback.rs | 117 | ||||
-rw-r--r-- | tests/napi/src/coerce.rs | 70 | ||||
-rw-r--r-- | tests/napi/src/date.rs | 74 | ||||
-rw-r--r-- | tests/napi/src/env.rs | 31 | ||||
-rw-r--r-- | tests/napi/src/error.rs | 288 | ||||
-rw-r--r-- | tests/napi/src/finalizer.rs | 141 | ||||
-rw-r--r-- | tests/napi/src/lib.rs | 171 | ||||
-rw-r--r-- | tests/napi/src/make_callback.rs | 85 | ||||
-rw-r--r-- | tests/napi/src/mem.rs | 34 | ||||
-rw-r--r-- | tests/napi/src/numbers.rs | 60 | ||||
-rw-r--r-- | tests/napi/src/object_wrap.rs | 156 | ||||
-rw-r--r-- | tests/napi/src/primitives.rs | 30 | ||||
-rw-r--r-- | tests/napi/src/promise.rs | 74 | ||||
-rw-r--r-- | tests/napi/src/properties.rs | 113 | ||||
-rw-r--r-- | tests/napi/src/strings.rs | 49 | ||||
-rw-r--r-- | tests/napi/src/symbol.rs | 39 | ||||
-rw-r--r-- | tests/napi/src/tsfn.rs | 108 | ||||
-rw-r--r-- | tests/napi/src/typedarray.rs | 157 |
22 files changed, 2241 insertions, 0 deletions
diff --git a/tests/napi/src/array.rs b/tests/napi/src/array.rs new file mode 100644 index 000000000..6df420eb5 --- /dev/null +++ b/tests/napi/src/array.rs @@ -0,0 +1,73 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. + +use crate::assert_napi_ok; +use crate::napi_get_callback_info; +use crate::napi_new_property; +use napi_sys::ValueType::napi_number; +use napi_sys::ValueType::napi_object; +use napi_sys::*; +use std::ptr; + +extern "C" fn test_array_new( + env: napi_env, + info: napi_callback_info, +) -> napi_value { + let (args, argc, _) = napi_get_callback_info!(env, info, 1); + assert_eq!(argc, 1); + + let mut ty = -1; + assert_napi_ok!(napi_typeof(env, args[0], &mut ty)); + assert_eq!(ty, napi_object); + + let mut value: napi_value = ptr::null_mut(); + assert_napi_ok!(napi_create_array(env, &mut value)); + + let mut length: u32 = 0; + assert_napi_ok!(napi_get_array_length(env, args[0], &mut length)); + + for i in 0..length { + let mut e: napi_value = ptr::null_mut(); + assert_napi_ok!(napi_get_element(env, args[0], i, &mut e)); + assert_napi_ok!(napi_set_element(env, value, i, e)); + } + + value +} + +extern "C" fn test_array_new_with_length( + env: napi_env, + info: napi_callback_info, +) -> napi_value { + let (args, argc, _) = napi_get_callback_info!(env, info, 1); + assert_eq!(argc, 1); + + let mut ty = -1; + assert_napi_ok!(napi_typeof(env, args[0], &mut ty)); + assert_eq!(ty, napi_number); + + let mut len: u32 = 0; + assert_napi_ok!(napi_get_value_uint32(env, args[0], &mut len)); + + let mut value: napi_value = ptr::null_mut(); + assert_napi_ok!(napi_create_array_with_length(env, len as usize, &mut value)); + + value +} + +pub fn init(env: napi_env, exports: napi_value) { + let properties = &[ + napi_new_property!(env, "test_array_new", test_array_new), + napi_new_property!( + env, + "test_array_new_with_length", + test_array_new_with_length + ), + ]; + + assert_napi_ok!(napi_define_properties( + env, + exports, + properties.len(), + properties.as_ptr() + )); +} diff --git a/tests/napi/src/arraybuffer.rs b/tests/napi/src/arraybuffer.rs new file mode 100644 index 000000000..8402f5d86 --- /dev/null +++ b/tests/napi/src/arraybuffer.rs @@ -0,0 +1,52 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. + +use crate::assert_napi_ok; +use crate::napi_get_callback_info; +use crate::napi_new_property; +use napi_sys::*; + +extern "C" fn test_detached( + env: napi_env, + info: napi_callback_info, +) -> napi_value { + let (args, argc, _) = napi_get_callback_info!(env, info, 1); + assert_eq!(argc, 1); + + let mut value = false; + assert_napi_ok!(napi_is_detached_arraybuffer(env, args[0], &mut value)); + assert!(!value); + assert_napi_ok!(napi_detach_arraybuffer(env, args[0])); + assert_napi_ok!(napi_is_detached_arraybuffer(env, args[0], &mut value)); + assert!(value); + args[0] +} + +extern "C" fn is_detached( + env: napi_env, + info: napi_callback_info, +) -> napi_value { + let (args, argc, _) = napi_get_callback_info!(env, info, 1); + assert_eq!(argc, 1); + + let mut value = false; + assert_napi_ok!(napi_is_detached_arraybuffer(env, args[0], &mut value)); + + let mut result = std::ptr::null_mut(); + assert_napi_ok!(napi_get_boolean(env, value, &mut result)); + + result +} + +pub fn init(env: napi_env, exports: napi_value) { + let properties = &[ + napi_new_property!(env, "test_detached", test_detached), + napi_new_property!(env, "is_detached", is_detached), + ]; + + assert_napi_ok!(napi_define_properties( + env, + exports, + properties.len(), + properties.as_ptr() + )); +} diff --git a/tests/napi/src/async.rs b/tests/napi/src/async.rs new file mode 100644 index 000000000..3d3827b51 --- /dev/null +++ b/tests/napi/src/async.rs @@ -0,0 +1,114 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. + +use crate::assert_napi_ok; +use crate::napi_get_callback_info; +use crate::napi_new_property; +use napi_sys::Status::napi_ok; +use napi_sys::ValueType::napi_function; +use napi_sys::*; +use std::os::raw::c_char; +use std::os::raw::c_void; +use std::ptr; + +pub struct Baton { + called: bool, + func: napi_ref, + task: napi_async_work, +} + +unsafe extern "C" fn execute(_env: napi_env, data: *mut c_void) { + let baton: &mut Baton = &mut *(data as *mut Baton); + assert!(!baton.called); + assert!(!baton.func.is_null()); + + baton.called = true; +} + +unsafe extern "C" fn complete( + env: napi_env, + status: napi_status, + data: *mut c_void, +) { + assert!(status == napi_ok); + let baton: Box<Baton> = Box::from_raw(data as *mut Baton); + assert!(baton.called); + assert!(!baton.func.is_null()); + + let mut global: napi_value = ptr::null_mut(); + assert_napi_ok!(napi_get_global(env, &mut global)); + + let mut callback: napi_value = ptr::null_mut(); + assert_napi_ok!(napi_get_reference_value(env, baton.func, &mut callback)); + + let mut _result: napi_value = ptr::null_mut(); + assert_napi_ok!(napi_call_function( + env, + global, + callback, + 0, + ptr::null(), + &mut _result + )); + assert_napi_ok!(napi_delete_reference(env, baton.func)); + assert_napi_ok!(napi_delete_async_work(env, baton.task)); +} + +extern "C" fn test_async_work( + env: napi_env, + info: napi_callback_info, +) -> napi_value { + let (args, argc, _) = napi_get_callback_info!(env, info, 1); + assert_eq!(argc, 1); + + let mut ty = -1; + assert_napi_ok!(napi_typeof(env, args[0], &mut ty)); + assert_eq!(ty, napi_function); + + let mut resource_name: napi_value = ptr::null_mut(); + assert_napi_ok!(napi_create_string_utf8( + env, + "test_async_resource".as_ptr() as *const c_char, + usize::MAX, + &mut resource_name, + )); + + let async_work: napi_async_work = ptr::null_mut(); + + let mut func: napi_ref = ptr::null_mut(); + assert_napi_ok!(napi_create_reference(env, args[0], 1, &mut func)); + let baton = Box::new(Baton { + called: false, + func, + task: async_work, + }); + let mut async_work = baton.task; + let baton_ptr = Box::into_raw(baton) as *mut c_void; + + assert_napi_ok!(napi_create_async_work( + env, + ptr::null_mut(), + resource_name, + Some(execute), + Some(complete), + baton_ptr, + &mut async_work, + )); + let mut baton = unsafe { Box::from_raw(baton_ptr as *mut Baton) }; + baton.task = async_work; + Box::into_raw(baton); + assert_napi_ok!(napi_queue_async_work(env, async_work)); + + ptr::null_mut() +} + +pub fn init(env: napi_env, exports: napi_value) { + let properties = + &[napi_new_property!(env, "test_async_work", test_async_work)]; + + assert_napi_ok!(napi_define_properties( + env, + exports, + properties.len(), + properties.as_ptr() + )); +} diff --git a/tests/napi/src/bigint.rs b/tests/napi/src/bigint.rs new file mode 100644 index 000000000..d86782331 --- /dev/null +++ b/tests/napi/src/bigint.rs @@ -0,0 +1,205 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. + +use crate::assert_napi_ok; +use crate::cstr; +use crate::napi_get_callback_info; +use crate::napi_new_property; +use napi_sys::Status::napi_pending_exception; +use napi_sys::ValueType::napi_bigint; +use napi_sys::*; +use std::ptr; + +extern "C" fn is_lossless( + env: napi_env, + info: napi_callback_info, +) -> napi_value { + let (args, argc, _) = napi_get_callback_info!(env, info, 2); + assert_eq!(argc, 2); + + let mut is_signed = false; + assert_napi_ok!(napi_get_value_bool(env, args[1], &mut is_signed)); + + let mut lossless = false; + + if is_signed { + let mut input: i64 = 0; + assert_napi_ok!(napi_get_value_bigint_int64( + env, + args[0], + &mut input, + &mut lossless + )); + } else { + let mut input: u64 = 0; + assert_napi_ok!(napi_get_value_bigint_uint64( + env, + args[0], + &mut input, + &mut lossless + )); + } + + let mut output: napi_value = ptr::null_mut(); + assert_napi_ok!(napi_get_boolean(env, lossless, &mut output)); + + output +} + +extern "C" fn test_int64( + env: napi_env, + info: napi_callback_info, +) -> napi_value { + let (args, _argc, _) = napi_get_callback_info!(env, info, 2); + + let mut ty = -1; + assert_napi_ok!(napi_typeof(env, args[0], &mut ty)); + assert_eq!(ty, napi_bigint); + + let mut input: i64 = 0; + let mut lossless = false; + assert_napi_ok!(napi_get_value_bigint_int64( + env, + args[0], + &mut input, + &mut lossless + )); + + let mut output: napi_value = ptr::null_mut(); + assert_napi_ok!(napi_create_bigint_int64(env, input, &mut output)); + + output +} + +extern "C" fn test_uint64( + env: napi_env, + info: napi_callback_info, +) -> napi_value { + let (args, _argc, _) = napi_get_callback_info!(env, info, 2); + + let mut ty = -1; + assert_napi_ok!(napi_typeof(env, args[0], &mut ty)); + assert_eq!(ty, napi_bigint); + + let mut input: u64 = 0; + let mut lossless = false; + assert_napi_ok!(napi_get_value_bigint_uint64( + env, + args[0], + &mut input, + &mut lossless + )); + + let mut output: napi_value = ptr::null_mut(); + assert_napi_ok!(napi_create_bigint_uint64(env, input, &mut output)); + + output +} + +extern "C" fn test_words( + env: napi_env, + info: napi_callback_info, +) -> napi_value { + let (args, _argc, _) = napi_get_callback_info!(env, info, 1); + + let mut ty = -1; + assert_napi_ok!(napi_typeof(env, args[0], &mut ty)); + assert_eq!(ty, napi_bigint); + + let mut expected_work_count = 0; + assert_napi_ok!(napi_get_value_bigint_words( + env, + args[0], + ptr::null_mut(), + &mut expected_work_count, + ptr::null_mut() + )); + + let mut sign_bit = 0; + let mut word_count: usize = 10; + let mut words: Vec<u64> = Vec::with_capacity(10); + + assert_napi_ok!(napi_get_value_bigint_words( + env, + args[0], + &mut sign_bit, + &mut word_count, + words.as_mut_ptr(), + )); + + assert_eq!(word_count, expected_work_count); + let mut output: napi_value = ptr::null_mut(); + + assert_napi_ok!(napi_create_bigint_words( + env, + sign_bit, + word_count, + words.as_ptr(), + &mut output, + )); + output +} + +extern "C" fn create_too_big_big_int( + env: napi_env, + _info: napi_callback_info, +) -> napi_value { + let sign_bit = 0; + let word_count = usize::MAX; + let words: Vec<u64> = Vec::with_capacity(10); + + let mut output: napi_value = ptr::null_mut(); + let result = unsafe { + napi_create_bigint_words( + env, + sign_bit, + word_count, + words.as_ptr(), + &mut output, + ) + }; + assert_eq!(result, 1); + + output +} + +extern "C" fn make_big_int_words_throw( + env: napi_env, + _info: napi_callback_info, +) -> napi_value { + let words: Vec<u64> = Vec::with_capacity(10); + let mut output = ptr::null_mut(); + + let status = unsafe { + napi_create_bigint_words(env, 0, usize::MAX, words.as_ptr(), &mut output) + }; + + if status != napi_pending_exception { + unsafe { + napi_throw_error( + env, + ptr::null_mut(), + cstr!("Expected status 'napi_pending_exception'"), + ) + }; + } + + ptr::null_mut() +} + +pub fn init(env: napi_env, exports: napi_value) { + let properties = &[ + napi_new_property!(env, "isLossless", is_lossless), + napi_new_property!(env, "testInt64", test_int64), + napi_new_property!(env, "testUint64", test_uint64), + napi_new_property!(env, "testWords", test_words), + napi_new_property!(env, "createTooBigBigInt", create_too_big_big_int), + napi_new_property!(env, "makeBigIntWordsThrow", make_big_int_words_throw), + ]; + + assert_napi_ok!(napi_define_properties( + env, + exports, + properties.len(), + properties.as_ptr() + )); +} diff --git a/tests/napi/src/callback.rs b/tests/napi/src/callback.rs new file mode 100644 index 000000000..8909f5176 --- /dev/null +++ b/tests/napi/src/callback.rs @@ -0,0 +1,117 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. + +use crate::assert_napi_ok; +use crate::napi_get_callback_info; +use crate::napi_new_property; +use napi_sys::ValueType::napi_function; +use napi_sys::ValueType::napi_object; +use napi_sys::ValueType::napi_undefined; +use napi_sys::*; +use std::ptr; + +/// `test_callback_run((a, b) => a + b, [1, 2])` => 3 +extern "C" fn test_callback_run( + env: napi_env, + info: napi_callback_info, +) -> napi_value { + // We want to have argv with size 4, even though the callback will have + // only two arguments. We'll assert that the remaining two args are undefined. + let (args, argc, _) = napi_get_callback_info!(env, info, 4); + assert_eq!(argc, 2); + + let mut ty = -1; + assert_napi_ok!(napi_typeof(env, args[0], &mut ty)); + assert_eq!(ty, napi_function); + + let mut ty = -1; + assert_napi_ok!(napi_typeof(env, args[1], &mut ty)); + assert_eq!(ty, napi_object); + + let mut ty = -1; + assert_napi_ok!(napi_typeof(env, args[2], &mut ty)); + assert_eq!(ty, napi_undefined); + + let mut ty = -1; + assert_napi_ok!(napi_typeof(env, args[3], &mut ty)); + assert_eq!(ty, napi_undefined); + + let mut len = 0; + assert_napi_ok!(napi_get_array_length(env, args[1], &mut len)); + + let mut argv = Vec::with_capacity(len as usize); + for index in 0..len { + let mut value: napi_value = ptr::null_mut(); + assert_napi_ok!(napi_get_element(env, args[1], index, &mut value)); + argv.push(value); + } + let mut global: napi_value = ptr::null_mut(); + assert_napi_ok!(napi_get_global(env, &mut global)); + + let mut result: napi_value = ptr::null_mut(); + assert_napi_ok!(napi_call_function( + env, + global, + args[0], + argv.len(), + argv.as_mut_ptr(), + &mut result, + )); + + result +} + +extern "C" fn test_callback_run_with_recv( + env: napi_env, + info: napi_callback_info, +) -> napi_value { + let (args, argc, _) = napi_get_callback_info!(env, info, 3); + assert_eq!(argc, 3); + + let mut ty = -1; + assert_napi_ok!(napi_typeof(env, args[0], &mut ty)); + assert_eq!(ty, napi_function); + + let mut ty = -1; + assert_napi_ok!(napi_typeof(env, args[1], &mut ty)); + assert_eq!(ty, napi_object); + + let mut len = 0; + assert_napi_ok!(napi_get_array_length(env, args[1], &mut len)); + + let mut argv = Vec::with_capacity(len as usize); + for index in 0..len { + let mut value: napi_value = ptr::null_mut(); + assert_napi_ok!(napi_get_element(env, args[1], index, &mut value)); + argv.push(value); + } + + let mut result: napi_value = ptr::null_mut(); + assert_napi_ok!(napi_call_function( + env, + args[2], // recv + args[0], // cb + argv.len(), + argv.as_mut_ptr(), + &mut result, + )); + + result +} + +pub fn init(env: napi_env, exports: napi_value) { + let properties = &[ + napi_new_property!(env, "test_callback_run", test_callback_run), + napi_new_property!( + env, + "test_callback_run_with_recv", + test_callback_run_with_recv + ), + ]; + + assert_napi_ok!(napi_define_properties( + env, + exports, + properties.len(), + properties.as_ptr() + )); +} diff --git a/tests/napi/src/coerce.rs b/tests/napi/src/coerce.rs new file mode 100644 index 000000000..a40578384 --- /dev/null +++ b/tests/napi/src/coerce.rs @@ -0,0 +1,70 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. + +use crate::assert_napi_ok; +use crate::napi_get_callback_info; +use crate::napi_new_property; +use napi_sys::*; +use std::ptr; + +extern "C" fn test_coerce_bool( + env: napi_env, + info: napi_callback_info, +) -> napi_value { + let (args, argc, _) = napi_get_callback_info!(env, info, 1); + assert_eq!(argc, 1); + + let mut value: napi_value = ptr::null_mut(); + assert_napi_ok!(napi_coerce_to_bool(env, args[0], &mut value)); + value +} + +extern "C" fn test_coerce_number( + env: napi_env, + info: napi_callback_info, +) -> napi_value { + let (args, argc, _) = napi_get_callback_info!(env, info, 1); + assert_eq!(argc, 1); + + let mut value: napi_value = ptr::null_mut(); + assert_napi_ok!(napi_coerce_to_number(env, args[0], &mut value)); + value +} + +extern "C" fn test_coerce_object( + env: napi_env, + info: napi_callback_info, +) -> napi_value { + let (args, argc, _) = napi_get_callback_info!(env, info, 1); + assert_eq!(argc, 1); + + let mut value: napi_value = ptr::null_mut(); + assert_napi_ok!(napi_coerce_to_object(env, args[0], &mut value)); + value +} + +extern "C" fn test_coerce_string( + env: napi_env, + info: napi_callback_info, +) -> napi_value { + let (args, argc, _) = napi_get_callback_info!(env, info, 1); + assert_eq!(argc, 1); + + let mut value: napi_value = ptr::null_mut(); + assert_napi_ok!(napi_coerce_to_string(env, args[0], &mut value)); + value +} +pub fn init(env: napi_env, exports: napi_value) { + let properties = &[ + napi_new_property!(env, "test_coerce_bool", test_coerce_bool), + napi_new_property!(env, "test_coerce_number", test_coerce_number), + napi_new_property!(env, "test_coerce_object", test_coerce_object), + napi_new_property!(env, "test_coerce_string", test_coerce_string), + ]; + + assert_napi_ok!(napi_define_properties( + env, + exports, + properties.len(), + properties.as_ptr() + )); +} diff --git a/tests/napi/src/date.rs b/tests/napi/src/date.rs new file mode 100644 index 000000000..4d3c155c3 --- /dev/null +++ b/tests/napi/src/date.rs @@ -0,0 +1,74 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. + +use crate::assert_napi_ok; +use crate::napi_get_callback_info; +use crate::napi_new_property; +use napi_sys::ValueType::napi_number; +use napi_sys::*; +use std::ptr; + +extern "C" fn create_date( + env: napi_env, + info: napi_callback_info, +) -> napi_value { + let (args, argc, _) = napi_get_callback_info!(env, info, 1); + assert_eq!(argc, 1); + + let mut ty = -1; + assert_napi_ok!(napi_typeof(env, args[0], &mut ty)); + assert_eq!(ty, napi_number); + + let mut time = -1.0; + assert_napi_ok!(napi_get_value_double(env, args[0], &mut time)); + + let mut date: napi_value = ptr::null_mut(); + assert_napi_ok!(napi_create_date(env, time, &mut date)); + + date +} + +extern "C" fn is_date(env: napi_env, info: napi_callback_info) -> napi_value { + let (args, argc, _) = napi_get_callback_info!(env, info, 1); + assert_eq!(argc, 1); + + let date: napi_value = args[0]; + let mut result: napi_value = std::ptr::null_mut(); + let mut is_date = false; + + assert_napi_ok!(napi_is_date(env, date, &mut is_date)); + assert_napi_ok!(napi_get_boolean(env, is_date, &mut result)); + + result +} + +extern "C" fn get_date_value( + env: napi_env, + info: napi_callback_info, +) -> napi_value { + let (args, argc, _) = napi_get_callback_info!(env, info, 1); + assert_eq!(argc, 1); + + let date: napi_value = args[0]; + let mut result: napi_value = std::ptr::null_mut(); + let mut value = 0.0; + + assert_napi_ok!(napi_get_date_value(env, date, &mut value)); + assert_napi_ok!(napi_create_double(env, value, &mut result)); + + result +} + +pub fn init(env: napi_env, exports: napi_value) { + let properties = &[ + napi_new_property!(env, "createDate", create_date), + napi_new_property!(env, "isDate", is_date), + napi_new_property!(env, "getDateValue", get_date_value), + ]; + + assert_napi_ok!(napi_define_properties( + env, + exports, + properties.len(), + properties.as_ptr() + )); +} diff --git a/tests/napi/src/env.rs b/tests/napi/src/env.rs new file mode 100644 index 000000000..ebc6532a3 --- /dev/null +++ b/tests/napi/src/env.rs @@ -0,0 +1,31 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. + +use crate::assert_napi_ok; +use crate::napi_get_callback_info; +use crate::napi_new_property; +use napi_sys::*; + +extern "C" fn get_node_global( + env: napi_env, + info: napi_callback_info, +) -> napi_value { + let (_, argc, _) = napi_get_callback_info!(env, info, 0); + assert_eq!(argc, 0); + + let mut result: napi_value = std::ptr::null_mut(); + assert_napi_ok!(napi_get_global(env, &mut result)); + + result +} + +pub fn init(env: napi_env, exports: napi_value) { + let properties = + &[napi_new_property!(env, "testNodeGlobal", get_node_global)]; + + assert_napi_ok!(napi_define_properties( + env, + exports, + properties.len(), + properties.as_ptr() + )); +} diff --git a/tests/napi/src/error.rs b/tests/napi/src/error.rs new file mode 100644 index 000000000..e0d79c836 --- /dev/null +++ b/tests/napi/src/error.rs @@ -0,0 +1,288 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. + +use crate::assert_napi_ok; +use crate::cstr; +use crate::napi_get_callback_info; +use crate::napi_new_property; +use napi_sys::*; +use std::ptr; + +extern "C" fn check_error( + env: napi_env, + info: napi_callback_info, +) -> napi_value { + let (args, argc, _) = napi_get_callback_info!(env, info, 1); + assert_eq!(argc, 1); + let mut r = false; + assert_napi_ok!(napi_is_error(env, args[0], &mut r)); + let mut result: napi_value = ptr::null_mut(); + assert_napi_ok!(napi_get_boolean(env, r, &mut result)); + result +} + +extern "C" fn create_error( + env: napi_env, + _info: napi_callback_info, +) -> napi_value { + let mut result: napi_value = ptr::null_mut(); + let mut message: napi_value = ptr::null_mut(); + assert_napi_ok!(napi_create_string_utf8( + env, + cstr!("error"), + usize::MAX, + &mut message + )); + assert_napi_ok!(napi_create_error( + env, + ptr::null_mut(), + message, + &mut result + )); + result +} + +extern "C" fn create_range_error( + env: napi_env, + _info: napi_callback_info, +) -> napi_value { + let mut result: napi_value = ptr::null_mut(); + let mut message: napi_value = ptr::null_mut(); + assert_napi_ok!(napi_create_string_utf8( + env, + cstr!("range error"), + usize::MAX, + &mut message + )); + assert_napi_ok!(napi_create_range_error( + env, + ptr::null_mut(), + message, + &mut result + )); + result +} + +extern "C" fn create_type_error( + env: napi_env, + _info: napi_callback_info, +) -> napi_value { + let mut result: napi_value = ptr::null_mut(); + let mut message: napi_value = ptr::null_mut(); + assert_napi_ok!(napi_create_string_utf8( + env, + cstr!("type error"), + usize::MAX, + &mut message + )); + assert_napi_ok!(napi_create_type_error( + env, + ptr::null_mut(), + message, + &mut result + )); + result +} + +extern "C" fn create_error_code( + env: napi_env, + _info: napi_callback_info, +) -> napi_value { + let mut result: napi_value = ptr::null_mut(); + let mut message: napi_value = ptr::null_mut(); + let mut code: napi_value = ptr::null_mut(); + assert_napi_ok!(napi_create_string_utf8( + env, + cstr!("Error [error]"), + usize::MAX, + &mut message + )); + assert_napi_ok!(napi_create_string_utf8( + env, + cstr!("ERR_TEST_CODE"), + usize::MAX, + &mut code + )); + assert_napi_ok!(napi_create_error(env, code, message, &mut result)); + result +} + +extern "C" fn create_range_error_code( + env: napi_env, + _info: napi_callback_info, +) -> napi_value { + let mut result: napi_value = ptr::null_mut(); + let mut message: napi_value = ptr::null_mut(); + let mut code: napi_value = ptr::null_mut(); + assert_napi_ok!(napi_create_string_utf8( + env, + cstr!("RangeError [range error]"), + usize::MAX, + &mut message + )); + assert_napi_ok!(napi_create_string_utf8( + env, + cstr!("ERR_TEST_CODE"), + usize::MAX, + &mut code + )); + assert_napi_ok!(napi_create_range_error(env, code, message, &mut result)); + result +} + +extern "C" fn create_type_error_code( + env: napi_env, + _info: napi_callback_info, +) -> napi_value { + let mut result: napi_value = ptr::null_mut(); + let mut message: napi_value = ptr::null_mut(); + let mut code: napi_value = ptr::null_mut(); + assert_napi_ok!(napi_create_string_utf8( + env, + cstr!("TypeError [type error]"), + usize::MAX, + &mut message + )); + assert_napi_ok!(napi_create_string_utf8( + env, + cstr!("ERR_TEST_CODE"), + usize::MAX, + &mut code + )); + assert_napi_ok!(napi_create_type_error(env, code, message, &mut result)); + result +} + +extern "C" fn throw_existing_error( + env: napi_env, + _info: napi_callback_info, +) -> napi_value { + let mut message: napi_value = ptr::null_mut(); + let mut error: napi_value = ptr::null_mut(); + assert_napi_ok!(napi_create_string_utf8( + env, + cstr!("existing error"), + usize::MAX, + &mut message + )); + assert_napi_ok!(napi_create_error( + env, + std::ptr::null_mut(), + message, + &mut error + )); + assert_napi_ok!(napi_throw(env, error)); + std::ptr::null_mut() +} + +extern "C" fn throw_error( + env: napi_env, + _info: napi_callback_info, +) -> napi_value { + assert_napi_ok!(napi_throw_error(env, std::ptr::null_mut(), cstr!("error"),)); + std::ptr::null_mut() +} + +extern "C" fn throw_range_error( + env: napi_env, + _info: napi_callback_info, +) -> napi_value { + assert_napi_ok!(napi_throw_range_error( + env, + std::ptr::null_mut(), + cstr!("range error"), + )); + std::ptr::null_mut() +} + +extern "C" fn throw_type_error( + env: napi_env, + _info: napi_callback_info, +) -> napi_value { + assert_napi_ok!(napi_throw_type_error( + env, + std::ptr::null_mut(), + cstr!("type error"), + )); + std::ptr::null_mut() +} + +extern "C" fn throw_arbitrary( + env: napi_env, + info: napi_callback_info, +) -> napi_value { + let (args, argc, _) = napi_get_callback_info!(env, info, 1); + assert_eq!(argc, 1); + assert_napi_ok!(napi_throw(env, args[0])); + std::ptr::null_mut() +} + +extern "C" fn throw_error_code( + env: napi_env, + _info: napi_callback_info, +) -> napi_value { + assert_napi_ok!(napi_throw_error( + env, + cstr!("ERR_TEST_CODE"), + cstr!("Error [error]"), + )); + std::ptr::null_mut() +} + +extern "C" fn throw_range_error_code( + env: napi_env, + _info: napi_callback_info, +) -> napi_value { + assert_napi_ok!(napi_throw_range_error( + env, + cstr!("ERR_TEST_CODE"), + cstr!("RangeError [range error]"), + )); + std::ptr::null_mut() +} + +extern "C" fn throw_type_error_code( + env: napi_env, + _info: napi_callback_info, +) -> napi_value { + assert_napi_ok!(napi_throw_type_error( + env, + cstr!("ERR_TEST_CODE"), + cstr!("TypeError [type error]"), + )); + std::ptr::null_mut() +} + +pub fn init(env: napi_env, exports: napi_value) { + let properties = &[ + napi_new_property!(env, "checkError", check_error), + napi_new_property!(env, "throwExistingError", throw_existing_error), + napi_new_property!(env, "throwError", throw_error), + napi_new_property!(env, "throwRangeError", throw_range_error), + napi_new_property!(env, "throwTypeError", throw_type_error), + // NOTE(bartlomieju): currently experimental api + // napi_new_property!(env, "throwSyntaxError", throw_syntax_error), + napi_new_property!(env, "throwErrorCode", throw_error_code), + napi_new_property!(env, "throwRangeErrorCode", throw_range_error_code), + napi_new_property!(env, "throwTypeErrorCode", throw_type_error_code), + // NOTE(bartlomieju): currently experimental api + // napi_new_property!(env, "throwSyntaxErrorCode", throw_syntax_error_code), + napi_new_property!(env, "throwArbitrary", throw_arbitrary), + napi_new_property!(env, "createError", create_error), + napi_new_property!(env, "createRangeError", create_range_error), + napi_new_property!(env, "createTypeError", create_type_error), + // NOTE(bartlomieju): currently experimental api + // napi_new_property!(env, "createSyntaxError", create_syntax_error), + napi_new_property!(env, "createErrorCode", create_error_code), + napi_new_property!(env, "createRangeErrorCode", create_range_error_code), + napi_new_property!(env, "createTypeErrorCode", create_type_error_code), + // NOTE(bartlomieju): currently experimental api + // napi_new_property!(env, "createSyntaxErrorCode", create_syntax_error_code), + ]; + + assert_napi_ok!(napi_define_properties( + env, + exports, + properties.len(), + properties.as_ptr() + )); +} diff --git a/tests/napi/src/finalizer.rs b/tests/napi/src/finalizer.rs new file mode 100644 index 000000000..9769e775e --- /dev/null +++ b/tests/napi/src/finalizer.rs @@ -0,0 +1,141 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. + +use crate::assert_napi_ok; +use crate::napi_get_callback_info; +use crate::napi_new_property; +use napi_sys::ValueType::napi_object; +use napi_sys::*; +use std::ptr; + +unsafe extern "C" fn finalize_cb( + _env: napi_env, + data: *mut ::std::os::raw::c_void, + hint: *mut ::std::os::raw::c_void, +) { + assert!(data.is_null()); + assert!(hint.is_null()); +} + +extern "C" fn test_bind_finalizer( + env: napi_env, + info: napi_callback_info, +) -> napi_value { + let (args, argc, _) = napi_get_callback_info!(env, info, 1); + assert_eq!(argc, 1); + + let mut ty = -1; + assert_napi_ok!(napi_typeof(env, args[0], &mut ty)); + assert_eq!(ty, napi_object); + + let obj = args[0]; + unsafe { + napi_add_finalizer( + env, + obj, + ptr::null_mut(), + Some(finalize_cb), + ptr::null_mut(), + ptr::null_mut(), + ) + }; + obj +} + +struct Thing { + _allocation: Vec<u8>, +} + +unsafe extern "C" fn finalize_cb_drop( + _env: napi_env, + data: *mut ::std::os::raw::c_void, + hint: *mut ::std::os::raw::c_void, +) { + let _ = Box::from_raw(data as *mut Thing); + assert!(hint.is_null()); +} + +extern "C" fn test_external_finalizer( + env: napi_env, + _: napi_callback_info, +) -> napi_value { + let data = Box::into_raw(Box::new(Thing { + _allocation: vec![1, 2, 3], + })); + + let mut result = ptr::null_mut(); + assert_napi_ok!(napi_create_external( + env, + data as _, + Some(finalize_cb_drop), + ptr::null_mut(), + &mut result + )); + result +} + +unsafe extern "C" fn finalize_cb_vec( + _env: napi_env, + data: *mut ::std::os::raw::c_void, + hint: *mut ::std::os::raw::c_void, +) { + let _ = Vec::from_raw_parts(data as *mut u8, 3, 3); + assert!(hint.is_null()); +} + +extern "C" fn test_external_buffer( + env: napi_env, + _: napi_callback_info, +) -> napi_value { + let mut result = ptr::null_mut(); + let buf: Vec<u8> = vec![1, 2, 3]; + assert_napi_ok!(napi_create_external_buffer( + env, + 3, + buf.as_ptr() as _, + Some(finalize_cb_vec), + ptr::null_mut(), + &mut result + )); + std::mem::forget(buf); + + result +} + +extern "C" fn test_external_arraybuffer( + env: napi_env, + _: napi_callback_info, +) -> napi_value { + let mut result = ptr::null_mut(); + let buf: Vec<u8> = vec![1, 2, 3]; + assert_napi_ok!(napi_create_external_arraybuffer( + env, + buf.as_ptr() as _, + 3, + Some(finalize_cb_vec), + ptr::null_mut(), + &mut result + )); + std::mem::forget(buf); + + result +} + +pub fn init(env: napi_env, exports: napi_value) { + let properties = &[ + napi_new_property!(env, "test_bind_finalizer", test_bind_finalizer), + napi_new_property!(env, "test_external_finalizer", test_external_finalizer), + napi_new_property!(env, "test_external_buffer", test_external_buffer), + napi_new_property!( + env, + "test_external_arraybuffer", + test_external_arraybuffer + ), + ]; + + assert_napi_ok!(napi_define_properties( + env, + exports, + properties.len(), + properties.as_ptr() + )); +} diff --git a/tests/napi/src/lib.rs b/tests/napi/src/lib.rs new file mode 100644 index 000000000..b9f93fbd6 --- /dev/null +++ b/tests/napi/src/lib.rs @@ -0,0 +1,171 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +#![allow(clippy::all)] +#![allow(clippy::undocumented_unsafe_blocks)] + +use std::ffi::c_void; + +use napi_sys::*; + +pub mod array; +pub mod arraybuffer; +pub mod r#async; +pub mod bigint; +pub mod callback; +pub mod coerce; +pub mod date; +pub mod env; +pub mod error; +pub mod finalizer; +pub mod make_callback; +pub mod mem; +pub mod numbers; +pub mod object_wrap; +pub mod primitives; +pub mod promise; +pub mod properties; +pub mod strings; +pub mod symbol; +pub mod tsfn; +pub mod typedarray; + +#[macro_export] +macro_rules! cstr { + ($s: literal) => {{ + std::ffi::CString::new($s).unwrap().into_raw() + }}; +} + +#[macro_export] +macro_rules! assert_napi_ok { + ($call: expr) => {{ + assert_eq!(unsafe { $call }, napi_sys::Status::napi_ok); + }}; +} + +#[macro_export] +macro_rules! napi_get_callback_info { + ($env: expr, $callback_info: expr, $size: literal) => {{ + let mut args = [std::ptr::null_mut(); $size]; + let mut argc = $size; + let mut this = std::ptr::null_mut(); + crate::assert_napi_ok!(napi_get_cb_info( + $env, + $callback_info, + &mut argc, + args.as_mut_ptr(), + &mut this, + std::ptr::null_mut(), + )); + (args, argc, this) + }}; +} + +#[macro_export] +macro_rules! napi_new_property { + ($env: expr, $name: expr, $value: expr) => { + napi_property_descriptor { + utf8name: concat!($name, "\0").as_ptr() as *const std::os::raw::c_char, + name: std::ptr::null_mut(), + method: Some($value), + getter: None, + setter: None, + data: std::ptr::null_mut(), + attributes: 0, + value: std::ptr::null_mut(), + } + }; +} + +extern "C" fn cleanup(arg: *mut c_void) { + println!("cleanup({})", arg as i64); +} + +extern "C" fn remove_this_hook(arg: *mut c_void) { + let env = arg as napi_env; + unsafe { napi_remove_env_cleanup_hook(env, Some(remove_this_hook), arg) }; +} + +static SECRET: i64 = 42; +static WRONG_SECRET: i64 = 17; +static THIRD_SECRET: i64 = 18; + +extern "C" fn install_cleanup_hook( + env: napi_env, + info: napi_callback_info, +) -> napi_value { + let (_args, argc, _) = napi_get_callback_info!(env, info, 1); + assert_eq!(argc, 0); + + unsafe { + napi_add_env_cleanup_hook(env, Some(cleanup), WRONG_SECRET as *mut c_void); + napi_add_env_cleanup_hook(env, Some(cleanup), SECRET as *mut c_void); + napi_add_env_cleanup_hook(env, Some(cleanup), THIRD_SECRET as *mut c_void); + napi_add_env_cleanup_hook(env, Some(remove_this_hook), env as *mut c_void); + napi_remove_env_cleanup_hook( + env, + Some(cleanup), + WRONG_SECRET as *mut c_void, + ); + } + + std::ptr::null_mut() +} + +pub fn init_cleanup_hook(env: napi_env, exports: napi_value) { + let properties = &[napi_new_property!( + env, + "installCleanupHook", + install_cleanup_hook + )]; + + assert_napi_ok!(napi_define_properties( + env, + exports, + properties.len(), + properties.as_ptr() + )); +} + +#[no_mangle] +unsafe extern "C" fn napi_register_module_v1( + env: napi_env, + _: napi_value, +) -> napi_value { + #[cfg(windows)] + { + napi_sys::setup(); + } + + // We create a fresh exports object and leave the passed + // exports object empty. + // + // https://github.com/denoland/deno/issues/17349 + let mut exports = std::ptr::null_mut(); + assert_napi_ok!(napi_create_object(env, &mut exports)); + + strings::init(env, exports); + numbers::init(env, exports); + typedarray::init(env, exports); + arraybuffer::init(env, exports); + array::init(env, exports); + env::init(env, exports); + error::init(env, exports); + finalizer::init(env, exports); + primitives::init(env, exports); + properties::init(env, exports); + promise::init(env, exports); + coerce::init(env, exports); + object_wrap::init(env, exports); + callback::init(env, exports); + r#async::init(env, exports); + date::init(env, exports); + tsfn::init(env, exports); + mem::init(env, exports); + bigint::init(env, exports); + symbol::init(env, exports); + make_callback::init(env, exports); + + init_cleanup_hook(env, exports); + + exports +} diff --git a/tests/napi/src/make_callback.rs b/tests/napi/src/make_callback.rs new file mode 100644 index 000000000..945df3452 --- /dev/null +++ b/tests/napi/src/make_callback.rs @@ -0,0 +1,85 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. + +use crate::assert_napi_ok; +use crate::cstr; +use napi_sys::ValueType::napi_function; +use napi_sys::*; +use std::ptr; + +extern "C" fn make_callback( + env: napi_env, + info: napi_callback_info, +) -> napi_value { + const MAX_ARGUMENTS: usize = 10; + const RESERVED_ARGUMENTS: usize = 3; + + let mut args = [std::ptr::null_mut(); MAX_ARGUMENTS]; + let mut argc = MAX_ARGUMENTS; + assert_napi_ok!(napi_get_cb_info( + env, + info, + &mut argc, + args.as_mut_ptr(), + ptr::null_mut(), + ptr::null_mut(), + )); + + assert!(argc > 0); + let resource = args[0]; + let recv = args[1]; + let func = args[2]; + + let mut argv: Vec<napi_value> = Vec::new(); + argv.resize(MAX_ARGUMENTS - RESERVED_ARGUMENTS, ptr::null_mut()); + for i in RESERVED_ARGUMENTS..argc { + argv[i - RESERVED_ARGUMENTS] = args[i]; + } + + let mut func_type: napi_valuetype = -1; + assert_napi_ok!(napi_typeof(env, func, &mut func_type)); + + let mut resource_name = ptr::null_mut(); + assert_napi_ok!(napi_create_string_utf8( + env, + cstr!("test"), + usize::MAX, + &mut resource_name + )); + + let mut context: napi_async_context = ptr::null_mut(); + assert_napi_ok!(napi_async_init(env, resource, resource_name, &mut context)); + + let mut result = ptr::null_mut(); + assert_eq!(func_type, napi_function); + assert_napi_ok!(napi_make_callback( + env, + context, + recv, + func, + argc - RESERVED_ARGUMENTS, + argv.as_mut_ptr(), + &mut result + )); + + assert_napi_ok!(napi_async_destroy(env, context)); + result +} + +pub fn init(env: napi_env, exports: napi_value) { + let mut fn_: napi_value = ptr::null_mut(); + + assert_napi_ok!(napi_create_function( + env, + ptr::null_mut(), + usize::MAX, + Some(make_callback), + ptr::null_mut(), + &mut fn_, + )); + assert_napi_ok!(napi_set_named_property( + env, + exports, + cstr!("makeCallback"), + fn_ + )); +} diff --git a/tests/napi/src/mem.rs b/tests/napi/src/mem.rs new file mode 100644 index 000000000..ebb6a5c7a --- /dev/null +++ b/tests/napi/src/mem.rs @@ -0,0 +1,34 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. + +use crate::assert_napi_ok; +use crate::napi_new_property; +use napi_sys::*; +use std::ptr; + +extern "C" fn adjust_external_memory( + env: napi_env, + _: napi_callback_info, +) -> napi_value { + let mut adjusted_value = 0; + + assert_napi_ok!(napi_adjust_external_memory(env, 1024, &mut adjusted_value)); + + let mut result = ptr::null_mut(); + assert_napi_ok!(napi_create_int64(env, adjusted_value, &mut result)); + result +} + +pub fn init(env: napi_env, exports: napi_value) { + let properties = &[napi_new_property!( + env, + "adjust_external_memory", + adjust_external_memory + )]; + + assert_napi_ok!(napi_define_properties( + env, + exports, + properties.len(), + properties.as_ptr() + )); +} diff --git a/tests/napi/src/numbers.rs b/tests/napi/src/numbers.rs new file mode 100644 index 000000000..777ccbfac --- /dev/null +++ b/tests/napi/src/numbers.rs @@ -0,0 +1,60 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. + +use crate::assert_napi_ok; +use crate::napi_get_callback_info; +use crate::napi_new_property; +use napi_sys::ValueType::napi_number; +use napi_sys::*; +use std::ptr; + +extern "C" fn test_int32( + env: napi_env, + info: napi_callback_info, +) -> napi_value { + let (args, argc, _) = napi_get_callback_info!(env, info, 1); + assert_eq!(argc, 1); + + let mut ty = -1; + assert_napi_ok!(napi_typeof(env, args[0], &mut ty)); + assert_eq!(ty, napi_number); + + let mut int32 = -1; + assert_napi_ok!(napi_get_value_int32(env, args[0], &mut int32)); + + let mut value: napi_value = ptr::null_mut(); + assert_napi_ok!(napi_create_int32(env, int32, &mut value)); + value +} + +extern "C" fn test_int64( + env: napi_env, + info: napi_callback_info, +) -> napi_value { + let (args, argc, _) = napi_get_callback_info!(env, info, 1); + assert_eq!(argc, 1); + + let mut ty = -1; + assert_napi_ok!(napi_typeof(env, args[0], &mut ty)); + assert_eq!(ty, napi_number); + + let mut int64 = -1; + assert_napi_ok!(napi_get_value_int64(env, args[0], &mut int64)); + + let mut value: napi_value = ptr::null_mut(); + assert_napi_ok!(napi_create_int64(env, int64, &mut value)); + value +} + +pub fn init(env: napi_env, exports: napi_value) { + let properties = &[ + napi_new_property!(env, "test_int32", test_int32), + napi_new_property!(env, "test_int64", test_int64), + ]; + + assert_napi_ok!(napi_define_properties( + env, + exports, + properties.len(), + properties.as_ptr() + )); +} diff --git a/tests/napi/src/object_wrap.rs b/tests/napi/src/object_wrap.rs new file mode 100644 index 000000000..d04107cf0 --- /dev/null +++ b/tests/napi/src/object_wrap.rs @@ -0,0 +1,156 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. + +use crate::assert_napi_ok; +use crate::napi_get_callback_info; +use crate::napi_new_property; +use napi_sys::ValueType::napi_number; +use napi_sys::*; +use std::os::raw::c_char; +use std::os::raw::c_void; +use std::ptr; + +pub struct NapiObject { + counter: i32, + _wrapper: napi_ref, +} + +impl NapiObject { + #[allow(clippy::new_ret_no_self)] + pub extern "C" fn new(env: napi_env, info: napi_callback_info) -> napi_value { + let mut new_target: napi_value = ptr::null_mut(); + assert_napi_ok!(napi_get_new_target(env, info, &mut new_target)); + let is_constructor = !new_target.is_null(); + + let (args, argc, this) = napi_get_callback_info!(env, info, 1); + assert_eq!(argc, 1); + + if is_constructor { + let mut value = 0; + + let mut ty = -1; + assert_napi_ok!(napi_typeof(env, args[0], &mut ty)); + assert_eq!(ty, napi_number); + + assert_napi_ok!(napi_get_value_int32(env, args[0], &mut value)); + + let mut wrapper: napi_ref = ptr::null_mut(); + let obj = Box::new(Self { + counter: value, + _wrapper: wrapper, + }); + assert_napi_ok!(napi_wrap( + env, + this, + Box::into_raw(obj) as *mut c_void, + None, + ptr::null_mut(), + &mut wrapper, + )); + + return this; + } + + unreachable!(); + } + + pub extern "C" fn set_value( + env: napi_env, + info: napi_callback_info, + ) -> napi_value { + let (args, argc, this) = napi_get_callback_info!(env, info, 1); + assert_eq!(argc, 1); + let mut obj: *mut Self = ptr::null_mut(); + assert_napi_ok!(napi_unwrap( + env, + this, + &mut obj as *mut _ as *mut *mut c_void + )); + + assert_napi_ok!(napi_get_value_int32(env, args[0], &mut (*obj).counter)); + + ptr::null_mut() + } + + pub extern "C" fn get_value( + env: napi_env, + info: napi_callback_info, + ) -> napi_value { + let (_args, argc, this) = napi_get_callback_info!(env, info, 0); + assert_eq!(argc, 0); + let mut obj: *mut Self = ptr::null_mut(); + assert_napi_ok!(napi_unwrap( + env, + this, + &mut obj as *mut _ as *mut *mut c_void + )); + + let mut num: napi_value = ptr::null_mut(); + assert_napi_ok!(napi_create_int32(env, (*obj).counter, &mut num)); + + num + } + + pub extern "C" fn increment( + env: napi_env, + info: napi_callback_info, + ) -> napi_value { + let (_args, argc, this) = napi_get_callback_info!(env, info, 0); + assert_eq!(argc, 0); + let mut obj: *mut Self = ptr::null_mut(); + assert_napi_ok!(napi_unwrap( + env, + this, + &mut obj as *mut _ as *mut *mut c_void + )); + + unsafe { + (*obj).counter += 1; + } + + ptr::null_mut() + } + + pub extern "C" fn factory( + env: napi_env, + info: napi_callback_info, + ) -> napi_value { + let (_args, argc, _this) = napi_get_callback_info!(env, info, 0); + assert_eq!(argc, 0); + + let int64 = 64; + let mut value: napi_value = ptr::null_mut(); + assert_napi_ok!(napi_create_int64(env, int64, &mut value)); + value + } +} + +pub fn init(env: napi_env, exports: napi_value) { + let mut static_prop = napi_new_property!(env, "factory", NapiObject::factory); + static_prop.attributes = PropertyAttributes::static_; + + let properties = &[ + napi_new_property!(env, "set_value", NapiObject::set_value), + napi_new_property!(env, "get_value", NapiObject::get_value), + napi_new_property!(env, "increment", NapiObject::increment), + static_prop, + ]; + + let mut cons: napi_value = ptr::null_mut(); + assert_napi_ok!(napi_define_class( + env, + "NapiObject\0".as_ptr() as *mut c_char, + usize::MAX, + Some(NapiObject::new), + ptr::null_mut(), + properties.len(), + properties.as_ptr(), + &mut cons, + )); + + assert_napi_ok!(napi_set_named_property( + env, + exports, + "NapiObject\0".as_ptr() as *const c_char, + cons, + )); +} diff --git a/tests/napi/src/primitives.rs b/tests/napi/src/primitives.rs new file mode 100644 index 000000000..28fb8ec3d --- /dev/null +++ b/tests/napi/src/primitives.rs @@ -0,0 +1,30 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. + +use crate::assert_napi_ok; +use crate::napi_new_property; +use napi_sys::*; +use std::ptr; + +extern "C" fn test_get_undefined( + env: napi_env, + _: napi_callback_info, +) -> napi_value { + let mut result = ptr::null_mut(); + assert_napi_ok!(napi_get_undefined(env, &mut result)); + result +} + +pub fn init(env: napi_env, exports: napi_value) { + let properties = &[napi_new_property!( + env, + "test_get_undefined", + test_get_undefined + )]; + + assert_napi_ok!(napi_define_properties( + env, + exports, + properties.len(), + properties.as_ptr() + )); +} diff --git a/tests/napi/src/promise.rs b/tests/napi/src/promise.rs new file mode 100644 index 000000000..82cd7a160 --- /dev/null +++ b/tests/napi/src/promise.rs @@ -0,0 +1,74 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. + +use crate::assert_napi_ok; +use crate::napi_get_callback_info; +use crate::napi_new_property; +use napi_sys::*; +use std::ptr; + +static mut CURRENT_DEFERRED: napi_deferred = ptr::null_mut(); + +extern "C" fn test_promise_new( + env: napi_env, + _info: napi_callback_info, +) -> napi_value { + let mut value: napi_value = ptr::null_mut(); + assert_napi_ok!(napi_create_promise(env, &mut CURRENT_DEFERRED, &mut value)); + value +} + +extern "C" fn test_promise_resolve( + env: napi_env, + info: napi_callback_info, +) -> napi_value { + let (args, argc, _) = napi_get_callback_info!(env, info, 1); + assert_eq!(argc, 1); + + assert_napi_ok!(napi_resolve_deferred(env, CURRENT_DEFERRED, args[0])); + unsafe { CURRENT_DEFERRED = ptr::null_mut() }; + ptr::null_mut() +} + +extern "C" fn test_promise_reject( + env: napi_env, + info: napi_callback_info, +) -> napi_value { + let (args, argc, _) = napi_get_callback_info!(env, info, 1); + assert_eq!(argc, 1); + + assert_napi_ok!(napi_reject_deferred(env, CURRENT_DEFERRED, args[0])); + unsafe { CURRENT_DEFERRED = ptr::null_mut() }; + ptr::null_mut() +} + +extern "C" fn test_promise_is( + env: napi_env, + info: napi_callback_info, +) -> napi_value { + let (args, argc, _) = napi_get_callback_info!(env, info, 1); + assert_eq!(argc, 1); + + let mut is_promise: bool = false; + assert_napi_ok!(napi_is_promise(env, args[0], &mut is_promise)); + + let mut result: napi_value = ptr::null_mut(); + assert_napi_ok!(napi_get_boolean(env, is_promise, &mut result)); + + result +} + +pub fn init(env: napi_env, exports: napi_value) { + let properties = &[ + napi_new_property!(env, "test_promise_new", test_promise_new), + napi_new_property!(env, "test_promise_resolve", test_promise_resolve), + napi_new_property!(env, "test_promise_reject", test_promise_reject), + napi_new_property!(env, "test_promise_is", test_promise_is), + ]; + + assert_napi_ok!(napi_define_properties( + env, + exports, + properties.len(), + properties.as_ptr() + )); +} diff --git a/tests/napi/src/properties.rs b/tests/napi/src/properties.rs new file mode 100644 index 000000000..43bef1949 --- /dev/null +++ b/tests/napi/src/properties.rs @@ -0,0 +1,113 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. + +use crate::assert_napi_ok; +use crate::cstr; +use napi_sys::PropertyAttributes::*; +use napi_sys::*; +use std::ptr; + +static NICE: i64 = 69; + +fn init_constants(env: napi_env) -> napi_value { + let mut constants: napi_value = ptr::null_mut(); + let mut value: napi_value = ptr::null_mut(); + + assert_napi_ok!(napi_create_object(env, &mut constants)); + assert_napi_ok!(napi_create_int64(env, NICE, &mut value)); + assert_napi_ok!(napi_set_named_property( + env, + constants, + cstr!("nice"), + value + )); + constants +} + +pub fn init(env: napi_env, exports: napi_value) { + let mut number: napi_value = ptr::null_mut(); + assert_napi_ok!(napi_create_double(env, 1.0, &mut number)); + + // Key name as napi_value representing `v8::String` + let mut name_value: napi_value = ptr::null_mut(); + assert_napi_ok!(napi_create_string_utf8( + env, + cstr!("key_v8_string"), + usize::MAX, + &mut name_value, + )); + + // Key symbol + let mut symbol_description: napi_value = ptr::null_mut(); + let mut name_symbol: napi_value = ptr::null_mut(); + assert_napi_ok!(napi_create_string_utf8( + env, + cstr!("key_v8_symbol"), + usize::MAX, + &mut symbol_description, + )); + assert_napi_ok!(napi_create_symbol( + env, + symbol_description, + &mut name_symbol + )); + + let properties = &[ + napi_property_descriptor { + utf8name: cstr!("test_simple_property"), + name: ptr::null_mut(), + method: None, + getter: None, + setter: None, + data: ptr::null_mut(), + attributes: enumerable | writable, + value: init_constants(env), + }, + napi_property_descriptor { + utf8name: cstr!("test_property_rw"), + name: ptr::null_mut(), + method: None, + getter: None, + setter: None, + data: ptr::null_mut(), + attributes: enumerable | writable, + value: number, + }, + napi_property_descriptor { + utf8name: cstr!("test_property_r"), + name: ptr::null_mut(), + method: None, + getter: None, + setter: None, + data: ptr::null_mut(), + attributes: enumerable, + value: number, + }, + napi_property_descriptor { + utf8name: ptr::null(), + name: name_value, + method: None, + getter: None, + setter: None, + data: ptr::null_mut(), + attributes: enumerable, + value: number, + }, + napi_property_descriptor { + utf8name: ptr::null(), + name: name_symbol, + method: None, + getter: None, + setter: None, + data: ptr::null_mut(), + attributes: enumerable, + value: number, + }, + ]; + + assert_napi_ok!(napi_define_properties( + env, + exports, + properties.len(), + properties.as_ptr() + )); +} diff --git a/tests/napi/src/strings.rs b/tests/napi/src/strings.rs new file mode 100644 index 000000000..301ab23df --- /dev/null +++ b/tests/napi/src/strings.rs @@ -0,0 +1,49 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. + +use crate::assert_napi_ok; +use crate::napi_get_callback_info; +use crate::napi_new_property; +use napi_sys::ValueType::napi_string; +use napi_sys::*; + +extern "C" fn test_utf8(env: napi_env, info: napi_callback_info) -> napi_value { + let (args, argc, _) = napi_get_callback_info!(env, info, 1); + assert_eq!(argc, 1); + + let mut ty = -1; + assert_napi_ok!(napi_typeof(env, args[0], &mut ty)); + assert_eq!(ty, napi_string); + + args[0] +} + +extern "C" fn test_utf16( + env: napi_env, + info: napi_callback_info, +) -> napi_value { + let (args, argc, _) = napi_get_callback_info!(env, info, 1); + assert_eq!(argc, 1); + + let mut ty = -1; + assert_napi_ok!(napi_typeof(env, args[0], &mut ty)); + assert_eq!(ty, napi_string); + + args[0] +} + +pub fn init(env: napi_env, exports: napi_value) { + let properties = &[ + // utf8 + napi_new_property!(env, "test_utf8", test_utf8), + // utf16 + napi_new_property!(env, "test_utf16", test_utf16), + // latin1 + ]; + + assert_napi_ok!(napi_define_properties( + env, + exports, + properties.len(), + properties.as_ptr() + )); +} diff --git a/tests/napi/src/symbol.rs b/tests/napi/src/symbol.rs new file mode 100644 index 000000000..6387d449f --- /dev/null +++ b/tests/napi/src/symbol.rs @@ -0,0 +1,39 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. + +use crate::assert_napi_ok; +use crate::napi_get_callback_info; +use crate::napi_new_property; +use napi_sys::ValueType::napi_string; +use napi_sys::*; + +extern "C" fn symbol_new( + env: napi_env, + info: napi_callback_info, +) -> napi_value { + let (args, argc, _) = napi_get_callback_info!(env, info, 1); + + let mut description: napi_value = std::ptr::null_mut(); + + if argc >= 1 { + let mut ty = -1; + assert_napi_ok!(napi_typeof(env, args[0], &mut ty)); + assert_eq!(ty, napi_string); + description = args[0]; + } + + let mut symbol: napi_value = std::ptr::null_mut(); + assert_napi_ok!(napi_create_symbol(env, description, &mut symbol)); + + symbol +} + +pub fn init(env: napi_env, exports: napi_value) { + let properties = &[napi_new_property!(env, "symbolNew", symbol_new)]; + + assert_napi_ok!(napi_define_properties( + env, + exports, + properties.len(), + properties.as_ptr() + )); +} diff --git a/tests/napi/src/tsfn.rs b/tests/napi/src/tsfn.rs new file mode 100644 index 000000000..dabc96f83 --- /dev/null +++ b/tests/napi/src/tsfn.rs @@ -0,0 +1,108 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. + +// This test performs initialization similar to napi-rs. +// https://github.com/napi-rs/napi-rs/commit/a5a04a4e545f268769cc78e2bd6c45af4336aac3 + +use napi_sys as sys; +use std::ffi::c_char; +use std::ffi::c_void; +use std::ptr; + +macro_rules! check_status_or_panic { + ($code:expr, $msg:expr) => {{ + let c = $code; + match c { + sys::Status::napi_ok => {} + _ => panic!($msg), + } + }}; +} + +fn create_custom_gc(env: sys::napi_env) { + let mut custom_gc_fn = ptr::null_mut(); + check_status_or_panic!( + unsafe { + sys::napi_create_function( + env, + "custom_gc".as_ptr() as *const c_char, + 9, + Some(empty), + ptr::null_mut(), + &mut custom_gc_fn, + ) + }, + "Create Custom GC Function in napi_register_module_v1 failed" + ); + let mut async_resource_name = ptr::null_mut(); + check_status_or_panic!( + unsafe { + sys::napi_create_string_utf8( + env, + "CustomGC".as_ptr() as *const c_char, + 8, + &mut async_resource_name, + ) + }, + "Create async resource string in napi_register_module_v1 napi_register_module_v1" + ); + let mut custom_gc_tsfn = ptr::null_mut(); + check_status_or_panic!( + unsafe { + sys::napi_create_threadsafe_function( + env, + custom_gc_fn, + ptr::null_mut(), + async_resource_name, + 0, + 1, + ptr::null_mut(), + Some(custom_gc_finalize), + ptr::null_mut(), + Some(custom_gc), + &mut custom_gc_tsfn, + ) + }, + "Create Custom GC ThreadsafeFunction in napi_register_module_v1 failed" + ); + check_status_or_panic!( + unsafe { sys::napi_unref_threadsafe_function(env, custom_gc_tsfn) }, + "Unref Custom GC ThreadsafeFunction in napi_register_module_v1 failed" + ); +} + +unsafe extern "C" fn empty( + _env: sys::napi_env, + _info: sys::napi_callback_info, +) -> sys::napi_value { + ptr::null_mut() +} + +unsafe extern "C" fn custom_gc_finalize( + _env: sys::napi_env, + _finalize_data: *mut c_void, + _finalize_hint: *mut c_void, +) { +} + +extern "C" fn custom_gc( + env: sys::napi_env, + _js_callback: sys::napi_value, + _context: *mut c_void, + data: *mut c_void, +) { + let mut ref_count = 0; + check_status_or_panic!( + unsafe { + sys::napi_reference_unref(env, data as sys::napi_ref, &mut ref_count) + }, + "Failed to unref Buffer reference in Custom GC" + ); + check_status_or_panic!( + unsafe { sys::napi_delete_reference(env, data as sys::napi_ref) }, + "Failed to delete Buffer reference in Custom GC" + ); +} + +pub fn init(env: sys::napi_env, _exports: sys::napi_value) { + create_custom_gc(env); +} diff --git a/tests/napi/src/typedarray.rs b/tests/napi/src/typedarray.rs new file mode 100644 index 000000000..b512bd32f --- /dev/null +++ b/tests/napi/src/typedarray.rs @@ -0,0 +1,157 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. + +use crate::assert_napi_ok; +use crate::napi_get_callback_info; +use crate::napi_new_property; +use core::ffi::c_void; +use napi_sys::Status::napi_ok; +use napi_sys::TypedarrayType; +use napi_sys::ValueType::napi_number; +use napi_sys::ValueType::napi_object; +use napi_sys::*; +use std::os::raw::c_char; +use std::ptr; + +extern "C" fn test_multiply( + env: napi_env, + info: napi_callback_info, +) -> napi_value { + let (args, argc, _) = napi_get_callback_info!(env, info, 2); + assert_eq!(argc, 2); + + let mut ty = -1; + assert_napi_ok!(napi_typeof(env, args[0], &mut ty)); + assert_eq!(ty, napi_object); + + let input_array = args[0]; + let mut is_typed_array = false; + assert!( + unsafe { napi_is_typedarray(env, input_array, &mut is_typed_array) } + == napi_ok + ); + + let mut ty = -1; + assert_napi_ok!(napi_typeof(env, args[1], &mut ty)); + assert_eq!(ty, napi_number); + + let mut multiplier: f64 = 0.0; + assert_napi_ok!(napi_get_value_double(env, args[1], &mut multiplier)); + + let mut ty = -1; + let mut input_buffer = ptr::null_mut(); + let mut byte_offset = 0; + let mut length = 0; + + assert_napi_ok!(napi_get_typedarray_info( + env, + input_array, + &mut ty, + &mut length, + ptr::null_mut(), + &mut input_buffer, + &mut byte_offset, + )); + + let mut data = ptr::null_mut(); + let mut byte_length = 0; + + assert_napi_ok!(napi_get_arraybuffer_info( + env, + input_buffer, + &mut data, + &mut byte_length + )); + + let mut output_buffer = ptr::null_mut(); + let mut output_ptr = ptr::null_mut(); + assert_napi_ok!(napi_create_arraybuffer( + env, + byte_length, + &mut output_ptr, + &mut output_buffer, + )); + + let mut output_array: napi_value = ptr::null_mut(); + assert_napi_ok!(napi_create_typedarray( + env, + ty, + length, + output_buffer, + byte_offset, + &mut output_array, + )); + + if ty == TypedarrayType::uint8_array { + let input_bytes = unsafe { (data as *mut u8).offset(byte_offset as isize) }; + let output_bytes = output_ptr as *mut u8; + for i in 0..length { + unsafe { + *output_bytes.offset(i as isize) = + (*input_bytes.offset(i as isize) as f64 * multiplier) as u8; + } + } + } else if ty == TypedarrayType::float64_array { + let input_doubles = + unsafe { (data as *mut f64).offset(byte_offset as isize) }; + let output_doubles = output_ptr as *mut f64; + for i in 0..length { + unsafe { + *output_doubles.offset(i as isize) = + *input_doubles.offset(i as isize) * multiplier; + } + } + } else { + assert_napi_ok!(napi_throw_error( + env, + ptr::null(), + "Typed array was of a type not expected by test.".as_ptr() + as *const c_char, + )); + return ptr::null_mut(); + } + + output_array +} + +extern "C" fn test_external( + env: napi_env, + _info: napi_callback_info, +) -> napi_value { + let mut arraybuffer: napi_value = ptr::null_mut(); + let mut external: Box<[u8; 4]> = Box::new([0, 1, 2, 3]); + assert_napi_ok!(napi_create_external_arraybuffer( + env, + external.as_mut_ptr() as *mut c_void, + external.len(), + None, + ptr::null_mut(), + &mut arraybuffer, + )); + + let mut typedarray: napi_value = ptr::null_mut(); + assert_napi_ok!(napi_create_typedarray( + env, + TypedarrayType::uint8_array, + external.len(), + arraybuffer, + 0, + &mut typedarray, + )); + + std::mem::forget(external); // Leak into JS land + typedarray +} + +pub fn init(env: napi_env, exports: napi_value) { + let properties = &[ + napi_new_property!(env, "test_external", test_external), + napi_new_property!(env, "test_multiply", test_multiply), + ]; + + assert_napi_ok!(napi_define_properties( + env, + exports, + properties.len(), + properties.as_ptr() + )); +} |