From fc635ae6088748e25c145dbb6e15eb79b2f481ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kr=C3=A6n=20Hansen?= Date: Sat, 28 Feb 2026 12:35:17 +0100 Subject: [PATCH 1/3] doc: add porting plan with difficulty ratings Enumerates all 58 test directories from Node.js's test/js-native-api and test/node-api, rates each by porting difficulty (Easy/Medium/Hard), and documents special considerations for tests with deep runtime dependencies (libuv, worker threads, SEA, node_api_post_finalizer, etc.). Co-Authored-By: Claude Sonnet 4.6 --- PORTING.md | 164 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 PORTING.md diff --git a/PORTING.md b/PORTING.md new file mode 100644 index 0000000..630c1f0 --- /dev/null +++ b/PORTING.md @@ -0,0 +1,164 @@ +# Porting Plan + +This document tracks the progress of porting tests from Node.js's test suite into the CTS. +The source directories are [`test/js-native-api`](https://github.com/nodejs/node/tree/main/test/js-native-api) +and [`test/node-api`](https://github.com/nodejs/node/tree/main/test/node-api) in the Node.js repository. + +Difficulty is assessed on two axes: +- **Size/complexity** — total lines of C/C++ and JS across all source files +- **Runtime-API dependence** — pure `js_native_api.h` is cheapest; Node.js extensions and direct + libuv calls require harness work or Node-only scoping + +| Rating | Meaning | +|---|---| +| Easy | Small test, pure `js_native_api.h` or trivial runtime API, straightforward 1:1 port | +| Medium | Moderate size or uses a Node.js extension API that the harness will need to abstract | +| Hard | Large test and/or deep libuv/worker/SEA dependency; may need new harness primitives or Node-only scoping | + +## Engine-specific (`js-native-api`) + +Tests covering the engine-specific part of Node-API, defined in `js_native_api.h`. + +| Directory | Status | Difficulty | +|---|---|---| +| `2_function_arguments` | Ported | — | +| `3_callbacks` | Not ported | Easy | +| `4_object_factory` | Not ported | Easy | +| `5_function_factory` | Not ported | Easy | +| `6_object_wrap` | Not ported | Medium | +| `7_factory_wrap` | Not ported | Easy | +| `8_passing_wrapped` | Not ported | Easy | +| `test_array` | Not ported | Easy | +| `test_bigint` | Not ported | Easy | +| `test_cannot_run_js` | Not ported | Medium | +| `test_constructor` | Not ported | Medium | +| `test_conversions` | Not ported | Medium | +| `test_dataview` | Not ported | Easy | +| `test_date` | Not ported | Easy | +| `test_error` | Not ported | Medium | +| `test_exception` | Not ported | Medium | +| `test_finalizer` | Not ported | Medium | +| `test_function` | Not ported | Medium | +| `test_general` | Not ported | Hard | +| `test_handle_scope` | Not ported | Easy | +| `test_instance_data` | Not ported | Easy | +| `test_new_target` | Not ported | Easy | +| `test_number` | Not ported | Easy | +| `test_object` | Not ported | Hard | +| `test_promise` | Not ported | Easy | +| `test_properties` | Not ported | Easy | +| `test_reference` | Not ported | Medium | +| `test_reference_double_free` | Not ported | Easy | +| `test_sharedarraybuffer` | Not ported | Medium | +| `test_string` | Not ported | Medium | +| `test_symbol` | Not ported | Easy | +| `test_typedarray` | Not ported | Medium | + +## Runtime-specific (`node-api`) + +Tests covering the runtime-specific part of Node-API, defined in `node_api.h`. + +| Directory | Status | Difficulty | +|---|---|---| +| `1_hello_world` | Not ported | Easy | +| `test_async` | Not ported | Hard | +| `test_async_cleanup_hook` | Not ported | Hard | +| `test_async_context` | Not ported | Hard | +| `test_buffer` | Not ported | Medium | +| `test_callback_scope` | Not ported | Hard | +| `test_cleanup_hook` | Not ported | Medium | +| `test_env_teardown_gc` | Not ported | Easy | +| `test_exception` | Not ported | Easy | +| `test_fatal` | Not ported | Hard | +| `test_fatal_exception` | Not ported | Easy | +| `test_general` | Not ported | Medium | +| `test_init_order` | Not ported | Medium | +| `test_instance_data` | Not ported | Hard | +| `test_make_callback` | Not ported | Hard | +| `test_make_callback_recurse` | Not ported | Hard | +| `test_null_init` | Not ported | Medium | +| `test_reference_by_node_api_version` | Not ported | Medium | +| `test_sea_addon` | Not ported | Hard | +| `test_threadsafe_function` | Not ported | Hard | +| `test_threadsafe_function_shutdown` | Not ported | Hard | +| `test_uv_loop` | Not ported | Hard | +| `test_uv_threadpool_size` | Not ported | Hard | +| `test_worker_buffer_callback` | Not ported | Hard | +| `test_worker_terminate` | Not ported | Hard | +| `test_worker_terminate_finalization` | Not ported | Hard | + +## Special Considerations + +### `node_api_post_finalizer` (`6_object_wrap`, `test_finalizer`) + +Both tests call `node_api_post_finalizer` to defer JS-touching work out of the GC finalizer and +onto the main thread. This is a Node.js extension not guaranteed to be present on other engines. +The CTS harness will need a platform-agnostic post-finalizer primitive that implementors can map +to their own deferred-callback mechanism, or the tests need to isolate the post-finalizer cases +into a Node-specific subtest. + +### `node_api_set_prototype` / `node_api_get_prototype` (`test_general`, js-native-api) + +The general test suite mixes standard `js_native_api.h` assertions with calls to +`node_api_set_prototype` and `node_api_get_prototype`, which are Node.js extensions. These do +not exist on other engines. The CTS port should split the affected test cases into an engine-agnostic +core and a Node-only annex, or guard those cases with a runtime capability check. + +### SharedArrayBuffer backing-store creation (`test_sharedarraybuffer`) + +While `napi_is_sharedarraybuffer` and `napi_get_typedarray_info` are part of `js_native_api.h`, +the test creates its SharedArrayBuffer via a Node-specific helper. The CTS version will need a +harness-provided factory (something like `create_shared_array_buffer(size)`) that each runtime +can implement using its own path. + +### libuv dependency (multiple `node-api` tests) + +The following tests call into libuv directly — `napi_get_uv_event_loop`, `uv_thread_t`, +`uv_mutex_t`, `uv_async_t`, `uv_check_t`, `uv_idle_t`, `uv_queue_work`, and related APIs: + +- `test_async`, `test_async_cleanup_hook`, `test_async_context` +- `test_callback_scope` +- `test_fatal` (uses `uv_thread_t` to test cross-thread fatal errors) +- `test_instance_data` (async work + threadsafe functions + `uv_thread_t`) +- `test_uv_loop`, `test_uv_threadpool_size` + +Porting options: +1. **Node-only scope** — mark these tests as Node.js-only and skip on other runtimes. +2. **Harness abstraction** — introduce a minimal platform-agnostic threading/async API in the + harness (e.g., `cts_thread_create`, `cts_async_schedule`) that implementors back with their + own event loop primitives (libuv, tokio, etc.). + +### Threadsafe functions (`test_threadsafe_function`, `test_threadsafe_function_shutdown`) + +`test_threadsafe_function` is the largest single test (~700 total lines across C and JS), covering +blocking/non-blocking queue modes, queue-full handling, multiple concurrent threads, finalization +ordering, uncaught exception propagation, and high-precision timing via `uv_hrtime`. The threading +primitives are libuv-specific (same concern as the section above). Porting this test likely depends +on resolving the libuv abstraction question first. + +### Worker threads (`test_worker_buffer_callback`, `test_worker_terminate`, `test_worker_terminate_finalization`) + +These three tests exercise addon behavior inside Node.js worker threads: buffer finalizer delivery +in worker contexts, function-call behavior under pending exceptions during worker shutdown, and +wrapped-object finalization on forced worker termination. Node.js worker threads have no direct +equivalent in most other Node-API runtimes. These tests are likely Node.js-only and should be +scoped accordingly. + +### SEA — Single Executable Applications (`test_sea_addon`) + +`test_sea_addon` verifies that a native addon can be loaded inside a Node.js Single Executable +Application. SEA is a Node.js-specific packaging feature with no equivalent in other runtimes. +This test should be excluded from the CTS scope or placed in a Node-only annex. + +### `napi_get_node_version` (`test_general`, node-api) + +`test_general` calls `napi_get_node_version`, which returns the Node.js major/minor/patch version. +No equivalent exists in other runtimes. The CTS port should either omit that assertion or expose a +harness helper (e.g., `cts_get_runtime_version`) that runtimes can optionally implement. + +### Legacy module registration (`test_null_init`) + +`test_null_init` exercises the deprecated `NAPI_MODULE` macro with a NULL init function, calling +`napi_module_register` directly. Some newer runtimes that implement Node-API may not support this +legacy registration path. If so, this test should be scoped as Node-only or skipped on runtimes +that only support `NAPI_MODULE_INIT`. From 6f23569ebb7c59690b420efec18cd5fd1b51b681 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kr=C3=A6n=20Hansen?= Date: Tue, 3 Mar 2026 09:35:22 +0100 Subject: [PATCH 2/3] doc: clarify napi_ vs node_api_ prefix convention and fix function names MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an "API Naming Convention" section explaining that the napi_/node_api_ prefix difference is historical (rename from "napi" to "Node API"), not an indicator of Node.js-specificity. What matters is the declaring header: js_native_api.h (engine-agnostic) vs node_api.h (runtime-specific). Also fix two function name errors in the Special Considerations section: - node_api_get_prototype → napi_get_prototype (actual name in source) - napi_is_sharedarraybuffer → node_api_is_sharedarraybuffer (correct prefix) - napi_get_typedarray_info → node_api_create_sharedarraybuffer (wrong function referenced; the real concern is backing-store allocation) Co-Authored-By: Claude Sonnet 4.6 --- PORTING.md | 47 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/PORTING.md b/PORTING.md index 630c1f0..ea8b467 100644 --- a/PORTING.md +++ b/PORTING.md @@ -4,6 +4,24 @@ This document tracks the progress of porting tests from Node.js's test suite int The source directories are [`test/js-native-api`](https://github.com/nodejs/node/tree/main/test/js-native-api) and [`test/node-api`](https://github.com/nodejs/node/tree/main/test/node-api) in the Node.js repository. +## API Naming Convention + +Node-API uses two function prefixes that are sometimes confused: + +- **`napi_`** — the original prefix, retained for backwards compatibility +- **`node_api_`** — the newer prefix, adopted after the project was renamed from "napi" to "Node API" + +The prefix alone does **not** indicate whether a function is Node.js-specific or runtime-agnostic. +What matters is which header the function is declared in: + +- `js_native_api.h` — engine-agnostic APIs, available across all Node-API runtimes +- `node_api.h` — runtime-specific APIs, currently defined by Node.js + +For example, `node_api_is_sharedarraybuffer` carries the newer `node_api_` prefix but is declared +in `js_native_api.h` and is therefore engine-agnostic. + +## Difficulty Ratings + Difficulty is assessed on two axes: - **Size/complexity** — total lines of C/C++ and JS across all source files - **Runtime-API dependence** — pure `js_native_api.h` is cheapest; Node.js extensions and direct @@ -92,24 +110,27 @@ Tests covering the runtime-specific part of Node-API, defined in `node_api.h`. ### `node_api_post_finalizer` (`6_object_wrap`, `test_finalizer`) Both tests call `node_api_post_finalizer` to defer JS-touching work out of the GC finalizer and -onto the main thread. This is a Node.js extension not guaranteed to be present on other engines. -The CTS harness will need a platform-agnostic post-finalizer primitive that implementors can map -to their own deferred-callback mechanism, or the tests need to isolate the post-finalizer cases -into a Node-specific subtest. +onto the main thread. The function is declared in `js_native_api.h` but is gated behind +`NAPI_EXPERIMENTAL`, so not all runtimes may implement it yet. The CTS harness will need a +platform-agnostic post-finalizer primitive that implementors can map to their own +deferred-callback mechanism, or the tests need to isolate the post-finalizer cases behind a +runtime capability check. -### `node_api_set_prototype` / `node_api_get_prototype` (`test_general`, js-native-api) +### `node_api_set_prototype` / `napi_get_prototype` (`test_general`, js-native-api) -The general test suite mixes standard `js_native_api.h` assertions with calls to -`node_api_set_prototype` and `node_api_get_prototype`, which are Node.js extensions. These do -not exist on other engines. The CTS port should split the affected test cases into an engine-agnostic -core and a Node-only annex, or guard those cases with a runtime capability check. +The general test suite mixes `js_native_api.h` assertions with calls to `node_api_set_prototype` +(gated behind `NAPI_EXPERIMENTAL`) and `napi_get_prototype` (standard). The experimental function +may not be implemented by all runtimes yet. The CTS port should split the affected test cases into +a stable core and an experimental annex, or guard the `node_api_set_prototype` cases with a +runtime capability check. ### SharedArrayBuffer backing-store creation (`test_sharedarraybuffer`) -While `napi_is_sharedarraybuffer` and `napi_get_typedarray_info` are part of `js_native_api.h`, -the test creates its SharedArrayBuffer via a Node-specific helper. The CTS version will need a -harness-provided factory (something like `create_shared_array_buffer(size)`) that each runtime -can implement using its own path. +`node_api_is_sharedarraybuffer` and `node_api_create_sharedarraybuffer` are both declared in +`js_native_api.h` and are engine-agnostic. However, the test also exercises creating a +SharedArrayBuffer from the C side via `node_api_create_sharedarraybuffer`, which allocates +backing store memory. The CTS version will need a harness-provided factory (something like +`create_shared_array_buffer(size)`) that each runtime can implement using its own path. ### libuv dependency (multiple `node-api` tests) From c5a560deb4c2f7952fd6ea419a9491e1f3b1fc6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kr=C3=A6n=20Hansen?= Date: Tue, 3 Mar 2026 19:35:59 +0100 Subject: [PATCH 3/3] Update PORTING.md Co-authored-by: Chengzhong Wu --- PORTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PORTING.md b/PORTING.md index ea8b467..834d704 100644 --- a/PORTING.md +++ b/PORTING.md @@ -15,7 +15,7 @@ The prefix alone does **not** indicate whether a function is Node.js-specific or What matters is which header the function is declared in: - `js_native_api.h` — engine-agnostic APIs, available across all Node-API runtimes -- `node_api.h` — runtime-specific APIs, currently defined by Node.js +- `node_api.h` — runtime-specific APIs, providing features beyond pure JavaScript value operations. For example, `node_api_is_sharedarraybuffer` carries the newer `node_api_` prefix but is declared in `js_native_api.h` and is therefore engine-agnostic.