Commit Graph
240 Commits
Author SHA1 Message Date
Chris Tate 42954a3266 Add mock.fn and t.mock.fn with Node's calls log and implementation controls
node:test's mock.fn(original[, implementation]) and t.mock.fn compile.
A Mock<F> is the function-with-properties record { %call, mock }: the
callable is a wrapper closure that shares the mock context with the mock
field. The context records each call's arguments, result, error and this,
and keeps the current implementation, the original and the one-time
implementations by call index. fn.mock supports, as in Node 24.22:

- calls, read as a copy of the log;
- callCount();
- mockImplementation(fn);
- mockImplementationOnce(fn[, onCall]), for the next call by default, a
  later registration for the same index replacing the earlier one;
- resetCalls();
- restore(), which brings back the original.

A throwing implementation records the error and rethrows it. Functions
with fixed parameters or a single rest array parameter are supported; a
union return type needs an undefined arm. mock.fn() without an original,
mock.method, the tracker's reset and restoreAll, and t.mock.method are
refused with SC2020.

The node:test fixture mock-fn compares the behavior with Node, and
tests/diagnostics/mock-fences.ts covers the refusals.
2026-10-16 00:22:22 -05:00
Chris Tate de0917284d Merge main 2026-10-16 00:05:07 -05:00
Chris Tate 93dcd9865e Merge main 2026-10-16 00:01:13 -05:00
Chris Tate 681f5ceee7 Add TestContext hooks, plan and fullName, and Node's todo and only rules
node:test changes, matching Node 24.22:

- t.before, t.after, t.beforeEach and t.afterEach lower. t.before runs
  when it is called; a throw fails the test and the subtests that follow,
  which skip their body and beforeEach hooks and run their afterEach hooks.
  t.beforeEach and t.afterEach wrap every descendant subtest. t.after runs
  after the test's afterEach chain, also when the body throws, and a throw
  fails the test.
- t.plan(count) counts the test's t.assert calls and subtests. A mismatch
  fails the test with Node's "plan expected N assertions but received M"
  string, unless an assertion failed first.
- t.fullName joins the names from the outermost suite or test with " > ".
- Tests and suites under a todo suite or test are todo, with a bare TODO
  directive, unless they are skipped or carry their own todo message. A
  todo suite reports its directive.
- describe.only, suite.only and { only: true } on a suite mark it. At each
  level, when a child is marked or contains a marked test or suite, only
  those children run.
- The failing-tests section lists failures in completion order, so
  subtests come before the test that ran them, and prints thrown strings
  quoted, as Node inspects them.

The fixtures ctx-hooks, ctx-plan, todo-suites, suite-variants,
only-nested and thrown-values compare the reporter output and exit code
with Node.
2026-10-15 23:16:04 -05:00
Chris Tate 7c09e1c020 Add assert.deepEqual, partialDeepStrictEqual and the Assert class 2026-10-15 22:01:38 -05:00
Chris Tate 77c9a2ff23 Merge main 2026-10-15 21:48:48 -05:00
Chris Tate 0ebc146405 Merge main 2026-10-15 21:07:04 -05:00
Chris Tate a3b6b05a4c Merge main 2026-10-15 20:42:11 -05:00
Chris Tate b00d65b8be Merge main 2026-10-15 19:57:06 -05:00
Chris Tate eb90bf7eee Merge main 2026-10-15 19:50:35 -05:00
Chris Tate f6dc19ad98 Merge main 2026-10-15 19:13:52 -05:00
Chris Tate f0151d8c17 Merge main 2026-10-15 19:06:52 -05:00
Chris Tate 7bb7cfb6a3 Merge main 2026-10-15 17:36:41 -05:00
Chris Tate 1251a04fdb Merge main 2026-10-15 17:34:50 -05:00
Chris Tate 1be58648bc Merge main 2026-10-15 17:31:00 -05:00
Chris Tate 8e5577b8f1 Merge main 2026-10-15 16:32:49 -05:00
Chris Tate aa5e626b06 Merge main 2026-10-15 16:32:19 -05:00
Chris Tate a5a3588d3d Add net socket address fields, write/end/setTimeout callbacks, close(hadError) and server connection limits
- socket.remotePort, remoteFamily, localAddress, localPort, localFamily,
  bytesRead, readyState, connecting and pending. The peer's fields are
  cached at first read as remoteAddress is (undefined while
  connecting), and the local ones are undefined while connecting and
  after close.
- write(data, cb) runs cb with null once the data is flushed, and
  end(cb) / end(data, cb) once the socket finishes.
- 'close' listeners receive hadError, 'ready' fires after 'connect',
  and 'data' listeners may take the string chunks setEncoding gives.
- setTimeout(ms, cb) adds cb as a once('timeout') listener (0 removes
  it), and setTimeout throws ERR_OUT_OF_RANGE for a negative, NaN or
  infinite msecs where it disabled the timer before. setKeepAlive
  chains.
