Skip to content

Commit 254e4d4

Browse files
hexbinoctclaude
andcommitted
feat: port test_typedarray SharedArrayBuffer test to CTS
Ports test/js-native-api/test_typedarray/test_sharedarraybuffer.js and its addon from nodejs/node, covering napi_create_typedarray over a SharedArrayBuffer-backed view. The existing test_typedarray addon cannot host it: its CreateTypedArray asserts napi_is_arraybuffer on the second argument, which is false for a SharedArrayBuffer. Upstream added a separate addon for the same reason. Gated on runtimeFeatures.typedarraySharedArrayBuffer, since the capability only landed in Node.js v26.2.0 and v24.18.0 (nodejs/node#62710). Fixes: #61 Signed-off-by: hexbinoct <abubakarm@gmail.com> Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent a91d9a5 commit 254e4d4

4 files changed

Lines changed: 206 additions & 0 deletions

File tree

‎implementors/node/features.js‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,13 @@ globalThis.runtimeFeatures = {
3131
major > 25 ||
3232
(major === 25 && minor >= 4) ||
3333
(major === 24 && (minor > 13 || (minor === 13 && patch >= 1))),
34+
35+
// napi_create_typedarray accepts a SharedArrayBuffer-backed buffer only
36+
// since Node.js v26.2.0 and v24.18.0 (nodejs/node#62710). The v25.x line
37+
// saw no release after that landed, and it was not backported to v20.x or
38+
// v22.x, where such calls fail with "invalid argument".
39+
typedarraySharedArrayBuffer:
40+
major > 26 ||
41+
(major === 26 && minor >= 2) ||
42+
(major === 24 && minor >= 18),
3443
};
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
add_node_api_cts_addon(test_typedarray test_typedarray.c)
2+
add_node_api_cts_addon(test_typedarray_sharedarraybuffer test_typedarray_sharedarraybuffer.c)
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
// napi_create_typedarray accepts a SharedArrayBuffer-backed buffer only on
2+
// newer Node.js releases (see implementors/node/features.js).
3+
if (!runtimeFeatures.typedarraySharedArrayBuffer) {
4+
skipTest();
5+
}
6+
7+
// Verify SharedArrayBuffer-backed typed arrays can be created through
8+
// napi_create_typedarray, while preserving the existing ArrayBuffer behavior.
9+
const addon = loadAddon('test_typedarray_sharedarraybuffer');
10+
11+
// Float16Array is an ES2025 addition, not exposed by default in older V8
12+
// versions. See the longer note in test.js.
13+
const hasFloat16Array = typeof Float16Array !== 'undefined';
14+
15+
const typedArrayCases = [
16+
{ type: Int8Array, values: [-1, 0, 127] },
17+
{ type: Uint8Array, values: [1, 2, 255] },
18+
{ type: Uint8ClampedArray, values: [0, 128, 255] },
19+
{ type: Int16Array, values: [-1, 0, 32767] },
20+
{ type: Uint16Array, values: [1, 2, 65535] },
21+
{ type: Int32Array, values: [-1, 0, 123456789] },
22+
{ type: Uint32Array, values: [1, 2, 4294967295] },
23+
...(hasFloat16Array ? [{ type: Float16Array, values: [0.5, -1.5, 42.25] }] : []),
24+
{ type: Float32Array, values: [0.5, -1.5, 42.25] },
25+
{ type: Float64Array, values: [0.5, -1.5, 42.25] },
26+
{ type: BigInt64Array, values: [1n, -2n, 123456789n] },
27+
{ type: BigUint64Array, values: [1n, 2n, 123456789n] },
28+
];
29+
30+
function createBuffer(Type, BufferType, length) {
31+
const byteOffset = Type.BYTES_PER_ELEMENT;
32+
const byteLength = byteOffset + (length * Type.BYTES_PER_ELEMENT);
33+
return {
34+
buffer: new BufferType(byteLength),
35+
byteOffset,
36+
};
37+
}
38+
39+
function verifyTypedArray(Type, buffer, byteOffset, values) {
40+
const template = new Type(buffer, byteOffset, values.length);
41+
const theArray = addon.CreateTypedArray(template, buffer);
42+
const theArrayBuffer = addon.GetArrayBuffer(theArray);
43+
44+
assert.ok(theArray instanceof Type);
45+
assert.strictEqual(theArray.buffer, buffer);
46+
assert.strictEqual(theArrayBuffer, buffer);
47+
assert.strictEqual(theArray.byteOffset, byteOffset);
48+
assert.strictEqual(theArray.length, values.length);
49+
50+
theArray.set(values);
51+
assert.deepStrictEqual(
52+
Array.from(new Type(buffer, byteOffset, values.length)),
53+
values,
54+
);
55+
}
56+
57+
// Keep the existing ArrayBuffer behavior covered while focusing this test
58+
// on SharedArrayBuffer-backed TypedArray creation.
59+
{
60+
const { buffer, byteOffset } = createBuffer(Uint8Array, ArrayBuffer, 3);
61+
verifyTypedArray(Uint8Array, buffer, byteOffset, [1, 2, 3]);
62+
}
63+
64+
// Verify all TypedArray variants can be created from a SharedArrayBuffer.
65+
for (const { type, values } of typedArrayCases) {
66+
const { buffer, byteOffset } = createBuffer(
67+
type,
68+
SharedArrayBuffer,
69+
values.length,
70+
);
71+
verifyTypedArray(type, buffer, byteOffset, values);
72+
}
73+
74+
// Test for creating TypedArrays with SharedArrayBuffer and invalid range.
75+
for (const { type, values } of typedArrayCases) {
76+
const { buffer, byteOffset } = createBuffer(
77+
type,
78+
SharedArrayBuffer,
79+
values.length,
80+
);
81+
const template = new type(buffer, byteOffset, values.length);
82+
83+
assert.throws(() => {
84+
addon.CreateTypedArray(template, buffer, values.length + 1, byteOffset);
85+
}, RangeError);
86+
}
87+
88+
// Test for creating TypedArrays with SharedArrayBuffer and invalid alignment.
89+
for (const { type, values } of typedArrayCases) {
90+
if (type.BYTES_PER_ELEMENT <= 1) {
91+
continue;
92+
}
93+
94+
const { buffer, byteOffset } = createBuffer(
95+
type,
96+
SharedArrayBuffer,
97+
values.length,
98+
);
99+
const template = new type(buffer, byteOffset, values.length);
100+
101+
assert.throws(() => {
102+
addon.CreateTypedArray(template, buffer, 1, byteOffset + 1);
103+
}, RangeError);
104+
}
105+
106+
// Test invalid arguments.
107+
{
108+
const template = new Uint8Array(1);
109+
110+
assert.throws(() => {
111+
addon.CreateTypedArray(template, {});
112+
}, { name: 'Error', message: 'Invalid argument' });
113+
114+
assert.throws(() => {
115+
addon.CreateTypedArray(template, 1);
116+
}, { name: 'Error', message: 'Invalid argument' });
117+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// Verify napi_create_typedarray() accepts SharedArrayBuffer-backed views
2+
// without changing its existing error handling.
3+
4+
#include <js_native_api.h>
5+
#include "../common.h"
6+
#include "../entry_point.h"
7+
8+
static napi_value CreateTypedArray(napi_env env, napi_callback_info info) {
9+
size_t argc = 4;
10+
napi_value args[4];
11+
NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL));
12+
13+
NODE_API_ASSERT(env, argc == 2 || argc == 4, "Wrong number of arguments");
14+
15+
bool is_typedarray;
16+
NODE_API_CALL(env, napi_is_typedarray(env, args[0], &is_typedarray));
17+
NODE_API_ASSERT(env,
18+
is_typedarray,
19+
"Wrong type of arguments. Expects a typed array as first "
20+
"argument.");
21+
22+
napi_typedarray_type type;
23+
size_t length;
24+
size_t byte_offset;
25+
NODE_API_CALL(env,
26+
napi_get_typedarray_info(
27+
env, args[0], &type, &length, NULL, NULL, &byte_offset));
28+
29+
if (argc == 4) {
30+
uint32_t uint32_length;
31+
NODE_API_CALL(env, napi_get_value_uint32(env, args[2], &uint32_length));
32+
length = uint32_length;
33+
34+
uint32_t uint32_byte_offset;
35+
NODE_API_CALL(env,
36+
napi_get_value_uint32(env, args[3], &uint32_byte_offset));
37+
byte_offset = uint32_byte_offset;
38+
}
39+
40+
napi_value typedarray;
41+
NODE_API_CALL(env,
42+
napi_create_typedarray(
43+
env, type, length, args[1], byte_offset, &typedarray));
44+
45+
return typedarray;
46+
}
47+
48+
static napi_value GetArrayBuffer(napi_env env, napi_callback_info info) {
49+
size_t argc = 1;
50+
napi_value args[1];
51+
NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL));
52+
53+
NODE_API_ASSERT(env, argc == 1, "Wrong number of arguments");
54+
55+
napi_value arraybuffer;
56+
NODE_API_CALL(env,
57+
napi_get_typedarray_info(
58+
env, args[0], NULL, NULL, NULL, &arraybuffer, NULL));
59+
60+
return arraybuffer;
61+
}
62+
63+
EXTERN_C_START
64+
napi_value Init(napi_env env, napi_value exports) {
65+
napi_property_descriptor descriptors[] = {
66+
DECLARE_NODE_API_PROPERTY("CreateTypedArray", CreateTypedArray),
67+
DECLARE_NODE_API_PROPERTY("GetArrayBuffer", GetArrayBuffer),
68+
};
69+
70+
NODE_API_CALL(
71+
env,
72+
napi_define_properties(env,
73+
exports,
74+
sizeof(descriptors) / sizeof(*descriptors),
75+
descriptors));
76+
77+
return exports;
78+
}
79+
EXTERN_C_END

0 commit comments

Comments
 (0)