Skip to content

Commit c64cd81

Browse files
gabrielschulhofmika-fischer
authored andcommitted
node-api: add unit test
1 parent 89067de commit c64cd81

File tree

3 files changed

+114
-0
lines changed

3 files changed

+114
-0
lines changed
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
#include <js_native_api.h>
2+
#include <node_api.h>
3+
#include <node_api_types.h>
4+
5+
#include <cstdio>
6+
#include <cstdlib>
7+
#include <memory>
8+
#include <thread> // NOLINT(build/c++11)
9+
#include <type_traits>
10+
#include <utility>
11+
#include <vector>
12+
13+
template <typename R, auto func, typename... Args>
14+
inline auto call(const char* name, Args&&... args) -> R {
15+
napi_status status;
16+
if constexpr (std::is_same_v<R, void>) {
17+
status = func(std::forward<Args>(args)...);
18+
if (status == napi_ok) {
19+
return;
20+
}
21+
} else {
22+
R ret;
23+
status = func(std::forward<Args>(args)..., &ret);
24+
if (status == napi_ok) {
25+
return ret;
26+
}
27+
}
28+
std::fprintf(stderr, "%s: %d\n", name, status);
29+
std::abort();
30+
}
31+
32+
#define NAPI_CALL(ret_type, func, ...) \
33+
call<ret_type, func>(#func, ##__VA_ARGS__)
34+
35+
void thread_func(napi_threadsafe_function tsfn) {
36+
fprintf(stderr, "thread_func: starting\n");
37+
auto status =
38+
napi_call_threadsafe_function(tsfn, nullptr, napi_tsfn_blocking);
39+
while (status == napi_ok) {
40+
std::this_thread::sleep_for(std::chrono::milliseconds(1));
41+
status = napi_call_threadsafe_function(tsfn, nullptr, napi_tsfn_blocking);
42+
}
43+
fprintf(stderr, "thread_func: Got status %d, exiting...\n", status);
44+
}
45+
46+
void tsfn_callback(napi_env env, napi_value js_cb, void* ctx, void* data) {
47+
if (env == nullptr) {
48+
fprintf(stderr, "tsfn_callback: env=%p\n", env);
49+
}
50+
}
51+
52+
void tsfn_finalize(napi_env env, void* finalize_data, void* finalize_hint) {
53+
fprintf(stderr, "tsfn_finalize: env=%p\n", env);
54+
}
55+
56+
std::vector<std::jthread> threads;
57+
58+
auto run(napi_env env, napi_callback_info info) -> napi_value {
59+
auto global = NAPI_CALL(napi_value, napi_get_global, env);
60+
auto undefined = NAPI_CALL(napi_value, napi_get_undefined, env);
61+
auto n_threads = 32;
62+
auto tsfn = NAPI_CALL(napi_threadsafe_function,
63+
napi_create_threadsafe_function,
64+
env,
65+
nullptr,
66+
global,
67+
undefined,
68+
0,
69+
n_threads,
70+
nullptr,
71+
tsfn_finalize,
72+
nullptr,
73+
tsfn_callback);
74+
for (auto i = 0; i < n_threads; ++i) {
75+
threads.emplace_back([tsfn] { thread_func(tsfn); });
76+
}
77+
NAPI_CALL(void, napi_unref_threadsafe_function, env, tsfn);
78+
return NAPI_CALL(napi_value, napi_get_undefined, env);
79+
}
80+
81+
napi_value init(napi_env env, napi_value exports) {
82+
return NAPI_CALL(
83+
napi_value, napi_create_function, env, nullptr, 0, run, nullptr);
84+
}
85+
86+
NAPI_MODULE(NODE_GYP_MODULE_NAME, init)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"targets": [
3+
{
4+
"target_name": "binding",
5+
"sources": ["binding.cc"],
6+
"cflags_cc": ["--std=c++20"],
7+
'cflags!': [ '-fno-exceptions', '-fno-rtti' ],
8+
'cflags_cc!': [ '-fno-exceptions', '-fno-rtti' ],
9+
}
10+
]
11+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
'use strict';
2+
3+
const common = require('../../common');
4+
const process = require('process');
5+
const assert = require('assert');
6+
const { fork } = require('child_process');
7+
const binding = require(`./build/${common.buildType}/binding`);
8+
9+
if (process.argv[2] === 'child') {
10+
binding();
11+
setTimeout(() => {}, 100);
12+
} else {
13+
const child = fork(__filename, ['child']);
14+
child.on('close', (code) => {
15+
assert.strictEqual(code, 0);
16+
});
17+
}

0 commit comments

Comments
 (0)