diff --git a/PORTING.md b/PORTING.md index 23bdc0b..5a63cf6 100644 --- a/PORTING.md +++ b/PORTING.md @@ -52,7 +52,7 @@ Tests covering the engine-specific part of Node-API, defined in `js_native_api.h | `test_cannot_run_js` | Not ported | Medium | | `test_constructor` | Ported ✅ | Medium | | `test_conversions` | Ported ✅ | Medium | -| `test_dataview` | Not ported | Medium | +| `test_dataview` | Ported ✅ | Medium | | `test_date` | Ported ✅ | Easy | | `test_error` | Ported ✅ | Medium | | `test_exception` | Not ported | Medium | diff --git a/implementors/node/features.js b/implementors/node/features.js index cd46f82..a50f614 100644 --- a/implementors/node/features.js +++ b/implementors/node/features.js @@ -2,7 +2,7 @@ // Each key corresponds to a NODE_API_EXPERIMENTAL_HAS_* compile-time macro. // Other implementors should set unsupported features to false or omit them. -const [major, minor] = process.version.slice(1).split('.').map(Number); +const [major, minor, patch] = process.version.slice(1).split(".").map(Number); globalThis.experimentalFeatures = { // node_api_is_sharedarraybuffer and node_api_create_sharedarraybuffer were @@ -12,4 +12,11 @@ globalThis.experimentalFeatures = { createObjectWithProperties: true, setPrototype: true, postFinalizer: true, + // napi_create_dataview accepts a SharedArrayBuffer-backed buffer only since + // Node.js v24.13.1 and v25.4.0 (nodejs/node#60473). It was not backported to + // v20.x or v22.x, where such calls fail with "invalid argument". + dataviewSharedArrayBuffer: + major > 25 || + (major === 25 && minor >= 4) || + (major === 24 && (minor > 13 || (minor === 13 && patch >= 1))), }; diff --git a/tests/js-native-api/test_dataview/CMakeLists.txt b/tests/js-native-api/test_dataview/CMakeLists.txt new file mode 100644 index 0000000..4411f2e --- /dev/null +++ b/tests/js-native-api/test_dataview/CMakeLists.txt @@ -0,0 +1 @@ +add_node_api_cts_addon(test_dataview test_dataview.c) diff --git a/tests/js-native-api/test_dataview/test.js b/tests/js-native-api/test_dataview/test.js new file mode 100644 index 0000000..12fd9c6 --- /dev/null +++ b/tests/js-native-api/test_dataview/test.js @@ -0,0 +1,24 @@ +"use strict"; + +// Testing api calls for dataview +const test_dataview = loadAddon("test_dataview"); + +// Test for creating dataview with ArrayBuffer +{ + const buffer = new ArrayBuffer(128); + const template = Reflect.construct(DataView, [buffer]); + + const theDataview = test_dataview.CreateDataViewFromJSDataView(template); + assert.ok( + theDataview instanceof DataView, + `Expect ${theDataview} to be a DataView`, + ); +} + +// Test for creating dataview with ArrayBuffer and invalid range +{ + const buffer = new ArrayBuffer(128); + assert.throws(() => { + test_dataview.CreateDataView(buffer, 10, 200); + }, RangeError); +} diff --git a/tests/js-native-api/test_dataview/test_dataview.c b/tests/js-native-api/test_dataview/test_dataview.c new file mode 100644 index 0000000..d6a85db --- /dev/null +++ b/tests/js-native-api/test_dataview/test_dataview.c @@ -0,0 +1,96 @@ +#include +#include +#include "../common.h" +#include "../entry_point.h" + +static napi_value CreateDataView(napi_env env, napi_callback_info info) { + size_t argc = 3; + napi_value args [3]; + NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); + + NODE_API_ASSERT(env, argc == 3, "Wrong number of arguments"); + + napi_valuetype valuetype0; + napi_value arraybuffer = args[0]; + + NODE_API_CALL(env, napi_typeof(env, arraybuffer, &valuetype0)); + NODE_API_ASSERT(env, valuetype0 == napi_object, + "Wrong type of arguments. Expects a ArrayBuffer as the first " + "argument."); + + napi_valuetype valuetype1; + NODE_API_CALL(env, napi_typeof(env, args[1], &valuetype1)); + + NODE_API_ASSERT(env, valuetype1 == napi_number, + "Wrong type of arguments. Expects a number as second argument."); + + size_t byte_offset = 0; + NODE_API_CALL(env, napi_get_value_uint32(env, args[1], (uint32_t*)(&byte_offset))); + + napi_valuetype valuetype2; + NODE_API_CALL(env, napi_typeof(env, args[2], &valuetype2)); + + NODE_API_ASSERT(env, valuetype2 == napi_number, + "Wrong type of arguments. Expects a number as third argument."); + + size_t length = 0; + NODE_API_CALL(env, napi_get_value_uint32(env, args[2], (uint32_t*)(&length))); + + napi_value output_dataview; + NODE_API_CALL(env, + napi_create_dataview(env, length, arraybuffer, + byte_offset, &output_dataview)); + + return output_dataview; +} + +static napi_value CreateDataViewFromJSDataView(napi_env env, napi_callback_info info) { + size_t argc = 1; + napi_value args [1]; + NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); + + NODE_API_ASSERT(env, argc == 1, "Wrong number of arguments"); + + napi_valuetype valuetype; + napi_value input_dataview = args[0]; + + NODE_API_CALL(env, napi_typeof(env, input_dataview, &valuetype)); + NODE_API_ASSERT(env, valuetype == napi_object, + "Wrong type of arguments. Expects a DataView as the first " + "argument."); + + bool is_dataview; + NODE_API_CALL(env, napi_is_dataview(env, input_dataview, &is_dataview)); + NODE_API_ASSERT(env, is_dataview, + "Wrong type of arguments. Expects a DataView as the first " + "argument."); + size_t byte_offset = 0; + size_t length = 0; + napi_value buffer; + NODE_API_CALL(env, + napi_get_dataview_info(env, input_dataview, &length, NULL, + &buffer, &byte_offset)); + + napi_value output_dataview; + NODE_API_CALL(env, + napi_create_dataview(env, length, buffer, + byte_offset, &output_dataview)); + + + return output_dataview; +} + +EXTERN_C_START +napi_value Init(napi_env env, napi_value exports) { + napi_property_descriptor descriptors[] = { + DECLARE_NODE_API_PROPERTY("CreateDataView", CreateDataView), + DECLARE_NODE_API_PROPERTY("CreateDataViewFromJSDataView", + CreateDataViewFromJSDataView) + }; + + NODE_API_CALL(env, napi_define_properties( + env, exports, sizeof(descriptors) / sizeof(*descriptors), descriptors)); + + return exports; +} +EXTERN_C_END diff --git a/tests/js-native-api/test_dataview/test_sharedarraybuffer.js b/tests/js-native-api/test_dataview/test_sharedarraybuffer.js new file mode 100644 index 0000000..3218008 --- /dev/null +++ b/tests/js-native-api/test_dataview/test_sharedarraybuffer.js @@ -0,0 +1,32 @@ +"use strict"; + +// napi_create_dataview accepts a SharedArrayBuffer-backed buffer only on newer +// Node.js releases (see implementors/node/features.js). +if (!experimentalFeatures.dataviewSharedArrayBuffer) { + skipTest(); +} + +// Testing api calls for dataview backed by a SharedArrayBuffer +const test_dataview = loadAddon("test_dataview"); + +// Test for creating dataview with SharedArrayBuffer +{ + const buffer = new SharedArrayBuffer(128); + const template = new DataView(buffer); + + const theDataview = test_dataview.CreateDataViewFromJSDataView(template); + assert.ok( + theDataview instanceof DataView, + `Expect ${theDataview} to be a DataView`, + ); + + assert.strictEqual(template.buffer, theDataview.buffer); +} + +// Test for creating dataview with SharedArrayBuffer and invalid range +{ + const buffer = new SharedArrayBuffer(128); + assert.throws(() => { + test_dataview.CreateDataView(buffer, 10, 200); + }, RangeError); +}