Upload Kmake

This commit is contained in:
Gorochu
2026-05-26 23:36:42 -07:00
parent ba051b2f74
commit 555ec72358
41615 changed files with 13344630 additions and 1 deletions

View File

@ -0,0 +1,347 @@
// For the purpose of this test we use libuv's threading library. When deciding
// on a threading library for a new project it bears remembering that in the
// future libuv may introduce API changes which may render it non-ABI-stable,
// which, in turn, may affect the ABI stability of the project despite its use
// of N-API.
#include <uv.h>
#include <node_api.h>
#include "../../js-native-api/common.h"
#define ARRAY_LENGTH 10000
#define MAX_QUEUE_SIZE 2
static uv_thread_t uv_threads[2];
static napi_threadsafe_function ts_fn;
typedef struct {
napi_threadsafe_function_call_mode block_on_full;
napi_threadsafe_function_release_mode abort;
bool start_secondary;
napi_ref js_finalize_cb;
uint32_t max_queue_size;
} ts_fn_hint;
static ts_fn_hint ts_info;
// Thread data to transmit to JS
static int ints[ARRAY_LENGTH];
static void secondary_thread(void* data) {
napi_threadsafe_function ts_fn = data;
if (napi_release_threadsafe_function(ts_fn, napi_tsfn_release) != napi_ok) {
napi_fatal_error("secondary_thread", NAPI_AUTO_LENGTH,
"napi_release_threadsafe_function failed", NAPI_AUTO_LENGTH);
}
}
// Source thread producing the data
static void data_source_thread(void* data) {
napi_threadsafe_function ts_fn = data;
int index;
void* hint;
ts_fn_hint *ts_fn_info;
napi_status status;
bool queue_was_full = false;
bool queue_was_closing = false;
if (napi_get_threadsafe_function_context(ts_fn, &hint) != napi_ok) {
napi_fatal_error("data_source_thread", NAPI_AUTO_LENGTH,
"napi_get_threadsafe_function_context failed", NAPI_AUTO_LENGTH);
}
ts_fn_info = (ts_fn_hint *)hint;
if (ts_fn_info != &ts_info) {
napi_fatal_error("data_source_thread", NAPI_AUTO_LENGTH,
"thread-safe function hint is not as expected", NAPI_AUTO_LENGTH);
}
if (ts_fn_info->start_secondary) {
if (napi_acquire_threadsafe_function(ts_fn) != napi_ok) {
napi_fatal_error("data_source_thread", NAPI_AUTO_LENGTH,
"napi_acquire_threadsafe_function failed", NAPI_AUTO_LENGTH);
}
if (uv_thread_create(&uv_threads[1], secondary_thread, ts_fn) != 0) {
napi_fatal_error("data_source_thread", NAPI_AUTO_LENGTH,
"failed to start secondary thread", NAPI_AUTO_LENGTH);
}
}
for (index = ARRAY_LENGTH - 1; index > -1 && !queue_was_closing; index--) {
status = napi_call_threadsafe_function(ts_fn, &ints[index],
ts_fn_info->block_on_full);
if (ts_fn_info->max_queue_size == 0 && (index % 1000 == 0)) {
// Let's make this thread really busy for 200 ms to give the main thread a
// chance to abort.
uint64_t start = uv_hrtime();
for (; uv_hrtime() - start < 200000000;);
}
switch (status) {
case napi_queue_full:
queue_was_full = true;
index++;
// fall through
case napi_ok:
continue;
case napi_closing:
queue_was_closing = true;
break;
default:
napi_fatal_error("data_source_thread", NAPI_AUTO_LENGTH,
"napi_call_threadsafe_function failed", NAPI_AUTO_LENGTH);
}
}
// Assert that the enqueuing of a value was refused at least once, if this is
// a non-blocking test run.
if (!ts_fn_info->block_on_full && !queue_was_full) {
napi_fatal_error("data_source_thread", NAPI_AUTO_LENGTH,
"queue was never full", NAPI_AUTO_LENGTH);
}
// Assert that the queue was marked as closing at least once, if this is an
// aborting test run.
if (ts_fn_info->abort == napi_tsfn_abort && !queue_was_closing) {
napi_fatal_error("data_source_thread", NAPI_AUTO_LENGTH,
"queue was never closing", NAPI_AUTO_LENGTH);
}
if (!queue_was_closing &&
napi_release_threadsafe_function(ts_fn, napi_tsfn_release) != napi_ok) {
napi_fatal_error("data_source_thread", NAPI_AUTO_LENGTH,
"napi_release_threadsafe_function failed", NAPI_AUTO_LENGTH);
}
}
// Getting the data into JS
static void call_js(napi_env env, napi_value cb, void* hint, void* data) {
if (!(env == NULL || cb == NULL)) {
napi_value argv, undefined;
NODE_API_CALL_RETURN_VOID(env, napi_create_int32(env, *(int*)data, &argv));
NODE_API_CALL_RETURN_VOID(env, napi_get_undefined(env, &undefined));
NODE_API_CALL_RETURN_VOID(env, napi_call_function(env, undefined, cb, 1, &argv,
NULL));
}
}
static napi_ref alt_ref;
// Getting the data into JS with the alternative reference
static void call_ref(napi_env env, napi_value _, void* hint, void* data) {
if (!(env == NULL || alt_ref == NULL)) {
napi_value fn, argv, undefined;
NODE_API_CALL_RETURN_VOID(env, napi_get_reference_value(env, alt_ref, &fn));
NODE_API_CALL_RETURN_VOID(env, napi_create_int32(env, *(int*)data, &argv));
NODE_API_CALL_RETURN_VOID(env, napi_get_undefined(env, &undefined));
NODE_API_CALL_RETURN_VOID(env, napi_call_function(env, undefined, fn, 1, &argv,
NULL));
}
}
// Cleanup
static napi_value StopThread(napi_env env, napi_callback_info info) {
size_t argc = 2;
napi_value argv[2];
NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, argv, NULL, NULL));
napi_valuetype value_type;
NODE_API_CALL(env, napi_typeof(env, argv[0], &value_type));
NODE_API_ASSERT(env, value_type == napi_function,
"StopThread argument is a function");
NODE_API_ASSERT(env, (ts_fn != NULL), "Existing threadsafe function");
NODE_API_CALL(env,
napi_create_reference(env, argv[0], 1, &(ts_info.js_finalize_cb)));
bool abort;
NODE_API_CALL(env, napi_get_value_bool(env, argv[1], &abort));
NODE_API_CALL(env,
napi_release_threadsafe_function(ts_fn,
abort ? napi_tsfn_abort : napi_tsfn_release));
ts_fn = NULL;
return NULL;
}
// Join the thread and inform JS that we're done.
static void join_the_threads(napi_env env, void *data, void *hint) {
uv_thread_t *the_threads = data;
ts_fn_hint *the_hint = hint;
napi_value js_cb, undefined;
uv_thread_join(&the_threads[0]);
if (the_hint->start_secondary) {
uv_thread_join(&the_threads[1]);
}
NODE_API_CALL_RETURN_VOID(env,
napi_get_reference_value(env, the_hint->js_finalize_cb, &js_cb));
NODE_API_CALL_RETURN_VOID(env, napi_get_undefined(env, &undefined));
NODE_API_CALL_RETURN_VOID(env,
napi_call_function(env, undefined, js_cb, 0, NULL, NULL));
NODE_API_CALL_RETURN_VOID(env, napi_delete_reference(env,
the_hint->js_finalize_cb));
if (alt_ref != NULL) {
NODE_API_CALL_RETURN_VOID(env, napi_delete_reference(env, alt_ref));
alt_ref = NULL;
}
}
static napi_value StartThreadInternal(napi_env env,
napi_callback_info info,
napi_threadsafe_function_call_js cb,
bool block_on_full,
bool alt_ref_js_cb) {
size_t argc = 4;
napi_value argv[4];
NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, argv, NULL, NULL));
if (alt_ref_js_cb) {
NODE_API_CALL(env, napi_create_reference(env, argv[0], 1, &alt_ref));
argv[0] = NULL;
}
ts_info.block_on_full =
(block_on_full ? napi_tsfn_blocking : napi_tsfn_nonblocking);
NODE_API_ASSERT(env, (ts_fn == NULL), "Existing thread-safe function");
napi_value async_name;
NODE_API_CALL(env, napi_create_string_utf8(env,
"N-API Thread-safe Function Test", NAPI_AUTO_LENGTH, &async_name));
NODE_API_CALL(env,
napi_get_value_uint32(env, argv[3], &ts_info.max_queue_size));
NODE_API_CALL(env, napi_create_threadsafe_function(env,
argv[0],
NULL,
async_name,
ts_info.max_queue_size,
2,
uv_threads,
join_the_threads,
&ts_info,
cb,
&ts_fn));
bool abort;
NODE_API_CALL(env, napi_get_value_bool(env, argv[1], &abort));
ts_info.abort = abort ? napi_tsfn_abort : napi_tsfn_release;
NODE_API_CALL(env,
napi_get_value_bool(env, argv[2], &(ts_info.start_secondary)));
NODE_API_ASSERT(env,
(uv_thread_create(&uv_threads[0], data_source_thread, ts_fn) == 0),
"Thread creation");
return NULL;
}
static napi_value Unref(napi_env env, napi_callback_info info) {
NODE_API_ASSERT(env, ts_fn != NULL, "No existing thread-safe function");
NODE_API_CALL(env, napi_unref_threadsafe_function(env, ts_fn));
return NULL;
}
static napi_value Release(napi_env env, napi_callback_info info) {
NODE_API_ASSERT(env, ts_fn != NULL, "No existing thread-safe function");
NODE_API_CALL(env, napi_release_threadsafe_function(ts_fn, napi_tsfn_release));
return NULL;
}
// Startup
static napi_value StartThread(napi_env env, napi_callback_info info) {
return StartThreadInternal(env, info, call_js,
/** block_on_full */true, /** alt_ref_js_cb */false);
}
static napi_value StartThreadNonblocking(napi_env env,
napi_callback_info info) {
return StartThreadInternal(env, info, call_js,
/** block_on_full */false, /** alt_ref_js_cb */false);
}
static napi_value StartThreadNoNative(napi_env env, napi_callback_info info) {
return StartThreadInternal(env, info, NULL,
/** block_on_full */true, /** alt_ref_js_cb */false);
}
static napi_value StartThreadNoJsFunc(napi_env env, napi_callback_info info) {
return StartThreadInternal(env, info, call_ref,
/** block_on_full */true, /** alt_ref_js_cb */true);
}
// Testing calling into JavaScript
static void ThreadSafeFunctionFinalize(napi_env env,
void* finalize_data,
void* finalize_hint) {
napi_ref js_func_ref = (napi_ref) finalize_data;
napi_value js_func;
napi_value recv;
NODE_API_CALL_RETURN_VOID(env, napi_get_reference_value(env, js_func_ref, &js_func));
NODE_API_CALL_RETURN_VOID(env, napi_get_global(env, &recv));
NODE_API_CALL_RETURN_VOID(env, napi_call_function(env, recv, js_func, 0, NULL, NULL));
NODE_API_CALL_RETURN_VOID(env, napi_delete_reference(env, js_func_ref));
}
// Testing calling into JavaScript
static napi_value CallIntoModule(napi_env env, napi_callback_info info) {
size_t argc = 4;
napi_value argv[4];
NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, argv, NULL, NULL));
napi_ref finalize_func;
NODE_API_CALL(env, napi_create_reference(env, argv[3], 1, &finalize_func));
napi_threadsafe_function tsfn;
NODE_API_CALL(env, napi_create_threadsafe_function(env, argv[0], argv[1], argv[2], 0, 1, finalize_func, ThreadSafeFunctionFinalize, NULL, NULL, &tsfn));
NODE_API_CALL(env, napi_call_threadsafe_function(tsfn, NULL, napi_tsfn_blocking));
NODE_API_CALL(env, napi_release_threadsafe_function(tsfn, napi_tsfn_release));
return NULL;
}
// Module init
static napi_value Init(napi_env env, napi_value exports) {
size_t index;
for (index = 0; index < ARRAY_LENGTH; index++) {
ints[index] = index;
}
napi_value js_array_length, js_max_queue_size;
napi_create_uint32(env, ARRAY_LENGTH, &js_array_length);
napi_create_uint32(env, MAX_QUEUE_SIZE, &js_max_queue_size);
napi_property_descriptor properties[] = {
{
"ARRAY_LENGTH",
NULL,
NULL,
NULL,
NULL,
js_array_length,
napi_enumerable,
NULL
},
{
"MAX_QUEUE_SIZE",
NULL,
NULL,
NULL,
NULL,
js_max_queue_size,
napi_enumerable,
NULL
},
DECLARE_NODE_API_PROPERTY("StartThread", StartThread),
DECLARE_NODE_API_PROPERTY("StartThreadNoNative", StartThreadNoNative),
DECLARE_NODE_API_PROPERTY("StartThreadNonblocking", StartThreadNonblocking),
DECLARE_NODE_API_PROPERTY("StartThreadNoJsFunc", StartThreadNoJsFunc),
DECLARE_NODE_API_PROPERTY("StopThread", StopThread),
DECLARE_NODE_API_PROPERTY("Unref", Unref),
DECLARE_NODE_API_PROPERTY("Release", Release),
DECLARE_NODE_API_PROPERTY("CallIntoModule", CallIntoModule),
};
NODE_API_CALL(env, napi_define_properties(env, exports,
sizeof(properties)/sizeof(properties[0]), properties));
return exports;
}
NAPI_MODULE(NODE_GYP_MODULE_NAME, Init)

