Skip to content

Commit 91f158e

Browse files
authored
Merge branch 'main' into eslint
2 parents b2c34f9 + d4adad0 commit 91f158e

File tree

4 files changed

+386
-1
lines changed

4 files changed

+386
-1
lines changed

PORTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ Tests covering the engine-specific part of Node-API, defined in `js_native_api.h
7171
| `test_sharedarraybuffer` | Not ported | Medium |
7272
| `test_string` | Not ported | Medium |
7373
| `test_symbol` | Ported ✅ | Easy |
74-
| `test_typedarray` | Not ported | Medium |
74+
| `test_typedarray` | Ported ✅ | Medium |
7575

7676
## Runtime-specific (`node-api`)
7777

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
add_node_api_cts_addon(test_typedarray test_typedarray.c)
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
"use strict";
2+
3+
// Testing api calls for arrays
4+
const test_typedarray = loadAddon("test_typedarray");
5+
6+
const byteArray = new Uint8Array(3);
7+
byteArray[0] = 0;
8+
byteArray[1] = 1;
9+
byteArray[2] = 2;
10+
assert.strictEqual(byteArray.length, 3);
11+
12+
const doubleArray = new Float64Array(3);
13+
doubleArray[0] = 0.0;
14+
doubleArray[1] = 1.1;
15+
doubleArray[2] = 2.2;
16+
assert.strictEqual(doubleArray.length, 3);
17+
18+
const byteResult = test_typedarray.Multiply(byteArray, 3);
19+
assert.ok(byteResult instanceof Uint8Array);
20+
assert.strictEqual(byteResult.length, 3);
21+
assert.strictEqual(byteResult[0], 0);
22+
assert.strictEqual(byteResult[1], 3);
23+
assert.strictEqual(byteResult[2], 6);
24+
25+
const doubleResult = test_typedarray.Multiply(doubleArray, -3);
26+
assert.ok(doubleResult instanceof Float64Array);
27+
assert.strictEqual(doubleResult.length, 3);
28+
assert.strictEqual(doubleResult[0], -0);
29+
assert.strictEqual(Math.round(10 * doubleResult[1]) / 10, -3.3);
30+
assert.strictEqual(Math.round(10 * doubleResult[2]) / 10, -6.6);
31+
32+
const externalResult = test_typedarray.External();
33+
assert.ok(externalResult instanceof Int8Array);
34+
assert.strictEqual(externalResult.length, 3);
35+
assert.strictEqual(externalResult[0], 0);
36+
assert.strictEqual(externalResult[1], 1);
37+
assert.strictEqual(externalResult[2], 2);
38+
39+
// Float16Array is an ES2025 addition; not exposed by default in older V8
40+
// versions (e.g. those shipped with Node 20.x / 22.x). Detect at runtime and
41+
// only exercise the Float16Array code paths when the engine supports it.
42+
const hasFloat16Array = typeof Float16Array !== "undefined";
43+
44+
// Validate creation of all kinds of TypedArrays
45+
const buffer = new ArrayBuffer(128);
46+
const arrayTypes = [
47+
Int8Array,
48+
Uint8Array,
49+
Uint8ClampedArray,
50+
Int16Array,
51+
Uint16Array,
52+
Int32Array,
53+
Uint32Array,
54+
...(hasFloat16Array ? [Float16Array] : []),
55+
Float32Array,
56+
Float64Array,
57+
BigInt64Array,
58+
BigUint64Array,
59+
];
60+
61+
arrayTypes.forEach((currentType) => {
62+
const template = Reflect.construct(currentType, buffer);
63+
const theArray = test_typedarray.CreateTypedArray(template, buffer);
64+
65+
assert.ok(
66+
theArray instanceof currentType,
67+
"Type of new array should match that of the template. " +
68+
`Expected type: ${currentType.name}, ` +
69+
`actual type: ${template.constructor.name}`,
70+
);
71+
assert.notStrictEqual(theArray, template);
72+
assert.strictEqual(theArray.buffer, buffer);
73+
});
74+
75+
arrayTypes.forEach((currentType) => {
76+
const template = Reflect.construct(currentType, buffer);
77+
assert.throws(() => {
78+
test_typedarray.CreateTypedArray(template, buffer, 0, 136);
79+
}, RangeError);
80+
});
81+
82+
const nonByteArrayTypes = [
83+
Int16Array,
84+
Uint16Array,
85+
Int32Array,
86+
Uint32Array,
87+
...(hasFloat16Array ? [Float16Array] : []),
88+
Float32Array,
89+
Float64Array,
90+
BigInt64Array,
91+
BigUint64Array,
92+
];
93+
nonByteArrayTypes.forEach((currentType) => {
94+
const template = Reflect.construct(currentType, buffer);
95+
assert.throws(() => {
96+
test_typedarray.CreateTypedArray(
97+
template,
98+
buffer,
99+
currentType.BYTES_PER_ELEMENT + 1,
100+
1,
101+
);
102+
}, RangeError);
103+
});
104+
105+
// Test detaching
106+
arrayTypes.forEach((currentType) => {
107+
const buffer = Reflect.construct(currentType, [8]);
108+
assert.strictEqual(buffer.length, 8);
109+
assert.ok(!test_typedarray.IsDetached(buffer.buffer));
110+
test_typedarray.Detach(buffer);
111+
assert.ok(test_typedarray.IsDetached(buffer.buffer));
112+
assert.strictEqual(buffer.length, 0);
113+
});
114+
{
115+
const buffer = test_typedarray.External();
116+
assert.ok(externalResult instanceof Int8Array);
117+
assert.strictEqual(externalResult.length, 3);
118+
assert.strictEqual(externalResult.byteLength, 3);
119+
assert.ok(!test_typedarray.IsDetached(buffer.buffer));
120+
test_typedarray.Detach(buffer);
121+
assert.ok(test_typedarray.IsDetached(buffer.buffer));
122+
assert.ok(externalResult instanceof Int8Array);
123+
assert.strictEqual(buffer.length, 0);
124+
assert.strictEqual(buffer.byteLength, 0);
125+
}
126+
127+
{
128+
const buffer = new ArrayBuffer(128);
129+
assert.ok(!test_typedarray.IsDetached(buffer));
130+
}
131+
132+
{
133+
const buffer = test_typedarray.NullArrayBuffer();
134+
assert.ok(buffer instanceof ArrayBuffer);
135+
assert.ok(test_typedarray.IsDetached(buffer));
136+
}
Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
1+
#include <js_native_api.h>
2+
#include <stdlib.h>
3+
#include <string.h>
4+
#include "../common.h"
5+
#include "../entry_point.h"
6+
7+
static napi_value Multiply(napi_env env, napi_callback_info info) {
8+
size_t argc = 2;
9+
napi_value args[2];
10+
NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL));
11+
12+
NODE_API_ASSERT(env, argc == 2, "Wrong number of arguments");
13+
14+
napi_valuetype valuetype0;
15+
NODE_API_CALL(env, napi_typeof(env, args[0], &valuetype0));
16+
17+
NODE_API_ASSERT(env, valuetype0 == napi_object,
18+
"Wrong type of arguments. Expects a typed array as first argument.");
19+
20+
napi_value input_array = args[0];
21+
bool is_typedarray;
22+
NODE_API_CALL(env, napi_is_typedarray(env, input_array, &is_typedarray));
23+
24+
NODE_API_ASSERT(env, is_typedarray,
25+
"Wrong type of arguments. Expects a typed array as first argument.");
26+
27+
napi_valuetype valuetype1;
28+
NODE_API_CALL(env, napi_typeof(env, args[1], &valuetype1));
29+
30+
NODE_API_ASSERT(env, valuetype1 == napi_number,
31+
"Wrong type of arguments. Expects a number as second argument.");
32+
33+
double multiplier;
34+
NODE_API_CALL(env, napi_get_value_double(env, args[1], &multiplier));
35+
36+
napi_typedarray_type type;
37+
napi_value input_buffer;
38+
size_t byte_offset;
39+
size_t i, length;
40+
NODE_API_CALL(env, napi_get_typedarray_info(
41+
env, input_array, &type, &length, NULL, &input_buffer, &byte_offset));
42+
43+
void* data;
44+
size_t byte_length;
45+
NODE_API_CALL(env, napi_get_arraybuffer_info(
46+
env, input_buffer, &data, &byte_length));
47+
48+
napi_value output_buffer;
49+
void* output_ptr = NULL;
50+
NODE_API_CALL(env, napi_create_arraybuffer(
51+
env, byte_length, &output_ptr, &output_buffer));
52+
53+
napi_value output_array;
54+
NODE_API_CALL(env, napi_create_typedarray(
55+
env, type, length, output_buffer, byte_offset, &output_array));
56+
57+
if (type == napi_uint8_array) {
58+
uint8_t* input_bytes = (uint8_t*)(data) + byte_offset;
59+
uint8_t* output_bytes = (uint8_t*)(output_ptr);
60+
for (i = 0; i < length; i++) {
61+
output_bytes[i] = (uint8_t)(input_bytes[i] * multiplier);
62+
}
63+
} else if (type == napi_float64_array) {
64+
double* input_doubles = (double*)((uint8_t*)(data) + byte_offset);
65+
double* output_doubles = (double*)(output_ptr);
66+
for (i = 0; i < length; i++) {
67+
output_doubles[i] = input_doubles[i] * multiplier;
68+
}
69+
} else {
70+
napi_throw_error(env, NULL,
71+
"Typed array was of a type not expected by test.");
72+
return NULL;
73+
}
74+
75+
return output_array;
76+
}
77+
78+
static void FinalizeCallback(node_api_basic_env env,
79+
void* finalize_data,
80+
void* finalize_hint) {
81+
free(finalize_data);
82+
}
83+
84+
static napi_value External(napi_env env, napi_callback_info info) {
85+
const uint8_t nElem = 3;
86+
int8_t* externalData = malloc(nElem*sizeof(int8_t));
87+
externalData[0] = 0;
88+
externalData[1] = 1;
89+
externalData[2] = 2;
90+
91+
napi_value output_buffer;
92+
NODE_API_CALL(env, napi_create_external_arraybuffer(
93+
env,
94+
externalData,
95+
nElem*sizeof(int8_t),
96+
FinalizeCallback,
97+
NULL, // finalize_hint
98+
&output_buffer));
99+
100+
napi_value output_array;
101+
NODE_API_CALL(env, napi_create_typedarray(env,
102+
napi_int8_array,
103+
nElem,
104+
output_buffer,
105+
0,
106+
&output_array));
107+
108+
return output_array;
109+
}
110+
111+
112+
static napi_value NullArrayBuffer(napi_env env, napi_callback_info info) {
113+
static void* data = NULL;
114+
napi_value arraybuffer;
115+
NODE_API_CALL(env,
116+
napi_create_external_arraybuffer(env, data, 0, NULL, NULL, &arraybuffer));
117+
return arraybuffer;
118+
}
119+
120+
static napi_value CreateTypedArray(napi_env env, napi_callback_info info) {
121+
size_t argc = 4;
122+
napi_value args[4];
123+
NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL));
124+
125+
NODE_API_ASSERT(env, argc == 2 || argc == 4, "Wrong number of arguments");
126+
127+
napi_value input_array = args[0];
128+
napi_valuetype valuetype0;
129+
NODE_API_CALL(env, napi_typeof(env, input_array, &valuetype0));
130+
131+
NODE_API_ASSERT(env, valuetype0 == napi_object,
132+
"Wrong type of arguments. Expects a typed array as first argument.");
133+
134+
bool is_typedarray;
135+
NODE_API_CALL(env, napi_is_typedarray(env, input_array, &is_typedarray));
136+
137+
NODE_API_ASSERT(env, is_typedarray,
138+
"Wrong type of arguments. Expects a typed array as first argument.");
139+
140+
napi_valuetype valuetype1;
141+
napi_value input_buffer = args[1];
142+
NODE_API_CALL(env, napi_typeof(env, input_buffer, &valuetype1));
143+
144+
NODE_API_ASSERT(env, valuetype1 == napi_object,
145+
"Wrong type of arguments. Expects an array buffer as second argument.");
146+
147+
bool is_arraybuffer;
148+
NODE_API_CALL(env, napi_is_arraybuffer(env, input_buffer, &is_arraybuffer));
149+
150+
NODE_API_ASSERT(env, is_arraybuffer,
151+
"Wrong type of arguments. Expects an array buffer as second argument.");
152+
153+
napi_typedarray_type type;
154+
napi_value in_array_buffer;
155+
size_t byte_offset;
156+
size_t length;
157+
NODE_API_CALL(env, napi_get_typedarray_info(
158+
env, input_array, &type, &length, NULL, &in_array_buffer, &byte_offset));
159+
160+
if (argc == 4) {
161+
napi_valuetype valuetype2;
162+
NODE_API_CALL(env, napi_typeof(env, args[2], &valuetype2));
163+
164+
NODE_API_ASSERT(env, valuetype2 == napi_number,
165+
"Wrong type of arguments. Expects a number as third argument.");
166+
167+
uint32_t uint32_length;
168+
NODE_API_CALL(env, napi_get_value_uint32(env, args[2], &uint32_length));
169+
length = uint32_length;
170+
171+
napi_valuetype valuetype3;
172+
NODE_API_CALL(env, napi_typeof(env, args[3], &valuetype3));
173+
174+
NODE_API_ASSERT(env, valuetype3 == napi_number,
175+
"Wrong type of arguments. Expects a number as third argument.");
176+
177+
uint32_t uint32_byte_offset;
178+
NODE_API_CALL(env, napi_get_value_uint32(env, args[3], &uint32_byte_offset));
179+
byte_offset = uint32_byte_offset;
180+
}
181+
182+
napi_value output_array;
183+
NODE_API_CALL(env, napi_create_typedarray(
184+
env, type, length, input_buffer, byte_offset, &output_array));
185+
186+
return output_array;
187+
}
188+
189+
static napi_value Detach(napi_env env, napi_callback_info info) {
190+
size_t argc = 1;
191+
napi_value args[1];
192+
NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL));
193+
NODE_API_ASSERT(env, argc == 1, "Wrong number of arguments.");
194+
195+
bool is_typedarray;
196+
NODE_API_CALL(env, napi_is_typedarray(env, args[0], &is_typedarray));
197+
NODE_API_ASSERT(
198+
env, is_typedarray,
199+
"Wrong type of arguments. Expects a typedarray as first argument.");
200+
201+
napi_value arraybuffer;
202+
NODE_API_CALL(env,
203+
napi_get_typedarray_info(
204+
env, args[0], NULL, NULL, NULL, &arraybuffer, NULL));
205+
NODE_API_CALL(env, napi_detach_arraybuffer(env, arraybuffer));
206+
207+
return NULL;
208+
}
209+
210+
static napi_value IsDetached(napi_env env, napi_callback_info info) {
211+
size_t argc = 1;
212+
napi_value args[1];
213+
NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL));
214+
NODE_API_ASSERT(env, argc == 1, "Wrong number of arguments.");
215+
216+
napi_value array_buffer = args[0];
217+
bool is_arraybuffer;
218+
NODE_API_CALL(env, napi_is_arraybuffer(env, array_buffer, &is_arraybuffer));
219+
NODE_API_ASSERT(env, is_arraybuffer,
220+
"Wrong type of arguments. Expects an array buffer as first argument.");
221+
222+
bool is_detached;
223+
NODE_API_CALL(env,
224+
napi_is_detached_arraybuffer(env, array_buffer, &is_detached));
225+
226+
napi_value result;
227+
NODE_API_CALL(env, napi_get_boolean(env, is_detached, &result));
228+
229+
return result;
230+
}
231+
232+
EXTERN_C_START
233+
napi_value Init(napi_env env, napi_value exports) {
234+
napi_property_descriptor descriptors[] = {
235+
DECLARE_NODE_API_PROPERTY("Multiply", Multiply),
236+
DECLARE_NODE_API_PROPERTY("External", External),
237+
DECLARE_NODE_API_PROPERTY("NullArrayBuffer", NullArrayBuffer),
238+
DECLARE_NODE_API_PROPERTY("CreateTypedArray", CreateTypedArray),
239+
DECLARE_NODE_API_PROPERTY("Detach", Detach),
240+
DECLARE_NODE_API_PROPERTY("IsDetached", IsDetached),
241+
};
242+
243+
NODE_API_CALL(env, napi_define_properties(
244+
env, exports, sizeof(descriptors) / sizeof(*descriptors), descriptors));
245+
246+
return exports;
247+
}
248+
EXTERN_C_END

0 commit comments

Comments
 (0)