Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion PORTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ Tests covering the engine-specific part of Node-API, defined in `js_native_api.h
| `test_sharedarraybuffer` | Not ported | Medium |
| `test_string` | Not ported | Medium |
| `test_symbol` | Ported ✅ | Easy |
| `test_typedarray` | Not ported | Medium |
| `test_typedarray` | Ported ✅ | Medium |

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

Expand Down
1 change: 1 addition & 0 deletions tests/js-native-api/test_typedarray/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
add_node_api_cts_addon(test_typedarray test_typedarray.c)
132 changes: 132 additions & 0 deletions tests/js-native-api/test_typedarray/test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
"use strict";

// Testing api calls for arrays
const test_typedarray = loadAddon("test_typedarray");

const byteArray = new Uint8Array(3);
byteArray[0] = 0;
byteArray[1] = 1;
byteArray[2] = 2;
assert.strictEqual(byteArray.length, 3);

const doubleArray = new Float64Array(3);
doubleArray[0] = 0.0;
doubleArray[1] = 1.1;
doubleArray[2] = 2.2;
assert.strictEqual(doubleArray.length, 3);

const byteResult = test_typedarray.Multiply(byteArray, 3);
assert.ok(byteResult instanceof Uint8Array);
assert.strictEqual(byteResult.length, 3);
assert.strictEqual(byteResult[0], 0);
assert.strictEqual(byteResult[1], 3);
assert.strictEqual(byteResult[2], 6);

const doubleResult = test_typedarray.Multiply(doubleArray, -3);
assert.ok(doubleResult instanceof Float64Array);
assert.strictEqual(doubleResult.length, 3);
assert.strictEqual(doubleResult[0], -0);
assert.strictEqual(Math.round(10 * doubleResult[1]) / 10, -3.3);
assert.strictEqual(Math.round(10 * doubleResult[2]) / 10, -6.6);

const externalResult = test_typedarray.External();
assert.ok(externalResult instanceof Int8Array);
assert.strictEqual(externalResult.length, 3);
assert.strictEqual(externalResult[0], 0);
assert.strictEqual(externalResult[1], 1);
assert.strictEqual(externalResult[2], 2);

// Validate creation of all kinds of TypedArrays
const buffer = new ArrayBuffer(128);
const arrayTypes = [
Int8Array,
Uint8Array,
Uint8ClampedArray,
Int16Array,
Uint16Array,
Int32Array,
Uint32Array,
Float16Array,
Float32Array,
Float64Array,
BigInt64Array,
BigUint64Array,
];

arrayTypes.forEach((currentType) => {
const template = Reflect.construct(currentType, buffer);
const theArray = test_typedarray.CreateTypedArray(template, buffer);

assert.ok(
theArray instanceof currentType,
"Type of new array should match that of the template. " +
`Expected type: ${currentType.name}, ` +
`actual type: ${template.constructor.name}`,
);
assert.notStrictEqual(theArray, template);
assert.strictEqual(theArray.buffer, buffer);
});

arrayTypes.forEach((currentType) => {
const template = Reflect.construct(currentType, buffer);
assert.throws(() => {
test_typedarray.CreateTypedArray(template, buffer, 0, 136);
}, RangeError);
});

const nonByteArrayTypes = [
Int16Array,
Uint16Array,
Int32Array,
Uint32Array,
Float16Array,
Float32Array,
Float64Array,
BigInt64Array,
BigUint64Array,
];
nonByteArrayTypes.forEach((currentType) => {
const template = Reflect.construct(currentType, buffer);
assert.throws(() => {
test_typedarray.CreateTypedArray(
template,
buffer,
currentType.BYTES_PER_ELEMENT + 1,
1,
);
console.log(`start of offset ${currentType}`);
}, RangeError);
});

// Test detaching
arrayTypes.forEach((currentType) => {
const buffer = Reflect.construct(currentType, [8]);
assert.strictEqual(buffer.length, 8);
assert.ok(!test_typedarray.IsDetached(buffer.buffer));
test_typedarray.Detach(buffer);
assert.ok(test_typedarray.IsDetached(buffer.buffer));
assert.strictEqual(buffer.length, 0);
});
{
const buffer = test_typedarray.External();
assert.ok(externalResult instanceof Int8Array);
assert.strictEqual(externalResult.length, 3);
assert.strictEqual(externalResult.byteLength, 3);
assert.ok(!test_typedarray.IsDetached(buffer.buffer));
test_typedarray.Detach(buffer);
assert.ok(test_typedarray.IsDetached(buffer.buffer));
assert.ok(externalResult instanceof Int8Array);
assert.strictEqual(buffer.length, 0);
assert.strictEqual(buffer.byteLength, 0);
}

{
const buffer = new ArrayBuffer(128);
assert.ok(!test_typedarray.IsDetached(buffer));
}

{
const buffer = test_typedarray.NullArrayBuffer();
assert.ok(buffer instanceof ArrayBuffer);
assert.ok(test_typedarray.IsDetached(buffer));
}
248 changes: 248 additions & 0 deletions tests/js-native-api/test_typedarray/test_typedarray.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,248 @@
#include <js_native_api.h>
#include <stdlib.h>
#include <string.h>
#include "../common.h"
#include "../entry_point.h"

static napi_value Multiply(napi_env env, napi_callback_info info) {
size_t argc = 2;
napi_value args[2];
NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL));

NODE_API_ASSERT(env, argc == 2, "Wrong number of arguments");

napi_valuetype valuetype0;
NODE_API_CALL(env, napi_typeof(env, args[0], &valuetype0));

NODE_API_ASSERT(env, valuetype0 == napi_object,
"Wrong type of arguments. Expects a typed array as first argument.");

napi_value input_array = args[0];
bool is_typedarray;
NODE_API_CALL(env, napi_is_typedarray(env, input_array, &is_typedarray));

NODE_API_ASSERT(env, is_typedarray,
"Wrong type of arguments. Expects a typed array as 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.");

double multiplier;
NODE_API_CALL(env, napi_get_value_double(env, args[1], &multiplier));

napi_typedarray_type type;
napi_value input_buffer;
size_t byte_offset;
size_t i, length;
NODE_API_CALL(env, napi_get_typedarray_info(
env, input_array, &type, &length, NULL, &input_buffer, &byte_offset));

void* data;
size_t byte_length;
NODE_API_CALL(env, napi_get_arraybuffer_info(
env, input_buffer, &data, &byte_length));

napi_value output_buffer;
void* output_ptr = NULL;
NODE_API_CALL(env, napi_create_arraybuffer(
env, byte_length, &output_ptr, &output_buffer));

napi_value output_array;
NODE_API_CALL(env, napi_create_typedarray(
env, type, length, output_buffer, byte_offset, &output_array));

if (type == napi_uint8_array) {
uint8_t* input_bytes = (uint8_t*)(data) + byte_offset;
uint8_t* output_bytes = (uint8_t*)(output_ptr);
for (i = 0; i < length; i++) {
output_bytes[i] = (uint8_t)(input_bytes[i] * multiplier);
}
} else if (type == napi_float64_array) {
double* input_doubles = (double*)((uint8_t*)(data) + byte_offset);
double* output_doubles = (double*)(output_ptr);
for (i = 0; i < length; i++) {
output_doubles[i] = input_doubles[i] * multiplier;
}
} else {
napi_throw_error(env, NULL,
"Typed array was of a type not expected by test.");
return NULL;
}

return output_array;
}

static void FinalizeCallback(node_api_basic_env env,
void* finalize_data,
void* finalize_hint) {
free(finalize_data);
}

static napi_value External(napi_env env, napi_callback_info info) {
const uint8_t nElem = 3;
int8_t* externalData = malloc(nElem*sizeof(int8_t));
externalData[0] = 0;
externalData[1] = 1;
externalData[2] = 2;

napi_value output_buffer;
NODE_API_CALL(env, napi_create_external_arraybuffer(
env,
externalData,
nElem*sizeof(int8_t),
FinalizeCallback,
NULL, // finalize_hint
&output_buffer));

napi_value output_array;
NODE_API_CALL(env, napi_create_typedarray(env,
napi_int8_array,
nElem,
output_buffer,
0,
&output_array));

return output_array;
}


static napi_value NullArrayBuffer(napi_env env, napi_callback_info info) {
static void* data = NULL;
napi_value arraybuffer;
NODE_API_CALL(env,
napi_create_external_arraybuffer(env, data, 0, NULL, NULL, &arraybuffer));
return arraybuffer;
}

static napi_value CreateTypedArray(napi_env env, napi_callback_info info) {
size_t argc = 4;
napi_value args[4];
NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL));

NODE_API_ASSERT(env, argc == 2 || argc == 4, "Wrong number of arguments");

napi_value input_array = args[0];
napi_valuetype valuetype0;
NODE_API_CALL(env, napi_typeof(env, input_array, &valuetype0));

NODE_API_ASSERT(env, valuetype0 == napi_object,
"Wrong type of arguments. Expects a typed array as first argument.");

bool is_typedarray;
NODE_API_CALL(env, napi_is_typedarray(env, input_array, &is_typedarray));

NODE_API_ASSERT(env, is_typedarray,
"Wrong type of arguments. Expects a typed array as first argument.");

napi_valuetype valuetype1;
napi_value input_buffer = args[1];
NODE_API_CALL(env, napi_typeof(env, input_buffer, &valuetype1));

NODE_API_ASSERT(env, valuetype1 == napi_object,
"Wrong type of arguments. Expects an array buffer as second argument.");

bool is_arraybuffer;
NODE_API_CALL(env, napi_is_arraybuffer(env, input_buffer, &is_arraybuffer));

NODE_API_ASSERT(env, is_arraybuffer,
"Wrong type of arguments. Expects an array buffer as second argument.");

napi_typedarray_type type;
napi_value in_array_buffer;
size_t byte_offset;
size_t length;
NODE_API_CALL(env, napi_get_typedarray_info(
env, input_array, &type, &length, NULL, &in_array_buffer, &byte_offset));

if (argc == 4) {
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.");

uint32_t uint32_length;
NODE_API_CALL(env, napi_get_value_uint32(env, args[2], &uint32_length));
length = uint32_length;

napi_valuetype valuetype3;
NODE_API_CALL(env, napi_typeof(env, args[3], &valuetype3));

NODE_API_ASSERT(env, valuetype3 == napi_number,
"Wrong type of arguments. Expects a number as third argument.");

uint32_t uint32_byte_offset;
NODE_API_CALL(env, napi_get_value_uint32(env, args[3], &uint32_byte_offset));
byte_offset = uint32_byte_offset;
}

napi_value output_array;
NODE_API_CALL(env, napi_create_typedarray(
env, type, length, input_buffer, byte_offset, &output_array));

return output_array;
}

static napi_value Detach(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.");

bool is_typedarray;
NODE_API_CALL(env, napi_is_typedarray(env, args[0], &is_typedarray));
NODE_API_ASSERT(
env, is_typedarray,
"Wrong type of arguments. Expects a typedarray as first argument.");

napi_value arraybuffer;
NODE_API_CALL(env,
napi_get_typedarray_info(
env, args[0], NULL, NULL, NULL, &arraybuffer, NULL));
NODE_API_CALL(env, napi_detach_arraybuffer(env, arraybuffer));

return NULL;
}

static napi_value IsDetached(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_value array_buffer = args[0];
bool is_arraybuffer;
NODE_API_CALL(env, napi_is_arraybuffer(env, array_buffer, &is_arraybuffer));
NODE_API_ASSERT(env, is_arraybuffer,
"Wrong type of arguments. Expects an array buffer as first argument.");

bool is_detached;
NODE_API_CALL(env,
napi_is_detached_arraybuffer(env, array_buffer, &is_detached));

napi_value result;
NODE_API_CALL(env, napi_get_boolean(env, is_detached, &result));

return result;
}

EXTERN_C_START
napi_value Init(napi_env env, napi_value exports) {
napi_property_descriptor descriptors[] = {
DECLARE_NODE_API_PROPERTY("Multiply", Multiply),
DECLARE_NODE_API_PROPERTY("External", External),
DECLARE_NODE_API_PROPERTY("NullArrayBuffer", NullArrayBuffer),
DECLARE_NODE_API_PROPERTY("CreateTypedArray", CreateTypedArray),
DECLARE_NODE_API_PROPERTY("Detach", Detach),
DECLARE_NODE_API_PROPERTY("IsDetached", IsDetached),
};

NODE_API_CALL(env, napi_define_properties(
env, exports, sizeof(descriptors) / sizeof(*descriptors), descriptors));

return exports;
}
EXTERN_C_END