View File

@ -0,0 +1,22 @@
{
'targets': [
{
'target_name': 'binding',
'sources': ['binding.c']
},
{
'target_name': 'test_uncaught_exception_v9',
'defines': [
'NAPI_VERSION=9'
],
'sources': ['test_uncaught_exception.c']
},
{
'target_name': 'test_uncaught_exception',
'defines': [
'NAPI_EXPERIMENTAL'
],
'sources': ['test_uncaught_exception.c']
}
]
}

View File

@ -0,0 +1,227 @@
'use strict';
const common = require('../../common');
const assert = require('assert');
const binding = require(`./build/${common.buildType}/binding`);
const { fork } = require('child_process');
const expectedArray = (function(arrayLength) {
const result = [];
for (let index = 0; index < arrayLength; index++) {
result.push(arrayLength - 1 - index);
}
return result;
})(binding.ARRAY_LENGTH);
// Handle the rapid teardown test case as the child process. We unref the
// thread-safe function after we have received two values. This causes the
// process to exit and the environment cleanup handler to be invoked.
if (process.argv[2] === 'child') {
let callCount = 0;
binding.StartThread((value) => {
callCount++;
console.log(value);
if (callCount === 2) {
binding.Unref();
}
}, false /* abort */, true /* launchSecondary */, +process.argv[3]);
// Release the thread-safe function from the main thread so that it may be
// torn down via the environment cleanup handler.
binding.Release();
return;
}
function testWithJSMarshaller({
threadStarter,
quitAfter,
abort,
maxQueueSize,
launchSecondary,
}) {
return new Promise((resolve) => {
const array = [];
binding[threadStarter](function testCallback(value) {
array.push(value);
if (array.length === quitAfter) {
setImmediate(() => {
binding.StopThread(common.mustCall(() => {
resolve(array);
}), !!abort);
});
}
}, !!abort, !!launchSecondary, maxQueueSize);
if (threadStarter === 'StartThreadNonblocking') {
// Let's make this thread really busy for a short while to ensure that
// the queue fills and the thread receives a napi_queue_full.
const start = Date.now();
while (Date.now() - start < 200);
}
});
}
function testUnref(queueSize) {
return new Promise((resolve, reject) => {
let output = '';
const child = fork(__filename, ['child', queueSize], {
stdio: [process.stdin, 'pipe', process.stderr, 'ipc'],
});
child.on('close', (code) => {
if (code === 0) {
resolve(output.match(/\S+/g));
} else {
reject(new Error('Child process died with code ' + code));
}
});
child.stdout.on('data', (data) => (output += data.toString()));
})
.then((result) => assert.strictEqual(result.indexOf(0), -1));
}
new Promise(function testWithoutJSMarshaller(resolve) {
let callCount = 0;
binding.StartThreadNoNative(function testCallback() {
callCount++;
// The default call-into-JS implementation passes no arguments.
assert.strictEqual(arguments.length, 0);
if (callCount === binding.ARRAY_LENGTH) {
setImmediate(() => {
binding.StopThread(common.mustCall(() => {
resolve();
}), false);
});
}
}, false /* abort */, false /* launchSecondary */, binding.MAX_QUEUE_SIZE);
})
// Start the thread in blocking mode, and assert that all values are passed.
// Quit after it's done.
.then(() => testWithJSMarshaller({
threadStarter: 'StartThread',
maxQueueSize: binding.MAX_QUEUE_SIZE,
quitAfter: binding.ARRAY_LENGTH,
}))
.then((result) => assert.deepStrictEqual(result, expectedArray))
// Start the thread in blocking mode, and assert that all values are passed.
// Quit after it's done.
// Doesn't pass the callback js function to napi_create_threadsafe_function.
// Instead, use an alternative reference to get js function called.
.then(() => testWithJSMarshaller({
threadStarter: 'StartThreadNoJsFunc',
maxQueueSize: binding.MAX_QUEUE_SIZE,
quitAfter: binding.ARRAY_LENGTH,
}))
.then((result) => assert.deepStrictEqual(result, expectedArray))
// Start the thread in blocking mode with an infinite queue, and assert that all
// values are passed. Quit after it's done.
.then(() => testWithJSMarshaller({
threadStarter: 'StartThread',
maxQueueSize: 0,
quitAfter: binding.ARRAY_LENGTH,
}))
.then((result) => assert.deepStrictEqual(result, expectedArray))
// Start the thread in non-blocking mode, and assert that all values are passed.
// Quit after it's done.
.then(() => testWithJSMarshaller({
threadStarter: 'StartThreadNonblocking',
maxQueueSize: binding.MAX_QUEUE_SIZE,
quitAfter: binding.ARRAY_LENGTH,
}))
.then((result) => assert.deepStrictEqual(result, expectedArray))
// Start the thread in blocking mode, and assert that all values are passed.
// Quit early, but let the thread finish.
.then(() => testWithJSMarshaller({
threadStarter: 'StartThread',
maxQueueSize: binding.MAX_QUEUE_SIZE,
quitAfter: 1,
}))
.then((result) => assert.deepStrictEqual(result, expectedArray))
// Start the thread in blocking mode with an infinite queue, and assert that all
// values are passed. Quit early, but let the thread finish.
.then(() => testWithJSMarshaller({
threadStarter: 'StartThread',
maxQueueSize: 0,
quitAfter: 1,
}))
.then((result) => assert.deepStrictEqual(result, expectedArray))
// Start the thread in non-blocking mode, and assert that all values are passed.
// Quit early, but let the thread finish.
.then(() => testWithJSMarshaller({
threadStarter: 'StartThreadNonblocking',
maxQueueSize: binding.MAX_QUEUE_SIZE,
quitAfter: 1,
}))
.then((result) => assert.deepStrictEqual(result, expectedArray))
// Start the thread in blocking mode, and assert that all values are passed.
// Quit early, but let the thread finish. Launch a secondary thread to test the
// reference counter incrementing functionality.
.then(() => testWithJSMarshaller({
threadStarter: 'StartThread',
quitAfter: 1,
maxQueueSize: binding.MAX_QUEUE_SIZE,
launchSecondary: true,
}))
.then((result) => assert.deepStrictEqual(result, expectedArray))
// Start the thread in non-blocking mode, and assert that all values are passed.
// Quit early, but let the thread finish. Launch a secondary thread to test the
// reference counter incrementing functionality.
.then(() => testWithJSMarshaller({
threadStarter: 'StartThreadNonblocking',
quitAfter: 1,
maxQueueSize: binding.MAX_QUEUE_SIZE,
launchSecondary: true,
}))
.then((result) => assert.deepStrictEqual(result, expectedArray))
// Start the thread in blocking mode, and assert that it could not finish.
// Quit early by aborting.
.then(() => testWithJSMarshaller({
threadStarter: 'StartThread',
quitAfter: 1,
maxQueueSize: binding.MAX_QUEUE_SIZE,
abort: true,
}))
.then((result) => assert.strictEqual(result.indexOf(0), -1))
// Start the thread in blocking mode with an infinite queue, and assert that it
// could not finish. Quit early by aborting.
.then(() => testWithJSMarshaller({
threadStarter: 'StartThread',
quitAfter: 1,
maxQueueSize: 0,
abort: true,
}))
.then((result) => assert.strictEqual(result.indexOf(0), -1))
// Start the thread in non-blocking mode, and assert that it could not finish.
// Quit early and aborting.
.then(() => testWithJSMarshaller({
threadStarter: 'StartThreadNonblocking',
quitAfter: 1,
maxQueueSize: binding.MAX_QUEUE_SIZE,
abort: true,
}))
.then((result) => assert.strictEqual(result.indexOf(0), -1))
// Make sure that threadsafe function isn't stalled when we hit
// `kMaxIterationCount` in `src/node_api.cc`
.then(() => testWithJSMarshaller({
threadStarter: 'StartThreadNonblocking',
maxQueueSize: binding.ARRAY_LENGTH >>> 1,
quitAfter: binding.ARRAY_LENGTH,
}))
.then((result) => assert.deepStrictEqual(result, expectedArray))
// Start a child process to test rapid teardown
.then(() => testUnref(binding.MAX_QUEUE_SIZE))
// Start a child process with an infinite queue to test rapid teardown
.then(() => testUnref(0));

