Skip to content

Commit 22953fd

Browse files
gabrielschulhofmika-fischer
authored andcommitted
node-api: add unit test
1 parent bfc729c commit 22953fd

File tree

3 files changed

+111
-0
lines changed

3 files changed

+111
-0
lines changed
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
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+
12+
template <typename R, auto func, typename... Args>
13+
inline auto call(const char* name, Args&&... args) -> R {
14+
napi_status status;
15+
if constexpr (std::is_same_v<R, void>) {
16+
status = func(std::forward<Args>(args)...);
17+
if (status == napi_ok) {
18+
return;
19+
}
20+
} else {
21+
R ret;
22+
status = func(std::forward<Args>(args)..., &ret);
23+
if (status == napi_ok) {
24+
return ret;
25+
}
26+
}
27+
std::fprintf(stderr, "%s: %d\n", name, status);
28+
std::abort();
29+
}
30+
31+
#define NAPI_CALL(ret_type, func, ...) \
32+
call<ret_type, func>(#func, ##__VA_ARGS__)
33+
34+
void thread_func(napi_threadsafe_function tsfn) {
35+
fprintf(stderr, "thread_func: starting\n");
36+
auto status =
37+
napi_call_threadsafe_function(tsfn, nullptr, napi_tsfn_blocking);
38+
while (status == napi_ok) {
39+
std::this_thread::sleep_for(std::chrono::milliseconds(1));
40+
status = napi_call_threadsafe_function(tsfn, nullptr, napi_tsfn_blocking);
41+
}
42+
fprintf(stderr, "thread_func: Got status %d, exiting...\n", status);
43+
}
44+
45+
void tsfn_callback(napi_env env, napi_value js_cb, void* ctx, void* data) {
46+
if (env == nullptr) {
47+
fprintf(stderr, "tsfn_callback: env=%p\n", env);
48+
}
49+
}
50+
51+
void tsfn_finalize(napi_env env, void* finalize_data, void* finalize_hint) {
52+
fprintf(stderr, "tsfn_finalize: env=%p\n", env);
53+
}
54+
55+
auto run(napi_env env, napi_callback_info info) -> napi_value {
56+
auto global = NAPI_CALL(napi_value, napi_get_global, env);
57+
auto undefined = NAPI_CALL(napi_value, napi_get_undefined, env);
58+
auto n_threads = 32;
59+
auto tsfn = NAPI_CALL(napi_threadsafe_function,
60+
napi_create_threadsafe_function,
61+
env,
62+
nullptr,
63+
global,
64+
undefined,
65+
0,
66+
n_threads,
67+
nullptr,
68+
tsfn_finalize,
69+
nullptr,
70+
tsfn_callback);
71+
for (auto i = 0; i < n_threads; ++i) {
72+
std::thread([tsfn] { thread_func(tsfn); }).detach();
73+
}
74+
NAPI_CALL(void, napi_unref_threadsafe_function, env, tsfn);
75+
return NAPI_CALL(napi_value, napi_get_undefined, env);
76+
}
77+
78+
napi_value init(napi_env env, napi_value exports) {
79+
return NAPI_CALL(
80+
napi_value, napi_create_function, env, nullptr, 0, run, nullptr);
81+
}
82+
83+
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)