- server.maxConnections closes connections past the cap and emits
  'drop' with their addresses; server.getConnections(cb) answers the
  count on the next tick.
- net.isIP, isIPv4 and isIPv6 follow Node's address patterns.
- A callback adapted to a void return keeps the identity of the
  function it wraps, so removing it by that function finds it.
Corpus 5644-5647 cover each case.
2026-10-15 15:59:17 -05:00
Chris Tate a8586d2c8d Merge main 2026-10-15 15:31:10 -05:00
Chris Tate 1ffbb28255 Follow Node's getOptions in the fs option checks
The fs validation ladder and the callback dispatch check their options
argument as Node's getOptions does. null, undefined and functions take
the defaults, and a string is the encoding. Numbers, booleans, bigints
and symbols throw ERR_INVALID_ARG_TYPE ('The "options" argument must be
one of type string or object'). assertEncoding lets 'buffer' through;
before, every 'buffer' encoding threw ERR_INVALID_ARG_VALUE.

With 'buffer':
- readFile and readFileSync read the file first, so a missing file
  reports ENOENT. Then buffer.toString('buffer') throws
  ERR_UNKNOWN_ENCODING; an empty file answers "".
- fs.mkdtemp's callback receives the path as a Buffer.
- mkdtempSync, opendirSync, createReadStream and createWriteStream
  throw the fence error.

fs.mkdtemp's callback form now checks its encoding. It also returns its
path in the requested encoding: re-encoded text for names other than
utf8, as the binding does.

Corpus 5545 covers these forms against Node 24.22.
2026-10-15 14:54:07 -05:00
Chris Tate 93371f83c9 Merge main 2026-10-15 13:42:34 -05:00
Chris Tate 9377dab890 Add fs.opendirSync, fs.promises.opendir and fs.Dir
opendirSync(path[, options]) and fs.promises.opendir(path[, options])
return a Dir that reads one Dirent at a time in OS order, as libuv's
uv_fs_readdir does. Dir supports path, readSync(), read(), closeSync(),
close() and for await. readSync and read answer null at the end. A
closed Dir throws ERR_DIR_CLOSED from readSync and closeSync, and
rejects with it from read and close.

for await over a Dir reads with read() until null and closes the Dir
in a finally, as Node's Dir.entries() does: normal exhaustion, break
and a throw all close it, and a loop whose body closes the Dir ends
with ERR_DIR_CLOSED.

A Dir also crosses 'unknown' slots as a native handle (Dir), so a
closure returning one can be passed to untyped JavaScript functions.
Through such a slot, path and closeSync() work, and other members throw
the "not supported yet" Error.

Open failures carry the opendir syscall and no path. options.bufferSize
is checked after the directory opens, with Node's ERR_OUT_OF_RANGE
messages. The options must be an object literal with a numeric
bufferSize and a utf8 encoding. Recursive walks, buffer encodings and
the callback forms are not lowered. TypeScript sources get a compile
diagnostic for them; in JavaScript sources, recursive walks and the
callback forms throw the fence error when the call runs.

Corpus 5544 covers both forms against Node 24.22.
2026-10-15 11:34:00 -05:00
Chris Tate edda7b99cd Merge main 2026-10-15 11:19:22 -05:00
Chris Tate c2940acacc Merge main 2026-10-15 11:13:49 -05:00
Chris Tate 8f350a5441 Find fs callbacks where Node's signatures put them 2026-10-15 10:56:41 -05:00
Chris Tate b706f2cef8 Merge main 2026-10-15 10:03:55 -05:00
Chris Tate d92b6c4ec8 Merge main 2026-10-15 09:23:58 -05:00
Chris Tate e779d212d8 Merge main 2026-10-15 09:21:42 -05:00
Chris Tate 59cdda3930 Merge main 2026-10-15 09:20:01 -05:00
Chris Tate cffc2ee71f Merge main 2026-10-15 09:18:26 -05:00
Chris Tate f325b5f116 Add the missing fs/promises functions and Node's fs argument checks 2026-10-15 09:13:46 -05:00
Chris Tate 1121fe20c2 Merge main 2026-10-15 08:18:16 -05:00
Chris Tate 2c00672bca Merge main 2026-10-15 08:09:02 -05:00
Chris Tate aecd35b6c2 Merge main 2026-10-15 08:03:25 -05:00
Chris Tate 0b468e40a1 Add fs.globSync, fs.glob and fs/promises glob
The three glob entry points run a port of Node 24's
lib/internal/fs/glob.js walk in scr_glob.c: the same LIFO queue of
(path, patterns) items over the sorted directory listings, the same
lstat, stat, readdir, realpath and seen-pattern caches, the same result
set in insertion order, and the same exclusion checks, so matches come
out in Node's order. Patterns compile with the existing minimatch port.
glob_match is split into a compile step and a test step so the walk can
reuse each compiled pattern and test it segment by segment.
nocaseMagicOnly is now an option, because exclude patterns turn it off.

Patterns (a string or string array) and options (cwd as a path or
file: URL, exclude as patterns or a function, followSymlinks,
withFileTypes) are validated in Node's order with Node's errors,
including the internal assertion Node hits for a non-string cwd with
exclude patterns. withFileTypes results are Dirent rows: name,
parentPath and the type probes. parentPath follows Node's rule for each
form: the joined path for globSync, the resolved path for fs/promises
glob.

fs.glob checks the callback and validates synchronously, then delivers
string[] or the walk's error through the filesystem callback queue.
fs/promises glob lowers as the source of a for await loop. The walk runs
when the loop starts, and the matches found before an error bind before
the error is thrown, as Node's async iterator yields them first. The
older glob(3)-based fs.glob branch is removed.

Corpus 5448-5452 and a node-types fixture check the behavior against
Node.
2026-10-15 07:59:19 -05:00
Chris Tate 31ba299f87 Complete fs.Stats in both lanes (#1025) 2026-10-15 07:54:30 -05:00
Chris Tate b86d83f525 Merge main into createCipheriv support 2026-10-15 05:22:43 -05:00
Chris Tate 9c11a8d1ff Merge main 2026-10-15 04:54:28 -05:00
Chris Tate bbc1d6d0b0 Merge main 2026-10-15 04:52:43 -05:00
Chris Tate af67284e3a Merge main 2026-10-15 04:50:57 -05:00
Chris Tate 7e99752246 Split the Limitations page into partials
docs/content/docs/limitations.mdx now holds the frontmatter, the
headings, the anchor spans and one <include> line per partial. The text
moves unchanged to docs/content/limitations/: one file per labeled
bullet (<section>/<label>.mdx) and one per section's other text
(<section>.mdx). Edits to different bullets no longer touch adjacent
lines of one file.

remarkDocsConventions splices the included partials into the page and
joins the lists that consecutive bullet partials contribute, so the page,
its Markdown twin and the search index render as before. The route tests
read the page with its partials inlined. A page that includes partials
takes its last-modified date, used by the sitemap, from the newest commit
to the page or any of its partials.

docs/scripts/limitations-partials.mjs joins the partials back into one
file, splits a single-file page, and merges a branch's edits to the
single-file page into the partials.
2026-10-15 04:31:49 -05:00
Chris Tate a08fbd2746 Merge main into createCipheriv support 2026-10-15 03:12:04 -05:00
Chris Tate 9a1effd421 Complete fs.Stats in the typed and callback lanes 2026-10-15 03:03:32 -05:00
Chris Tate 15202442be Merge main 2026-10-15 02:52:25 -05:00
Chris Tate 0b27e07e7a Merge main 2026-10-15 02:38:31 -05:00
Chris Tate 5d3315e268 Merge main 2026-10-15 02:36:37 -05:00
Chris Tate 4819818cdf Add assert.AssertionError with Node's properties and constructor
Assertion failures throw an assert.AssertionError with Node 24.22's
generatedMessage, code, actual, expected, operator and diff properties,
in Node's key order. new AssertionError(options) validates its options
and builds Node's message from operator, actual and expected.
AssertionError type annotations, instanceof and assert.throws(fn,
AssertionError) compile.

Failure paths record actual, expected and operator before they throw;
passing assertions do no extra work. The deep forms lower through a
per-type function that returns the verdict, so the operands stay call
temporaries. assert.equal and notEqual inspect their operands only when
they fail.

Values without a checked-dynamic form, and values whose type can be
cyclic, record undefined.
2026-10-15 02:27:13 -05:00
Chris Tate 5336966743 Merge main into createCipheriv support
Keeps the cipher support together with the hash, random and
timingSafeEqual surface added on main.
2026-10-15 02:22:02 -05:00
Chris Tate 1843399f25 Pass results from fs.mkdir, readFile and write callback forms 2026-10-15 02:18:22 -05:00
Chris Tate 14bcd1aad4 Add secret KeyObjects: createSecretKey, generateKey and generateKeySync
crypto.createSecretKey and generateKey/generateKeySync for "hmac" and
"aes" return SecretKeyObject values, native dyn handles over a copy of
the key bytes. The type and symmetricKeySize getters, export() as a
Buffer or a JWK, equals(), instanceof KeyObject, String(),
JSON.stringify and util.inspect follow Node 24.22, as do the argument
checks, their order and their errors. createHmac and hkdf/hkdfSync
accept these keys. toCryptoKey() and KeyObject.from() need WebCrypto
values and are refused with SC2020.

Dyn handle ops gain a @@toStringTag that differs from the class name
and a flag for views with no properties, which util.inspect prints at
any depth. KeyObject method calls dispatch through dynInvoke.
2026-10-15 01:51:36 -05:00