View File

@ -0,0 +1,22 @@
'use strict';
// Flags: --no-force-node-api-uncaught-exceptions-policy
const common = require('../../common');
const binding = require(`./build/${common.buildType}/test_uncaught_exception_v9`);
process.on(
'uncaughtException',
common.mustNotCall('uncaught callback errors should be suppressed ' +
'with the option --no-force-node-api-uncaught-exceptions-policy'),
);
binding.CallIntoModule(
common.mustCall(() => {
throw new Error('callback error');
}),
{},
'resource_name',
common.mustCall(function finalizer() {
throw new Error('finalizer error');
}),
);

View File

@ -0,0 +1,62 @@
#include <node_api.h>
#include "../../js-native-api/common.h"
// Testing calling into JavaScript
static void ThreadSafeFunctionFinalize(napi_env env,
void* finalize_data,
void* finalize_hint) {
napi_ref js_func_ref = (napi_ref)finalize_data;
napi_value js_func;
napi_value recv;
NODE_API_CALL_RETURN_VOID(
env, napi_get_reference_value(env, js_func_ref, &js_func));
NODE_API_CALL_RETURN_VOID(env, napi_get_global(env, &recv));
NODE_API_CALL_RETURN_VOID(
env, napi_call_function(env, recv, js_func, 0, NULL, NULL));
NODE_API_CALL_RETURN_VOID(env, napi_delete_reference(env, js_func_ref));
}
// Testing calling into JavaScript
static napi_value CallIntoModule(napi_env env, napi_callback_info info) {
size_t argc = 4;
napi_value argv[4];
NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, argv, NULL, NULL));
napi_ref finalize_func;
NODE_API_CALL(env, napi_create_reference(env, argv[3], 1, &finalize_func));
napi_threadsafe_function tsfn;
NODE_API_CALL(env,
napi_create_threadsafe_function(env,
argv[0],
argv[1],
argv[2],
0,
1,
finalize_func,
ThreadSafeFunctionFinalize,
NULL,
NULL,
&tsfn));
NODE_API_CALL(env,
napi_call_threadsafe_function(tsfn, NULL, napi_tsfn_blocking));
NODE_API_CALL(env, napi_release_threadsafe_function(tsfn, napi_tsfn_release));
return NULL;
}
// Module init
static napi_value Init(napi_env env, napi_value exports) {
napi_property_descriptor properties[] = {
DECLARE_NODE_API_PROPERTY("CallIntoModule", CallIntoModule),
};
NODE_API_CALL(
env,
napi_define_properties(env,
exports,
sizeof(properties) / sizeof(properties[0]),
properties));
return exports;
}
NAPI_MODULE(NODE_GYP_MODULE_NAME, Init)

