summaryrefslogtreecommitdiff
path: root/test_napi
diff options
context:
space:
mode:
authorDivy Srivastava <dj.srivastava23@gmail.com>2022-10-05 07:06:44 -0700
committerGitHub <noreply@github.com>2022-10-05 19:36:44 +0530
commit0b016a7fb8639ce49603c8c339539174b191a4b1 (patch)
treec511060d701db60ede0214b7280e89c5749bbe62 /test_napi
parent3a3a8484069c9c6955fcb83ea761f9f74638175a (diff)
feat(npm): implement Node API (#13633)
This PR implements the NAPI for loading native modules into Deno. Co-authored-by: Bartek Iwańczuk <biwanczuk@gmail.com> Co-authored-by: DjDeveloper <43033058+DjDeveloperr@users.noreply.github.com> Co-authored-by: Ryan Dahl <ry@tinyclouds.org>
Diffstat (limited to 'test_napi')
-rw-r--r--test_napi/.gitignore4
-rw-r--r--test_napi/Cargo.toml20
-rw-r--r--test_napi/array_test.js19
-rw-r--r--test_napi/async_test.js16
-rw-r--r--test_napi/build.rs7
-rw-r--r--test_napi/callback_test.js38
-rw-r--r--test_napi/coerce_test.js74
-rw-r--r--test_napi/common.js20
-rw-r--r--test_napi/numbers_test.js18
-rw-r--r--test_napi/object_wrap_test.js17
-rw-r--r--test_napi/promise_test.js34
-rw-r--r--test_napi/properties_test.js15
-rw-r--r--test_napi/src/array.rs73
-rw-r--r--test_napi/src/async.rs112
-rw-r--r--test_napi/src/callback.rs113
-rw-r--r--test_napi/src/coerce.rs71
-rw-r--r--test_napi/src/lib.rs78
-rw-r--r--test_napi/src/numbers.rs55
-rw-r--r--test_napi/src/object_wrap.rs154
-rw-r--r--test_napi/src/promise.rs76
-rw-r--r--test_napi/src/properties.rs89
-rw-r--r--test_napi/src/strings.rs45
-rw-r--r--test_napi/src/typedarray.rs53
-rw-r--r--test_napi/strings_test.js15
-rw-r--r--test_napi/tests/napi_tests.rs45
-rw-r--r--test_napi/typedarray_test.js12
26 files changed, 1273 insertions, 0 deletions
diff --git a/test_napi/.gitignore b/test_napi/.gitignore
new file mode 100644
index 000000000..6fdcc4a66
--- /dev/null
+++ b/test_napi/.gitignore
@@ -0,0 +1,4 @@
+package-lock.json
+
+# Test generated artifacts
+.swc \ No newline at end of file
diff --git a/test_napi/Cargo.toml b/test_napi/Cargo.toml
new file mode 100644
index 000000000..09faa4175
--- /dev/null
+++ b/test_napi/Cargo.toml
@@ -0,0 +1,20 @@
+# Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
+
+[package]
+name = "test_napi"
+version = "0.1.0"
+authors = ["the deno authors"]
+edition = "2021"
+publish = false
+
+[lib]
+crate-type = ["cdylib"]
+
+[dependencies]
+napi-sys = { version = "2.2.2", default-features = false, features = ["napi4"] }
+
+[dev-dependencies]
+test_util = { path = "../test_util" }
+
+[build-dependencies]
+napi-build = "1"
diff --git a/test_napi/array_test.js b/test_napi/array_test.js
new file mode 100644
index 000000000..314ea5e50
--- /dev/null
+++ b/test_napi/array_test.js
@@ -0,0 +1,19 @@
+// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
+
+import { assertEquals, loadTestLibrary } from "./common.js";
+
+const array = loadTestLibrary();
+
+Deno.test("napi array new", function () {
+ const e = [0, "Hello", {}];
+ const r = array.test_array_new(e);
+ assertEquals(typeof r, "object");
+ assertEquals(r.length, 3);
+ assertEquals(e, r);
+});
+
+Deno.test("napi array new with length", function () {
+ const r = array.test_array_new_with_length(100);
+ assertEquals(typeof r, "object");
+ assertEquals(r.length, 100);
+});
diff --git a/test_napi/async_test.js b/test_napi/async_test.js
new file mode 100644
index 000000000..ea1b714bd
--- /dev/null
+++ b/test_napi/async_test.js
@@ -0,0 +1,16 @@
+// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
+
+import { assertEquals, loadTestLibrary } from "./common.js";
+
+const asyncTask = loadTestLibrary();
+
+Deno.test("napi async task schedule", async () => {
+ let called = false;
+ await new Promise((resolve) => {
+ asyncTask.test_async_work(() => {
+ called = true;
+ resolve();
+ });
+ });
+ assertEquals(called, true);
+});
diff --git a/test_napi/build.rs b/test_napi/build.rs
new file mode 100644
index 000000000..9d3021a0e
--- /dev/null
+++ b/test_napi/build.rs
@@ -0,0 +1,7 @@
+// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
+
+extern crate napi_build;
+
+fn main() {
+ napi_build::setup();
+}
diff --git a/test_napi/callback_test.js b/test_napi/callback_test.js
new file mode 100644
index 000000000..debb1d7ba
--- /dev/null
+++ b/test_napi/callback_test.js
@@ -0,0 +1,38 @@
+// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
+
+import { assertEquals, loadTestLibrary } from "./common.js";
+
+const callback = loadTestLibrary();
+
+Deno.test("napi callback run with args", function () {
+ const result = callback.test_callback_run((a, b) => a + b, [1, 2]);
+ assertEquals(result, 3);
+});
+
+Deno.test("napi callback run with args (no return)", function () {
+ const result = callback.test_callback_run(() => {}, []);
+ assertEquals(result, undefined);
+});
+
+Deno.test("napi callback run with args (extra arguments)", function () {
+ const result = callback.test_callback_run((a, b) => a + b, [
+ "Hello,",
+ " Deno!",
+ 1,
+ 2,
+ 3,
+ ]);
+ assertEquals(result, "Hello, Deno!");
+});
+
+Deno.test("napi callback run with args & recv", function () {
+ const result = callback.test_callback_run_with_recv(
+ function () {
+ assertEquals(this, 69);
+ return this;
+ },
+ [],
+ 69,
+ );
+ assertEquals(result, 69);
+});
diff --git a/test_napi/coerce_test.js b/test_napi/coerce_test.js
new file mode 100644
index 000000000..be0ee03e7
--- /dev/null
+++ b/test_napi/coerce_test.js
@@ -0,0 +1,74 @@
+// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
+
+import { assertEquals, loadTestLibrary } from "./common.js";
+
+const coerce = loadTestLibrary();
+
+Deno.test("napi coerce bool", function () {
+ assertEquals(coerce.test_coerce_bool(true), true);
+ assertEquals(coerce.test_coerce_bool(false), false);
+ assertEquals(coerce.test_coerce_bool(0), false);
+ assertEquals(coerce.test_coerce_bool(69), true);
+ assertEquals(coerce.test_coerce_bool(Number.MAX_SAFE_INTEGER), true);
+ assertEquals(coerce.test_coerce_bool(new Array(10)), true);
+ assertEquals(coerce.test_coerce_bool("Hello, Deno!"), true);
+ assertEquals(coerce.test_coerce_bool(Symbol("[[test]]")), true);
+ assertEquals(coerce.test_coerce_bool({}), true);
+ assertEquals(coerce.test_coerce_bool(() => false), true);
+ assertEquals(coerce.test_coerce_bool(undefined), false);
+ assertEquals(coerce.test_coerce_bool(null), false);
+});
+
+Deno.test("napi coerce number", function () {
+ assertEquals(coerce.test_coerce_number(true), 1);
+ assertEquals(coerce.test_coerce_number(false), 0);
+ assertEquals(coerce.test_coerce_number(0), 0);
+ assertEquals(coerce.test_coerce_number(69), 69);
+ assertEquals(coerce.test_coerce_number(""), 0);
+ assertEquals(
+ coerce.test_coerce_number(Number.MAX_SAFE_INTEGER),
+ Number.MAX_SAFE_INTEGER,
+ );
+ assertEquals(coerce.test_coerce_number(new Array(10)), NaN);
+ assertEquals(coerce.test_coerce_number("Hello, Deno!"), NaN);
+ assertEquals(coerce.test_coerce_number({}), NaN);
+ assertEquals(coerce.test_coerce_number(() => false), NaN);
+ assertEquals(coerce.test_coerce_number(undefined), NaN);
+ assertEquals(coerce.test_coerce_number(null), 0);
+});
+
+Deno.test("napi coerce string", function () {
+ assertEquals(coerce.test_coerce_string(true), "true");
+ assertEquals(coerce.test_coerce_string(false), "false");
+ assertEquals(coerce.test_coerce_string(0), "0");
+ assertEquals(coerce.test_coerce_string(69), "69");
+ assertEquals(coerce.test_coerce_string(""), "");
+ assertEquals(
+ coerce.test_coerce_string(Number.MAX_SAFE_INTEGER),
+ "9007199254740991",
+ );
+ assertEquals(coerce.test_coerce_string(new Array(10)), ",,,,,,,,,");
+ assertEquals(coerce.test_coerce_string("Hello, Deno!"), "Hello, Deno!");
+ assertEquals(coerce.test_coerce_string({}), "[object Object]");
+ assertEquals(coerce.test_coerce_string(() => false), "() => false");
+ assertEquals(coerce.test_coerce_string(undefined), "undefined");
+ assertEquals(coerce.test_coerce_string(null), "null");
+});
+
+Deno.test("napi coerce object", function () {
+ assertEquals(coerce.test_coerce_object(true), new Boolean(true));
+ assertEquals(coerce.test_coerce_object(false), new Boolean(false));
+ assertEquals(coerce.test_coerce_object(0), new Number(0));
+ assertEquals(coerce.test_coerce_object(69), new Number(0));
+ assertEquals(coerce.test_coerce_object(""), new String(""));
+ assertEquals(
+ coerce.test_coerce_object(Number.MAX_SAFE_INTEGER),
+ new Number(Number.MAX_SAFE_INTEGER),
+ );
+ assertEquals(coerce.test_coerce_object(new Array(10)), new Array(10));
+ assertEquals(
+ coerce.test_coerce_object("Hello, Deno!"),
+ new String("Hello, Deno!"),
+ );
+ assertEquals(coerce.test_coerce_object({}), {});
+});
diff --git a/test_napi/common.js b/test_napi/common.js
new file mode 100644
index 000000000..13dad6cfc
--- /dev/null
+++ b/test_napi/common.js
@@ -0,0 +1,20 @@
+// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
+
+export {
+ assert,
+ assertEquals,
+ assertRejects,
+} from "../test_util/std/testing/asserts.ts";
+export { fromFileUrl } from "../test_util/std/path/mod.ts";
+
+const targetDir = Deno.execPath().replace(/[^\/\\]+$/, "");
+const [libPrefix, libSuffix] = {
+ darwin: ["lib", "dylib"],
+ linux: ["lib", "so"],
+ windows: ["", "dll"],
+}[Deno.build.os];
+
+export function loadTestLibrary() {
+ const specifier = `${targetDir}/${libPrefix}test_napi.${libSuffix}`;
+ return Deno.core.ops.op_napi_open(specifier); // Internal, used in ext/node
+}
diff --git a/test_napi/numbers_test.js b/test_napi/numbers_test.js
new file mode 100644
index 000000000..2f778285a
--- /dev/null
+++ b/test_napi/numbers_test.js
@@ -0,0 +1,18 @@
+// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
+
+import { assertEquals, loadTestLibrary } from "./common.js";
+
+const numbers = loadTestLibrary();
+
+Deno.test("napi int32", function () {
+ assertEquals(numbers.test_int32(69), 69);
+ assertEquals(numbers.test_int32(Number.MAX_SAFE_INTEGER), -1);
+});
+
+Deno.test("napi int64", function () {
+ assertEquals(numbers.test_int64(69), 69);
+ assertEquals(
+ numbers.test_int64(Number.MAX_SAFE_INTEGER),
+ Number.MAX_SAFE_INTEGER,
+ );
+});
diff --git a/test_napi/object_wrap_test.js b/test_napi/object_wrap_test.js
new file mode 100644
index 000000000..2263894cd
--- /dev/null
+++ b/test_napi/object_wrap_test.js
@@ -0,0 +1,17 @@
+// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
+
+import { assertEquals, loadTestLibrary } from "./common.js";
+
+const objectWrap = loadTestLibrary();
+
+Deno.test("napi object wrap new", function () {
+ const obj = new objectWrap.NapiObject(0);
+ assertEquals(obj.get_value(), 0);
+ obj.set_value(10);
+ assertEquals(obj.get_value(), 10);
+ obj.increment();
+ assertEquals(obj.get_value(), 11);
+ obj.increment();
+ obj.set_value(10);
+ assertEquals(obj.get_value(), 10);
+});
diff --git a/test_napi/promise_test.js b/test_napi/promise_test.js
new file mode 100644
index 000000000..86a3f134b
--- /dev/null
+++ b/test_napi/promise_test.js
@@ -0,0 +1,34 @@
+// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
+
+import { assertEquals, assertRejects, loadTestLibrary } from "./common.js";
+
+const promise = loadTestLibrary();
+
+Deno.test("napi new promise and resolve", async () => {
+ const p = promise.test_promise_new();
+ promise.test_promise_resolve(69);
+
+ assertEquals(await p, 69);
+});
+
+Deno.test("napi new promise and reject", () => {
+ const p = promise.test_promise_new();
+
+ assertRejects(async () => {
+ promise.test_promise_reject(new TypeError("pikaboo"));
+ await p;
+ }, TypeError);
+});
+
+Deno.test("napi new promise and reject", async () => {
+ const p = promise.test_promise_new();
+ const is = promise.test_promise_is(p);
+ assertEquals(typeof is, "boolean");
+ assertEquals(is, true);
+
+ assertEquals(promise.test_promise_is(undefined), false);
+ assertEquals(promise.test_promise_is({}), false);
+ promise.test_promise_resolve(69);
+
+ assertEquals(await p, 69);
+});
diff --git a/test_napi/properties_test.js b/test_napi/properties_test.js
new file mode 100644
index 000000000..b24c5649e
--- /dev/null
+++ b/test_napi/properties_test.js
@@ -0,0 +1,15 @@
+// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
+
+import { assertEquals, loadTestLibrary } from "./common.js";
+
+const properties = loadTestLibrary();
+
+Deno.test("napi properties", () => {
+ properties.test_property_rw = 1;
+ assertEquals(properties.test_property_rw, 1);
+ properties.test_property_rw = 2;
+ assertEquals(properties.test_property_rw, 2);
+
+ // assertEquals(properties.test_property_r, 2);
+ // assertRejects(() => properties.test_property_r = 3);
+});
diff --git a/test_napi/src/array.rs b/test_napi/src/array.rs
new file mode 100644
index 000000000..767aa08b1
--- /dev/null
+++ b/test_napi/src/array.rs
@@ -0,0 +1,73 @@
+// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
+
+use napi_sys::Status::napi_ok;
+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, _) = crate::get_callback_info!(env, info, 1);
+ assert_eq!(argc, 1);
+
+ let mut ty = -1;
+ assert!(unsafe { napi_typeof(env, args[0], &mut ty) } == napi_ok);
+ assert_eq!(ty, napi_object);
+
+ let mut value: napi_value = ptr::null_mut();
+ assert!(unsafe { napi_create_array(env, &mut value) } == napi_ok);
+
+ let mut length: u32 = 0;
+ assert!(
+ unsafe { napi_get_array_length(env, args[0], &mut length) } == napi_ok
+ );
+
+ for i in 0..length {
+ let mut e: napi_value = ptr::null_mut();
+ assert!(unsafe { napi_get_element(env, args[0], i, &mut e) } == napi_ok);
+ assert!(unsafe { napi_set_element(env, value, i, e) } == napi_ok);
+ }
+
+ value
+}
+
+extern "C" fn test_array_new_with_length(
+ env: napi_env,
+ info: napi_callback_info,
+) -> napi_value {
+ let (args, argc, _) = crate::get_callback_info!(env, info, 1);
+ assert_eq!(argc, 1);
+
+ let mut ty = -1;
+ assert!(unsafe { napi_typeof(env, args[0], &mut ty) } == napi_ok);
+ assert_eq!(ty, napi_number);
+
+ let mut len: u32 = 0;
+ assert!(unsafe { napi_get_value_uint32(env, args[0], &mut len) } == napi_ok);
+
+ let mut value: napi_value = ptr::null_mut();
+ assert!(
+ unsafe { napi_create_array_with_length(env, len as usize, &mut value) }
+ == napi_ok
+ );
+
+ value
+}
+
+pub fn init(env: napi_env, exports: napi_value) {
+ let properties = &[
+ crate::new_property!(env, "test_array_new\0", test_array_new),
+ crate::new_property!(
+ env,
+ "test_array_new_with_length\0",
+ test_array_new_with_length
+ ),
+ ];
+
+ unsafe {
+ napi_define_properties(env, exports, properties.len(), properties.as_ptr())
+ };
+}
diff --git a/test_napi/src/async.rs b/test_napi/src/async.rs
new file mode 100644
index 000000000..d14871a7c
--- /dev/null
+++ b/test_napi/src/async.rs
@@ -0,0 +1,112 @@
+// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
+
+use napi_sys::Status::napi_ok;
+use napi_sys::ValueType::napi_function;
+use napi_sys::*;
+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_get_global(env, &mut global) == napi_ok);
+
+ let mut callback: napi_value = ptr::null_mut();
+ assert!(napi_get_reference_value(env, baton.func, &mut callback) == napi_ok);
+
+ let mut _result: napi_value = ptr::null_mut();
+ assert!(
+ napi_call_function(env, global, callback, 0, ptr::null(), &mut _result)
+ == napi_ok
+ );
+
+ assert!(napi_delete_reference(env, baton.func) == napi_ok);
+ assert!(napi_delete_async_work(env, baton.task) == napi_ok);
+}
+
+extern "C" fn test_async_work(
+ env: napi_env,
+ info: napi_callback_info,
+) -> napi_value {
+ let (args, argc, _) = crate::get_callback_info!(env, info, 1);
+ assert_eq!(argc, 1);
+
+ let mut ty = -1;
+ assert!(unsafe { napi_typeof(env, args[0], &mut ty) } == napi_ok);
+ assert_eq!(ty, napi_function);
+
+ let mut resource_name: napi_value = ptr::null_mut();
+ assert!(
+ unsafe {
+ napi_create_string_utf8(
+ env,
+ "test_async_resource\0".as_ptr() as *const i8,
+ usize::MAX,
+ &mut resource_name,
+ )
+ } == napi_ok
+ );
+
+ let mut async_work: napi_async_work = ptr::null_mut();
+
+ let mut func: napi_ref = ptr::null_mut();
+ assert!(
+ unsafe { napi_create_reference(env, args[0], 1, &mut func) } == napi_ok
+ );
+ let baton = Box::new(Baton {
+ called: false,
+ func,
+ task: async_work,
+ });
+
+ assert!(
+ unsafe {
+ napi_create_async_work(
+ env,
+ ptr::null_mut(),
+ resource_name,
+ Some(execute),
+ Some(complete),
+ Box::into_raw(baton) as *mut c_void,
+ &mut async_work,
+ )
+ } == napi_ok
+ );
+ assert!(unsafe { napi_queue_async_work(env, async_work) } == napi_ok);
+
+ ptr::null_mut()
+}
+
+pub fn init(env: napi_env, exports: napi_value) {
+ let properties = &[crate::new_property!(
+ env,
+ "test_async_work\0",
+ test_async_work
+ )];
+
+ unsafe {
+ napi_define_properties(env, exports, properties.len(), properties.as_ptr())
+ };
+}
diff --git a/test_napi/src/callback.rs b/test_napi/src/callback.rs
new file mode 100644
index 000000000..bf6062913
--- /dev/null
+++ b/test_napi/src/callback.rs
@@ -0,0 +1,113 @@
+// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
+
+use napi_sys::Status::napi_ok;
+use napi_sys::ValueType::napi_function;
+use napi_sys::ValueType::napi_object;
+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 {
+ let (args, argc, _) = crate::get_callback_info!(env, info, 2);
+ assert_eq!(argc, 2);
+
+ let mut ty = -1;
+ assert!(unsafe { napi_typeof(env, args[0], &mut ty) } == napi_ok);
+ assert_eq!(ty, napi_function);
+
+ let mut ty = -1;
+ assert!(unsafe { napi_typeof(env, args[1], &mut ty) } == napi_ok);
+ assert_eq!(ty, napi_object);
+
+ let mut len = 0;
+ assert!(unsafe { napi_get_array_length(env, args[1], &mut len) } == napi_ok);
+
+ let mut argv = Vec::with_capacity(len as usize);
+ for index in 0..len {
+ let mut value: napi_value = ptr::null_mut();
+ assert!(
+ unsafe { napi_get_element(env, args[1], index, &mut value) } == napi_ok
+ );
+ argv.push(value);
+ }
+ let mut global: napi_value = ptr::null_mut();
+ assert!(unsafe { napi_get_global(env, &mut global) } == napi_ok);
+
+ let mut result: napi_value = ptr::null_mut();
+ assert!(
+ unsafe {
+ napi_call_function(
+ env,
+ global,
+ args[0],
+ argv.len(),
+ argv.as_mut_ptr(),
+ &mut result,
+ )
+ } == napi_ok
+ );
+
+ result
+}
+
+extern "C" fn test_callback_run_with_recv(
+ env: napi_env,
+ info: napi_callback_info,
+) -> napi_value {
+ let (args, argc, _) = crate::get_callback_info!(env, info, 3);
+ assert_eq!(argc, 3);
+
+ let mut ty = -1;
+ assert!(unsafe { napi_typeof(env, args[0], &mut ty) } == napi_ok);
+ assert_eq!(ty, napi_function);
+
+ let mut ty = -1;
+ assert!(unsafe { napi_typeof(env, args[1], &mut ty) } == napi_ok);
+ assert_eq!(ty, napi_object);
+
+ let mut len = 0;
+ assert!(unsafe { napi_get_array_length(env, args[1], &mut len) } == napi_ok);
+
+ let mut argv = Vec::with_capacity(len as usize);
+ for index in 0..len {
+ let mut value: napi_value = ptr::null_mut();
+ assert!(
+ unsafe { napi_get_element(env, args[1], index, &mut value) } == napi_ok
+ );
+ argv.push(value);
+ }
+
+ let mut result: napi_value = ptr::null_mut();
+ assert!(
+ unsafe {
+ napi_call_function(
+ env,
+ args[2], // recv
+ args[0], // cb
+ argv.len(),
+ argv.as_mut_ptr(),
+ &mut result,
+ )
+ } == napi_ok
+ );
+
+ result
+}
+
+pub fn init(env: napi_env, exports: napi_value) {
+ let properties = &[
+ crate::new_property!(env, "test_callback_run\0", test_callback_run),
+ crate::new_property!(
+ env,
+ "test_callback_run_with_recv\0",
+ test_callback_run_with_recv
+ ),
+ ];
+
+ unsafe {
+ napi_define_properties(env, exports, properties.len(), properties.as_ptr())
+ };
+}
diff --git a/test_napi/src/coerce.rs b/test_napi/src/coerce.rs
new file mode 100644
index 000000000..611540fae
--- /dev/null
+++ b/test_napi/src/coerce.rs
@@ -0,0 +1,71 @@
+// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
+
+use napi_sys::Status::napi_ok;
+use napi_sys::*;
+use std::ptr;
+
+extern "C" fn test_coerce_bool(
+ env: napi_env,
+ info: napi_callback_info,
+) -> napi_value {
+ let (args, argc, _) = crate::get_callback_info!(env, info, 1);
+ assert_eq!(argc, 1);
+
+ let mut value: napi_value = ptr::null_mut();
+ assert!(unsafe { napi_coerce_to_bool(env, args[0], &mut value) } == napi_ok);
+ value
+}
+
+extern "C" fn test_coerce_number(
+ env: napi_env,
+ info: napi_callback_info,
+) -> napi_value {
+ let (args, argc, _) = crate::get_callback_info!(env, info, 1);
+ assert_eq!(argc, 1);
+
+ let mut value: napi_value = ptr::null_mut();
+ assert!(
+ unsafe { napi_coerce_to_number(env, args[0], &mut value) } == napi_ok
+ );
+ value
+}
+
+extern "C" fn test_coerce_object(
+ env: napi_env,
+ info: napi_callback_info,
+) -> napi_value {
+ let (args, argc, _) = crate::get_callback_info!(env, info, 1);
+ assert_eq!(argc, 1);
+
+ let mut value: napi_value = ptr::null_mut();
+ assert!(
+ unsafe { napi_coerce_to_object(env, args[0], &mut value) } == napi_ok
+ );
+ value
+}
+
+extern "C" fn test_coerce_string(
+ env: napi_env,
+ info: napi_callback_info,
+) -> napi_value {
+ let (args, argc, _) = crate::get_callback_info!(env, info, 1);
+ assert_eq!(argc, 1);
+
+ let mut value: napi_value = ptr::null_mut();
+ assert!(
+ unsafe { napi_coerce_to_string(env, args[0], &mut value) } == napi_ok
+ );
+ value
+}
+pub fn init(env: napi_env, exports: napi_value) {
+ let properties = &[
+ crate::new_property!(env, "test_coerce_bool\0", test_coerce_bool),
+ crate::new_property!(env, "test_coerce_number\0", test_coerce_number),
+ crate::new_property!(env, "test_coerce_object\0", test_coerce_object),
+ crate::new_property!(env, "test_coerce_string\0", test_coerce_string),
+ ];
+
+ unsafe {
+ napi_define_properties(env, exports, properties.len(), properties.as_ptr())
+ };
+}
diff --git a/test_napi/src/lib.rs b/test_napi/src/lib.rs
new file mode 100644
index 000000000..e058686c5
--- /dev/null
+++ b/test_napi/src/lib.rs
@@ -0,0 +1,78 @@
+// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
+#![allow(clippy::all)]
+#![allow(clippy::undocumented_unsafe_blocks)]
+
+use napi_sys::*;
+
+pub mod array;
+pub mod r#async;
+pub mod callback;
+pub mod coerce;
+pub mod numbers;
+pub mod object_wrap;
+pub mod promise;
+pub mod properties;
+pub mod strings;
+pub mod typedarray;
+
+#[macro_export]
+macro_rules! get_callback_info {
+ ($env: expr, $callback_info: expr, $size: literal) => {{
+ let mut args = [ptr::null_mut(); $size];
+ let mut argc = $size;
+ let mut this = ptr::null_mut();
+ unsafe {
+ assert!(
+ napi_get_cb_info(
+ $env,
+ $callback_info,
+ &mut argc,
+ args.as_mut_ptr(),
+ &mut this,
+ ptr::null_mut(),
+ ) == napi_ok,
+ )
+ };
+ (args, argc, this)
+ }};
+}
+
+#[macro_export]
+macro_rules! new_property {
+ ($env: expr, $name: expr, $value: expr) => {
+ napi_property_descriptor {
+ utf8name: $name.as_ptr() as *const i8,
+ name: ptr::null_mut(),
+ method: Some($value),
+ getter: None,
+ setter: None,
+ data: ptr::null_mut(),
+ attributes: 0,
+ value: ptr::null_mut(),
+ }
+ };
+}
+
+#[no_mangle]
+unsafe extern "C" fn napi_register_module_v1(
+ env: napi_env,
+ exports: napi_value,
+) -> napi_value {
+ #[cfg(windows)]
+ {
+ napi_sys::setup();
+ }
+
+ strings::init(env, exports);
+ numbers::init(env, exports);
+ typedarray::init(env, exports);
+ array::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);
+
+ exports
+}
diff --git a/test_napi/src/numbers.rs b/test_napi/src/numbers.rs
new file mode 100644
index 000000000..a6628af13
--- /dev/null
+++ b/test_napi/src/numbers.rs
@@ -0,0 +1,55 @@
+// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
+
+use napi_sys::Status::napi_ok;
+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, _) = crate::get_callback_info!(env, info, 1);
+ assert_eq!(argc, 1);
+
+ let mut ty = -1;
+ assert!(unsafe { napi_typeof(env, args[0], &mut ty) } == napi_ok);
+ assert_eq!(ty, napi_number);
+
+ let mut int32 = -1;
+ assert!(unsafe { napi_get_value_int32(env, args[0], &mut int32) } == napi_ok);
+
+ let mut value: napi_value = ptr::null_mut();
+ assert!(unsafe { napi_create_int32(env, int32, &mut value) } == napi_ok);
+ value
+}
+
+extern "C" fn test_int64(
+ env: napi_env,
+ info: napi_callback_info,
+) -> napi_value {
+ let (args, argc, _) = crate::get_callback_info!(env, info, 1);
+ assert_eq!(argc, 1);
+
+ let mut ty = -1;
+ assert!(unsafe { napi_typeof(env, args[0], &mut ty) } == napi_ok);
+ assert_eq!(ty, napi_number);
+
+ let mut int64 = -1;
+ assert!(unsafe { napi_get_value_int64(env, args[0], &mut int64) } == napi_ok);
+
+ let mut value: napi_value = ptr::null_mut();
+ assert!(unsafe { napi_create_int64(env, int64, &mut value) } == napi_ok);
+ value
+}
+
+pub fn init(env: napi_env, exports: napi_value) {
+ let properties = &[
+ crate::new_property!(env, "test_int32\0", test_int32),
+ crate::new_property!(env, "test_int64\0", test_int64),
+ ];
+
+ unsafe {
+ napi_define_properties(env, exports, properties.len(), properties.as_ptr())
+ };
+}
diff --git a/test_napi/src/object_wrap.rs b/test_napi/src/object_wrap.rs
new file mode 100644
index 000000000..3b849b2dc
--- /dev/null
+++ b/test_napi/src/object_wrap.rs
@@ -0,0 +1,154 @@
+// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
+
+use napi_sys::Status::napi_ok;
+use napi_sys::ValueType::napi_number;
+use napi_sys::*;
+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!(
+ unsafe { napi_get_new_target(env, info, &mut new_target) } == napi_ok
+ );
+ let is_constructor = !new_target.is_null();
+
+ let (args, argc, this) = crate::get_callback_info!(env, info, 1);
+ assert_eq!(argc, 1);
+
+ if is_constructor {
+ let mut value = 0;
+
+ let mut ty = -1;
+ assert!(unsafe { napi_typeof(env, args[0], &mut ty) } == napi_ok);
+ assert_eq!(ty, napi_number);
+
+ assert!(
+ unsafe { napi_get_value_int32(env, args[0], &mut value) } == napi_ok
+ );
+
+ let mut wrapper: napi_ref = ptr::null_mut();
+ let obj = Box::new(Self {
+ counter: value,
+ _wrapper: wrapper,
+ });
+ assert!(
+ unsafe {
+ napi_wrap(
+ env,
+ this,
+ Box::into_raw(obj) as *mut c_void,
+ None,
+ ptr::null_mut(),
+ &mut wrapper,
+ )
+ } == napi_ok
+ );
+
+ return this;
+ }
+
+ unreachable!();
+ }
+
+ pub extern "C" fn set_value(
+ env: napi_env,
+ info: napi_callback_info,
+ ) -> napi_value {
+ let (args, argc, this) = crate::get_callback_info!(env, info, 1);
+ assert_eq!(argc, 1);
+ let mut obj: *mut Self = ptr::null_mut();
+ assert!(
+ unsafe { napi_unwrap(env, this, &mut obj as *mut _ as *mut *mut c_void) }
+ == napi_ok
+ );
+
+ assert!(
+ unsafe { napi_get_value_int32(env, args[0], &mut (*obj).counter) }
+ == napi_ok
+ );
+
+ ptr::null_mut()
+ }
+
+ pub extern "C" fn get_value(
+ env: napi_env,
+ info: napi_callback_info,
+ ) -> napi_value {
+ let (_args, argc, this) = crate::get_callback_info!(env, info, 0);
+ assert_eq!(argc, 0);
+ let mut obj: *mut Self = ptr::null_mut();
+ assert!(
+ unsafe { napi_unwrap(env, this, &mut obj as *mut _ as *mut *mut c_void) }
+ == napi_ok
+ );
+
+ let mut num: napi_value = ptr::null_mut();
+ assert!(
+ unsafe { napi_create_int32(env, (*obj).counter, &mut num) } == napi_ok
+ );
+
+ num
+ }
+
+ pub extern "C" fn increment(
+ env: napi_env,
+ info: napi_callback_info,
+ ) -> napi_value {
+ let (_args, argc, this) = crate::get_callback_info!(env, info, 0);
+ assert_eq!(argc, 0);
+ let mut obj: *mut Self = ptr::null_mut();
+ assert!(
+ unsafe { napi_unwrap(env, this, &mut obj as *mut _ as *mut *mut c_void) }
+ == napi_ok
+ );
+
+ unsafe {
+ (*obj).counter += 1;
+ }
+
+ ptr::null_mut()
+ }
+}
+
+pub fn init(env: napi_env, exports: napi_value) {
+ let properties = &[
+ crate::new_property!(env, "set_value\0", NapiObject::set_value),
+ crate::new_property!(env, "get_value\0", NapiObject::get_value),
+ crate::new_property!(env, "increment\0", NapiObject::increment),
+ ];
+
+ let mut cons: napi_value = ptr::null_mut();
+ assert!(
+ unsafe {
+ napi_define_class(
+ env,
+ "NapiObject\0".as_ptr() as *mut i8,
+ usize::MAX,
+ Some(NapiObject::new),
+ ptr::null_mut(),
+ properties.len(),
+ properties.as_ptr(),
+ &mut cons,
+ )
+ } == napi_ok
+ );
+
+ assert!(
+ unsafe {
+ napi_set_named_property(
+ env,
+ exports,
+ "NapiObject\0".as_ptr() as *const i8,
+ cons,
+ )
+ } == napi_ok
+ );
+}
diff --git a/test_napi/src/promise.rs b/test_napi/src/promise.rs
new file mode 100644
index 000000000..ebb9dedab
--- /dev/null
+++ b/test_napi/src/promise.rs
@@ -0,0 +1,76 @@
+// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
+
+use napi_sys::Status::napi_ok;
+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!(
+ unsafe { napi_create_promise(env, &mut CURRENT_DEFERRED, &mut value) }
+ == napi_ok
+ );
+ value
+}
+
+extern "C" fn test_promise_resolve(
+ env: napi_env,
+ info: napi_callback_info,
+) -> napi_value {
+ let (args, argc, _) = crate::get_callback_info!(env, info, 1);
+ assert_eq!(argc, 1);
+
+ assert!(
+ unsafe { napi_resolve_deferred(env, CURRENT_DEFERRED, args[0]) } == napi_ok
+ );
+ 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, _) = crate::get_callback_info!(env, info, 1);
+ assert_eq!(argc, 1);
+
+ assert!(
+ unsafe { napi_reject_deferred(env, CURRENT_DEFERRED, args[0]) } == napi_ok
+ );
+ 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, _) = crate::get_callback_info!(env, info, 1);
+ assert_eq!(argc, 1);
+
+ let mut is_promise: bool = false;
+ assert!(unsafe { napi_is_promise(env, args[0], &mut is_promise) } == napi_ok);
+
+ let mut result: napi_value = ptr::null_mut();
+ assert!(unsafe { napi_get_boolean(env, is_promise, &mut result) } == napi_ok);
+
+ result
+}
+
+pub fn init(env: napi_env, exports: napi_value) {
+ let properties = &[
+ crate::new_property!(env, "test_promise_new\0", test_promise_new),
+ crate::new_property!(env, "test_promise_resolve\0", test_promise_resolve),
+ crate::new_property!(env, "test_promise_reject\0", test_promise_reject),
+ crate::new_property!(env, "test_promise_is\0", test_promise_is),
+ ];
+
+ unsafe {
+ napi_define_properties(env, exports, properties.len(), properties.as_ptr())
+ };
+}
diff --git a/test_napi/src/properties.rs b/test_napi/src/properties.rs
new file mode 100644
index 000000000..89d95d6c6
--- /dev/null
+++ b/test_napi/src/properties.rs
@@ -0,0 +1,89 @@
+// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
+
+use napi_sys::PropertyAttributes::*;
+use napi_sys::Status::napi_ok;
+use napi_sys::*;
+use std::ptr;
+
+pub fn init(env: napi_env, exports: napi_value) {
+ let mut number: napi_value = ptr::null_mut();
+ assert!(unsafe { napi_create_double(env, 1.0, &mut number) } == napi_ok);
+
+ // Key name as napi_value representing `v8::String`
+ let mut name_value: napi_value = ptr::null_mut();
+ assert!(
+ unsafe {
+ napi_create_string_utf8(
+ env,
+ "key_v8_string".as_ptr() as *const i8,
+ usize::MAX,
+ &mut name_value,
+ )
+ } == napi_ok
+ );
+
+ // Key symbol
+ let mut symbol_description: napi_value = ptr::null_mut();
+ let mut name_symbol: napi_value = ptr::null_mut();
+ assert!(
+ unsafe {
+ napi_create_string_utf8(
+ env,
+ "key_v8_symbol".as_ptr() as *const i8,
+ usize::MAX,
+ &mut symbol_description,
+ )
+ } == napi_ok
+ );
+ assert!(
+ unsafe { napi_create_symbol(env, symbol_description, &mut name_symbol) }
+ == napi_ok
+ );
+
+ let properties = &[
+ napi_property_descriptor {
+ utf8name: "test_property_rw\0".as_ptr() as *const i8,
+ name: ptr::null_mut(),
+ method: None,
+ getter: None,
+ setter: None,
+ data: ptr::null_mut(),
+ attributes: enumerable | writable,
+ value: number,
+ },
+ napi_property_descriptor {
+ utf8name: "test_property_r\0".as_ptr() as *const i8,
+ 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,
+ },
+ ];
+
+ unsafe {
+ napi_define_properties(env, exports, properties.len(), properties.as_ptr())
+ };
+}
diff --git a/test_napi/src/strings.rs b/test_napi/src/strings.rs
new file mode 100644
index 000000000..f4139c85a
--- /dev/null
+++ b/test_napi/src/strings.rs
@@ -0,0 +1,45 @@
+// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
+
+use napi_sys::Status::napi_ok;
+use napi_sys::ValueType::napi_string;
+use napi_sys::*;
+use std::ptr;
+
+extern "C" fn test_utf8(env: napi_env, info: napi_callback_info) -> napi_value {
+ let (args, argc, _) = crate::get_callback_info!(env, info, 1);
+ assert_eq!(argc, 1);
+
+ let mut ty = -1;
+ assert!(unsafe { napi_typeof(env, args[0], &mut ty) } == napi_ok);
+ assert_eq!(ty, napi_string);
+
+ args[0]
+}
+
+extern "C" fn test_utf16(
+ env: napi_env,
+ info: napi_callback_info,
+) -> napi_value {
+ let (args, argc, _) = crate::get_callback_info!(env, info, 1);
+ assert_eq!(argc, 1);
+
+ let mut ty = -1;
+ assert!(unsafe { napi_typeof(env, args[0], &mut ty) } == napi_ok);
+ assert_eq!(ty, napi_string);
+
+ args[0]
+}
+
+pub fn init(env: napi_env, exports: napi_value) {
+ let properties = &[
+ // utf8
+ crate::new_property!(env, "test_utf8\0", test_utf8),
+ // utf16
+ crate::new_property!(env, "test_utf16\0", test_utf16),
+ // latin1
+ ];
+
+ unsafe {
+ napi_define_properties(env, exports, properties.len(), properties.as_ptr())
+ };
+}
diff --git a/test_napi/src/typedarray.rs b/test_napi/src/typedarray.rs
new file mode 100644
index 000000000..f7d2e2f24
--- /dev/null
+++ b/test_napi/src/typedarray.rs
@@ -0,0 +1,53 @@
+// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
+
+use core::ffi::c_void;
+use napi_sys::Status::napi_ok;
+use napi_sys::TypedarrayType::uint8_array;
+use napi_sys::*;
+use std::ptr;
+
+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!(
+ unsafe {
+ napi_create_external_arraybuffer(
+ env,
+ external.as_mut_ptr() as *mut c_void,
+ external.len(),
+ None,
+ ptr::null_mut(),
+ &mut arraybuffer,
+ )
+ } == napi_ok
+ );
+
+ let mut typedarray: napi_value = ptr::null_mut();
+ assert!(
+ unsafe {
+ napi_create_typedarray(
+ env,
+ uint8_array,
+ external.len(),
+ arraybuffer,
+ 0,
+ &mut typedarray,
+ )
+ } == napi_ok
+ );
+
+ std::mem::forget(external); // Leak into JS land
+ typedarray
+}
+
+pub fn init(env: napi_env, exports: napi_value) {
+ let properties =
+ &[crate::new_property!(env, "test_external\0", test_external)];
+
+ unsafe {
+ napi_define_properties(env, exports, properties.len(), properties.as_ptr())
+ };
+}
diff --git a/test_napi/strings_test.js b/test_napi/strings_test.js
new file mode 100644
index 000000000..20e95ba61
--- /dev/null
+++ b/test_napi/strings_test.js
@@ -0,0 +1,15 @@
+// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
+
+import { assertEquals, loadTestLibrary } from "./common.js";
+
+const strings = loadTestLibrary();
+
+Deno.test("napi string utf8", function () {
+ assertEquals(strings.test_utf8(""), "");
+ assertEquals(strings.test_utf8("🦕"), "🦕");
+});
+
+Deno.test("napi string", function () {
+ assertEquals(strings.test_utf16(""), "");
+ assertEquals(strings.test_utf16("🦕"), "🦕");
+});
diff --git a/test_napi/tests/napi_tests.rs b/test_napi/tests/napi_tests.rs
new file mode 100644
index 000000000..41ec5c851
--- /dev/null
+++ b/test_napi/tests/napi_tests.rs
@@ -0,0 +1,45 @@
+// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
+
+use std::process::Command;
+use test_util::deno_cmd;
+
+#[cfg(debug_assertions)]
+const BUILD_VARIANT: &str = "debug";
+
+#[cfg(not(debug_assertions))]
+const BUILD_VARIANT: &str = "release";
+
+fn build() {
+ let mut build_plugin_base = Command::new("cargo");
+ let mut build_plugin =
+ build_plugin_base.arg("build").arg("-p").arg("test_napi");
+ if BUILD_VARIANT == "release" {
+ build_plugin = build_plugin.arg("--release");
+ }
+ let build_plugin_output = build_plugin.output().unwrap();
+ assert!(build_plugin_output.status.success());
+}
+
+#[test]
+fn napi_tests() {
+ build();
+
+ let output = deno_cmd()
+ .current_dir(test_util::napi_tests_path())
+ .arg("test")
+ .arg("--allow-read")
+ .arg("--allow-env")
+ .arg("--allow-ffi")
+ .arg("--unstable")
+ .spawn()
+ .unwrap()
+ .wait_with_output()
+ .unwrap();
+ let stdout = std::str::from_utf8(&output.stdout).unwrap();
+ let stderr = std::str::from_utf8(&output.stderr).unwrap();
+ if !output.status.success() {
+ println!("stdout {}", stdout);
+ println!("stderr {}", stderr);
+ }
+ assert!(output.status.success());
+}
diff --git a/test_napi/typedarray_test.js b/test_napi/typedarray_test.js
new file mode 100644
index 000000000..a3c7322f7
--- /dev/null
+++ b/test_napi/typedarray_test.js
@@ -0,0 +1,12 @@
+// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
+
+import { assertEquals, loadTestLibrary } from "./common.js";
+
+const typedarray = loadTestLibrary();
+
+Deno.test("napi typedarray external", function () {
+ assertEquals(
+ new Uint8Array(typedarray.test_external()),
+ new Uint8Array([0, 1, 2, 3]),
+ );
+});