Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ if(MSVC)
execute_process(COMMAND ${CMAKE_AR} /def:${NODE_API_DEF} /out:${NODE_API_LIB} ${CMAKE_STATIC_LINKER_FLAGS})
endif()

function(add_node_api_cts_addon ADDON_NAME SRC)
add_library(${ADDON_NAME} SHARED ${SRC})
function(add_node_api_cts_addon ADDON_NAME)
add_library(${ADDON_NAME} SHARED ${ARGN})
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

set_target_properties(${ADDON_NAME} PROPERTIES
PREFIX ""
SUFFIX ".node"
Expand Down
24 changes: 20 additions & 4 deletions implementors/node/assert.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,24 @@

import { ok } from "node:assert/strict";
import {
ok,
strictEqual,
notStrictEqual,
deepStrictEqual,
throws,
} from "node:assert/strict";

const assert = (value, message) => {
ok(value, message);
};
const assert = Object.assign(
Copy link
Member

@legendecas legendecas Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Non-blocking: I would prefer avoiding the assert() and assert.<method> style in this harness. We could update test cases to use proper asserts like assert.strictEqual whenever possible.

Copy link
Contributor Author

@kraenhansen kraenhansen Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That was my initial thought as well (which is why I didn't add it initially).

I realised later as I was porting tests that it's probably more important that the tests are ported as close to their original source as possible - to minimise the risk of loosing coverage. With these helpers it's more obvious that we're actually testing the same as the Node.js test suite.

I suggest we keep this as is for now and when we have more tests ported and ideally multiple implementors running these tests we can start refactoring them in isolation.

How does that plan sound to you?

(value, message) => ok(value, message),
{
ok: (value, message) => ok(value, message),
strictEqual: (actual, expected, message) =>
strictEqual(actual, expected, message),
notStrictEqual: (actual, expected, message) =>
notStrictEqual(actual, expected, message),
deepStrictEqual: (actual, expected, message) =>
deepStrictEqual(actual, expected, message),
throws: (fn, error, message) => throws(fn, error, message),
},
);

Object.assign(globalThis, { assert });
13 changes: 13 additions & 0 deletions implementors/node/gc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
const gcUntil = async (name, condition) => {
let count = 0;
while (!condition()) {
await new Promise((resolve) => setImmediate(resolve));
if (++count < 10) {
globalThis.gc();
} else {
throw new Error(`GC test "${name}" failed after ${count} attempts`);
}
}
};

Object.assign(globalThis, { gcUntil });
9 changes: 9 additions & 0 deletions implementors/node/tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ const LOAD_ADDON_MODULE_PATH = path.join(
"node",
"load-addon.js"
);
const GC_MODULE_PATH = path.join(
ROOT_PATH,
"implementors",
"node",
"gc.js"
);

export function listDirectoryEntries(dir: string) {
const entries = fs.readdirSync(dir, { withFileTypes: true });
Expand Down Expand Up @@ -51,10 +57,13 @@ export function runFileInSubprocess(
process.execPath,
[
// Using file scheme prefix when to enable imports on Windows
"--expose-gc",
"--import",
"file://" + ASSERT_MODULE_PATH,
"--import",
"file://" + LOAD_ADDON_MODULE_PATH,
"--import",
"file://" + GC_MODULE_PATH,
filePath,
],
{ cwd }
Expand Down
50 changes: 50 additions & 0 deletions tests/harness/assert.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,53 @@ try {
if (!threw) {
throw new Error('Global assert(false, message) must throw');
}

// assert.ok
if (typeof assert.ok !== 'function') {
throw new Error('Expected assert.ok to be a function');
}
assert.ok(true);
threw = false;
try { assert.ok(false); } catch { threw = true; }
if (!threw) throw new Error('assert.ok(false) must throw');

// assert.strictEqual
if (typeof assert.strictEqual !== 'function') {
throw new Error('Expected assert.strictEqual to be a function');
}
assert.strictEqual(1, 1);
assert.strictEqual('a', 'a');
assert.strictEqual(NaN, NaN); // uses Object.is semantics
threw = false;
try { assert.strictEqual(1, 2); } catch { threw = true; }
if (!threw) throw new Error('assert.strictEqual(1, 2) must throw');

// assert.notStrictEqual
if (typeof assert.notStrictEqual !== 'function') {
throw new Error('Expected assert.notStrictEqual to be a function');
}
assert.notStrictEqual(1, 2);
assert.notStrictEqual('a', 'b');
threw = false;
try { assert.notStrictEqual(1, 1); } catch { threw = true; }
if (!threw) throw new Error('assert.notStrictEqual(1, 1) must throw');

// assert.deepStrictEqual
if (typeof assert.deepStrictEqual !== 'function') {
throw new Error('Expected assert.deepStrictEqual to be a function');
}
assert.deepStrictEqual({ a: 1 }, { a: 1 });
assert.deepStrictEqual([1, 2, 3], [1, 2, 3]);
threw = false;
try { assert.deepStrictEqual({ a: 1 }, { a: 2 }); } catch { threw = true; }
if (!threw) throw new Error('assert.deepStrictEqual({ a: 1 }, { a: 2 }) must throw');

// assert.throws
if (typeof assert.throws !== 'function') {
throw new Error('Expected assert.throws to be a function');
}
assert.throws(() => { throw new Error('oops'); }, /oops/);
assert.throws(() => { throw new TypeError('bad'); }, TypeError);
threw = false;
try { assert.throws(() => { /* does not throw */ }); } catch { threw = true; }
if (!threw) throw new Error('assert.throws must throw when fn does not throw');
27 changes: 27 additions & 0 deletions tests/harness/gc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
if (typeof gcUntil !== 'function') {
throw new Error('Expected a global gcUntil function');
}

// gcUntil should resolve once the condition becomes true
let count = 0;
await gcUntil('test-passes', () => {
count++;
return count >= 2;
});
if (count < 2) {
throw new Error(`Expected condition to be checked at least twice, got ${count}`);
}

// gcUntil should throw after exhausting retries when condition never becomes true
let threw = false;
try {
await gcUntil('test-fails', () => false);
} catch (error) {
threw = true;
if (!error.message.includes('test-fails')) {
throw new Error(`Expected error message to include 'test-fails' but got: ${error.message}`);
}
}
if (!threw) {
throw new Error('gcUntil must throw when the condition never becomes true');
}