View File

@ -0,0 +1,7 @@
'use strict';
const common = require('../../common');
const binding = require(`./build/${common.buildType}/test_uncaught_exception`);
const { testUncaughtException } = require('./uncaught_exception');
testUncaughtException(binding);

View File

@ -0,0 +1,8 @@
'use strict';
// Flags: --force-node-api-uncaught-exceptions-policy
const common = require('../../common');
const binding = require(`./build/${common.buildType}/test_uncaught_exception_v9`);
const { testUncaughtException } = require('./uncaught_exception');
testUncaughtException(binding);

View File

@ -0,0 +1,31 @@
'use strict';
const common = require('../../common');
const assert = require('assert');
function testUncaughtException(binding) {
const callbackCheck = common.mustCall((err) => {
assert.throws(() => { throw err; }, /callback error/);
process.removeListener('uncaughtException', callbackCheck);
process.on('uncaughtException', finalizerCheck);
});
const finalizerCheck = common.mustCall((err) => {
assert.throws(() => { throw err; }, /finalizer error/);
});
process.on('uncaughtException', callbackCheck);
binding.CallIntoModule(
common.mustCall(() => {
throw new Error('callback error');
}),
{},
'resource_name',
common.mustCall(function finalizer() {
throw new Error('finalizer error');
}),
);
}
module.exports = {
testUncaughtException,
};