Skip to content

Commit a8f4477

Browse files
kraenhansenclaude
andauthored
feat: port 15 easy js-native-api tests to CTS (#25)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent e347af0 commit a8f4477

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+2908
-18
lines changed

PORTING.md

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -40,37 +40,37 @@ Tests covering the engine-specific part of Node-API, defined in `js_native_api.h
4040

4141
| Directory | Status | Difficulty |
4242
| ---------------------------- | ---------- | ---------- |
43-
| `2_function_arguments` | Ported ||
44-
| `3_callbacks` | Not ported | Easy |
45-
| `4_object_factory` | Not ported | Easy |
46-
| `5_function_factory` | Not ported | Easy |
43+
| `2_function_arguments` | Ported ||
44+
| `3_callbacks` | Ported ✅ | Easy |
45+
| `4_object_factory` | Ported ✅ | Easy |
46+
| `5_function_factory` | Ported ✅ | Easy |
4747
| `6_object_wrap` | Not ported | Medium |
48-
| `7_factory_wrap` | Not ported | Easy |
49-
| `8_passing_wrapped` | Not ported | Easy |
50-
| `test_array` | Not ported | Easy |
51-
| `test_bigint` | Not ported | Easy |
48+
| `7_factory_wrap` | Ported ✅ | Easy |
49+
| `8_passing_wrapped` | Ported ✅ | Easy |
50+
| `test_array` | Ported ✅ | Easy |
51+
| `test_bigint` | Ported ✅ | Easy |
5252
| `test_cannot_run_js` | Not ported | Medium |
5353
| `test_constructor` | Not ported | Medium |
5454
| `test_conversions` | Not ported | Medium |
55-
| `test_dataview` | Not ported | Easy |
56-
| `test_date` | Not ported | Easy |
55+
| `test_dataview` | Not ported | Medium |
56+
| `test_date` | Ported ✅ | Easy |
5757
| `test_error` | Not ported | Medium |
5858
| `test_exception` | Not ported | Medium |
5959
| `test_finalizer` | Not ported | Medium |
6060
| `test_function` | Not ported | Medium |
6161
| `test_general` | Not ported | Hard |
62-
| `test_handle_scope` | Not ported | Easy |
63-
| `test_instance_data` | Not ported | Easy |
64-
| `test_new_target` | Not ported | Easy |
65-
| `test_number` | Not ported | Easy |
62+
| `test_handle_scope` | Ported ✅ | Easy |
63+
| `test_instance_data` | Not ported | Medium |
64+
| `test_new_target` | Ported ✅ | Easy |
65+
| `test_number` | Ported ✅ | Easy |
6666
| `test_object` | Not ported | Hard |
67-
| `test_promise` | Not ported | Easy |
68-
| `test_properties` | Not ported | Easy |
67+
| `test_promise` | Ported ✅ | Easy |
68+
| `test_properties` | Ported ✅ | Easy |
6969
| `test_reference` | Not ported | Medium |
70-
| `test_reference_double_free` | Not ported | Easy |
70+
| `test_reference_double_free` | Ported ✅ | Easy |
7171
| `test_sharedarraybuffer` | Not ported | Medium |
7272
| `test_string` | Not ported | Medium |
73-
| `test_symbol` | Not ported | Easy |
73+
| `test_symbol` | Ported ✅ | Easy |
7474
| `test_typedarray` | Not ported | Medium |
7575

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

implementors/node/must-call.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
const pendingCalls = [];
2+
3+
/**
4+
* Wraps a function and asserts it is called exactly `exact` times before the
5+
* process exits. If `fn` is omitted, a no-op function is used.
6+
*
7+
* Usage:
8+
* promise.then(mustCall((result) => {
9+
* assert.strictEqual(result, 42);
10+
* }));
11+
*/
12+
const mustCall = (fn, exact = 1) => {
13+
const entry = {
14+
exact,
15+
actual: 0,
16+
name: fn?.name || "<anonymous>",
17+
error: new Error(), // capture call-site stack
18+
};
19+
pendingCalls.push(entry);
20+
return function(...args) {
21+
entry.actual++;
22+
if (fn) return fn.apply(this, args);
23+
};
24+
};
25+
26+
/**
27+
* Returns a function that throws immediately if called.
28+
*/
29+
const mustNotCall = (msg) => {
30+
return () => {
31+
throw new Error(msg || "mustNotCall function was called");
32+
};
33+
};
34+
35+
process.on("exit", () => {
36+
for (const entry of pendingCalls) {
37+
if (entry.actual !== entry.exact) {
38+
entry.error.message =
39+
`mustCall "${entry.name}" expected ${entry.exact} call(s) ` +
40+
`but got ${entry.actual}`;
41+
throw entry.error;
42+
}
43+
}
44+
});
45+
46+
Object.assign(globalThis, { mustCall, mustNotCall });

implementors/node/tests.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@ const GC_MODULE_PATH = path.join(
3434
"node",
3535
"gc.js"
3636
);
37+
const MUST_CALL_MODULE_PATH = path.join(
38+
ROOT_PATH,
39+
"implementors",
40+
"node",
41+
"must-call.js"
42+
);
3743

3844
export function listDirectoryEntries(dir: string) {
3945
const entries = fs.readdirSync(dir, { withFileTypes: true });
@@ -72,6 +78,8 @@ export function runFileInSubprocess(
7278
"file://" + LOAD_ADDON_MODULE_PATH,
7379
"--import",
7480
"file://" + GC_MODULE_PATH,
81+
"--import",
82+
"file://" + MUST_CALL_MODULE_PATH,
7583
filePath,
7684
],
7785
{ cwd }

0 commit comments

Comments
 (0)