summaryrefslogtreecommitdiff
path: root/tests/node_compat/test
diff options
context:
space:
mode:
authorMatt Mastracci <matthew@mastracci.com>2024-02-10 13:22:13 -0700
committerGitHub <noreply@github.com>2024-02-10 20:22:13 +0000
commitf5e46c9bf2f50d66a953fa133161fc829cecff06 (patch)
tree8faf2f5831c1c7b11d842cd9908d141082c869a5 /tests/node_compat/test
parentd2477f780630a812bfd65e3987b70c0d309385bb (diff)
chore: move cli/tests/ -> tests/ (#22369)
This looks like a massive PR, but it's only a move from cli/tests -> tests, and updates of relative paths for files. This is the first step towards aggregate all of the integration test files under tests/, which will lead to a set of integration tests that can run without the CLI binary being built. While we could leave these tests under `cli`, it would require us to keep a more complex directory structure for the various test runners. In addition, we have a lot of complexity to ignore various test files in the `cli` project itself (cargo publish exclusion rules, autotests = false, etc). And finally, the `tests/` folder will eventually house the `test_ffi`, `test_napi` and other testing code, reducing the size of the root repo directory. For easier review, the extremely large and noisy "move" is in the first commit (with no changes -- just a move), while the remainder of the changes to actual files is in the second commit.
Diffstat (limited to 'tests/node_compat/test')
-rw-r--r--tests/node_compat/test/common/child_process.js56
-rw-r--r--tests/node_compat/test/common/countdown.js35
-rw-r--r--tests/node_compat/test/common/dns.js327
-rw-r--r--tests/node_compat/test/common/duplexpair.js55
-rw-r--r--tests/node_compat/test/common/fixtures.js45
-rw-r--r--tests/node_compat/test/common/hijackstdio.js39
-rw-r--r--tests/node_compat/test/common/index.js496
-rw-r--r--tests/node_compat/test/common/index.mjs115
-rw-r--r--tests/node_compat/test/common/internet.js68
-rw-r--r--tests/node_compat/test/common/package.json1
-rw-r--r--tests/node_compat/test/common/tmpdir.js79
-rw-r--r--tests/node_compat/test/fixtures/GH-1899-output.js30
-rw-r--r--tests/node_compat/test/fixtures/a.js53
-rw-r--r--tests/node_compat/test/fixtures/child-process-spawn-node.js14
-rw-r--r--tests/node_compat/test/fixtures/child_process_should_emit_error.js36
-rw-r--r--tests/node_compat/test/fixtures/echo.js41
-rw-r--r--tests/node_compat/test/fixtures/elipses.txt1
-rw-r--r--tests/node_compat/test/fixtures/empty.txt0
-rw-r--r--tests/node_compat/test/fixtures/exit.js31
-rw-r--r--tests/node_compat/test/fixtures/keys/agent1-cert.pem23
-rw-r--r--tests/node_compat/test/fixtures/keys/agent1-key.pem27
-rw-r--r--tests/node_compat/test/fixtures/keys/ca1-cert.pem22
-rw-r--r--tests/node_compat/test/fixtures/loop.js17
-rw-r--r--tests/node_compat/test/fixtures/package.json1
-rw-r--r--tests/node_compat/test/fixtures/print-chars.js35
-rw-r--r--tests/node_compat/test/fixtures/x.txt1
-rw-r--r--tests/node_compat/test/internet/package.json1
-rw-r--r--tests/node_compat/test/internet/test-dns-any.js194
-rw-r--r--tests/node_compat/test/internet/test-dns-idna2008.js76
-rw-r--r--tests/node_compat/test/internet/test-dns-ipv4.js257
-rw-r--r--tests/node_compat/test/internet/test-dns-ipv6.js250
-rw-r--r--tests/node_compat/test/internet/test-dns-lookup.js61
-rw-r--r--tests/node_compat/test/internet/test-dns-promises-resolve.js49
-rw-r--r--tests/node_compat/test/internet/test-dns-regress-6244.js35
-rw-r--r--tests/node_compat/test/internet/test-dns-setserver-in-callback-of-resolve4.js25
-rw-r--r--tests/node_compat/test/internet/test-dns.js766
-rw-r--r--tests/node_compat/test/internet/test-http-https-default-ports.js46
-rw-r--r--tests/node_compat/test/parallel/package.json1
-rw-r--r--tests/node_compat/test/parallel/test-assert-async.js244
-rw-r--r--tests/node_compat/test/parallel/test-assert-fail.js51
-rw-r--r--tests/node_compat/test/parallel/test-assert-strict-exists.js13
-rw-r--r--tests/node_compat/test/parallel/test-assert.js1615
-rw-r--r--tests/node_compat/test/parallel/test-bad-unicode.js40
-rw-r--r--tests/node_compat/test/parallel/test-btoa-atob.js46
-rw-r--r--tests/node_compat/test/parallel/test-buffer-alloc.js1200
-rw-r--r--tests/node_compat/test/parallel/test-buffer-arraybuffer.js159
-rw-r--r--tests/node_compat/test/parallel/test-buffer-ascii.js53
-rw-r--r--tests/node_compat/test/parallel/test-buffer-badhex.js55
-rw-r--r--tests/node_compat/test/parallel/test-buffer-bigint64.js62
-rw-r--r--tests/node_compat/test/parallel/test-buffer-bytelength.js139
-rw-r--r--tests/node_compat/test/parallel/test-buffer-compare-offset.js101
-rw-r--r--tests/node_compat/test/parallel/test-buffer-concat.js107
-rw-r--r--tests/node_compat/test/parallel/test-buffer-constants.js25
-rw-r--r--tests/node_compat/test/parallel/test-buffer-copy.js243
-rw-r--r--tests/node_compat/test/parallel/test-buffer-equals.js32
-rw-r--r--tests/node_compat/test/parallel/test-buffer-failed-alloc-typed-arrays.js40
-rw-r--r--tests/node_compat/test/parallel/test-buffer-fakes.js61
-rw-r--r--tests/node_compat/test/parallel/test-buffer-from.js73
-rw-r--r--tests/node_compat/test/parallel/test-buffer-includes.js317
-rw-r--r--tests/node_compat/test/parallel/test-buffer-indexof.js646
-rw-r--r--tests/node_compat/test/parallel/test-buffer-inheritance.js46
-rw-r--r--tests/node_compat/test/parallel/test-buffer-isencoding.js45
-rw-r--r--tests/node_compat/test/parallel/test-buffer-iterator.js69
-rw-r--r--tests/node_compat/test/parallel/test-buffer-new.js18
-rw-r--r--tests/node_compat/test/parallel/test-buffer-no-negative-allocation.js45
-rw-r--r--tests/node_compat/test/parallel/test-buffer-nopendingdep-map.js20
-rw-r--r--tests/node_compat/test/parallel/test-buffer-of-no-deprecation.js14
-rw-r--r--tests/node_compat/test/parallel/test-buffer-over-max-length.js37
-rw-r--r--tests/node_compat/test/parallel/test-buffer-parent-property.js28
-rw-r--r--tests/node_compat/test/parallel/test-buffer-read.js113
-rw-r--r--tests/node_compat/test/parallel/test-buffer-readdouble.js151
-rw-r--r--tests/node_compat/test/parallel/test-buffer-readfloat.js113
-rw-r--r--tests/node_compat/test/parallel/test-buffer-readint.js204
-rw-r--r--tests/node_compat/test/parallel/test-buffer-readuint.js172
-rw-r--r--tests/node_compat/test/parallel/test-buffer-safe-unsafe.js31
-rw-r--r--tests/node_compat/test/parallel/test-buffer-slice.js136
-rw-r--r--tests/node_compat/test/parallel/test-buffer-slow.js69
-rw-r--r--tests/node_compat/test/parallel/test-buffer-swap.js159
-rw-r--r--tests/node_compat/test/parallel/test-buffer-tojson.js42
-rw-r--r--tests/node_compat/test/parallel/test-buffer-tostring-range.js107
-rw-r--r--tests/node_compat/test/parallel/test-buffer-tostring-rangeerror.js28
-rw-r--r--tests/node_compat/test/parallel/test-buffer-tostring.js44
-rw-r--r--tests/node_compat/test/parallel/test-buffer-writedouble.js140
-rw-r--r--tests/node_compat/test/parallel/test-buffer-writefloat.js124
-rw-r--r--tests/node_compat/test/parallel/test-buffer-writeint.js277
-rw-r--r--tests/node_compat/test/parallel/test-buffer-writeuint.js237
-rw-r--r--tests/node_compat/test/parallel/test-buffer-zero-fill-cli.js39
-rw-r--r--tests/node_compat/test/parallel/test-buffer-zero-fill-reset.js26
-rw-r--r--tests/node_compat/test/parallel/test-buffer-zero-fill.js21
-rw-r--r--tests/node_compat/test/parallel/test-child-process-default-options.js58
-rw-r--r--tests/node_compat/test/parallel/test-child-process-double-pipe.js129
-rw-r--r--tests/node_compat/test/parallel/test-child-process-exec-abortcontroller-promisified.js54
-rw-r--r--tests/node_compat/test/parallel/test-child-process-exec-cwd.js46
-rw-r--r--tests/node_compat/test/parallel/test-child-process-exec-encoding.js59
-rw-r--r--tests/node_compat/test/parallel/test-child-process-exec-env.js71
-rw-r--r--tests/node_compat/test/parallel/test-child-process-exec-error.js51
-rw-r--r--tests/node_compat/test/parallel/test-child-process-exec-kill-throws.js42
-rw-r--r--tests/node_compat/test/parallel/test-child-process-exec-maxbuf.js161
-rw-r--r--tests/node_compat/test/parallel/test-child-process-exec-std-encoding.js33
-rw-r--r--tests/node_compat/test/parallel/test-child-process-exec-stdout-stderr-data-string.js20
-rw-r--r--tests/node_compat/test/parallel/test-child-process-exec-timeout-not-expired.js45
-rw-r--r--tests/node_compat/test/parallel/test-child-process-execfile-maxbuf.js99
-rw-r--r--tests/node_compat/test/parallel/test-child-process-execfile.js135
-rw-r--r--tests/node_compat/test/parallel/test-child-process-execfilesync-maxbuf.js60
-rw-r--r--tests/node_compat/test/parallel/test-child-process-execsync-maxbuf.js76
-rw-r--r--tests/node_compat/test/parallel/test-child-process-exit-code.js51
-rw-r--r--tests/node_compat/test/parallel/test-child-process-flush-stdio.js40
-rw-r--r--tests/node_compat/test/parallel/test-child-process-fork-ref.js72
-rw-r--r--tests/node_compat/test/parallel/test-child-process-fork-ref2.js63
-rw-r--r--tests/node_compat/test/parallel/test-child-process-ipc-next-tick.js52
-rw-r--r--tests/node_compat/test/parallel/test-child-process-ipc.js73
-rw-r--r--tests/node_compat/test/parallel/test-child-process-kill.js48
-rw-r--r--tests/node_compat/test/parallel/test-child-process-set-blocking.js43
-rw-r--r--tests/node_compat/test/parallel/test-child-process-spawn-args.js62
-rw-r--r--tests/node_compat/test/parallel/test-child-process-spawn-event.js34
-rw-r--r--tests/node_compat/test/parallel/test-child-process-spawnsync-args.js55
-rw-r--r--tests/node_compat/test/parallel/test-child-process-spawnsync-env.js47
-rw-r--r--tests/node_compat/test/parallel/test-child-process-spawnsync-maxbuf.js65
-rw-r--r--tests/node_compat/test/parallel/test-child-process-spawnsync-validation-errors.js223
-rw-r--r--tests/node_compat/test/parallel/test-child-process-spawnsync.js74
-rw-r--r--tests/node_compat/test/parallel/test-child-process-stdio-inherit.js66
-rw-r--r--tests/node_compat/test/parallel/test-child-process-stdout-flush-exit.js67
-rw-r--r--tests/node_compat/test/parallel/test-child-process-stdout-flush.js58
-rw-r--r--tests/node_compat/test/parallel/test-console-async-write-error.js22
-rw-r--r--tests/node_compat/test/parallel/test-console-group.js248
-rw-r--r--tests/node_compat/test/parallel/test-console-instance.js156
-rw-r--r--tests/node_compat/test/parallel/test-console-log-stdio-broken-dest.js31
-rw-r--r--tests/node_compat/test/parallel/test-console-log-throw-primitive.js21
-rw-r--r--tests/node_compat/test/parallel/test-console-no-swallow-stack-overflow.js26
-rw-r--r--tests/node_compat/test/parallel/test-console-sync-write-error.js46
-rw-r--r--tests/node_compat/test/parallel/test-console-table.js300
-rw-r--r--tests/node_compat/test/parallel/test-console-tty-colors.js102
-rw-r--r--tests/node_compat/test/parallel/test-crypto-dh-shared.js22
-rw-r--r--tests/node_compat/test/parallel/test-crypto-dh.js214
-rw-r--r--tests/node_compat/test/parallel/test-crypto-hkdf.js203
-rw-r--r--tests/node_compat/test/parallel/test-crypto-hmac.js483
-rw-r--r--tests/node_compat/test/parallel/test-crypto-prime.js302
-rw-r--r--tests/node_compat/test/parallel/test-crypto-secret-keygen.js144
-rw-r--r--tests/node_compat/test/parallel/test-crypto-stream.js96
-rw-r--r--tests/node_compat/test/parallel/test-crypto-update-encoding.js29
-rw-r--r--tests/node_compat/test/parallel/test-crypto-x509.js109
-rw-r--r--tests/node_compat/test/parallel/test-dgram-close-during-bind.js26
-rw-r--r--tests/node_compat/test/parallel/test-dgram-close-signal.js38
-rw-r--r--tests/node_compat/test/parallel/test-dgram-custom-lookup.js56
-rw-r--r--tests/node_compat/test/parallel/test-dgram-ipv6only.js44
-rw-r--r--tests/node_compat/test/parallel/test-dgram-send-cb-quelches-error.js47
-rw-r--r--tests/node_compat/test/parallel/test-dgram-socket-buffer-size.js178
-rw-r--r--tests/node_compat/test/parallel/test-dgram-udp6-link-local-address.js61
-rw-r--r--tests/node_compat/test/parallel/test-diagnostics-channel-has-subscribers.js17
-rw-r--r--tests/node_compat/test/parallel/test-diagnostics-channel-object-channel-pub-sub.js53
-rw-r--r--tests/node_compat/test/parallel/test-diagnostics-channel-pub-sub.js51
-rw-r--r--tests/node_compat/test/parallel/test-diagnostics-channel-symbol-named.js35
-rw-r--r--tests/node_compat/test/parallel/test-diagnostics-channel-udp.js22
-rw-r--r--tests/node_compat/test/parallel/test-dns-lookup.js179
-rw-r--r--tests/node_compat/test/parallel/test-dns-memory-error.js23
-rw-r--r--tests/node_compat/test/parallel/test-dns-promises-exists.js40
-rw-r--r--tests/node_compat/test/parallel/test-dns-resolveany.js78
-rw-r--r--tests/node_compat/test/parallel/test-dns-resolvens-typeerror.js62
-rw-r--r--tests/node_compat/test/parallel/test-dns-setservers-type-check.js127
-rw-r--r--tests/node_compat/test/parallel/test-dns.js471
-rw-r--r--tests/node_compat/test/parallel/test-eval-strict-referenceerror.js34
-rw-r--r--tests/node_compat/test/parallel/test-eval.js14
-rw-r--r--tests/node_compat/test/parallel/test-event-emitter-add-listeners.js93
-rw-r--r--tests/node_compat/test/parallel/test-event-emitter-emit-context.js25
-rw-r--r--tests/node_compat/test/parallel/test-event-emitter-error-monitor.js39
-rw-r--r--tests/node_compat/test/parallel/test-event-emitter-errors.js44
-rw-r--r--tests/node_compat/test/parallel/test-event-emitter-get-max-listeners.js26
-rw-r--r--tests/node_compat/test/parallel/test-event-emitter-invalid-listener.js27
-rw-r--r--tests/node_compat/test/parallel/test-event-emitter-listener-count.js25
-rw-r--r--tests/node_compat/test/parallel/test-event-emitter-listeners-side-effects.js67
-rw-r--r--tests/node_compat/test/parallel/test-event-emitter-listeners.js131
-rw-r--r--tests/node_compat/test/parallel/test-event-emitter-max-listeners.js80
-rw-r--r--tests/node_compat/test/parallel/test-event-emitter-method-names.js42
-rw-r--r--tests/node_compat/test/parallel/test-event-emitter-modify-in-emit.js87
-rw-r--r--tests/node_compat/test/parallel/test-event-emitter-no-error-provided-to-error-event.js65
-rw-r--r--tests/node_compat/test/parallel/test-event-emitter-num-args.js61
-rw-r--r--tests/node_compat/test/parallel/test-event-emitter-once.js77
-rw-r--r--tests/node_compat/test/parallel/test-event-emitter-prepend.js50
-rw-r--r--tests/node_compat/test/parallel/test-event-emitter-remove-all-listeners.js130
-rw-r--r--tests/node_compat/test/parallel/test-event-emitter-remove-listeners.js177
-rw-r--r--tests/node_compat/test/parallel/test-event-emitter-set-max-listeners-side-effects.js39
-rw-r--r--tests/node_compat/test/parallel/test-event-emitter-special-event-names.js44
-rw-r--r--tests/node_compat/test/parallel/test-event-emitter-subclass.js74
-rw-r--r--tests/node_compat/test/parallel/test-event-emitter-symbols.js30
-rw-r--r--tests/node_compat/test/parallel/test-events-list.js26
-rw-r--r--tests/node_compat/test/parallel/test-events-on-async-iterator.js399
-rw-r--r--tests/node_compat/test/parallel/test-events-once.js272
-rw-r--r--tests/node_compat/test/parallel/test-events-uncaught-exception-stack.js23
-rw-r--r--tests/node_compat/test/parallel/test-eventtarget-brandcheck.js104
-rw-r--r--tests/node_compat/test/parallel/test-exception-handler.js47
-rw-r--r--tests/node_compat/test/parallel/test-exception-handler2.js43
-rw-r--r--tests/node_compat/test/parallel/test-file-read-noexist.js39
-rw-r--r--tests/node_compat/test/parallel/test-file-write-stream.js91
-rw-r--r--tests/node_compat/test/parallel/test-file-write-stream2.js116
-rw-r--r--tests/node_compat/test/parallel/test-file-write-stream3.js221
-rw-r--r--tests/node_compat/test/parallel/test-file-write-stream4.js28
-rw-r--r--tests/node_compat/test/parallel/test-fs-access.js242
-rw-r--r--tests/node_compat/test/parallel/test-fs-append-file-sync.js115
-rw-r--r--tests/node_compat/test/parallel/test-fs-append-file.js202
-rw-r--r--tests/node_compat/test/parallel/test-fs-chmod-mask.js106
-rw-r--r--tests/node_compat/test/parallel/test-fs-chmod.js167
-rw-r--r--tests/node_compat/test/parallel/test-fs-chown-type-check.js60
-rw-r--r--tests/node_compat/test/parallel/test-fs-copyfile.js174
-rw-r--r--tests/node_compat/test/parallel/test-fs-empty-readStream.js57
-rw-r--r--tests/node_compat/test/parallel/test-fs-mkdir.js379
-rw-r--r--tests/node_compat/test/parallel/test-fs-open-flags.js101
-rw-r--r--tests/node_compat/test/parallel/test-fs-open-mode-mask.js48
-rw-r--r--tests/node_compat/test/parallel/test-fs-open-no-close.js38
-rw-r--r--tests/node_compat/test/parallel/test-fs-open-numeric-flags.js23
-rw-r--r--tests/node_compat/test/parallel/test-fs-open.js128
-rw-r--r--tests/node_compat/test/parallel/test-fs-opendir.js300
-rw-r--r--tests/node_compat/test/parallel/test-fs-read-stream-autoClose.js23
-rw-r--r--tests/node_compat/test/parallel/test-fs-read-stream-concurrent-reads.js54
-rw-r--r--tests/node_compat/test/parallel/test-fs-read-stream-double-close.js26
-rw-r--r--tests/node_compat/test/parallel/test-fs-read-stream-encoding.js24
-rw-r--r--tests/node_compat/test/parallel/test-fs-read-stream-fd.js53
-rw-r--r--tests/node_compat/test/parallel/test-fs-read-stream-inherit.js212
-rw-r--r--tests/node_compat/test/parallel/test-fs-read-stream-patch-open.js24
-rw-r--r--tests/node_compat/test/parallel/test-fs-read-stream-resume.js59
-rw-r--r--tests/node_compat/test/parallel/test-fs-read-stream-throw-type-error.js84
-rw-r--r--tests/node_compat/test/parallel/test-fs-read-stream.js284
-rw-r--r--tests/node_compat/test/parallel/test-fs-read-type.js250
-rw-r--r--tests/node_compat/test/parallel/test-fs-read-zero-length.js25
-rw-r--r--tests/node_compat/test/parallel/test-fs-read.js109
-rw-r--r--tests/node_compat/test/parallel/test-fs-readdir-stack-overflow.js26
-rw-r--r--tests/node_compat/test/parallel/test-fs-readdir.js60
-rw-r--r--tests/node_compat/test/parallel/test-fs-readfile-empty.js52
-rw-r--r--tests/node_compat/test/parallel/test-fs-realpath-native.js25
-rw-r--r--tests/node_compat/test/parallel/test-fs-rmdir-recursive-sync-warns-not-found.js30
-rw-r--r--tests/node_compat/test/parallel/test-fs-rmdir-recursive-sync-warns-on-file.js30
-rw-r--r--tests/node_compat/test/parallel/test-fs-rmdir-recursive-throws-not-found.js43
-rw-r--r--tests/node_compat/test/parallel/test-fs-rmdir-recursive-throws-on-file.js36
-rw-r--r--tests/node_compat/test/parallel/test-fs-rmdir-recursive-warns-not-found.js29
-rw-r--r--tests/node_compat/test/parallel/test-fs-rmdir-recursive-warns-on-file.js29
-rw-r--r--tests/node_compat/test/parallel/test-fs-rmdir-recursive.js252
-rw-r--r--tests/node_compat/test/parallel/test-fs-rmdir-type-check.js29
-rw-r--r--tests/node_compat/test/parallel/test-fs-watchfile.js112
-rw-r--r--tests/node_compat/test/parallel/test-fs-write-buffer.js172
-rw-r--r--tests/node_compat/test/parallel/test-fs-write-file-buffer.js62
-rw-r--r--tests/node_compat/test/parallel/test-fs-write-file-invalid-path.js53
-rw-r--r--tests/node_compat/test/parallel/test-fs-write-file-sync.js128
-rw-r--r--tests/node_compat/test/parallel/test-fs-write-file.js115
-rw-r--r--tests/node_compat/test/parallel/test-fs-write-no-fd.js19
-rw-r--r--tests/node_compat/test/parallel/test-fs-write-stream-autoclose-option.js66
-rw-r--r--tests/node_compat/test/parallel/test-fs-write-stream-close-without-callback.js20
-rw-r--r--tests/node_compat/test/parallel/test-fs-write-stream-double-close.js53
-rw-r--r--tests/node_compat/test/parallel/test-fs-write-stream-end.js67
-rw-r--r--tests/node_compat/test/parallel/test-fs-write-stream-fs.js45
-rw-r--r--tests/node_compat/test/parallel/test-fs-write-stream-throw-type-error.js39
-rw-r--r--tests/node_compat/test/parallel/test-fs-write-stream.js74
-rw-r--r--tests/node_compat/test/parallel/test-fs-write-sync.js63
-rw-r--r--tests/node_compat/test/parallel/test-fs-write.js212
-rw-r--r--tests/node_compat/test/parallel/test-fs-writev-sync.js104
-rw-r--r--tests/node_compat/test/parallel/test-handle-wrap-close-abort.js44
-rw-r--r--tests/node_compat/test/parallel/test-http-agent-getname.js63
-rw-r--r--tests/node_compat/test/parallel/test-http-client-get-url.js53
-rw-r--r--tests/node_compat/test/parallel/test-http-client-read-in-error.js48
-rw-r--r--tests/node_compat/test/parallel/test-http-localaddress.js64
-rw-r--r--tests/node_compat/test/parallel/test-http-outgoing-internal-headernames-getter.js30
-rw-r--r--tests/node_compat/test/parallel/test-http-outgoing-internal-headernames-setter.js22
-rw-r--r--tests/node_compat/test/parallel/test-http-outgoing-internal-headers.js51
-rw-r--r--tests/node_compat/test/parallel/test-http-outgoing-renderHeaders.js57
-rw-r--r--tests/node_compat/test/parallel/test-http-outgoing-settimeout.js37
-rw-r--r--tests/node_compat/test/parallel/test-http-url.parse-auth-with-header-in-request.js59
-rw-r--r--tests/node_compat/test/parallel/test-http-url.parse-auth.js55
-rw-r--r--tests/node_compat/test/parallel/test-http-url.parse-basic.js65
-rw-r--r--tests/node_compat/test/parallel/test-http-url.parse-https.request.js69
-rw-r--r--tests/node_compat/test/parallel/test-http-url.parse-only-support-http-https-protocol.js52
-rw-r--r--tests/node_compat/test/parallel/test-http-url.parse-path.js53
-rw-r--r--tests/node_compat/test/parallel/test-http-url.parse-post.js61
-rw-r--r--tests/node_compat/test/parallel/test-http-url.parse-search.js54
-rw-r--r--tests/node_compat/test/parallel/test-net-access-byteswritten.js28
-rw-r--r--tests/node_compat/test/parallel/test-net-better-error-messages-listen-path.js17
-rw-r--r--tests/node_compat/test/parallel/test-net-better-error-messages-path.js29
-rw-r--r--tests/node_compat/test/parallel/test-net-better-error-messages-port-hostname.js44
-rw-r--r--tests/node_compat/test/parallel/test-net-connect-after-destroy.js16
-rw-r--r--tests/node_compat/test/parallel/test-net-connect-buffer.js86
-rw-r--r--tests/node_compat/test/parallel/test-net-connect-buffer2.js63
-rw-r--r--tests/node_compat/test/parallel/test-net-connect-destroy.js14
-rw-r--r--tests/node_compat/test/parallel/test-net-connect-immediate-destroy.js18
-rw-r--r--tests/node_compat/test/parallel/test-net-connect-immediate-finish.js66
-rw-r--r--tests/node_compat/test/parallel/test-net-connect-no-arg.js42
-rw-r--r--tests/node_compat/test/parallel/test-net-dns-error.js48
-rw-r--r--tests/node_compat/test/parallel/test-net-during-close.js49
-rw-r--r--tests/node_compat/test/parallel/test-net-end-close.js44
-rw-r--r--tests/node_compat/test/parallel/test-net-end-without-connect.js34
-rw-r--r--tests/node_compat/test/parallel/test-net-isip.js103
-rw-r--r--tests/node_compat/test/parallel/test-net-isipv4.js53
-rw-r--r--tests/node_compat/test/parallel/test-net-isipv6.js251
-rw-r--r--tests/node_compat/test/parallel/test-net-listen-close-server-callback-is-not-function.js18
-rw-r--r--tests/node_compat/test/parallel/test-net-listen-close-server.js37
-rw-r--r--tests/node_compat/test/parallel/test-net-listen-invalid-port.js52
-rw-r--r--tests/node_compat/test/parallel/test-net-listening.js23
-rw-r--r--tests/node_compat/test/parallel/test-net-localerror.js51
-rw-r--r--tests/node_compat/test/parallel/test-net-options-lookup.js59
-rw-r--r--tests/node_compat/test/parallel/test-net-pipe-connect-errors.js104
-rw-r--r--tests/node_compat/test/parallel/test-net-server-call-listen-multiple-times.js56
-rw-r--r--tests/node_compat/test/parallel/test-net-server-listen-options-signal.js39
-rw-r--r--tests/node_compat/test/parallel/test-net-server-listen-options.js101
-rw-r--r--tests/node_compat/test/parallel/test-net-server-listen-path.js100
-rw-r--r--tests/node_compat/test/parallel/test-net-server-listen-remove-callback.js51
-rw-r--r--tests/node_compat/test/parallel/test-net-server-options.js23
-rw-r--r--tests/node_compat/test/parallel/test-net-server-try-ports.js54
-rw-r--r--tests/node_compat/test/parallel/test-net-server-unref-persistent.js19
-rw-r--r--tests/node_compat/test/parallel/test-net-server-unref.js37
-rw-r--r--tests/node_compat/test/parallel/test-net-socket-destroy-twice.js43
-rw-r--r--tests/node_compat/test/parallel/test-net-socket-no-halfopen-enforcer.js18
-rw-r--r--tests/node_compat/test/parallel/test-net-socket-timeout.js88
-rw-r--r--tests/node_compat/test/parallel/test-net-timeout-no-handle.js24
-rw-r--r--tests/node_compat/test/parallel/test-net-write-arguments.js46
-rw-r--r--tests/node_compat/test/parallel/test-next-tick-doesnt-hang.js37
-rw-r--r--tests/node_compat/test/parallel/test-next-tick-fixed-queue-regression.js25
-rw-r--r--tests/node_compat/test/parallel/test-next-tick-intentional-starvation.js68
-rw-r--r--tests/node_compat/test/parallel/test-next-tick-ordering.js62
-rw-r--r--tests/node_compat/test/parallel/test-next-tick-ordering2.js46
-rw-r--r--tests/node_compat/test/parallel/test-next-tick-when-exiting.js21
-rw-r--r--tests/node_compat/test/parallel/test-next-tick.js70
-rw-r--r--tests/node_compat/test/parallel/test-nodeeventtarget.js190
-rw-r--r--tests/node_compat/test/parallel/test-os.js280
-rw-r--r--tests/node_compat/test/parallel/test-outgoing-message-destroy.js20
-rw-r--r--tests/node_compat/test/parallel/test-outgoing-message-pipe.js22
-rw-r--r--tests/node_compat/test/parallel/test-parse-args.mjs1001
-rw-r--r--tests/node_compat/test/parallel/test-path-basename.js83
-rw-r--r--tests/node_compat/test/parallel/test-path-dirname.js66
-rw-r--r--tests/node_compat/test/parallel/test-path-extname.js106
-rw-r--r--tests/node_compat/test/parallel/test-path-isabsolute.js35
-rw-r--r--tests/node_compat/test/parallel/test-path-join.js150
-rw-r--r--tests/node_compat/test/parallel/test-path-makelong.js94
-rw-r--r--tests/node_compat/test/parallel/test-path-normalize.js79
-rw-r--r--tests/node_compat/test/parallel/test-path-parse-format.js233
-rw-r--r--tests/node_compat/test/parallel/test-path-posix-exists.js13
-rw-r--r--tests/node_compat/test/parallel/test-path-relative.js76
-rw-r--r--tests/node_compat/test/parallel/test-path-resolve.js96
-rw-r--r--tests/node_compat/test/parallel/test-path-win32-exists.js13
-rw-r--r--tests/node_compat/test/parallel/test-path-zero-length-strings.js46
-rw-r--r--tests/node_compat/test/parallel/test-path.js80
-rw-r--r--tests/node_compat/test/parallel/test-process-beforeexit.js88
-rw-r--r--tests/node_compat/test/parallel/test-process-binding-internalbinding-allowlist.js48
-rw-r--r--tests/node_compat/test/parallel/test-process-env-allowed-flags.js109
-rw-r--r--tests/node_compat/test/parallel/test-process-exit-from-before-exit.js37
-rw-r--r--tests/node_compat/test/parallel/test-process-exit-handler.js21
-rw-r--r--tests/node_compat/test/parallel/test-process-exit-recursive.js44
-rw-r--r--tests/node_compat/test/parallel/test-process-exit.js42
-rw-r--r--tests/node_compat/test/parallel/test-process-kill-pid.js116
-rw-r--r--tests/node_compat/test/parallel/test-process-uptime.js44
-rw-r--r--tests/node_compat/test/parallel/test-promise-unhandled-silent.js28
-rw-r--r--tests/node_compat/test/parallel/test-promise-unhandled-throw-handler.js43
-rw-r--r--tests/node_compat/test/parallel/test-querystring-escape.js48
-rw-r--r--tests/node_compat/test/parallel/test-querystring-maxKeys-non-finite.js65
-rw-r--r--tests/node_compat/test/parallel/test-querystring-multichar-separator.js32
-rw-r--r--tests/node_compat/test/parallel/test-querystring.js489
-rw-r--r--tests/node_compat/test/parallel/test-readline-emit-keypress-events.js79
-rw-r--r--tests/node_compat/test/parallel/test-readline-interface-escapecodetimeout.js53
-rw-r--r--tests/node_compat/test/parallel/test-readline-interface.js1217
-rw-r--r--tests/node_compat/test/parallel/test-readline-keys.js351
-rw-r--r--tests/node_compat/test/parallel/test-readline-position.js43
-rw-r--r--tests/node_compat/test/parallel/test-readline-reopen.js51
-rw-r--r--tests/node_compat/test/parallel/test-readline-set-raw-mode.js97
-rw-r--r--tests/node_compat/test/parallel/test-readline-undefined-columns.js53
-rw-r--r--tests/node_compat/test/parallel/test-readline.js158
-rw-r--r--tests/node_compat/test/parallel/test-stdin-from-file-spawn.js52
-rw-r--r--tests/node_compat/test/parallel/test-stream-add-abort-signal.js34
-rw-r--r--tests/node_compat/test/parallel/test-stream-aliases-legacy.js21
-rw-r--r--tests/node_compat/test/parallel/test-stream-auto-destroy.js119
-rw-r--r--tests/node_compat/test/parallel/test-stream-await-drain-writers-in-synchronously-recursion-write.js35
-rw-r--r--tests/node_compat/test/parallel/test-stream-backpressure.js46
-rw-r--r--tests/node_compat/test/parallel/test-stream-big-packet.js72
-rw-r--r--tests/node_compat/test/parallel/test-stream-big-push.js81
-rw-r--r--tests/node_compat/test/parallel/test-stream-buffer-list.js91
-rw-r--r--tests/node_compat/test/parallel/test-stream-construct.js287
-rw-r--r--tests/node_compat/test/parallel/test-stream-destroy-event-order.js31
-rw-r--r--tests/node_compat/test/parallel/test-stream-duplex-destroy.js264
-rw-r--r--tests/node_compat/test/parallel/test-stream-duplex-end.js48
-rw-r--r--tests/node_compat/test/parallel/test-stream-duplex-from.js413
-rw-r--r--tests/node_compat/test/parallel/test-stream-duplex-props.js38
-rw-r--r--tests/node_compat/test/parallel/test-stream-duplex-readable-end.js36
-rw-r--r--tests/node_compat/test/parallel/test-stream-duplex-writable-finished.js37
-rw-r--r--tests/node_compat/test/parallel/test-stream-duplex.js140
-rw-r--r--tests/node_compat/test/parallel/test-stream-end-paused.js57
-rw-r--r--tests/node_compat/test/parallel/test-stream-error-once.js26
-rw-r--r--tests/node_compat/test/parallel/test-stream-events-prepend.js33
-rw-r--r--tests/node_compat/test/parallel/test-stream-inheritance.js70
-rw-r--r--tests/node_compat/test/parallel/test-stream-ispaused.js51
-rw-r--r--tests/node_compat/test/parallel/test-stream-objectmode-undefined.js51
-rw-r--r--tests/node_compat/test/parallel/test-stream-once-readable-pipe.js68
-rw-r--r--tests/node_compat/test/parallel/test-stream-pipe-after-end.js76
-rw-r--r--tests/node_compat/test/parallel/test-stream-pipe-await-drain-manual-resume.js82
-rw-r--r--tests/node_compat/test/parallel/test-stream-pipe-await-drain-push-while-write.js43
-rw-r--r--tests/node_compat/test/parallel/test-stream-pipe-await-drain.js74
-rw-r--r--tests/node_compat/test/parallel/test-stream-pipe-cleanup-pause.js44
-rw-r--r--tests/node_compat/test/parallel/test-stream-pipe-cleanup.js132
-rw-r--r--tests/node_compat/test/parallel/test-stream-pipe-error-handling.js131
-rw-r--r--tests/node_compat/test/parallel/test-stream-pipe-event.js58
-rw-r--r--tests/node_compat/test/parallel/test-stream-pipe-flow-after-unpipe.js36
-rw-r--r--tests/node_compat/test/parallel/test-stream-pipe-flow.js97
-rw-r--r--tests/node_compat/test/parallel/test-stream-pipe-manual-resume.js42
-rw-r--r--tests/node_compat/test/parallel/test-stream-pipe-multiple-pipes.js58
-rw-r--r--tests/node_compat/test/parallel/test-stream-pipe-needDrain.js38
-rw-r--r--tests/node_compat/test/parallel/test-stream-pipe-same-destination-twice.js85
-rw-r--r--tests/node_compat/test/parallel/test-stream-pipe-unpipe-streams.js103
-rw-r--r--tests/node_compat/test/parallel/test-stream-pipe-without-listenerCount.js24
-rw-r--r--tests/node_compat/test/parallel/test-stream-pipeline-async-iterator.js38
-rw-r--r--tests/node_compat/test/parallel/test-stream-pipeline-queued-end-in-destroy.js46
-rw-r--r--tests/node_compat/test/parallel/test-stream-pipeline-with-empty-string.js25
-rw-r--r--tests/node_compat/test/parallel/test-stream-push-strings.js74
-rw-r--r--tests/node_compat/test/parallel/test-stream-readable-aborted.js73
-rw-r--r--tests/node_compat/test/parallel/test-stream-readable-add-chunk-during-data.js28
-rw-r--r--tests/node_compat/test/parallel/test-stream-readable-constructor-set-methods.js18
-rw-r--r--tests/node_compat/test/parallel/test-stream-readable-data.js26
-rw-r--r--tests/node_compat/test/parallel/test-stream-readable-destroy.js412
-rw-r--r--tests/node_compat/test/parallel/test-stream-readable-didRead.js118
-rw-r--r--tests/node_compat/test/parallel/test-stream-readable-emit-readable-short-stream.js153
-rw-r--r--tests/node_compat/test/parallel/test-stream-readable-emittedReadable.js80
-rw-r--r--tests/node_compat/test/parallel/test-stream-readable-end-destroyed.js24
-rw-r--r--tests/node_compat/test/parallel/test-stream-readable-ended.js53
-rw-r--r--tests/node_compat/test/parallel/test-stream-readable-error-end.js22
-rw-r--r--tests/node_compat/test/parallel/test-stream-readable-event.js135
-rw-r--r--tests/node_compat/test/parallel/test-stream-readable-flow-recursion.js84
-rw-r--r--tests/node_compat/test/parallel/test-stream-readable-hwm-0-async.js34
-rw-r--r--tests/node_compat/test/parallel/test-stream-readable-hwm-0-no-flow-data.js111
-rw-r--r--tests/node_compat/test/parallel/test-stream-readable-hwm-0.js37
-rw-r--r--tests/node_compat/test/parallel/test-stream-readable-infinite-read.js39
-rw-r--r--tests/node_compat/test/parallel/test-stream-readable-invalid-chunk.js41
-rw-r--r--tests/node_compat/test/parallel/test-stream-readable-needReadable.js106
-rw-r--r--tests/node_compat/test/parallel/test-stream-readable-next-no-null.js26
-rw-r--r--tests/node_compat/test/parallel/test-stream-readable-no-unneeded-readable.js69
-rw-r--r--tests/node_compat/test/parallel/test-stream-readable-object-multi-push-async.js190
-rw-r--r--tests/node_compat/test/parallel/test-stream-readable-pause-and-resume.js81
-rw-r--r--tests/node_compat/test/parallel/test-stream-readable-readable-then-resume.js38
-rw-r--r--tests/node_compat/test/parallel/test-stream-readable-readable.js52
-rw-r--r--tests/node_compat/test/parallel/test-stream-readable-reading-readingMore.js178
-rw-r--r--tests/node_compat/test/parallel/test-stream-readable-resume-hwm.js28
-rw-r--r--tests/node_compat/test/parallel/test-stream-readable-resumeScheduled.js72
-rw-r--r--tests/node_compat/test/parallel/test-stream-readable-setEncoding-existing-buffers.js67
-rw-r--r--tests/node_compat/test/parallel/test-stream-readable-setEncoding-null.js22
-rw-r--r--tests/node_compat/test/parallel/test-stream-readable-unshift.js177
-rw-r--r--tests/node_compat/test/parallel/test-stream-readable-with-unimplemented-_read.js20
-rw-r--r--tests/node_compat/test/parallel/test-stream-readableListening-state.js41
-rw-r--r--tests/node_compat/test/parallel/test-stream-transform-callback-twice.js21
-rw-r--r--tests/node_compat/test/parallel/test-stream-transform-constructor-set-methods.js50
-rw-r--r--tests/node_compat/test/parallel/test-stream-transform-destroy.js150
-rw-r--r--tests/node_compat/test/parallel/test-stream-transform-final-sync.js117
-rw-r--r--tests/node_compat/test/parallel/test-stream-transform-final.js119
-rw-r--r--tests/node_compat/test/parallel/test-stream-transform-flush-data.js35
-rw-r--r--tests/node_compat/test/parallel/test-stream-transform-objectmode-falsey-value.js58
-rw-r--r--tests/node_compat/test/parallel/test-stream-transform-split-highwatermark.js80
-rw-r--r--tests/node_compat/test/parallel/test-stream-transform-split-objectmode.js88
-rw-r--r--tests/node_compat/test/parallel/test-stream-uint8array.js108
-rw-r--r--tests/node_compat/test/parallel/test-stream-unpipe-event.js92
-rw-r--r--tests/node_compat/test/parallel/test-stream-unshift-empty-chunk.js87
-rw-r--r--tests/node_compat/test/parallel/test-stream-unshift-read-race.js135
-rw-r--r--tests/node_compat/test/parallel/test-stream-writable-change-default-encoding.js85
-rw-r--r--tests/node_compat/test/parallel/test-stream-writable-clear-buffer.js42
-rw-r--r--tests/node_compat/test/parallel/test-stream-writable-constructor-set-methods.js48
-rw-r--r--tests/node_compat/test/parallel/test-stream-writable-decoded-encoding.js65
-rw-r--r--tests/node_compat/test/parallel/test-stream-writable-destroy.js496
-rw-r--r--tests/node_compat/test/parallel/test-stream-writable-end-cb-error.js85
-rw-r--r--tests/node_compat/test/parallel/test-stream-writable-end-multiple.js29
-rw-r--r--tests/node_compat/test/parallel/test-stream-writable-ended-state.js39
-rw-r--r--tests/node_compat/test/parallel/test-stream-writable-finish-destroyed.js50
-rw-r--r--tests/node_compat/test/parallel/test-stream-writable-finished-state.js29
-rw-r--r--tests/node_compat/test/parallel/test-stream-writable-finished.js106
-rw-r--r--tests/node_compat/test/parallel/test-stream-writable-invalid-chunk.js43
-rw-r--r--tests/node_compat/test/parallel/test-stream-writable-needdrain-state.js32
-rw-r--r--tests/node_compat/test/parallel/test-stream-writable-null.js54
-rw-r--r--tests/node_compat/test/parallel/test-stream-writable-properties.js29
-rw-r--r--tests/node_compat/test/parallel/test-stream-writable-writable.js55
-rw-r--r--tests/node_compat/test/parallel/test-stream-writable-write-cb-error.js65
-rw-r--r--tests/node_compat/test/parallel/test-stream-writable-write-cb-twice.js59
-rw-r--r--tests/node_compat/test/parallel/test-stream-writable-write-error.js82
-rw-r--r--tests/node_compat/test/parallel/test-stream-writable-write-writev-finish.js159
-rw-r--r--tests/node_compat/test/parallel/test-stream-writableState-ending.js44
-rw-r--r--tests/node_compat/test/parallel/test-stream-writableState-uncorked-bufferedRequestCount.js64
-rw-r--r--tests/node_compat/test/parallel/test-stream-write-destroy.js69
-rw-r--r--tests/node_compat/test/parallel/test-stream-write-drain.js23
-rw-r--r--tests/node_compat/test/parallel/test-stream-write-final.js31
-rw-r--r--tests/node_compat/test/parallel/test-stream-writev.js137
-rw-r--r--tests/node_compat/test/parallel/test-stream2-base64-single-char-read-end.js63
-rw-r--r--tests/node_compat/test/parallel/test-stream2-basic.js452
-rw-r--r--tests/node_compat/test/parallel/test-stream2-compatibility.js77
-rw-r--r--tests/node_compat/test/parallel/test-stream2-decode-partial.js30
-rw-r--r--tests/node_compat/test/parallel/test-stream2-finish-pipe.js51
-rw-r--r--tests/node_compat/test/parallel/test-stream2-large-read-stall.js81
-rw-r--r--tests/node_compat/test/parallel/test-stream2-objects.js304
-rw-r--r--tests/node_compat/test/parallel/test-stream2-pipe-error-handling.js113
-rw-r--r--tests/node_compat/test/parallel/test-stream2-pipe-error-once-listener.js60
-rw-r--r--tests/node_compat/test/parallel/test-stream2-push.js143
-rw-r--r--tests/node_compat/test/parallel/test-stream2-read-sync-stack.js53
-rw-r--r--tests/node_compat/test/parallel/test-stream2-readable-empty-buffer-no-eof.js124
-rw-r--r--tests/node_compat/test/parallel/test-stream2-readable-from-list.js108
-rw-r--r--tests/node_compat/test/parallel/test-stream2-readable-legacy-drain.js62
-rw-r--r--tests/node_compat/test/parallel/test-stream2-readable-non-empty-end.js79
-rw-r--r--tests/node_compat/test/parallel/test-stream2-readable-wrap-destroy.js34
-rw-r--r--tests/node_compat/test/parallel/test-stream2-readable-wrap-empty.js45
-rw-r--r--tests/node_compat/test/parallel/test-stream2-readable-wrap-error.js44
-rw-r--r--tests/node_compat/test/parallel/test-stream2-readable-wrap.js107
-rw-r--r--tests/node_compat/test/parallel/test-stream2-set-encoding.js330
-rw-r--r--tests/node_compat/test/parallel/test-stream2-transform.js501
-rw-r--r--tests/node_compat/test/parallel/test-stream2-unpipe-drain.js79
-rw-r--r--tests/node_compat/test/parallel/test-stream2-unpipe-leak.js80
-rw-r--r--tests/node_compat/test/parallel/test-stream2-writable.js466
-rw-r--r--tests/node_compat/test/parallel/test-stream3-cork-end.js98
-rw-r--r--tests/node_compat/test/parallel/test-stream3-cork-uncork.js93
-rw-r--r--tests/node_compat/test/parallel/test-stream3-pause-then-read.js177
-rw-r--r--tests/node_compat/test/parallel/test-streams-highwatermark.js94
-rw-r--r--tests/node_compat/test/parallel/test-timers-api-refs.js28
-rw-r--r--tests/node_compat/test/parallel/test-timers-args.js38
-rw-r--r--tests/node_compat/test/parallel/test-timers-clear-null-does-not-throw-error.js18
-rw-r--r--tests/node_compat/test/parallel/test-timers-clear-object-does-not-throw-error.js15
-rw-r--r--tests/node_compat/test/parallel/test-timers-clear-timeout-interval-equivalent.js25
-rw-r--r--tests/node_compat/test/parallel/test-timers-clearImmediate.js20
-rw-r--r--tests/node_compat/test/parallel/test-timers-interval-throw.js24
-rw-r--r--tests/node_compat/test/parallel/test-timers-non-integer-delay.js88
-rw-r--r--tests/node_compat/test/parallel/test-timers-refresh.js109
-rw-r--r--tests/node_compat/test/parallel/test-timers-same-timeout-wrong-list-deleted.js41
-rw-r--r--tests/node_compat/test/parallel/test-timers-timeout-with-non-integer.js22
-rw-r--r--tests/node_compat/test/parallel/test-timers-uncaught-exception.js46
-rw-r--r--tests/node_compat/test/parallel/test-timers-unref-throw-then-ref.js26
-rw-r--r--tests/node_compat/test/parallel/test-timers-user-call.js47
-rw-r--r--tests/node_compat/test/parallel/test-timers-zero-timeout.js56
-rw-r--r--tests/node_compat/test/parallel/test-tty-stdin-end.js14
-rw-r--r--tests/node_compat/test/parallel/test-ttywrap-invalid-fd.js74
-rw-r--r--tests/node_compat/test/parallel/test-url-domain-ascii-unicode.js38
-rw-r--r--tests/node_compat/test/parallel/test-url-fileurltopath.js161
-rw-r--r--tests/node_compat/test/parallel/test-url-format-invalid-input.js34
-rw-r--r--tests/node_compat/test/parallel/test-url-format-whatwg.js149
-rw-r--r--tests/node_compat/test/parallel/test-url-format.js284
-rw-r--r--tests/node_compat/test/parallel/test-url-parse-invalid-input.js83
-rw-r--r--tests/node_compat/test/parallel/test-url-parse-query.js97
-rw-r--r--tests/node_compat/test/parallel/test-url-pathtofileurl.js153
-rw-r--r--tests/node_compat/test/parallel/test-url-relative.js441
-rw-r--r--tests/node_compat/test/parallel/test-url-urltooptions.js45
-rw-r--r--tests/node_compat/test/parallel/test-util-deprecate-invalid-code.js21
-rw-r--r--tests/node_compat/test/parallel/test-util-deprecate.js64
-rw-r--r--tests/node_compat/test/parallel/test-util-format.js504
-rw-r--r--tests/node_compat/test/parallel/test-util-inherits.js117
-rw-r--r--tests/node_compat/test/parallel/test-util-inspect-long-running.js27
-rw-r--r--tests/node_compat/test/parallel/test-util-inspect-namespace.js28
-rw-r--r--tests/node_compat/test/parallel/test-util-inspect-proxy.js172
-rw-r--r--tests/node_compat/test/parallel/test-util-inspect.js3201
-rw-r--r--tests/node_compat/test/parallel/test-util-isDeepStrictEqual.js608
-rw-r--r--tests/node_compat/test/parallel/test-util-promisify.js218
-rw-r--r--tests/node_compat/test/parallel/test-util-types-exists.js13
-rw-r--r--tests/node_compat/test/parallel/test-util-types.js304
-rw-r--r--tests/node_compat/test/parallel/test-util.js202
-rw-r--r--tests/node_compat/test/parallel/test-vm-new-script-this-context.js75
-rw-r--r--tests/node_compat/test/parallel/test-vm-static-this.js72
-rw-r--r--tests/node_compat/test/parallel/test-webcrypto-sign-verify.js154
-rw-r--r--tests/node_compat/test/parallel/test-whatwg-encoding-custom-api-basics.js68
-rw-r--r--tests/node_compat/test/parallel/test-whatwg-encoding-custom-textdecoder-ignorebom.js37
-rw-r--r--tests/node_compat/test/parallel/test-whatwg-encoding-custom-textdecoder-streaming.js45
-rw-r--r--tests/node_compat/test/parallel/test-whatwg-events-add-event-listener-options-passive.js72
-rw-r--r--tests/node_compat/test/parallel/test-whatwg-events-add-event-listener-options-signal.js166
-rw-r--r--tests/node_compat/test/parallel/test-whatwg-events-customevent.js40
-rw-r--r--tests/node_compat/test/parallel/test-whatwg-url-custom-deepequal.js25
-rw-r--r--tests/node_compat/test/parallel/test-whatwg-url-custom-global.js33
-rw-r--r--tests/node_compat/test/parallel/test-whatwg-url-custom-href-side-effect.js22
-rw-r--r--tests/node_compat/test/parallel/test-whatwg-url-custom-tostringtag.js39
-rw-r--r--tests/node_compat/test/parallel/test-whatwg-url-override-hostname.js27
-rw-r--r--tests/node_compat/test/parallel/test-whatwg-url-properties.js111
-rw-r--r--tests/node_compat/test/parallel/test-zlib-close-after-error.js23
-rw-r--r--tests/node_compat/test/parallel/test-zlib-close-after-write.js37
-rw-r--r--tests/node_compat/test/parallel/test-zlib-convenience-methods.js144
-rw-r--r--tests/node_compat/test/parallel/test-zlib-deflate-raw-inherits.js34
-rw-r--r--tests/node_compat/test/parallel/test-zlib-destroy-pipe.js28
-rw-r--r--tests/node_compat/test/parallel/test-zlib-empty-buffer.js35
-rw-r--r--tests/node_compat/test/parallel/test-zlib-from-string.js90
-rw-r--r--tests/node_compat/test/parallel/test-zlib-invalid-input.js68
-rw-r--r--tests/node_compat/test/parallel/test-zlib-no-stream.js21
-rw-r--r--tests/node_compat/test/parallel/test-zlib-random-byte-pipes.js166
-rw-r--r--tests/node_compat/test/parallel/test-zlib-sync-no-event.js26
-rw-r--r--tests/node_compat/test/parallel/test-zlib-truncated.js71
-rw-r--r--tests/node_compat/test/parallel/test-zlib-unzip-one-byte-chunks.js37
-rw-r--r--tests/node_compat/test/parallel/test-zlib-write-after-end.js23
-rw-r--r--tests/node_compat/test/parallel/test-zlib-write-after-flush.js57
-rw-r--r--tests/node_compat/test/parallel/test-zlib-zero-byte.js53
-rw-r--r--tests/node_compat/test/parallel/test-zlib-zero-windowBits.js41
-rw-r--r--tests/node_compat/test/pseudo-tty/console-dumb-tty.js16
-rw-r--r--tests/node_compat/test/pseudo-tty/console_colors.js29
-rw-r--r--tests/node_compat/test/pseudo-tty/no_dropped_stdio.js26
-rw-r--r--tests/node_compat/test/pseudo-tty/no_interleaved_stdio.js28
-rw-r--r--tests/node_compat/test/pseudo-tty/package.json1
-rw-r--r--tests/node_compat/test/pseudo-tty/test-tty-color-support-warning-2.js15
-rw-r--r--tests/node_compat/test/pseudo-tty/test-tty-color-support-warning.js16
-rw-r--r--tests/node_compat/test/pseudo-tty/test-tty-stdin-end.js14
-rw-r--r--tests/node_compat/test/pseudo-tty/test-tty-stdout-end.js11
-rw-r--r--tests/node_compat/test/pummel/package.json1
-rw-r--r--tests/node_compat/test/sequential/package.json1
-rw-r--r--tests/node_compat/test/sequential/test-child-process-exit.js69
589 files changed, 58527 insertions, 0 deletions
diff --git a/tests/node_compat/test/common/child_process.js b/tests/node_compat/test/common/child_process.js
new file mode 100644
index 000000000..b860d7697
--- /dev/null
+++ b/tests/node_compat/test/common/child_process.js
@@ -0,0 +1,56 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const assert = require('assert');
+const common = require('./');
+
+// Workaround for Windows Server 2008R2
+// When CMD is used to launch a process and CMD is killed too quickly, the
+// process can stay behind running in suspended state, never completing.
+function cleanupStaleProcess(filename) {
+ if (!common.isWindows) {
+ return;
+ }
+ process.once('beforeExit', () => {
+ const basename = filename.replace(/.*[/\\]/g, '');
+ try {
+ require('child_process')
+ .execFileSync(`${process.env.SystemRoot}\\System32\\wbem\\WMIC.exe`, [
+ 'process',
+ 'where',
+ `commandline like '%${basename}%child'`,
+ 'delete',
+ '/nointeractive',
+ ]);
+ } catch {
+ // Ignore failures, there might not be any stale process to clean up.
+ }
+ });
+}
+
+// This should keep the child process running long enough to expire
+// the timeout.
+const kExpiringChildRunTime = common.platformTimeout(20 * 1000);
+const kExpiringParentTimer = 1;
+assert(kExpiringChildRunTime > kExpiringParentTimer);
+
+function logAfterTime(time) {
+ setTimeout(() => {
+ // The following console statements are part of the test.
+ console.log('child stdout');
+ console.error('child stderr');
+ }, time);
+}
+
+module.exports = {
+ cleanupStaleProcess,
+ logAfterTime,
+ kExpiringChildRunTime,
+ kExpiringParentTimer,
+};
diff --git a/tests/node_compat/test/common/countdown.js b/tests/node_compat/test/common/countdown.js
new file mode 100644
index 000000000..a7ae0d029
--- /dev/null
+++ b/tests/node_compat/test/common/countdown.js
@@ -0,0 +1,35 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const assert = require('assert');
+const kLimit = Symbol('limit');
+const kCallback = Symbol('callback');
+const common = require('./');
+
+class Countdown {
+ constructor(limit, cb) {
+ assert.strictEqual(typeof limit, 'number');
+ assert.strictEqual(typeof cb, 'function');
+ this[kLimit] = limit;
+ this[kCallback] = common.mustCall(cb);
+ }
+
+ dec() {
+ assert(this[kLimit] > 0, 'Countdown expired');
+ if (--this[kLimit] === 0)
+ this[kCallback]();
+ return this[kLimit];
+ }
+
+ get remaining() {
+ return this[kLimit];
+ }
+}
+
+module.exports = Countdown;
diff --git a/tests/node_compat/test/common/dns.js b/tests/node_compat/test/common/dns.js
new file mode 100644
index 000000000..54df6a55e
--- /dev/null
+++ b/tests/node_compat/test/common/dns.js
@@ -0,0 +1,327 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const assert = require('assert');
+const os = require('os');
+
+const types = {
+ A: 1,
+ AAAA: 28,
+ NS: 2,
+ CNAME: 5,
+ SOA: 6,
+ PTR: 12,
+ MX: 15,
+ TXT: 16,
+ ANY: 255,
+ CAA: 257,
+};
+
+const classes = {
+ IN: 1,
+};
+
+// Naïve DNS parser/serializer.
+
+function readDomainFromPacket(buffer, offset) {
+ assert.ok(offset < buffer.length);
+ const length = buffer[offset];
+ if (length === 0) {
+ return { nread: 1, domain: '' };
+ } else if ((length & 0xC0) === 0) {
+ offset += 1;
+ const chunk = buffer.toString('ascii', offset, offset + length);
+ // Read the rest of the domain.
+ const { nread, domain } = readDomainFromPacket(buffer, offset + length);
+ return {
+ nread: 1 + length + nread,
+ domain: domain ? `${chunk}.${domain}` : chunk,
+ };
+ }
+ // Pointer to another part of the packet.
+ assert.strictEqual(length & 0xC0, 0xC0);
+ // eslint-disable-next-line space-infix-ops, space-unary-ops
+ const pointeeOffset = buffer.readUInt16BE(offset) &~ 0xC000;
+ return {
+ nread: 2,
+ domain: readDomainFromPacket(buffer, pointeeOffset),
+ };
+}
+
+function parseDNSPacket(buffer) {
+ assert.ok(buffer.length > 12);
+
+ const parsed = {
+ id: buffer.readUInt16BE(0),
+ flags: buffer.readUInt16BE(2),
+ };
+
+ const counts = [
+ ['questions', buffer.readUInt16BE(4)],
+ ['answers', buffer.readUInt16BE(6)],
+ ['authorityAnswers', buffer.readUInt16BE(8)],
+ ['additionalRecords', buffer.readUInt16BE(10)],
+ ];
+
+ let offset = 12;
+ for (const [ sectionName, count ] of counts) {
+ parsed[sectionName] = [];
+ for (let i = 0; i < count; ++i) {
+ const { nread, domain } = readDomainFromPacket(buffer, offset);
+ offset += nread;
+
+ const type = buffer.readUInt16BE(offset);
+
+ const rr = {
+ domain,
+ cls: buffer.readUInt16BE(offset + 2),
+ };
+ offset += 4;
+
+ for (const name in types) {
+ if (types[name] === type)
+ rr.type = name;
+ }
+
+ if (sectionName !== 'questions') {
+ rr.ttl = buffer.readInt32BE(offset);
+ const dataLength = buffer.readUInt16BE(offset);
+ offset += 6;
+
+ switch (type) {
+ case types.A:
+ assert.strictEqual(dataLength, 4);
+ rr.address = `${buffer[offset + 0]}.${buffer[offset + 1]}.` +
+ `${buffer[offset + 2]}.${buffer[offset + 3]}`;
+ break;
+ case types.AAAA:
+ assert.strictEqual(dataLength, 16);
+ rr.address = buffer.toString('hex', offset, offset + 16)
+ .replace(/(.{4}(?!$))/g, '$1:');
+ break;
+ case types.TXT:
+ {
+ let position = offset;
+ rr.entries = [];
+ while (position < offset + dataLength) {
+ const txtLength = buffer[offset];
+ rr.entries.push(buffer.toString('utf8',
+ position + 1,
+ position + 1 + txtLength));
+ position += 1 + txtLength;
+ }
+ assert.strictEqual(position, offset + dataLength);
+ break;
+ }
+ case types.MX:
+ {
+ rr.priority = buffer.readInt16BE(buffer, offset);
+ offset += 2;
+ const { nread, domain } = readDomainFromPacket(buffer, offset);
+ rr.exchange = domain;
+ assert.strictEqual(nread, dataLength);
+ break;
+ }
+ case types.NS:
+ case types.CNAME:
+ case types.PTR:
+ {
+ const { nread, domain } = readDomainFromPacket(buffer, offset);
+ rr.value = domain;
+ assert.strictEqual(nread, dataLength);
+ break;
+ }
+ case types.SOA:
+ {
+ const mname = readDomainFromPacket(buffer, offset);
+ const rname = readDomainFromPacket(buffer, offset + mname.nread);
+ rr.nsname = mname.domain;
+ rr.hostmaster = rname.domain;
+ const trailerOffset = offset + mname.nread + rname.nread;
+ rr.serial = buffer.readUInt32BE(trailerOffset);
+ rr.refresh = buffer.readUInt32BE(trailerOffset + 4);
+ rr.retry = buffer.readUInt32BE(trailerOffset + 8);
+ rr.expire = buffer.readUInt32BE(trailerOffset + 12);
+ rr.minttl = buffer.readUInt32BE(trailerOffset + 16);
+
+ assert.strictEqual(trailerOffset + 20, dataLength);
+ break;
+ }
+ default:
+ throw new Error(`Unknown RR type ${rr.type}`);
+ }
+ offset += dataLength;
+ }
+
+ parsed[sectionName].push(rr);
+
+ assert.ok(offset <= buffer.length);
+ }
+ }
+
+ assert.strictEqual(offset, buffer.length);
+ return parsed;
+}
+
+function writeIPv6(ip) {
+ const parts = ip.replace(/^:|:$/g, '').split(':');
+ const buf = Buffer.alloc(16);
+
+ let offset = 0;
+ for (const part of parts) {
+ if (part === '') {
+ offset += 16 - 2 * (parts.length - 1);
+ } else {
+ buf.writeUInt16BE(parseInt(part, 16), offset);
+ offset += 2;
+ }
+ }
+
+ return buf;
+}
+
+function writeDomainName(domain) {
+ return Buffer.concat(domain.split('.').map((label) => {
+ assert(label.length < 64);
+ return Buffer.concat([
+ Buffer.from([label.length]),
+ Buffer.from(label, 'ascii'),
+ ]);
+ }).concat([Buffer.alloc(1)]));
+}
+
+function writeDNSPacket(parsed) {
+ const buffers = [];
+ const kStandardResponseFlags = 0x8180;
+
+ buffers.push(new Uint16Array([
+ parsed.id,
+ parsed.flags === undefined ? kStandardResponseFlags : parsed.flags,
+ parsed.questions && parsed.questions.length,
+ parsed.answers && parsed.answers.length,
+ parsed.authorityAnswers && parsed.authorityAnswers.length,
+ parsed.additionalRecords && parsed.additionalRecords.length,
+ ]));
+
+ for (const q of parsed.questions) {
+ assert(types[q.type]);
+ buffers.push(writeDomainName(q.domain));
+ buffers.push(new Uint16Array([
+ types[q.type],
+ q.cls === undefined ? classes.IN : q.cls,
+ ]));
+ }
+
+ for (const rr of [].concat(parsed.answers,
+ parsed.authorityAnswers,
+ parsed.additionalRecords)) {
+ if (!rr) continue;
+
+ assert(types[rr.type]);
+ buffers.push(writeDomainName(rr.domain));
+ buffers.push(new Uint16Array([
+ types[rr.type],
+ rr.cls === undefined ? classes.IN : rr.cls,
+ ]));
+ buffers.push(new Int32Array([rr.ttl]));
+
+ const rdLengthBuf = new Uint16Array(1);
+ buffers.push(rdLengthBuf);
+
+ switch (rr.type) {
+ case 'A':
+ rdLengthBuf[0] = 4;
+ buffers.push(new Uint8Array(rr.address.split('.')));
+ break;
+ case 'AAAA':
+ rdLengthBuf[0] = 16;
+ buffers.push(writeIPv6(rr.address));
+ break;
+ case 'TXT': {
+ const total = rr.entries.map((s) => s.length).reduce((a, b) => a + b);
+ // Total length of all strings + 1 byte each for their lengths.
+ rdLengthBuf[0] = rr.entries.length + total;
+ for (const txt of rr.entries) {
+ buffers.push(new Uint8Array([Buffer.byteLength(txt)]));
+ buffers.push(Buffer.from(txt));
+ }
+ break;
+ }
+ case 'MX':
+ rdLengthBuf[0] = 2;
+ buffers.push(new Uint16Array([rr.priority]));
+ // fall through
+ case 'NS':
+ case 'CNAME':
+ case 'PTR':
+ {
+ const domain = writeDomainName(rr.exchange || rr.value);
+ rdLengthBuf[0] += domain.length;
+ buffers.push(domain);
+ break;
+ }
+ case 'SOA':
+ {
+ const mname = writeDomainName(rr.nsname);
+ const rname = writeDomainName(rr.hostmaster);
+ rdLengthBuf[0] = mname.length + rname.length + 20;
+ buffers.push(mname, rname);
+ buffers.push(new Uint32Array([
+ rr.serial, rr.refresh, rr.retry, rr.expire, rr.minttl,
+ ]));
+ break;
+ }
+ case 'CAA':
+ {
+ rdLengthBuf[0] = 5 + rr.issue.length + 2;
+ buffers.push(Buffer.from([Number(rr.critical)]));
+ buffers.push(Buffer.from([Number(5)]));
+ buffers.push(Buffer.from('issue' + rr.issue));
+ break;
+ }
+ default:
+ throw new Error(`Unknown RR type ${rr.type}`);
+ }
+ }
+
+ return Buffer.concat(buffers.map((typedArray) => {
+ const buf = Buffer.from(typedArray.buffer,
+ typedArray.byteOffset,
+ typedArray.byteLength);
+ if (os.endianness() === 'LE') {
+ if (typedArray.BYTES_PER_ELEMENT === 2) buf.swap16();
+ if (typedArray.BYTES_PER_ELEMENT === 4) buf.swap32();
+ }
+ return buf;
+ }));
+}
+
+const mockedErrorCode = 'ENOTFOUND';
+const mockedSysCall = 'getaddrinfo';
+
+function errorLookupMock(code = mockedErrorCode, syscall = mockedSysCall) {
+ return function lookupWithError(hostname, dnsopts, cb) {
+ const err = new Error(`${syscall} ${code} ${hostname}`);
+ err.code = code;
+ err.errno = code;
+ err.syscall = syscall;
+ err.hostname = hostname;
+ cb(err);
+ };
+}
+
+module.exports = {
+ types,
+ classes,
+ writeDNSPacket,
+ parseDNSPacket,
+ errorLookupMock,
+ mockedErrorCode,
+ mockedSysCall,
+};
diff --git a/tests/node_compat/test/common/duplexpair.js b/tests/node_compat/test/common/duplexpair.js
new file mode 100644
index 000000000..6e5286cc8
--- /dev/null
+++ b/tests/node_compat/test/common/duplexpair.js
@@ -0,0 +1,55 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const { Duplex } = require('stream');
+const assert = require('assert');
+
+const kCallback = Symbol('Callback');
+const kOtherSide = Symbol('Other');
+
+class DuplexSocket extends Duplex {
+ constructor() {
+ super();
+ this[kCallback] = null;
+ this[kOtherSide] = null;
+ }
+
+ _read() {
+ const callback = this[kCallback];
+ if (callback) {
+ this[kCallback] = null;
+ callback();
+ }
+ }
+
+ _write(chunk, encoding, callback) {
+ assert.notStrictEqual(this[kOtherSide], null);
+ assert.strictEqual(this[kOtherSide][kCallback], null);
+ if (chunk.length === 0) {
+ process.nextTick(callback);
+ } else {
+ this[kOtherSide].push(chunk);
+ this[kOtherSide][kCallback] = callback;
+ }
+ }
+
+ _final(callback) {
+ this[kOtherSide].on('end', callback);
+ this[kOtherSide].push(null);
+ }
+}
+
+function makeDuplexPair() {
+ const clientSide = new DuplexSocket();
+ const serverSide = new DuplexSocket();
+ clientSide[kOtherSide] = serverSide;
+ serverSide[kOtherSide] = clientSide;
+ return { clientSide, serverSide };
+}
+
+module.exports = makeDuplexPair;
diff --git a/tests/node_compat/test/common/fixtures.js b/tests/node_compat/test/common/fixtures.js
new file mode 100644
index 000000000..64b888eb6
--- /dev/null
+++ b/tests/node_compat/test/common/fixtures.js
@@ -0,0 +1,45 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const path = require('path');
+const fs = require('fs');
+const { pathToFileURL } = require('url');
+
+const fixturesDir = path.join(__dirname, '..', 'fixtures');
+
+function fixturesPath(...args) {
+ return path.join(fixturesDir, ...args);
+}
+
+function fixturesFileURL(...args) {
+ return pathToFileURL(fixturesPath(...args));
+}
+
+function readFixtureSync(args, enc) {
+ if (Array.isArray(args))
+ return fs.readFileSync(fixturesPath(...args), enc);
+ return fs.readFileSync(fixturesPath(args), enc);
+}
+
+function readFixtureKey(name, enc) {
+ return fs.readFileSync(fixturesPath('keys', name), enc);
+}
+
+function readFixtureKeys(enc, ...names) {
+ return names.map((name) => readFixtureKey(name, enc));
+}
+
+module.exports = {
+ fixturesDir,
+ path: fixturesPath,
+ fileURL: fixturesFileURL,
+ readSync: readFixtureSync,
+ readKey: readFixtureKey,
+ readKeys: readFixtureKeys,
+};
diff --git a/tests/node_compat/test/common/hijackstdio.js b/tests/node_compat/test/common/hijackstdio.js
new file mode 100644
index 000000000..38582ece2
--- /dev/null
+++ b/tests/node_compat/test/common/hijackstdio.js
@@ -0,0 +1,39 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+// Hijack stdout and stderr
+const stdWrite = {};
+function hijackStdWritable(name, listener) {
+ const stream = process[name];
+ const _write = stdWrite[name] = stream.write;
+
+ stream.writeTimes = 0;
+ stream.write = function(data, callback) {
+ try {
+ listener(data);
+ } catch (e) {
+ process.nextTick(() => { throw e; });
+ }
+
+ _write.call(stream, data, callback);
+ stream.writeTimes++;
+ };
+}
+
+function restoreWritable(name) {
+ process[name].write = stdWrite[name];
+ delete process[name].writeTimes;
+}
+
+module.exports = {
+ hijackStdout: hijackStdWritable.bind(null, 'stdout'),
+ hijackStderr: hijackStdWritable.bind(null, 'stderr'),
+ restoreStdout: restoreWritable.bind(null, 'stdout'),
+ restoreStderr: restoreWritable.bind(null, 'stderr'),
+};
diff --git a/tests/node_compat/test/common/index.js b/tests/node_compat/test/common/index.js
new file mode 100644
index 000000000..9f5b4814c
--- /dev/null
+++ b/tests/node_compat/test/common/index.js
@@ -0,0 +1,496 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+
+/**
+ * This file is meant as a replacement for the original common/index.js
+ *
+ * That file has a lot of node functionality not currently supported, so this is a lite
+ * version of that file, which most tests should be able to use
+ */
+'use strict';
+const assert = require("assert");
+const path = require("path");
+const util = require("util");
+const tmpdir = require("./tmpdir");
+
+function platformTimeout(ms) {
+ return ms;
+}
+
+let localhostIPv4 = null;
+
+let knownGlobals = [
+ AbortSignal,
+ addEventListener,
+ alert,
+ atob,
+ btoa,
+ Buffer,
+ caches,
+ clearImmediate,
+ close,
+ closed,
+ confirm,
+ console,
+ createImageBitmap,
+ crypto,
+ Deno,
+ dispatchEvent,
+ EventSource,
+ fetch,
+ getParent,
+ global,
+ global.clearInterval,
+ global.clearTimeout,
+ global.setInterval,
+ global.setTimeout,
+ localStorage,
+ location,
+ name,
+ navigator,
+ onload,
+ onunload,
+ process,
+ prompt,
+ queueMicrotask,
+ removeEventListener,
+ reportError,
+ self,
+ sessionStorage,
+ setImmediate,
+ window,
+];
+
+if (global.AbortController)
+ knownGlobals.push(global.AbortController);
+
+if (global.gc) {
+ knownGlobals.push(global.gc);
+}
+
+if (global.performance) {
+ knownGlobals.push(global.performance);
+}
+if (global.PerformanceMark) {
+ knownGlobals.push(global.PerformanceMark);
+}
+if (global.PerformanceMeasure) {
+ knownGlobals.push(global.PerformanceMeasure);
+}
+
+if (global.structuredClone) {
+ knownGlobals.push(global.structuredClone);
+}
+
+function allowGlobals(...allowlist) {
+ knownGlobals = knownGlobals.concat(allowlist);
+}
+
+if (process.env.NODE_TEST_KNOWN_GLOBALS !== '0') {
+ if (process.env.NODE_TEST_KNOWN_GLOBALS) {
+ const knownFromEnv = process.env.NODE_TEST_KNOWN_GLOBALS.split(',');
+ allowGlobals(...knownFromEnv);
+ }
+
+ function leakedGlobals() {
+ const leaked = [];
+
+ for (const val in global) {
+ if (!knownGlobals.includes(global[val])) {
+ leaked.push(val);
+ }
+ }
+
+ return leaked;
+ }
+
+ process.on('exit', function() {
+ const leaked = leakedGlobals();
+ if (leaked.length > 0) {
+ assert.fail(`Unexpected global(s) found: ${leaked.join(', ')}`);
+ }
+ });
+}
+
+function _expectWarning(name, expected, code) {
+ if (typeof expected === 'string') {
+ expected = [[expected, code]];
+ } else if (!Array.isArray(expected)) {
+ expected = Object.entries(expected).map(([a, b]) => [b, a]);
+ } else if (!(Array.isArray(expected[0]))) {
+ expected = [[expected[0], expected[1]]];
+ }
+ // Deprecation codes are mandatory, everything else is not.
+ if (name === 'DeprecationWarning') {
+ expected.forEach(([_, code]) => assert(code, expected));
+ }
+ return mustCall((warning) => {
+ const [ message, code ] = expected.shift();
+ assert.strictEqual(warning.name, name);
+ if (typeof message === 'string') {
+ assert.strictEqual(warning.message, message);
+ } else {
+ assert.match(warning.message, message);
+ }
+ assert.strictEqual(warning.code, code);
+ }, expected.length);
+}
+
+let catchWarning;
+
+// Accepts a warning name and description or array of descriptions or a map of
+// warning names to description(s) ensures a warning is generated for each
+// name/description pair.
+// The expected messages have to be unique per `expectWarning()` call.
+function expectWarning(nameOrMap, expected, code) {
+ if (catchWarning === undefined) {
+ catchWarning = {};
+ process.on('warning', (warning) => {
+ if (!catchWarning[warning.name]) {
+ throw new TypeError(
+ `"${warning.name}" was triggered without being expected.\n` +
+ util.inspect(warning)
+ );
+ }
+ catchWarning[warning.name](warning);
+ });
+ }
+ if (typeof nameOrMap === 'string') {
+ catchWarning[nameOrMap] = _expectWarning(nameOrMap, expected, code);
+ } else {
+ Object.keys(nameOrMap).forEach((name) => {
+ catchWarning[name] = _expectWarning(name, nameOrMap[name]);
+ });
+ }
+}
+
+/**
+ * Useful for testing expected internal/error objects
+ *
+ * @param {Error} error
+ */
+function expectsError(validator, exact) {
+ /**
+ * @param {Error} error
+ */
+ return mustCall((...args) => {
+ if (args.length !== 1) {
+ // Do not use `assert.strictEqual()` to prevent `inspect` from
+ // always being called.
+ assert.fail(`Expected one argument, got ${util.inspect(args)}`);
+ }
+ const error = args.pop();
+ const descriptor = Object.getOwnPropertyDescriptor(error, 'message');
+ // The error message should be non-enumerable
+ assert.strictEqual(descriptor.enumerable, false);
+
+ assert.throws(() => { throw error; }, validator);
+ return true;
+ }, exact);
+}
+
+const noop = () => {};
+
+/**
+ * @param {Function} fn
+ * @param {number} exact
+ */
+function mustCall(fn, exact) {
+ return _mustCallInner(fn, exact, "exact");
+}
+
+function mustCallAtLeast(fn, minimum) {
+ return _mustCallInner(fn, minimum, 'minimum');
+}
+
+function mustSucceed(fn, exact) {
+ return mustCall(function(err, ...args) {
+ assert.ifError(err);
+ if (typeof fn === 'function')
+ return fn.apply(this, args);
+ }, exact);
+}
+
+const mustCallChecks = [];
+/**
+ * @param {number} exitCode
+ */
+function runCallChecks(exitCode) {
+ if (exitCode !== 0) return;
+
+ const failed = mustCallChecks.filter(function (context) {
+ if ("minimum" in context) {
+ context.messageSegment = `at least ${context.minimum}`;
+ return context.actual < context.minimum;
+ }
+ context.messageSegment = `exactly ${context.exact}`;
+ return context.actual !== context.exact;
+ });
+
+ failed.forEach(function (context) {
+ console.log(
+ "Mismatched %s function calls. Expected %s, actual %d.",
+ context.name,
+ context.messageSegment,
+ context.actual,
+ );
+ console.log(context.stack.split("\n").slice(2).join("\n"));
+ });
+
+ if (failed.length) process.exit(1);
+}
+
+/**
+ * @param {Function} fn
+ * @param {"exact" | "minimum"} field
+ */
+function _mustCallInner(fn, criteria = 1, field) {
+ // @ts-ignore
+ if (process._exiting) {
+ throw new Error("Cannot use common.mustCall*() in process exit handler");
+ }
+ if (typeof fn === "number") {
+ criteria = fn;
+ fn = noop;
+ } else if (fn === undefined) {
+ fn = noop;
+ }
+
+ if (typeof criteria !== "number") {
+ throw new TypeError(`Invalid ${field} value: ${criteria}`);
+ }
+
+ let context;
+ if (field === "exact") {
+ context = {
+ exact: criteria,
+ actual: 0,
+ stack: util.inspect(new Error()),
+ name: fn.name || "<anonymous>",
+ };
+ } else {
+ context = {
+ minimum: criteria,
+ actual: 0,
+ stack: util.inspect(new Error()),
+ name: fn.name || "<anonymous>",
+ };
+ }
+
+ // Add the exit listener only once to avoid listener leak warnings
+ if (mustCallChecks.length === 0) process.on("exit", runCallChecks);
+
+ mustCallChecks.push(context);
+
+ return function () {
+ context.actual++;
+ return fn.apply(this, arguments);
+ };
+}
+
+/**
+ * @param {string=} msg
+ */
+function mustNotCall(msg) {
+ /**
+ * @param {any[]} args
+ */
+ return function mustNotCall(...args) {
+ const argsInfo = args.length > 0
+ ? `\ncalled with arguments: ${args.map(util.inspect).join(", ")}`
+ : "";
+ assert.fail(
+ `${msg || "function should not have been called"} at unknown` +
+ argsInfo,
+ );
+ };
+}
+
+const _mustNotMutateObjectDeepProxies = new WeakMap();
+
+function mustNotMutateObjectDeep(original) {
+ // Return primitives and functions directly. Primitives are immutable, and
+ // proxied functions are impossible to compare against originals, e.g. with
+ // `assert.deepEqual()`.
+ if (original === null || typeof original !== 'object') {
+ return original;
+ }
+
+ const cachedProxy = _mustNotMutateObjectDeepProxies.get(original);
+ if (cachedProxy) {
+ return cachedProxy;
+ }
+
+ const _mustNotMutateObjectDeepHandler = {
+ __proto__: null,
+ defineProperty(target, property, descriptor) {
+ assert.fail(`Expected no side effects, got ${inspect(property)} ` +
+ 'defined');
+ },
+ deleteProperty(target, property) {
+ assert.fail(`Expected no side effects, got ${inspect(property)} ` +
+ 'deleted');
+ },
+ get(target, prop, receiver) {
+ return mustNotMutateObjectDeep(Reflect.get(target, prop, receiver));
+ },
+ preventExtensions(target) {
+ assert.fail('Expected no side effects, got extensions prevented on ' +
+ inspect(target));
+ },
+ set(target, property, value, receiver) {
+ assert.fail(`Expected no side effects, got ${inspect(value)} ` +
+ `assigned to ${inspect(property)}`);
+ },
+ setPrototypeOf(target, prototype) {
+ assert.fail(`Expected no side effects, got set prototype to ${prototype}`);
+ }
+ };
+
+ const proxy = new Proxy(original, _mustNotMutateObjectDeepHandler);
+ _mustNotMutateObjectDeepProxies.set(original, proxy);
+ return proxy;
+}
+
+// A helper function to simplify checking for ERR_INVALID_ARG_TYPE output.
+function invalidArgTypeHelper(input) {
+ if (input == null) {
+ return ` Received ${input}`;
+ }
+ if (typeof input === "function" && input.name) {
+ return ` Received function ${input.name}`;
+ }
+ if (typeof input === "object") {
+ if (input.constructor && input.constructor.name) {
+ return ` Received an instance of ${input.constructor.name}`;
+ }
+ return ` Received ${util.inspect(input, { depth: -1 })}`;
+ }
+ let inspected = util.inspect(input, { colors: false });
+ if (inspected.length > 25) {
+ inspected = `${inspected.slice(0, 25)}...`;
+ }
+ return ` Received type ${typeof input} (${inspected})`;
+}
+
+const isWindows = process.platform === 'win32';
+const isAIX = process.platform === 'aix';
+const isSunOS = process.platform === 'sunos';
+const isFreeBSD = process.platform === 'freebsd';
+const isOpenBSD = process.platform === 'openbsd';
+const isLinux = process.platform === 'linux';
+const isOSX = process.platform === 'darwin';
+
+const isDumbTerminal = process.env.TERM === 'dumb';
+
+function skipIfDumbTerminal() {
+ if (isDumbTerminal) {
+ skip('skipping - dumb terminal');
+ }
+}
+
+function printSkipMessage(msg) {
+ console.log(`1..0 # Skipped: ${msg}`);
+}
+
+function skip(msg) {
+ printSkipMessage(msg);
+ process.exit(0);
+}
+
+const PIPE = (() => {
+ const localRelative = path.relative(process.cwd(), `${tmpdir.path}/`);
+ const pipePrefix = isWindows ? "\\\\.\\pipe\\" : localRelative;
+ const pipeName = `node-test.${process.pid}.sock`;
+ return path.join(pipePrefix, pipeName);
+})();
+
+function getArrayBufferViews(buf) {
+ const { buffer, byteOffset, byteLength } = buf;
+
+ const out = [];
+
+ const arrayBufferViews = [
+ Int8Array,
+ Uint8Array,
+ Uint8ClampedArray,
+ Int16Array,
+ Uint16Array,
+ Int32Array,
+ Uint32Array,
+ Float32Array,
+ Float64Array,
+ DataView,
+ ];
+
+ for (const type of arrayBufferViews) {
+ const { BYTES_PER_ELEMENT = 1 } = type;
+ if (byteLength % BYTES_PER_ELEMENT === 0) {
+ out.push(new type(buffer, byteOffset, byteLength / BYTES_PER_ELEMENT));
+ }
+ }
+ return out;
+}
+
+function getBufferSources(buf) {
+ return [...getArrayBufferViews(buf), new Uint8Array(buf).buffer];
+}
+
+const pwdCommand = isWindows ?
+ ['cmd.exe', ['/d', '/c', 'cd']] :
+ ['pwd', []];
+
+module.exports = {
+ allowGlobals,
+ expectsError,
+ expectWarning,
+ getArrayBufferViews,
+ getBufferSources,
+ hasCrypto: true,
+ hasIntl: true,
+ hasMultiLocalhost() {
+ return false;
+ },
+ invalidArgTypeHelper,
+ mustCall,
+ mustCallAtLeast,
+ mustNotCall,
+ mustNotMutateObjectDeep,
+ mustSucceed,
+ PIPE,
+ platformTimeout,
+ printSkipMessage,
+ pwdCommand,
+ skipIfDumbTerminal,
+ isDumbTerminal,
+ isWindows,
+ isAIX,
+ isSunOS,
+ isFreeBSD,
+ isOpenBSD,
+ isLinux,
+ isOSX,
+ isMainThread: true, // TODO(f3n67u): replace with `worker_thread.isMainThread` when `worker_thread` implemented
+ skip,
+ get hasIPv6() {
+ const iFaces = require('os').networkInterfaces();
+ const re = isWindows ? /Loopback Pseudo-Interface/ : /lo/;
+ return Object.keys(iFaces).some((name) => {
+ return re.test(name) &&
+ iFaces[name].some(({ family }) => family === 'IPv6');
+ });
+ },
+
+ get localhostIPv4() {
+ if (localhostIPv4 !== null) return localhostIPv4;
+ if (localhostIPv4 === null) localhostIPv4 = '127.0.0.1';
+
+ return localhostIPv4;
+ },
+
+ get PORT() {
+ return 12346;
+ },
+};
diff --git a/tests/node_compat/test/common/index.mjs b/tests/node_compat/test/common/index.mjs
new file mode 100644
index 000000000..25fe5cbb0
--- /dev/null
+++ b/tests/node_compat/test/common/index.mjs
@@ -0,0 +1,115 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+import { createRequire } from 'module';
+
+const require = createRequire(import.meta.url);
+const common = require('./index.js');
+
+const {
+ isMainThread,
+ isWindows,
+ isAIX,
+ isIBMi,
+ isLinuxPPCBE,
+ isSunOS,
+ isDumbTerminal,
+ isFreeBSD,
+ isOpenBSD,
+ isLinux,
+ isOSX,
+ enoughTestMem,
+ buildType,
+ localIPv6Hosts,
+ opensslCli,
+ PIPE,
+ hasCrypto,
+ hasIPv6,
+ childShouldThrowAndAbort,
+ checkoutEOL,
+ createZeroFilledFile,
+ platformTimeout,
+ allowGlobals,
+ mustCall,
+ mustCallAtLeast,
+ mustSucceed,
+ hasMultiLocalhost,
+ skipIfDumbTerminal,
+ skipIfEslintMissing,
+ canCreateSymLink,
+ getCallSite,
+ mustNotCall,
+ mustNotMutateObjectDeep,
+ parseTestFlags,
+ printSkipMessage,
+ skip,
+ nodeProcessAborted,
+ isAlive,
+ expectWarning,
+ expectsError,
+ skipIfInspectorDisabled,
+ skipIf32Bits,
+ getArrayBufferViews,
+ getBufferSources,
+ getTTYfd,
+ runWithInvalidFD,
+ spawnPromisified,
+} = common;
+
+const getPort = () => common.PORT;
+
+export {
+ isMainThread,
+ isWindows,
+ isAIX,
+ isIBMi,
+ isLinuxPPCBE,
+ isSunOS,
+ isDumbTerminal,
+ isFreeBSD,
+ isOpenBSD,
+ isLinux,
+ isOSX,
+ enoughTestMem,
+ buildType,
+ localIPv6Hosts,
+ opensslCli,
+ PIPE,
+ hasCrypto,
+ hasIPv6,
+ childShouldThrowAndAbort,
+ checkoutEOL,
+ createZeroFilledFile,
+ platformTimeout,
+ allowGlobals,
+ mustCall,
+ mustCallAtLeast,
+ mustSucceed,
+ hasMultiLocalhost,
+ skipIfDumbTerminal,
+ skipIfEslintMissing,
+ canCreateSymLink,
+ getCallSite,
+ mustNotCall,
+ mustNotMutateObjectDeep,
+ parseTestFlags,
+ printSkipMessage,
+ skip,
+ nodeProcessAborted,
+ isAlive,
+ expectWarning,
+ expectsError,
+ skipIfInspectorDisabled,
+ skipIf32Bits,
+ getArrayBufferViews,
+ getBufferSources,
+ getTTYfd,
+ runWithInvalidFD,
+ createRequire,
+ spawnPromisified,
+ getPort,
+};
diff --git a/tests/node_compat/test/common/internet.js b/tests/node_compat/test/common/internet.js
new file mode 100644
index 000000000..b42fda66c
--- /dev/null
+++ b/tests/node_compat/test/common/internet.js
@@ -0,0 +1,68 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+'use strict';
+
+// Utilities for internet-related tests
+
+const addresses = {
+ // A generic host that has registered common DNS records,
+ // supports both IPv4 and IPv6, and provides basic HTTP/HTTPS services
+ INET_HOST: 'nodejs.org',
+ // A host that provides IPv4 services
+ INET4_HOST: 'nodejs.org',
+ // A host that provides IPv6 services
+ INET6_HOST: 'nodejs.org',
+ // An accessible IPv4 IP,
+ // defaults to the Google Public DNS IPv4 address
+ INET4_IP: '8.8.8.8',
+ // An accessible IPv6 IP,
+ // defaults to the Google Public DNS IPv6 address
+ INET6_IP: '2001:4860:4860::8888',
+ // An invalid host that cannot be resolved
+ // See https://tools.ietf.org/html/rfc2606#section-2
+ INVALID_HOST: 'something.invalid',
+ // A host with MX records registered
+ MX_HOST: 'nodejs.org',
+ // On some systems, .invalid returns a server failure/try again rather than
+ // record not found. Use this to guarantee record not found.
+ NOT_FOUND: 'come.on.fhqwhgads.test',
+ // A host with SRV records registered
+ // TODO(kt3k): Temporarily use _caldav._tcp.google.com instead of
+ // _jabber._tcp.google.com, which currently doesn't respond
+ // SRV_HOST: '_jabber._tcp.google.com',
+ SRV_HOST: '_caldav._tcp.google.com',
+ // A host with PTR records registered
+ PTR_HOST: '8.8.8.8.in-addr.arpa',
+ // A host with NAPTR records registered
+ NAPTR_HOST: 'sip2sip.info',
+ // A host with SOA records registered
+ SOA_HOST: 'nodejs.org',
+ // A host with CAA record registered
+ CAA_HOST: 'google.com',
+ // A host with CNAME records registered
+ CNAME_HOST: 'blog.nodejs.org',
+ // A host with NS records registered
+ NS_HOST: 'nodejs.org',
+ // A host with TXT records registered
+ TXT_HOST: 'nodejs.org',
+ // An accessible IPv4 DNS server
+ DNS4_SERVER: '8.8.8.8',
+ // An accessible IPv4 DNS server
+ DNS6_SERVER: '2001:4860:4860::8888'
+};
+
+for (const key of Object.keys(addresses)) {
+ const envName = `NODE_TEST_${key}`;
+ if (process.env[envName]) {
+ addresses[key] = process.env[envName];
+ }
+}
+
+module.exports = {
+ addresses
+};
diff --git a/tests/node_compat/test/common/package.json b/tests/node_compat/test/common/package.json
new file mode 100644
index 000000000..0967ef424
--- /dev/null
+++ b/tests/node_compat/test/common/package.json
@@ -0,0 +1 @@
+{}
diff --git a/tests/node_compat/test/common/tmpdir.js b/tests/node_compat/test/common/tmpdir.js
new file mode 100644
index 000000000..886c4a107
--- /dev/null
+++ b/tests/node_compat/test/common/tmpdir.js
@@ -0,0 +1,79 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const fs = require('fs');
+const path = require('path');
+const { isMainThread } = require('worker_threads');
+
+function rmSync(pathname) {
+ fs.rmSync(pathname, { maxRetries: 3, recursive: true, force: true });
+}
+
+const testRoot = process.env.NODE_TEST_DIR ?
+ fs.realpathSync(process.env.NODE_TEST_DIR) : path.resolve(__dirname, '..');
+
+// Using a `.` prefixed name, which is the convention for "hidden" on POSIX,
+// gets tools to ignore it by default or by simple rules, especially eslint.
+const tmpdirName = '.tmp.' +
+ (process.env.TEST_SERIAL_ID || process.env.TEST_THREAD_ID || '0');
+const tmpPath = path.join(testRoot, tmpdirName);
+
+let firstRefresh = true;
+function refresh() {
+ rmSync(tmpPath);
+ fs.mkdirSync(tmpPath);
+
+ if (firstRefresh) {
+ firstRefresh = false;
+ // Clean only when a test uses refresh. This allows for child processes to
+ // use the tmpdir and only the parent will clean on exit.
+ process.on('exit', onexit);
+ }
+}
+
+function onexit() {
+ // Change directory to avoid possible EBUSY
+ if (isMainThread)
+ process.chdir(testRoot);
+
+ try {
+ rmSync(tmpPath);
+ } catch (e) {
+ console.error('Can\'t clean tmpdir:', tmpPath);
+
+ const files = fs.readdirSync(tmpPath);
+ console.error('Files blocking:', files);
+
+ if (files.some((f) => f.startsWith('.nfs'))) {
+ // Warn about NFS "silly rename"
+ console.error('Note: ".nfs*" might be files that were open and ' +
+ 'unlinked but not closed.');
+ console.error('See http://nfs.sourceforge.net/#faq_d2 for details.');
+ }
+
+ console.error();
+ throw e;
+ }
+}
+
+function resolve(...paths) {
+ return path.resolve(tmpPath, ...paths);
+}
+
+function hasEnoughSpace(size) {
+ const { bavail, bsize } = fs.statfsSync(tmpPath);
+ return bavail >= Math.ceil(size / bsize);
+}
+
+module.exports = {
+ path: tmpPath,
+ refresh,
+ hasEnoughSpace,
+ resolve,
+};
diff --git a/tests/node_compat/test/fixtures/GH-1899-output.js b/tests/node_compat/test/fixtures/GH-1899-output.js
new file mode 100644
index 000000000..d647eb320
--- /dev/null
+++ b/tests/node_compat/test/fixtures/GH-1899-output.js
@@ -0,0 +1,30 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+console.log('hello, world!');
+
diff --git a/tests/node_compat/test/fixtures/a.js b/tests/node_compat/test/fixtures/a.js
new file mode 100644
index 000000000..9f5a21a06
--- /dev/null
+++ b/tests/node_compat/test/fixtures/a.js
@@ -0,0 +1,53 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+const c = require('./b/c');
+
+console.error('load fixtures/a.js');
+
+var string = 'A';
+
+exports.SomeClass = c.SomeClass;
+
+exports.A = function() {
+ return string;
+};
+
+exports.C = function() {
+ return c.C();
+};
+
+exports.D = function() {
+ return c.D();
+};
+
+exports.number = 42;
+
+process.on('exit', function() {
+ string = 'A done';
+});
diff --git a/tests/node_compat/test/fixtures/child-process-spawn-node.js b/tests/node_compat/test/fixtures/child-process-spawn-node.js
new file mode 100644
index 000000000..da2b557c9
--- /dev/null
+++ b/tests/node_compat/test/fixtures/child-process-spawn-node.js
@@ -0,0 +1,14 @@
+const assert = require("assert");
+// TODO(kt3k): Uncomment this when util.debuglog is added
+// const debug = require('util').debuglog('test');
+const debug = console.log;
+
+function onmessage(m) {
+ debug("CHILD got message:", m);
+ assert.ok(m.hello);
+ process.removeListener("message", onmessage);
+}
+
+process.on("message", onmessage);
+// TODO(kt3k): Uncomment the below when the ipc features are ready
+// process.send({ foo: 'bar' });
diff --git a/tests/node_compat/test/fixtures/child_process_should_emit_error.js b/tests/node_compat/test/fixtures/child_process_should_emit_error.js
new file mode 100644
index 000000000..5a56c312b
--- /dev/null
+++ b/tests/node_compat/test/fixtures/child_process_should_emit_error.js
@@ -0,0 +1,36 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+const exec = require('child_process').exec;
+
+[0, 1].forEach(function(i) {
+ exec('ls', function(err, stdout, stderr) {
+ console.log(i);
+ throw new Error('hello world');
+ });
+});
diff --git a/tests/node_compat/test/fixtures/echo.js b/tests/node_compat/test/fixtures/echo.js
new file mode 100644
index 000000000..893099e9b
--- /dev/null
+++ b/tests/node_compat/test/fixtures/echo.js
@@ -0,0 +1,41 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+const common = require('../common');
+const assert = require('assert');
+
+process.stdout.write('hello world\r\n');
+
+// TODO(PolarETech): process.openStdin() is not yet implemented.
+// Use process.stdin instead.
+var stdin = process.stdin;
+// var stdin = process.openStdin();
+
+stdin.on('data', function(data) {
+ process.stdout.write(data.toString());
+});
diff --git a/tests/node_compat/test/fixtures/elipses.txt b/tests/node_compat/test/fixtures/elipses.txt
new file mode 100644
index 000000000..610560050
--- /dev/null
+++ b/tests/node_compat/test/fixtures/elipses.txt
@@ -0,0 +1 @@
+………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………… \ No newline at end of file
diff --git a/tests/node_compat/test/fixtures/empty.txt b/tests/node_compat/test/fixtures/empty.txt
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/node_compat/test/fixtures/empty.txt
diff --git a/tests/node_compat/test/fixtures/exit.js b/tests/node_compat/test/fixtures/exit.js
new file mode 100644
index 000000000..ca80f4828
--- /dev/null
+++ b/tests/node_compat/test/fixtures/exit.js
@@ -0,0 +1,31 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// TODO(PolarETech): The process.argv[3] should be argv[2].
+
+process.exit(process.argv[3] || 1);
diff --git a/tests/node_compat/test/fixtures/keys/agent1-cert.pem b/tests/node_compat/test/fixtures/keys/agent1-cert.pem
new file mode 100644
index 000000000..bef645b0f
--- /dev/null
+++ b/tests/node_compat/test/fixtures/keys/agent1-cert.pem
@@ -0,0 +1,23 @@
+-----BEGIN CERTIFICATE-----
+MIID6DCCAtCgAwIBAgIUFH02wcL3Qgben6tfIibXitsApCYwDQYJKoZIhvcNAQEL
+BQAwejELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQswCQYDVQQHDAJTRjEPMA0G
+A1UECgwGSm95ZW50MRAwDgYDVQQLDAdOb2RlLmpzMQwwCgYDVQQDDANjYTExIDAe
+BgkqhkiG9w0BCQEWEXJ5QHRpbnljbG91ZHMub3JnMCAXDTIyMDkwMzIxNDAzN1oY
+DzIyOTYwNjE3MjE0MDM3WjB9MQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ0ExCzAJ
+BgNVBAcMAlNGMQ8wDQYDVQQKDAZKb3llbnQxEDAOBgNVBAsMB05vZGUuanMxDzAN
+BgNVBAMMBmFnZW50MTEgMB4GCSqGSIb3DQEJARYRcnlAdGlueWNsb3Vkcy5vcmcw
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDUVjIK+yDTgnCT3CxChO0E
+37q9VuHdrlKeKLeQzUJW2yczSfNzX/0zfHpjY+zKWie39z3HCJqWxtiG2wxiOI8c
+3WqWOvzVmdWADlh6EfkIlg+E7VC6JaKDA+zabmhPvnuu3JzogBMnsWl68lCXzuPx
+deQAmEwNtqjrh74DtM+Ud0ulb//Ixjxo1q3rYKu+aaexSramuee6qJta2rjrB4l8
+B/bU+j1mDf9XQQfSjo9jRnp4hiTFdBl2k+lZzqE2L/rhu6EMjA2IhAq/7xA2MbLo
+9cObVUin6lfoo5+JKRgT9Fp2xEgDOit+2EA/S6oUfPNeLSVUqmXOSWlXlwlb9Nxr
+AgMBAAGjYTBfMF0GCCsGAQUFBwEBBFEwTzAjBggrBgEFBQcwAYYXaHR0cDovL29j
+c3Aubm9kZWpzLm9yZy8wKAYIKwYBBQUHMAKGHGh0dHA6Ly9jYS5ub2RlanMub3Jn
+L2NhLmNlcnQwDQYJKoZIhvcNAQELBQADggEBAMM0mBBjLMt9pYXePtUeNO0VTw9y
+FWCM8nAcAO2kRNwkJwcsispNpkcsHZ5o8Xf5mpCotdvziEWG1hyxwU6nAWyNOLcN
+G0a0KUfbMO3B6ZYe1GwPDjXaQnv75SkAdxgX5zOzca3xnhITcjUUGjQ0fbDfwFV5
+ix8mnzvfXjDONdEznVa7PFcN6QliFUMwR/h8pCRHtE5+a10OSPeJSrGG+FtrGnRW
+G1IJUv6oiGF/MvWCr84REVgc1j78xomGANJIu2hN7bnD1nEMON6em8IfnDOUtynV
+9wfWTqiQYD5Zifj6WcGa0aAHMuetyFG4lIfMAHmd3gaKpks7j9l26LwRPvI=
+-----END CERTIFICATE-----
diff --git a/tests/node_compat/test/fixtures/keys/agent1-key.pem b/tests/node_compat/test/fixtures/keys/agent1-key.pem
new file mode 100644
index 000000000..1bd840716
--- /dev/null
+++ b/tests/node_compat/test/fixtures/keys/agent1-key.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEA1FYyCvsg04Jwk9wsQoTtBN+6vVbh3a5Snii3kM1CVtsnM0nz
+c1/9M3x6Y2Psylont/c9xwialsbYhtsMYjiPHN1qljr81ZnVgA5YehH5CJYPhO1Q
+uiWigwPs2m5oT757rtyc6IATJ7FpevJQl87j8XXkAJhMDbao64e+A7TPlHdLpW//
+yMY8aNat62CrvmmnsUq2prnnuqibWtq46weJfAf21Po9Zg3/V0EH0o6PY0Z6eIYk
+xXQZdpPpWc6hNi/64buhDIwNiIQKv+8QNjGy6PXDm1VIp+pX6KOfiSkYE/RadsRI
+AzorfthAP0uqFHzzXi0lVKplzklpV5cJW/TcawIDAQABAoIBAAvbtHfAhpjJVBgt
+15rvaX04MWmZjIugzKRgib/gdq/7FTlcC+iJl85kSUF7tyGl30n62MxgwqFhAX6m
+hQ6HMhbelrFFIhGbwbyhEHfgwROlrcAysKt0pprCgVvBhrnNXYLqdyjU3jz9P3LK
+TY3s0/YMK2uNFdI+PTjKH+Z9Foqn9NZUnUonEDepGyuRO7fLeccWJPv2L4CR4a/5
+ku4VbDgVpvVSVRG3PSVzbmxobnpdpl52og+T7tPx1cLnIknPtVljXPWtZdfekh2E
+eAp2KxCCHOKzzG3ItBKsVu0woeqEpy8JcoO6LbgmEoVnZpgmtQClbBgef8+i+oGE
+BgW9nmECgYEA8gA63QQuZOUC56N1QXURexN2PogF4wChPaCTFbQSJXvSBkQmbqfL
+qRSD8P0t7GOioPrQK6pDwFf4BJB01AvkDf8Z6DxxOJ7cqIC7LOwDupXocWX7Q0Qk
+O6cwclBVsrDZK00v60uRRpl/a39GW2dx7IiQDkKQndLh3/0TbMIWHNcCgYEA4J6r
+yinZbLpKw2+ezhi4B4GT1bMLoKboJwpZVyNZZCzYR6ZHv+lS7HR/02rcYMZGoYbf
+n7OHwF4SrnUS7vPhG4g2ZsOhKQnMvFSQqpGmK1ZTuoKGAevyvtouhK/DgtLWzGvX
+9fSahiq/UvfXs/z4M11q9Rv9ztPCmG1cwSEHlo0CgYEAogQNZJK8DMhVnYcNpXke
+7uskqtCeQE/Xo06xqkIYNAgloBRYNpUYAGa/vsOBz1UVN/kzDUi8ezVp0oRz8tLT
+J5u2WIi+tE2HJTiqF3UbOfvK1sCT64DfUSCpip7GAQ/tFNRkVH8PD9kMOYfILsGe
+v+DdsO5Xq5HXrwHb02BNNZkCgYBsl8lt33WiPx5OBfS8pu6xkk+qjPkeHhM2bKZs
+nkZlS9j0KsudWGwirN/vkkYg8zrKdK5AQ0dqFRDrDuasZ3N5IA1M+V88u+QjWK7o
+B6pSYVXxYZDv9OZSpqC+vUrEQLJf+fNakXrzSk9dCT1bYv2Lt6ox/epix7XYg2bI
+Z/OHMQKBgQC2FUGhlndGeugTJaoJ8nhT/0VfRUX/h6sCgSerk5qFr/hNCBV4T022
+x0NDR2yLG6MXyqApJpG6rh3QIDElQoQCNlI3/KJ6JfEfmqrLLN2OigTvA5sE4fGU
+Dp/ha8OQAx95EwXuaG7LgARduvOIK3x8qi8KsZoUGJcg2ywurUbkWA==
+-----END RSA PRIVATE KEY-----
diff --git a/tests/node_compat/test/fixtures/keys/ca1-cert.pem b/tests/node_compat/test/fixtures/keys/ca1-cert.pem
new file mode 100644
index 000000000..e1a012c6b
--- /dev/null
+++ b/tests/node_compat/test/fixtures/keys/ca1-cert.pem
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDlDCCAnygAwIBAgIUSrFsjf1qfQ0t/KvfnEsOksatAikwDQYJKoZIhvcNAQEL
+BQAwejELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQswCQYDVQQHDAJTRjEPMA0G
+A1UECgwGSm95ZW50MRAwDgYDVQQLDAdOb2RlLmpzMQwwCgYDVQQDDANjYTExIDAe
+BgkqhkiG9w0BCQEWEXJ5QHRpbnljbG91ZHMub3JnMCAXDTIyMDkwMzIxNDAzN1oY
+DzIyOTYwNjE3MjE0MDM3WjB6MQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ0ExCzAJ
+BgNVBAcMAlNGMQ8wDQYDVQQKDAZKb3llbnQxEDAOBgNVBAsMB05vZGUuanMxDDAK
+BgNVBAMMA2NhMTEgMB4GCSqGSIb3DQEJARYRcnlAdGlueWNsb3Vkcy5vcmcwggEi
+MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDNvf4OGGep+ak+4DNjbuNgy0S/
+AZPxahEFp4gpbcvsi9YLOPZ31qpilQeQf7d27scIZ02Qx1YBAzljxELB8H/ZxuYS
+cQK0s+DNP22xhmgwMWznO7TezkHP5ujN2UkbfbUpfUxGFgncXeZf9wR7yFWppeHi
+RWNBOgsvY7sTrS12kXjWGjqntF7xcEDHc7h+KyF6ZjVJZJCnP6pJEQ+rUjd51eCZ
+Xt4WjowLnQiCS1VKzXiP83a++Ma1BKKkUitTR112/Uwd5eGoiByhmLzb/BhxnHJN
+07GXjhlMItZRm/jfbZsx1mwnNOO3tx4r08l+DaqkinIadvazs+1ugCaKQn8xAgMB
+AAGjEDAOMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFqG0RXURDam
+56x5accdg9sY5zEGP5VQhkK3ZDc2NyNNa25rwvrjCpO+e0OSwKAmm4aX6iIf2woY
+wF2f9swWYzxn9CG4fDlUA8itwlnHxupeL4fGMTYb72vf31plUXyBySRsTwHwBloc
+F7KvAZpYYKN9EMH1S/267By6H2I33BT/Ethv//n8dSfmuCurR1kYRaiOC4PVeyFk
+B3sj8TtolrN0y/nToWUhmKiaVFnDx3odQ00yhmxR3t21iB7yDkko6D8Vf2dVC4j/
+YYBVprXGlTP/hiYRLDoP20xKOYznx5cvHPJ9p+lVcOZUJsJj/Iy750+2n5UiBmXt
+lz88C25ucKA=
+-----END CERTIFICATE-----
diff --git a/tests/node_compat/test/fixtures/loop.js b/tests/node_compat/test/fixtures/loop.js
new file mode 100644
index 000000000..f9bcfc66e
--- /dev/null
+++ b/tests/node_compat/test/fixtures/loop.js
@@ -0,0 +1,17 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+var t = 1;
+var k = 1;
+console.log('A message', 5);
+while (t > 0) {
+ if (t++ === 1000) {
+ t = 0;
+ console.log(`Outputted message #${k++}`);
+ }
+}
+process.exit(55);
diff --git a/tests/node_compat/test/fixtures/package.json b/tests/node_compat/test/fixtures/package.json
new file mode 100644
index 000000000..0967ef424
--- /dev/null
+++ b/tests/node_compat/test/fixtures/package.json
@@ -0,0 +1 @@
+{}
diff --git a/tests/node_compat/test/fixtures/print-chars.js b/tests/node_compat/test/fixtures/print-chars.js
new file mode 100644
index 000000000..2519c77fd
--- /dev/null
+++ b/tests/node_compat/test/fixtures/print-chars.js
@@ -0,0 +1,35 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// TODO(PolarETech): The process.argv[3] should be argv[2].
+
+const assert = require('assert');
+
+var n = parseInt(process.argv[3]);
+
+process.stdout.write('c'.repeat(n));
diff --git a/tests/node_compat/test/fixtures/x.txt b/tests/node_compat/test/fixtures/x.txt
new file mode 100644
index 000000000..cd470e619
--- /dev/null
+++ b/tests/node_compat/test/fixtures/x.txt
@@ -0,0 +1 @@
+xyz
diff --git a/tests/node_compat/test/internet/package.json b/tests/node_compat/test/internet/package.json
new file mode 100644
index 000000000..0967ef424
--- /dev/null
+++ b/tests/node_compat/test/internet/package.json
@@ -0,0 +1 @@
+{}
diff --git a/tests/node_compat/test/internet/test-dns-any.js b/tests/node_compat/test/internet/test-dns-any.js
new file mode 100644
index 000000000..b8a70b8e2
--- /dev/null
+++ b/tests/node_compat/test/internet/test-dns-any.js
@@ -0,0 +1,194 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 16.13.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// TODO(cmorten): enable remaining tests once functionality is implemented.
+
+'use strict';
+
+const common = require('../common');
+
+const assert = require('assert');
+const dns = require('dns');
+const net = require('net');
+
+let running = false;
+const queue = [];
+
+const dnsPromises = dns.promises;
+const isIPv4 = net.isIPv4;
+const isIPv6 = net.isIPv6;
+
+dns.setServers([ '8.8.8.8', '8.8.4.4' ]);
+
+function checkWrap(req) {
+ assert.ok(typeof req === 'object');
+}
+
+const checkers = {
+ checkA(r) {
+ assert.ok(isIPv4(r.address));
+ // assert.strictEqual(typeof r.ttl, 'number');
+ assert.strictEqual(r.type, 'A');
+ },
+ checkAAAA(r) {
+ assert.ok(isIPv6(r.address));
+ // assert.strictEqual(typeof r.ttl, 'number');
+ assert.strictEqual(r.type, 'AAAA');
+ },
+ checkCNAME(r) {
+ assert.ok(r.value);
+ assert.strictEqual(typeof r.value, 'string');
+ assert.strictEqual(r.type, 'CNAME');
+ },
+ checkMX(r) {
+ assert.strictEqual(typeof r.exchange, 'string');
+ assert.strictEqual(typeof r.priority, 'number');
+ assert.strictEqual(r.type, 'MX');
+ },
+ checkNAPTR(r) {
+ assert.strictEqual(typeof r.flags, 'string');
+ assert.strictEqual(typeof r.service, 'string');
+ assert.strictEqual(typeof r.regexp, 'string');
+ assert.strictEqual(typeof r.replacement, 'string');
+ assert.strictEqual(typeof r.order, 'number');
+ assert.strictEqual(typeof r.preference, 'number');
+ assert.strictEqual(r.type, 'NAPTR');
+ },
+ checkNS(r) {
+ assert.strictEqual(typeof r.value, 'string');
+ assert.strictEqual(r.type, 'NS');
+ },
+ checkPTR(r) {
+ assert.strictEqual(typeof r.value, 'string');
+ assert.strictEqual(r.type, 'PTR');
+ },
+ checkTXT(r) {
+ assert.ok(Array.isArray(r.entries));
+ assert.ok(r.entries.length > 0);
+ assert.strictEqual(r.type, 'TXT');
+ },
+ checkSOA(r) {
+ assert.strictEqual(typeof r.nsname, 'string');
+ assert.strictEqual(typeof r.hostmaster, 'string');
+ assert.strictEqual(typeof r.serial, 'number');
+ assert.strictEqual(typeof r.refresh, 'number');
+ assert.strictEqual(typeof r.retry, 'number');
+ assert.strictEqual(typeof r.expire, 'number');
+ assert.strictEqual(typeof r.minttl, 'number');
+ assert.strictEqual(r.type, 'SOA');
+ },
+ checkSRV(r) {
+ assert.strictEqual(typeof r.name, 'string');
+ assert.strictEqual(typeof r.port, 'number');
+ assert.strictEqual(typeof r.priority, 'number');
+ assert.strictEqual(typeof r.weight, 'number');
+ assert.strictEqual(r.type, 'SRV');
+ }
+};
+
+function TEST(f) {
+ function next() {
+ const f = queue.shift();
+ if (f) {
+ running = true;
+ f(done);
+ }
+ }
+
+ function done() {
+ running = false;
+ process.nextTick(next);
+ }
+
+ queue.push(f);
+
+ if (!running) {
+ next();
+ }
+}
+
+function processResult(res) {
+ assert.ok(Array.isArray(res));
+ assert.ok(res.length > 0);
+
+ const types = {};
+ res.forEach((obj) => {
+ types[obj.type] = true;
+ checkers[`check${obj.type}`](obj);
+ });
+
+ return types;
+}
+
+TEST(async function test_sip2sip_for_naptr(done) {
+ function validateResult(res) {
+ const types = processResult(res);
+ assert.ok(
+ types.A && types.NS && types.NAPTR && types.SOA,
+ `Missing record type, found ${Object.keys(types)}`
+ );
+ }
+
+ validateResult(await dnsPromises.resolve('sip2sip.info', 'ANY'));
+
+ const req = dns.resolve(
+ 'sip2sip.info',
+ 'ANY',
+ common.mustSucceed((ret) => {
+ validateResult(ret);
+ done();
+ }));
+
+ checkWrap(req);
+});
+
+TEST(async function test_google_for_cname_and_srv(done) {
+ function validateResult(res) {
+ const types = processResult(res);
+ assert.ok(types.SRV);
+ }
+
+ // TODO(kt3k): Temporarily use _caldav._tcp.google.com instead of
+ // _jabber._tcp.google.com, which currently doesn't respond
+ // validateResult(await dnsPromises.resolve('_jabber._tcp.google.com', 'ANY'));
+ validateResult(await dnsPromises.resolve('_caldav._tcp.google.com', 'ANY'));
+
+
+ // TODO(kt3k): Temporarily use _caldav._tcp.google.com instead of
+ // _jabber._tcp.google.com, which currently doesn't respond
+ const req = dns.resolve(
+ // '_jabber._tcp.google.com',
+ '_caldav._tcp.google.com',
+ 'ANY',
+ common.mustSucceed((ret) => {
+ validateResult(ret);
+ done();
+ }));
+
+ checkWrap(req);
+});
+
+// TODO(bartlomieju): this test started failing on CI on Dec 28th, 2023 returning
+// ENOTFOUND. It's unclear what's going on, since `dig -x 8.8.8.8.in-addr.arpa`
+// TEST(async function test_ptr(done) {
+// function validateResult(res) {
+// const types = processResult(res);
+// assert.ok(types.PTR);
+// }
+
+// validateResult(await dnsPromises.resolve('8.8.8.8.in-addr.arpa', 'ANY'));
+
+// const req = dns.resolve(
+// '8.8.8.8.in-addr.arpa',
+// 'ANY',
+// common.mustSucceed((ret) => {
+// validateResult(ret);
+// done();
+// }));
+
+// checkWrap(req);
+// });
diff --git a/tests/node_compat/test/internet/test-dns-idna2008.js b/tests/node_compat/test/internet/test-dns-idna2008.js
new file mode 100644
index 000000000..7308f9deb
--- /dev/null
+++ b/tests/node_compat/test/internet/test-dns-idna2008.js
@@ -0,0 +1,76 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+// Verify that non-ASCII hostnames are handled correctly as IDNA 2008.
+//
+// * Tests will fail with NXDOMAIN when UTF-8 leaks through to a getaddrinfo()
+// that doesn't support IDNA at all.
+//
+// * "straße.de" will resolve to the wrong address when the resolver supports
+// only IDNA 2003 (e.g., glibc until 2.28) because it encodes it wrong.
+
+const { mustCall } = require('../common');
+const assert = require('assert');
+const dns = require('dns');
+const { addresses } = require('../common/internet');
+
+const fixture = {
+ hostname: 'straße.de',
+ expectedAddress: '81.169.145.78',
+ dnsServer: addresses.DNS4_SERVER,
+ family: 4,
+};
+
+// Explicitly use well-behaved DNS servers that are known to be able to resolve
+// the query (which is a.k.a xn--strae-oqa.de).
+dns.setServers([fixture.dnsServer]);
+
+dns.lookup(
+ fixture.hostname,
+ { family: fixture.family },
+ mustCall((err, address) => {
+ if (err && err.errno === 'ESERVFAIL') {
+ assert.ok(err.message.includes('queryA ESERVFAIL straße.de'));
+ return;
+ }
+ assert.ifError(err);
+ assert.strictEqual(address, fixture.expectedAddress);
+ }),
+);
+
+dns.promises.lookup(fixture.hostname, { family: fixture.family })
+ .then(({ address }) => {
+ assert.strictEqual(address, fixture.expectedAddress);
+ }, (err) => {
+ if (err && err.errno === 'ESERVFAIL') {
+ assert.ok(err.message.includes('queryA ESERVFAIL straße.de'));
+ } else {
+ throw err;
+ }
+ }).finally(mustCall());
+
+dns.resolve4(fixture.hostname, mustCall((err, addresses) => {
+ if (err && err.errno === 'ESERVFAIL') {
+ assert.ok(err.message.includes('queryA ESERVFAIL straße.de'));
+ return;
+ }
+ assert.ifError(err);
+ assert.deepStrictEqual(addresses, [fixture.expectedAddress]);
+}));
+
+const p = new dns.promises.Resolver().resolve4(fixture.hostname);
+p.then((addresses) => {
+ assert.deepStrictEqual(addresses, [fixture.expectedAddress]);
+}, (err) => {
+ if (err && err.errno === 'ESERVFAIL') {
+ assert.ok(err.message.includes('queryA ESERVFAIL straße.de'));
+ } else {
+ throw err;
+ }
+}).finally(mustCall());
diff --git a/tests/node_compat/test/internet/test-dns-ipv4.js b/tests/node_compat/test/internet/test-dns-ipv4.js
new file mode 100644
index 000000000..43b60950a
--- /dev/null
+++ b/tests/node_compat/test/internet/test-dns-ipv4.js
@@ -0,0 +1,257 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 16.13.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+'use strict';
+
+// TODO: enable remaining tests once functionality is implemented.
+
+const common = require('../common');
+const { addresses } = require('../common/internet');
+const assert = require('assert');
+const dns = require('dns');
+const net = require('net');
+// const util = require('util');
+const isIPv4 = net.isIPv4;
+
+const dnsPromises = dns.promises;
+let running = false;
+const queue = [];
+
+function TEST(f) {
+ function next() {
+ const f = queue.shift();
+ if (f) {
+ running = true;
+ console.log(f.name);
+ f(done);
+ }
+ }
+
+ function done() {
+ running = false;
+ process.nextTick(next);
+ }
+
+ queue.push(f);
+
+ if (!running) {
+ next();
+ }
+}
+
+function checkWrap(req) {
+ assert.ok(typeof req === 'object');
+}
+
+TEST(async function test_resolve4(done) {
+ function validateResult(res) {
+ assert.ok(res.length > 0);
+
+ for (let i = 0; i < res.length; i++) {
+ assert.ok(isIPv4(res[i]));
+ }
+ }
+
+ validateResult(await dnsPromises.resolve4(addresses.INET4_HOST));
+
+ const req = dns.resolve4(
+ addresses.INET4_HOST,
+ common.mustSucceed((ips) => {
+ validateResult(ips);
+ done();
+ }));
+
+ checkWrap(req);
+});
+
+// TEST(async function test_reverse_ipv4(done) {
+// function validateResult(res) {
+// assert.ok(res.length > 0);
+
+// for (let i = 0; i < res.length; i++) {
+// assert.ok(res[i]);
+// assert.ok(typeof res[i] === 'string');
+// }
+// }
+
+// validateResult(await dnsPromises.reverse(addresses.INET4_IP));
+
+// const req = dns.reverse(
+// addresses.INET4_IP,
+// common.mustSucceed((domains) => {
+// validateResult(domains);
+// done();
+// }));
+
+// checkWrap(req);
+// });
+
+TEST(async function test_lookup_ipv4_explicit(done) {
+ function validateResult(res) {
+ assert.ok(net.isIPv4(res.address));
+ assert.strictEqual(res.family, 4);
+ }
+
+ validateResult(await dnsPromises.lookup(addresses.INET4_HOST, 4));
+
+ const req = dns.lookup(
+ addresses.INET4_HOST, 4,
+ common.mustSucceed((ip, family) => {
+ validateResult({ address: ip, family });
+ done();
+ }));
+
+ checkWrap(req);
+});
+
+TEST(async function test_lookup_ipv4_implicit(done) {
+ function validateResult(res) {
+ assert.ok(net.isIPv4(res.address));
+ assert.strictEqual(res.family, 4);
+ }
+
+ validateResult(await dnsPromises.lookup(addresses.INET4_HOST));
+
+ const req = dns.lookup(
+ addresses.INET4_HOST,
+ common.mustSucceed((ip, family) => {
+ validateResult({ address: ip, family });
+ done();
+ }));
+
+ checkWrap(req);
+});
+
+TEST(async function test_lookup_ipv4_explicit_object(done) {
+ function validateResult(res) {
+ assert.ok(net.isIPv4(res.address));
+ assert.strictEqual(res.family, 4);
+ }
+
+ validateResult(await dnsPromises.lookup(addresses.INET4_HOST, { family: 4 }));
+
+ const req = dns.lookup(addresses.INET4_HOST, {
+ family: 4
+ }, common.mustSucceed((ip, family) => {
+ validateResult({ address: ip, family });
+ done();
+ }));
+
+ checkWrap(req);
+});
+
+TEST(async function test_lookup_ipv4_hint_addrconfig(done) {
+ function validateResult(res) {
+ assert.ok(net.isIPv4(res.address));
+ assert.strictEqual(res.family, 4);
+ }
+
+ validateResult(await dnsPromises.lookup(addresses.INET4_HOST, {
+ hints: dns.ADDRCONFIG
+ }));
+
+ const req = dns.lookup(addresses.INET4_HOST, {
+ hints: dns.ADDRCONFIG
+ }, common.mustSucceed((ip, family) => {
+ validateResult({ address: ip, family });
+ done();
+ }));
+
+ checkWrap(req);
+});
+
+TEST(async function test_lookup_ip_ipv4(done) {
+ function validateResult(res) {
+ assert.strictEqual(res.address, '127.0.0.1');
+ assert.strictEqual(res.family, 4);
+ }
+
+ validateResult(await dnsPromises.lookup('127.0.0.1'));
+
+ const req = dns.lookup('127.0.0.1',
+ common.mustSucceed((ip, family) => {
+ validateResult({ address: ip, family });
+ done();
+ }));
+
+ checkWrap(req);
+});
+
+TEST(async function test_lookup_localhost_ipv4(done) {
+ function validateResult(res) {
+ assert.strictEqual(res.address, '127.0.0.1');
+ assert.strictEqual(res.family, 4);
+ }
+
+ validateResult(await dnsPromises.lookup('localhost', 4));
+
+ const req = dns.lookup('localhost', 4,
+ common.mustSucceed((ip, family) => {
+ validateResult({ address: ip, family });
+ done();
+ }));
+
+ checkWrap(req);
+});
+
+TEST(async function test_lookup_all_ipv4(done) {
+ function validateResult(res) {
+ assert.ok(Array.isArray(res));
+ assert.ok(res.length > 0);
+
+ res.forEach((ip) => {
+ assert.ok(isIPv4(ip.address));
+ assert.strictEqual(ip.family, 4);
+ });
+ }
+
+ validateResult(await dnsPromises.lookup(addresses.INET4_HOST, {
+ all: true,
+ family: 4
+ }));
+
+ const req = dns.lookup(
+ addresses.INET4_HOST,
+ { all: true, family: 4 },
+ common.mustSucceed((ips) => {
+ validateResult(ips);
+ done();
+ })
+ );
+
+ checkWrap(req);
+});
+
+// TEST(async function test_lookupservice_ip_ipv4(done) {
+// function validateResult(res) {
+// assert.strictEqual(typeof res.hostname, 'string');
+// assert(res.hostname);
+// assert(['http', 'www', '80'].includes(res.service));
+// }
+
+// validateResult(await dnsPromises.lookupService('127.0.0.1', 80));
+
+// const req = dns.lookupService(
+// '127.0.0.1', 80,
+// common.mustSucceed((hostname, service) => {
+// validateResult({ hostname, service });
+// done();
+// })
+// );
+
+// checkWrap(req);
+// });
+
+// TEST(function test_lookupservice_ip_ipv4_promise(done) {
+// util.promisify(dns.lookupService)('127.0.0.1', 80)
+// .then(common.mustCall(({ hostname, service }) => {
+// assert.strictEqual(typeof hostname, 'string');
+// assert(hostname.length > 0);
+// assert(['http', 'www', '80'].includes(service));
+// done();
+// }));
+// });
diff --git a/tests/node_compat/test/internet/test-dns-ipv6.js b/tests/node_compat/test/internet/test-dns-ipv6.js
new file mode 100644
index 000000000..4b94d6041
--- /dev/null
+++ b/tests/node_compat/test/internet/test-dns-ipv6.js
@@ -0,0 +1,250 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 16.13.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+'use strict';
+
+// TODO: enable remaining tests once functionality is implemented.
+
+const common = require('../common');
+const { addresses } = require('../common/internet');
+if (!common.hasIPv6)
+ common.skip('this test, no IPv6 support');
+
+const assert = require('assert');
+const dns = require('dns');
+const net = require('net');
+const dnsPromises = dns.promises;
+const isIPv6 = net.isIPv6;
+
+let running = false;
+const queue = [];
+
+function TEST(f) {
+ function next() {
+ const f = queue.shift();
+ if (f) {
+ running = true;
+ console.log(f.name);
+ f(done);
+ }
+ }
+
+ function done() {
+ running = false;
+ process.nextTick(next);
+ }
+
+ queue.push(f);
+
+ if (!running) {
+ next();
+ }
+}
+
+function checkWrap(req) {
+ assert.ok(typeof req === 'object');
+}
+
+TEST(async function test_resolve6(done) {
+ function validateResult(res) {
+ assert.ok(res.length > 0);
+
+ for (let i = 0; i < res.length; i++) {
+ assert.ok(isIPv6(res[i]));
+ }
+ }
+
+ validateResult(await dnsPromises.resolve6(addresses.INET6_HOST));
+
+ const req = dns.resolve6(
+ addresses.INET6_HOST,
+ common.mustSucceed((ips) => {
+ validateResult(ips);
+ done();
+ }));
+
+ checkWrap(req);
+});
+
+// TEST(async function test_reverse_ipv6(done) {
+// function validateResult(res) {
+// assert.ok(res.length > 0);
+
+// for (let i = 0; i < res.length; i++) {
+// assert.ok(typeof res[i] === 'string');
+// }
+// }
+
+// validateResult(await dnsPromises.reverse(addresses.INET6_IP));
+
+// const req = dns.reverse(
+// addresses.INET6_IP,
+// common.mustSucceed((domains) => {
+// validateResult(domains);
+// done();
+// }));
+
+// checkWrap(req);
+// });
+
+TEST(async function test_lookup_ipv6_explicit(done) {
+ function validateResult(res) {
+ assert.ok(isIPv6(res.address));
+ assert.strictEqual(res.family, 6);
+ }
+
+ validateResult(await dnsPromises.lookup(addresses.INET6_HOST, 6));
+
+ const req = dns.lookup(
+ addresses.INET6_HOST,
+ 6,
+ common.mustSucceed((ip, family) => {
+ validateResult({ address: ip, family });
+ done();
+ }));
+
+ checkWrap(req);
+});
+
+// This ends up just being too problematic to test
+// TEST(function test_lookup_ipv6_implicit(done) {
+// var req = dns.lookup(addresses.INET6_HOST, function(err, ip, family) {
+// assert.ifError(err);
+// assert.ok(net.isIPv6(ip));
+// assert.strictEqual(family, 6);
+
+// done();
+// });
+
+// checkWrap(req);
+// });
+
+TEST(async function test_lookup_ipv6_explicit_object(done) {
+ function validateResult(res) {
+ assert.ok(isIPv6(res.address));
+ assert.strictEqual(res.family, 6);
+ }
+
+ validateResult(await dnsPromises.lookup(addresses.INET6_HOST, { family: 6 }));
+
+ const req = dns.lookup(addresses.INET6_HOST, {
+ family: 6
+ }, common.mustSucceed((ip, family) => {
+ validateResult({ address: ip, family });
+ done();
+ }));
+
+ checkWrap(req);
+});
+
+TEST(function test_lookup_ipv6_hint(done) {
+ const req = dns.lookup(addresses.INET6_HOST, {
+ family: 6,
+ hints: dns.V4MAPPED
+ }, common.mustCall((err, ip, family) => {
+ if (err) {
+ // FreeBSD does not support V4MAPPED
+ if (common.isFreeBSD) {
+ assert(err instanceof Error);
+ assert.strictEqual(err.code, 'EAI_BADFLAGS');
+ assert.strictEqual(err.hostname, addresses.INET_HOST);
+ assert.match(err.message, /getaddrinfo EAI_BADFLAGS/);
+ done();
+ return;
+ }
+
+ assert.ifError(err);
+ }
+
+ assert.ok(isIPv6(ip));
+ assert.strictEqual(family, 6);
+
+ done();
+ }));
+
+ checkWrap(req);
+});
+
+TEST(async function test_lookup_ip_ipv6(done) {
+ function validateResult(res) {
+ assert.ok(isIPv6(res.address));
+ assert.strictEqual(res.family, 6);
+ }
+
+ validateResult(await dnsPromises.lookup('::1'));
+
+ const req = dns.lookup(
+ '::1',
+ common.mustSucceed((ip, family) => {
+ validateResult({ address: ip, family });
+ done();
+ }));
+
+ checkWrap(req);
+});
+
+TEST(async function test_lookup_all_ipv6(done) {
+ function validateResult(res) {
+ assert.ok(Array.isArray(res));
+ assert.ok(res.length > 0);
+
+ res.forEach((ip) => {
+ assert.ok(isIPv6(ip.address),
+ `Invalid IPv6: ${ip.address.toString()}`);
+ assert.strictEqual(ip.family, 6);
+ });
+ }
+
+ validateResult(await dnsPromises.lookup(addresses.INET6_HOST, {
+ all: true,
+ family: 6
+ }));
+
+ const req = dns.lookup(
+ addresses.INET6_HOST,
+ { all: true, family: 6 },
+ common.mustSucceed((ips) => {
+ validateResult(ips);
+ done();
+ })
+ );
+
+ checkWrap(req);
+});
+
+// TEST(function test_lookupservice_ip_ipv6(done) {
+// const req = dns.lookupService(
+// '::1', 80,
+// common.mustCall((err, host, service) => {
+// if (err) {
+// // Not skipping the test, rather checking an alternative result,
+// // i.e. that ::1 may not be configured (e.g. in /etc/hosts)
+// assert.strictEqual(err.code, 'ENOTFOUND');
+// return done();
+// }
+// assert.strictEqual(typeof host, 'string');
+// assert(host);
+// assert(['http', 'www', '80'].includes(service));
+// done();
+// })
+// );
+
+// checkWrap(req);
+// });
+
+// Disabled because it appears to be not working on Linux.
+// TEST(function test_lookup_localhost_ipv6(done) {
+// var req = dns.lookup('localhost', 6, function(err, ip, family) {
+// assert.ifError(err);
+// assert.ok(net.isIPv6(ip));
+// assert.strictEqual(family, 6);
+//
+// done();
+// });
+//
+// checkWrap(req);
+// });
diff --git a/tests/node_compat/test/internet/test-dns-lookup.js b/tests/node_compat/test/internet/test-dns-lookup.js
new file mode 100644
index 000000000..cfd3e758c
--- /dev/null
+++ b/tests/node_compat/test/internet/test-dns-lookup.js
@@ -0,0 +1,61 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+require('../common');
+const common = require('../common');
+const dns = require('dns');
+const dnsPromises = dns.promises;
+const { addresses } = require('../common/internet');
+const assert = require('assert');
+
+assert.rejects(
+ dnsPromises.lookup(addresses.NOT_FOUND, {
+ hints: 0,
+ family: 0,
+ all: false,
+ }),
+ {
+ code: 'ENOTFOUND',
+ message: `getaddrinfo ENOTFOUND ${addresses.NOT_FOUND}`,
+ },
+);
+
+assert.rejects(
+ dnsPromises.lookup(addresses.NOT_FOUND, {
+ hints: 0,
+ family: 0,
+ all: true,
+ }),
+ {
+ code: 'ENOTFOUND',
+ message: `getaddrinfo ENOTFOUND ${addresses.NOT_FOUND}`,
+ },
+);
+
+dns.lookup(addresses.NOT_FOUND, {
+ hints: 0,
+ family: 0,
+ all: true,
+}, common.mustCall((error) => {
+ assert.strictEqual(error.code, 'ENOTFOUND');
+ assert.strictEqual(
+ error.message,
+ `getaddrinfo ENOTFOUND ${addresses.NOT_FOUND}`,
+ );
+ assert.strictEqual(error.syscall, 'getaddrinfo');
+ assert.strictEqual(error.hostname, addresses.NOT_FOUND);
+}));
+
+assert.throws(
+ () => dnsPromises.lookup(addresses.NOT_FOUND, {
+ family: 'ipv4',
+ all: 'all',
+ }),
+ { code: 'ERR_INVALID_ARG_VALUE' },
+);
diff --git a/tests/node_compat/test/internet/test-dns-promises-resolve.js b/tests/node_compat/test/internet/test-dns-promises-resolve.js
new file mode 100644
index 000000000..e4ee5f782
--- /dev/null
+++ b/tests/node_compat/test/internet/test-dns-promises-resolve.js
@@ -0,0 +1,49 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+
+const dnsPromises = require('dns').promises;
+
+// Error when rrtype is invalid.
+{
+ const rrtype = 'DUMMY';
+ assert.throws(
+ () => dnsPromises.resolve('example.org', rrtype),
+ {
+ code: 'ERR_INVALID_ARG_VALUE',
+ name: 'TypeError',
+ message: `The argument 'rrtype' is invalid. Received '${rrtype}'`,
+ },
+ );
+}
+
+// Error when rrtype is a number.
+{
+ const rrtype = 0;
+ assert.throws(
+ () => dnsPromises.resolve('example.org', rrtype),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: 'The "rrtype" argument must be of type string. ' +
+ `Received type ${typeof rrtype} (${rrtype})`,
+ },
+ );
+}
+
+// Setting rrtype to undefined should work like resolve4.
+{
+ (async function() {
+ const rrtype = undefined;
+ const result = await dnsPromises.resolve('example.org', rrtype);
+ assert.ok(result !== undefined);
+ assert.ok(result.length > 0);
+ })().then(common.mustCall());
+}
diff --git a/tests/node_compat/test/internet/test-dns-regress-6244.js b/tests/node_compat/test/internet/test-dns-regress-6244.js
new file mode 100644
index 000000000..988cf21ee
--- /dev/null
+++ b/tests/node_compat/test/internet/test-dns-regress-6244.js
@@ -0,0 +1,35 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const dns = require('dns');
+
+// Should not segfault.
+// Ref: https://github.com/nodejs/node-v0.x-archive/issues/6244
+dns.resolve4('127.0.0.1', common.mustCall());
diff --git a/tests/node_compat/test/internet/test-dns-setserver-in-callback-of-resolve4.js b/tests/node_compat/test/internet/test-dns-setserver-in-callback-of-resolve4.js
new file mode 100644
index 000000000..b4360c205
--- /dev/null
+++ b/tests/node_compat/test/internet/test-dns-setserver-in-callback-of-resolve4.js
@@ -0,0 +1,25 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+// We don't care about `err` in the callback function of `dns.resolve4`. We just
+// want to test whether `dns.setServers` that is run after `resolve4` will cause
+// a crash or not. If it doesn't crash, the test succeeded.
+
+const common = require('../common');
+const { addresses } = require('../common/internet');
+const dns = require('dns');
+
+dns.resolve4(
+ addresses.INET4_HOST,
+ common.mustCall(function(/* err, nameServers */) {
+ dns.setServers([ addresses.DNS4_SERVER ]);
+ }));
+
+// Test https://github.com/nodejs/node/issues/14734
+dns.resolve4(addresses.INET4_HOST, common.mustCall());
diff --git a/tests/node_compat/test/internet/test-dns.js b/tests/node_compat/test/internet/test-dns.js
new file mode 100644
index 000000000..8aaeb728d
--- /dev/null
+++ b/tests/node_compat/test/internet/test-dns.js
@@ -0,0 +1,766 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 16.13.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// Flags: --expose-internals
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+
+// TODO(cmorten): enable remaining tests once functionality is implemented.
+
+const common = require('../common');
+const { addresses } = require('../common/internet');
+const { internalBinding } = require('internal/test/binding');
+// const { getSystemErrorName } = require('util');
+const assert = require('assert');
+const dns = require('dns');
+const net = require('net');
+const isIPv4 = net.isIPv4;
+const isIPv6 = net.isIPv6;
+const util = require('util');
+const dnsPromises = dns.promises;
+
+let expected = 0;
+let completed = 0;
+let running = false;
+const queue = [];
+
+
+function TEST(f) {
+ function next() {
+ const f = queue.shift();
+ if (f) {
+ running = true;
+ console.log(f.name);
+ f(done);
+ }
+ }
+
+ function done() {
+ running = false;
+ completed++;
+ process.nextTick(next);
+ }
+
+ expected++;
+ queue.push(f);
+
+ if (!running) {
+ next();
+ }
+}
+
+
+function checkWrap(req) {
+ assert.strictEqual(typeof req, 'object');
+}
+
+
+// TEST(function test_reverse_bogus(done) {
+// dnsPromises.reverse('bogus ip')
+// .then(common.mustNotCall())
+// .catch(common.mustCall((err) => {
+// assert.strictEqual(err.code, 'EINVAL');
+// assert.strictEqual(getSystemErrorName(err.errno), 'EINVAL');
+// }));
+
+// assert.throws(() => {
+// dns.reverse('bogus ip', common.mustNotCall());
+// }, /^Error: getHostByAddr EINVAL bogus ip$/);
+// done();
+// });
+
+// TEST(async function test_resolve4_ttl(done) {
+// function validateResult(result) {
+// assert.ok(result.length > 0);
+
+// for (const item of result) {
+// assert.strictEqual(typeof item, 'object');
+// assert.strictEqual(typeof item.ttl, 'number');
+// assert.strictEqual(typeof item.address, 'string');
+// assert.ok(item.ttl >= 0);
+// assert.ok(isIPv4(item.address));
+// }
+// }
+
+// validateResult(await dnsPromises.resolve4(addresses.INET4_HOST, {
+// ttl: true
+// }));
+
+// const req = dns.resolve4(addresses.INET4_HOST, {
+// ttl: true
+// }, function(err, result) {
+// assert.ifError(err);
+// validateResult(result);
+// done();
+// });
+
+// checkWrap(req);
+// });
+
+// TEST(async function test_resolve6_ttl(done) {
+// function validateResult(result) {
+// assert.ok(result.length > 0);
+
+// for (const item of result) {
+// assert.strictEqual(typeof item, 'object');
+// assert.strictEqual(typeof item.ttl, 'number');
+// assert.strictEqual(typeof item.address, 'string');
+// assert.ok(item.ttl >= 0);
+// assert.ok(isIPv6(item.address));
+// }
+// }
+
+// validateResult(await dnsPromises.resolve6(addresses.INET6_HOST, {
+// ttl: true
+// }));
+
+// const req = dns.resolve6(addresses.INET6_HOST, {
+// ttl: true
+// }, function(err, result) {
+// assert.ifError(err);
+// validateResult(result);
+// done();
+// });
+
+// checkWrap(req);
+// });
+
+TEST(async function test_resolveMx(done) {
+ function validateResult(result) {
+ assert.ok(result.length > 0);
+
+ for (const item of result) {
+ assert.strictEqual(typeof item, 'object');
+ assert.ok(item.exchange);
+ assert.strictEqual(typeof item.exchange, 'string');
+ assert.strictEqual(typeof item.priority, 'number');
+ }
+ }
+
+ validateResult(await dnsPromises.resolveMx(addresses.MX_HOST));
+
+ const req = dns.resolveMx(addresses.MX_HOST, function(err, result) {
+ assert.ifError(err);
+ validateResult(result);
+ done();
+ });
+
+ checkWrap(req);
+});
+
+// TODO(bartlomieju): this test became very flaky on CI, returning `UNKNOWN`
+// instead of `ENOTFOUND`.
+// TEST(function test_resolveMx_failure(done) {
+// dnsPromises.resolveMx(addresses.NOT_FOUND)
+// .then(common.mustNotCall())
+// .catch(common.mustCall((err) => {
+// assert.strictEqual(err.code, 'ENOTFOUND');
+// }));
+
+// const req = dns.resolveMx(addresses.NOT_FOUND, function(err, result) {
+// assert.ok(err instanceof Error);
+// assert.strictEqual(err.code, 'ENOTFOUND');
+
+// assert.strictEqual(result, undefined);
+
+// done();
+// });
+
+// checkWrap(req);
+// });
+
+TEST(async function test_resolveNs(done) {
+ function validateResult(result) {
+ assert.ok(result.length > 0);
+
+ for (const item of result) {
+ assert.ok(item);
+ assert.strictEqual(typeof item, 'string');
+ }
+ }
+
+ validateResult(await dnsPromises.resolveNs(addresses.NS_HOST));
+
+ const req = dns.resolveNs(addresses.NS_HOST, function(err, names) {
+ assert.ifError(err);
+ validateResult(names);
+ done();
+ });
+
+ checkWrap(req);
+});
+
+// TODO(bartlomieju): this test became very flaky on CI, returning `UNKNOWN`
+// instead of `ENOTFOUND`.
+// TEST(function test_resolveNs_failure(done) {
+// dnsPromises.resolveNs(addresses.NOT_FOUND)
+// .then(common.mustNotCall())
+// .catch(common.mustCall((err) => {
+// assert.strictEqual(err.code, 'ENOTFOUND');
+// }));
+
+// const req = dns.resolveNs(addresses.NOT_FOUND, function(err, result) {
+// assert.ok(err instanceof Error);
+// assert.strictEqual(err.code, 'ENOTFOUND');
+
+// assert.strictEqual(result, undefined);
+
+// done();
+// });
+
+// checkWrap(req);
+// });
+
+TEST(async function test_resolveSrv(done) {
+ function validateResult(result) {
+ assert.ok(result.length > 0);
+
+ for (const item of result) {
+ assert.strictEqual(typeof item, 'object');
+ assert.ok(item.name);
+ assert.strictEqual(typeof item.name, 'string');
+ assert.strictEqual(typeof item.port, 'number');
+ assert.strictEqual(typeof item.priority, 'number');
+ assert.strictEqual(typeof item.weight, 'number');
+ }
+ }
+
+ validateResult(await dnsPromises.resolveSrv(addresses.SRV_HOST));
+
+ const req = dns.resolveSrv(addresses.SRV_HOST, function(err, result) {
+ assert.ifError(err);
+ validateResult(result);
+ done();
+ });
+
+ checkWrap(req);
+});
+
+// TODO(bartlomieju): this test became very flaky on CI, returning `UNKNOWN`
+// instead of `ENOTFOUND`.
+// TEST(function test_resolveSrv_failure(done) {
+// dnsPromises.resolveSrv(addresses.NOT_FOUND)
+// .then(common.mustNotCall())
+// .catch(common.mustCall((err) => {
+// assert.strictEqual(err.code, 'ENOTFOUND');
+// }));
+
+// const req = dns.resolveSrv(addresses.NOT_FOUND, function(err, result) {
+// assert.ok(err instanceof Error);
+// assert.strictEqual(err.code, 'ENOTFOUND');
+
+// assert.strictEqual(result, undefined);
+
+// done();
+// });
+
+// checkWrap(req);
+// });
+
+// TODO(bartlomieju): this test started failing on CI on Dec 28th, 2023 returning
+// ENOTFOUND. It's unclear what's going on, since `dig -x 8.8.8.8.in-addr.arpa`
+// returns correct PTR record.
+// TEST(async function test_resolvePtr(done) {
+// function validateResult(result) {
+// assert.ok(result.length > 0);
+
+// for (const item of result) {
+// assert.ok(item);
+// assert.strictEqual(typeof item, 'string');
+// }
+// }
+
+// validateResult(await dnsPromises.resolvePtr(addresses.PTR_HOST));
+
+// const req = dns.resolvePtr(addresses.PTR_HOST, function(err, result) {
+// assert.ifError(err);
+// validateResult(result);
+// done();
+// });
+
+// checkWrap(req);
+// });
+
+// TODO(bartlomieju): this test became very flaky on CI, returning `UNKNOWN`
+// instead of `ENOTFOUND`.
+// TEST(function test_resolvePtr_failure(done) {
+// dnsPromises.resolvePtr(addresses.NOT_FOUND)
+// .then(common.mustNotCall())
+// .catch(common.mustCall((err) => {
+// assert.strictEqual(err.code, 'ENOTFOUND');
+// }));
+
+// const req = dns.resolvePtr(addresses.NOT_FOUND, function(err, result) {
+// assert.ok(err instanceof Error);
+// assert.strictEqual(err.code, 'ENOTFOUND');
+
+// assert.strictEqual(result, undefined);
+
+// done();
+// });
+
+// checkWrap(req);
+// });
+
+TEST(async function test_resolveNaptr(done) {
+ function validateResult(result) {
+ assert.ok(result.length > 0);
+
+ for (const item of result) {
+ assert.strictEqual(typeof item, 'object');
+ assert.strictEqual(typeof item.flags, 'string');
+ assert.strictEqual(typeof item.service, 'string');
+ assert.strictEqual(typeof item.regexp, 'string');
+ assert.strictEqual(typeof item.replacement, 'string');
+ assert.strictEqual(typeof item.order, 'number');
+ assert.strictEqual(typeof item.preference, 'number');
+ }
+ }
+
+ validateResult(await dnsPromises.resolveNaptr(addresses.NAPTR_HOST));
+
+ const req = dns.resolveNaptr(addresses.NAPTR_HOST, function(err, result) {
+ assert.ifError(err);
+ validateResult(result);
+ done();
+ });
+
+ checkWrap(req);
+});
+
+// TODO(bartlomieju): this test became very flaky on CI, returning `UNKNOWN`
+// instead of `ENOTFOUND`.
+// TEST(function test_resolveNaptr_failure(done) {
+// dnsPromises.resolveNaptr(addresses.NOT_FOUND)
+// .then(common.mustNotCall())
+// .catch(common.mustCall((err) => {
+// assert.strictEqual(err.code, 'ENOTFOUND');
+// }));
+
+// const req = dns.resolveNaptr(addresses.NOT_FOUND, function(err, result) {
+// assert.ok(err instanceof Error);
+// assert.strictEqual(err.code, 'ENOTFOUND');
+
+// assert.strictEqual(result, undefined);
+
+// done();
+// });
+
+// checkWrap(req);
+// });
+
+TEST(async function test_resolveSoa(done) {
+ function validateResult(result) {
+ assert.strictEqual(typeof result, 'object');
+ assert.strictEqual(typeof result.nsname, 'string');
+ assert.ok(result.nsname.length > 0);
+ assert.strictEqual(typeof result.hostmaster, 'string');
+ assert.ok(result.hostmaster.length > 0);
+ assert.strictEqual(typeof result.serial, 'number');
+ assert.ok((result.serial > 0) && (result.serial < 4294967295));
+ assert.strictEqual(typeof result.refresh, 'number');
+ assert.ok((result.refresh > 0) && (result.refresh < 2147483647));
+ assert.strictEqual(typeof result.retry, 'number');
+ assert.ok((result.retry > 0) && (result.retry < 2147483647));
+ assert.strictEqual(typeof result.expire, 'number');
+ assert.ok((result.expire > 0) && (result.expire < 2147483647));
+ assert.strictEqual(typeof result.minttl, 'number');
+ assert.ok((result.minttl >= 0) && (result.minttl < 2147483647));
+ }
+
+ validateResult(await dnsPromises.resolveSoa(addresses.SOA_HOST));
+
+ const req = dns.resolveSoa(addresses.SOA_HOST, function(err, result) {
+ assert.ifError(err);
+ validateResult(result);
+ done();
+ });
+
+ checkWrap(req);
+});
+
+// TODO(bartlomieju): this test became very flaky on CI, returning `UNKNOWN`
+// instead of `ENOTFOUND`.
+// TEST(function test_resolveSoa_failure(done) {
+// dnsPromises.resolveSoa(addresses.NOT_FOUND)
+// .then(common.mustNotCall())
+// .catch(common.mustCall((err) => {
+// assert.strictEqual(err.code, 'ENOTFOUND');
+// }));
+
+// const req = dns.resolveSoa(addresses.NOT_FOUND, function(err, result) {
+// assert.ok(err instanceof Error);
+// assert.strictEqual(err.code, 'ENOTFOUND');
+
+// assert.strictEqual(result, undefined);
+
+// done();
+// });
+
+// checkWrap(req);
+// });
+
+TEST(async function test_resolveCaa(done) {
+ function validateResult(result) {
+ assert.ok(Array.isArray(result),
+ `expected array, got ${util.inspect(result)}`);
+ assert.strictEqual(result.length, 1);
+ assert.strictEqual(typeof result[0].critical, 'number');
+ assert.strictEqual(result[0].critical, 0);
+ assert.strictEqual(result[0].issue, 'pki.goog');
+ }
+
+ validateResult(await dnsPromises.resolveCaa(addresses.CAA_HOST));
+
+ const req = dns.resolveCaa(addresses.CAA_HOST, function(err, records) {
+ assert.ifError(err);
+ validateResult(records);
+ done();
+ });
+
+ checkWrap(req);
+});
+
+// NOTE(bartlomieju): this test started failing around July 11th, 2023.
+// TEST(async function test_resolveCname(done) {
+// function validateResult(result) {
+// assert.ok(result.length > 0);
+//
+// for (const item of result) {
+// assert.ok(item);
+// assert.strictEqual(typeof item, 'string');
+// }
+// }
+//
+// validateResult(await dnsPromises.resolveCname(addresses.CNAME_HOST));
+//
+// const req = dns.resolveCname(addresses.CNAME_HOST, function(err, names) {
+// assert.ifError(err);
+// validateResult(names);
+// done();
+// });
+//
+// checkWrap(req);
+// });
+
+// TODO(bartlomieju): this test became very flaky on CI, returning `UNKNOWN`
+// instead of `ENOTFOUND`.
+// TEST(function test_resolveCname_failure(done) {
+// dnsPromises.resolveCname(addresses.NOT_FOUND)
+// .then(common.mustNotCall())
+// .catch(common.mustCall((err) => {
+// assert.strictEqual(err.code, 'ENOTFOUND');
+// }));
+
+// const req = dns.resolveCname(addresses.NOT_FOUND, function(err, result) {
+// assert.ok(err instanceof Error);
+// assert.strictEqual(err.code, 'ENOTFOUND');
+
+// assert.strictEqual(result, undefined);
+
+// done();
+// });
+
+// checkWrap(req);
+// });
+
+
+TEST(async function test_resolveTxt(done) {
+ function validateResult(result) {
+ assert.ok(Array.isArray(result[0]));
+ assert.strictEqual(result.length, 1);
+ assert(result[0][0].startsWith('v=spf1'));
+ }
+
+ validateResult(await dnsPromises.resolveTxt(addresses.TXT_HOST));
+
+ const req = dns.resolveTxt(addresses.TXT_HOST, function(err, records) {
+ assert.ifError(err);
+ validateResult(records);
+ done();
+ });
+
+ checkWrap(req);
+});
+
+// TODO(bartlomieju): this test became very flaky on CI, returning `UNKNOWN`
+// instead of `ENOTFOUND`.
+// TEST(function test_resolveTxt_failure(done) {
+// dnsPromises.resolveTxt(addresses.NOT_FOUND)
+// .then(common.mustNotCall())
+// .catch(common.mustCall((err) => {
+// assert.strictEqual(err.code, 'ENOTFOUND');
+// }));
+
+// const req = dns.resolveTxt(addresses.NOT_FOUND, function(err, result) {
+// assert.ok(err instanceof Error);
+// assert.strictEqual(err.code, 'ENOTFOUND');
+
+// assert.strictEqual(result, undefined);
+
+// done();
+// });
+
+// checkWrap(req);
+// });
+
+
+TEST(function test_lookup_failure(done) {
+ dnsPromises.lookup(addresses.NOT_FOUND, 4)
+ .then(common.mustNotCall())
+ .catch(common.expectsError({ code: dns.NOTFOUND }));
+
+ const req = dns.lookup(addresses.NOT_FOUND, 4, (err) => {
+ assert.ok(err instanceof Error);
+ assert.strictEqual(err.code, dns.NOTFOUND);
+ assert.strictEqual(err.code, 'ENOTFOUND');
+ assert.doesNotMatch(err.message, /ENOENT/);
+ assert.ok(err.message.includes(addresses.NOT_FOUND));
+
+ done();
+ });
+
+ checkWrap(req);
+});
+
+
+TEST(async function test_lookup_ip_all(done) {
+ function validateResult(result) {
+ assert.ok(Array.isArray(result));
+ assert.ok(result.length > 0);
+ assert.strictEqual(result[0].address, '127.0.0.1');
+ assert.strictEqual(result[0].family, 4);
+ }
+
+ validateResult(await dnsPromises.lookup('127.0.0.1', { all: true }));
+
+ const req = dns.lookup(
+ '127.0.0.1',
+ { all: true },
+ function(err, ips, family) {
+ assert.ifError(err);
+ assert.strictEqual(family, undefined);
+ validateResult(ips);
+ done();
+ }
+ );
+
+ checkWrap(req);
+});
+
+
+TEST(function test_lookup_ip_all_promise(done) {
+ const req = util.promisify(dns.lookup)('127.0.0.1', { all: true })
+ .then(function(ips) {
+ assert.ok(Array.isArray(ips));
+ assert.ok(ips.length > 0);
+ assert.strictEqual(ips[0].address, '127.0.0.1');
+ assert.strictEqual(ips[0].family, 4);
+
+ done();
+ });
+
+ checkWrap(req);
+});
+
+
+TEST(function test_lookup_ip_promise(done) {
+ util.promisify(dns.lookup)('127.0.0.1')
+ .then(function({ address, family }) {
+ assert.strictEqual(address, '127.0.0.1');
+ assert.strictEqual(family, 4);
+
+ done();
+ });
+});
+
+
+TEST(async function test_lookup_null_all(done) {
+ assert.deepStrictEqual(await dnsPromises.lookup(null, { all: true }), []);
+
+ const req = dns.lookup(null, { all: true }, (err, ips) => {
+ assert.ifError(err);
+ assert.ok(Array.isArray(ips));
+ assert.strictEqual(ips.length, 0);
+
+ done();
+ });
+
+ checkWrap(req);
+});
+
+
+TEST(async function test_lookup_all_mixed(done) {
+ function validateResult(result) {
+ assert.ok(Array.isArray(result));
+ assert.ok(result.length > 0);
+
+ result.forEach(function(ip) {
+ if (isIPv4(ip.address))
+ assert.strictEqual(ip.family, 4);
+ else if (isIPv6(ip.address))
+ assert.strictEqual(ip.family, 6);
+ else
+ assert.fail('unexpected IP address');
+ });
+ }
+
+ validateResult(await dnsPromises.lookup(addresses.INET_HOST, { all: true }));
+
+ const req = dns.lookup(addresses.INET_HOST, {
+ all: true
+ }, function(err, ips) {
+ assert.ifError(err);
+ validateResult(ips);
+ done();
+ });
+
+ checkWrap(req);
+});
+
+
+// TEST(function test_lookupservice_invalid(done) {
+// dnsPromises.lookupService('1.2.3.4', 80)
+// .then(common.mustNotCall())
+// .catch(common.expectsError({ code: 'ENOTFOUND' }));
+
+// const req = dns.lookupService('1.2.3.4', 80, (err) => {
+// assert(err instanceof Error);
+// assert.strictEqual(err.code, 'ENOTFOUND');
+// assert.match(err.message, /1\.2\.3\.4/);
+
+// done();
+// });
+
+// checkWrap(req);
+// });
+
+
+// TEST(function test_reverse_failure(done) {
+// dnsPromises.reverse('203.0.113.0')
+// .then(common.mustNotCall())
+// .catch(common.expectsError({
+// code: 'ENOTFOUND',
+// hostname: '203.0.113.0'
+// }));
+
+// // 203.0.113.0/24 are addresses reserved for (RFC) documentation use only
+// const req = dns.reverse('203.0.113.0', function(err) {
+// assert(err instanceof Error);
+// assert.strictEqual(err.code, 'ENOTFOUND'); // Silly error code...
+// assert.strictEqual(err.hostname, '203.0.113.0');
+// assert.match(err.message, /203\.0\.113\.0/);
+
+// done();
+// });
+
+// checkWrap(req);
+// });
+
+
+// TODO(bartlomieju): this test became very flaky on CI, returning `UNKNOWN`
+// instead of `ENOTFOUND`.
+// TEST(function test_lookup_failure(done) {
+// dnsPromises.lookup(addresses.NOT_FOUND)
+// .then(common.mustNotCall())
+// .catch(common.expectsError({
+// code: 'ENOTFOUND',
+// hostname: addresses.NOT_FOUND
+// }));
+
+// const req = dns.lookup(addresses.NOT_FOUND, (err) => {
+// assert(err instanceof Error);
+// assert.strictEqual(err.code, 'ENOTFOUND'); // Silly error code...
+// assert.strictEqual(err.hostname, addresses.NOT_FOUND);
+// assert.ok(err.message.includes(addresses.NOT_FOUND));
+
+// done();
+// });
+
+// checkWrap(req);
+// });
+
+
+// TODO(bartlomieju): this test became very flaky on CI, returning `UNKNOWN`
+// instead of `ENOTFOUND`.
+// TEST(function test_resolve_failure(done) {
+// const req = dns.resolve4(addresses.NOT_FOUND, (err) => {
+// assert(err instanceof Error);
+
+// switch (err.code) {
+// case 'ENOTFOUND':
+// case 'ESERVFAIL':
+// break;
+// default:
+// assert.strictEqual(err.code, 'ENOTFOUND'); // Silly error code...
+// break;
+// }
+
+// assert.strictEqual(err.hostname, addresses.NOT_FOUND);
+// assert.ok(err.message.includes(addresses.NOT_FOUND));
+
+// done();
+// });
+
+// checkWrap(req);
+// });
+
+
+let getaddrinfoCallbackCalled = false;
+
+console.log(`looking up ${addresses.INET4_HOST}..`);
+
+const cares = internalBinding('cares_wrap');
+const req = new cares.GetAddrInfoReqWrap();
+cares.getaddrinfo(req, addresses.INET4_HOST, 4,
+ /* hints */ 0, /* verbatim */ true);
+
+req.oncomplete = function(err, domains) {
+ assert.strictEqual(err, 0);
+ console.log(`${addresses.INET4_HOST} = ${domains}`);
+ assert.ok(Array.isArray(domains));
+ assert.ok(domains.length >= 1);
+ assert.strictEqual(typeof domains[0], 'string');
+ getaddrinfoCallbackCalled = true;
+};
+
+process.on('exit', function() {
+ console.log(`${completed} tests completed`);
+ assert.strictEqual(running, false);
+ assert.strictEqual(completed, expected);
+ assert.ok(getaddrinfoCallbackCalled);
+});
+
+// Should not throw.
+dns.lookup(addresses.INET6_HOST, 6, common.mustCall());
+dns.lookup(addresses.INET_HOST, {}, common.mustCall());
+// dns.lookupService('0.0.0.0', '0', common.mustCall());
+// dns.lookupService('0.0.0.0', 0, common.mustCall());
+(async function() {
+ await dnsPromises.lookup(addresses.INET6_HOST, 6);
+ await dnsPromises.lookup(addresses.INET_HOST, {});
+})().then(common.mustCall());
diff --git a/tests/node_compat/test/internet/test-http-https-default-ports.js b/tests/node_compat/test/internet/test-http-https-default-ports.js
new file mode 100644
index 000000000..ef3edd2fc
--- /dev/null
+++ b/tests/node_compat/test/internet/test-http-https-default-ports.js
@@ -0,0 +1,46 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const { addresses } = require('../common/internet');
+
+if (!common.hasCrypto)
+ common.skip('missing crypto');
+
+const https = require('https');
+
+const http = require('http');
+
+https.get(`https://${addresses.INET_HOST}/`, common.mustCall((res) => {
+ res.resume();
+}));
+
+http.get(`http://${addresses.INET_HOST}/`, common.mustCall((res) => {
+ res.resume();
+}));
diff --git a/tests/node_compat/test/parallel/package.json b/tests/node_compat/test/parallel/package.json
new file mode 100644
index 000000000..0967ef424
--- /dev/null
+++ b/tests/node_compat/test/parallel/package.json
@@ -0,0 +1 @@
+{}
diff --git a/tests/node_compat/test/parallel/test-assert-async.js b/tests/node_compat/test/parallel/test-assert-async.js
new file mode 100644
index 000000000..a2a8315d8
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-assert-async.js
@@ -0,0 +1,244 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+
+// Run all tests in parallel and check their outcome at the end.
+const promises = [];
+
+// Thenable object without `catch` method,
+// shouldn't be considered as a valid Thenable
+const invalidThenable = {
+ then: (fulfill, reject) => {
+ fulfill();
+ },
+};
+
+// Function that returns a Thenable function,
+// a function with `catch` and `then` methods attached,
+// shouldn't be considered as a valid Thenable.
+const invalidThenableFunc = () => {
+ function f() {}
+
+ f.then = (fulfill, reject) => {
+ fulfill();
+ };
+ f.catch = () => {};
+
+ return f;
+};
+
+// Test assert.rejects() and assert.doesNotReject() by checking their
+// expected output and by verifying that they do not work sync
+
+// Check `assert.rejects`.
+{
+ const rejectingFn = async () => assert.fail();
+ const errObj = {
+ code: 'ERR_ASSERTION',
+ name: 'AssertionError',
+ message: 'Failed'
+ };
+
+ // `assert.rejects` accepts a function or a promise
+ // or a thenable as first argument.
+ promises.push(assert.rejects(rejectingFn, errObj));
+ promises.push(assert.rejects(rejectingFn(), errObj));
+
+ const validRejectingThenable = {
+ then: (fulfill, reject) => {
+ reject({ code: 'FAIL' });
+ },
+ catch: () => {}
+ };
+ promises.push(assert.rejects(validRejectingThenable, { code: 'FAIL' }));
+
+ // `assert.rejects` should not accept thenables that
+ // use a function as `obj` and that have no `catch` handler.
+ promises.push(assert.rejects(
+ assert.rejects(invalidThenable, {}),
+ {
+ code: 'ERR_INVALID_ARG_TYPE'
+ })
+ );
+ promises.push(assert.rejects(
+ assert.rejects(invalidThenableFunc, {}),
+ {
+ code: 'ERR_INVALID_RETURN_VALUE'
+ })
+ );
+
+ const err = new Error('foobar');
+ const validate = () => { return 'baz'; };
+ promises.push(assert.rejects(
+ () => assert.rejects(Promise.reject(err), validate),
+ {
+ message: 'The "validate" validation function is expected to ' +
+ "return \"true\". Received 'baz'\n\nCaught error:\n\n" +
+ 'Error: foobar',
+ code: 'ERR_ASSERTION',
+ actual: err,
+ expected: validate,
+ name: 'AssertionError',
+ operator: 'rejects',
+ }
+ ));
+}
+
+{
+ const handler = (err) => {
+ assert(err instanceof assert.AssertionError,
+ `${err.name} is not instance of AssertionError`);
+ assert.strictEqual(err.code, 'ERR_ASSERTION');
+ assert.strictEqual(err.message,
+ 'Missing expected rejection (mustNotCall).');
+ assert.strictEqual(err.operator, 'rejects');
+ assert.ok(!err.stack.includes('at Function.rejects'));
+ return true;
+ };
+
+ let promise = assert.rejects(async () => {}, common.mustNotCall());
+ promises.push(assert.rejects(promise, common.mustCall(handler)));
+
+ promise = assert.rejects(() => {}, common.mustNotCall());
+ promises.push(assert.rejects(promise, {
+ name: 'TypeError',
+ code: 'ERR_INVALID_RETURN_VALUE',
+ // FIXME(JakobJingleheimer): This should match on key words, like /Promise/ and /undefined/.
+ message: 'Expected instance of Promise to be returned ' +
+ 'from the "promiseFn" function but got undefined.'
+ }));
+
+ promise = assert.rejects(Promise.resolve(), common.mustNotCall());
+ promises.push(assert.rejects(promise, common.mustCall(handler)));
+}
+
+{
+ const THROWN_ERROR = new Error();
+
+ promises.push(assert.rejects(() => {
+ throw THROWN_ERROR;
+ }, {}).catch(common.mustCall((err) => {
+ assert.strictEqual(err, THROWN_ERROR);
+ })));
+}
+
+promises.push(assert.rejects(
+ assert.rejects('fail', {}),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ message: 'The "promiseFn" argument must be of type function or an ' +
+ "instance of Promise. Received type string ('fail')"
+ }
+));
+
+{
+ const handler = (generated, actual, err) => {
+ assert.strictEqual(err.generatedMessage, generated);
+ assert.strictEqual(err.code, 'ERR_ASSERTION');
+ assert.strictEqual(err.actual, actual);
+ assert.strictEqual(err.operator, 'rejects');
+ assert.match(err.stack, /rejects/);
+ return true;
+ };
+ const err = new Error();
+ promises.push(assert.rejects(
+ assert.rejects(Promise.reject(null), { code: 'FOO' }),
+ handler.bind(null, true, null)
+ ));
+ promises.push(assert.rejects(
+ assert.rejects(Promise.reject(5), { code: 'FOO' }, 'AAAAA'),
+ handler.bind(null, false, 5)
+ ));
+ promises.push(assert.rejects(
+ assert.rejects(Promise.reject(err), { code: 'FOO' }, 'AAAAA'),
+ handler.bind(null, false, err)
+ ));
+}
+
+// Check `assert.doesNotReject`.
+{
+ // `assert.doesNotReject` accepts a function or a promise
+ // or a thenable as first argument.
+ /* eslint-disable no-restricted-syntax */
+ let promise = assert.doesNotReject(() => new Map(), common.mustNotCall());
+ promises.push(assert.rejects(promise, {
+ message: 'Expected instance of Promise to be returned ' +
+ 'from the "promiseFn" function but got an instance of Map.',
+ code: 'ERR_INVALID_RETURN_VALUE',
+ name: 'TypeError'
+ }));
+ promises.push(assert.doesNotReject(async () => {}));
+ promises.push(assert.doesNotReject(Promise.resolve()));
+
+ // `assert.doesNotReject` should not accept thenables that
+ // use a function as `obj` and that have no `catch` handler.
+ const validFulfillingThenable = {
+ then: (fulfill, reject) => {
+ fulfill();
+ },
+ catch: () => {}
+ };
+ promises.push(assert.doesNotReject(validFulfillingThenable));
+ promises.push(assert.rejects(
+ assert.doesNotReject(invalidThenable),
+ {
+ code: 'ERR_INVALID_ARG_TYPE'
+ })
+ );
+ promises.push(assert.rejects(
+ assert.doesNotReject(invalidThenableFunc),
+ {
+ code: 'ERR_INVALID_RETURN_VALUE'
+ })
+ );
+
+ const handler1 = (err) => {
+ assert(err instanceof assert.AssertionError,
+ `${err.name} is not instance of AssertionError`);
+ assert.strictEqual(err.code, 'ERR_ASSERTION');
+ assert.strictEqual(err.message, 'Failed');
+ return true;
+ };
+ const handler2 = (err) => {
+ assert(err instanceof assert.AssertionError,
+ `${err.name} is not instance of AssertionError`);
+ assert.strictEqual(err.code, 'ERR_ASSERTION');
+ assert.strictEqual(err.message,
+ 'Got unwanted rejection.\nActual message: "Failed"');
+ assert.strictEqual(err.operator, 'doesNotReject');
+ assert.ok(err.stack);
+ assert.ok(!err.stack.includes('at Function.doesNotReject'));
+ return true;
+ };
+
+ const rejectingFn = async () => assert.fail();
+
+ promise = assert.doesNotReject(rejectingFn, common.mustCall(handler1));
+ promises.push(assert.rejects(promise, common.mustCall(handler2)));
+
+ promise = assert.doesNotReject(rejectingFn(), common.mustCall(handler1));
+ promises.push(assert.rejects(promise, common.mustCall(handler2)));
+
+ promise = assert.doesNotReject(() => assert.fail(), common.mustNotCall());
+ promises.push(assert.rejects(promise, common.mustCall(handler1)));
+
+ promises.push(assert.rejects(
+ assert.doesNotReject(123),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ message: 'The "promiseFn" argument must be of type ' +
+ 'function or an instance of Promise. Received type number (123)'
+ }
+ ));
+ /* eslint-enable no-restricted-syntax */
+}
+
+// Make sure all async code gets properly executed.
+Promise.all(promises).then(common.mustCall());
diff --git a/tests/node_compat/test/parallel/test-assert-fail.js b/tests/node_compat/test/parallel/test-assert-fail.js
new file mode 100644
index 000000000..03def3a88
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-assert-fail.js
@@ -0,0 +1,51 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const assert = require('assert');
+
+// No args
+assert.throws(
+ () => { assert.fail(); },
+ {
+ code: 'ERR_ASSERTION',
+ name: 'AssertionError',
+ message: 'Failed',
+ operator: 'fail',
+ actual: undefined,
+ expected: undefined,
+ generatedMessage: true,
+ stack: /Failed/
+ }
+);
+
+// One arg = message
+assert.throws(() => {
+ assert.fail('custom message');
+}, {
+ code: 'ERR_ASSERTION',
+ name: 'AssertionError',
+ message: 'custom message',
+ operator: 'fail',
+ actual: undefined,
+ expected: undefined,
+ generatedMessage: false
+});
+
+// One arg = Error
+assert.throws(() => {
+ assert.fail(new TypeError('custom message'));
+}, {
+ name: 'TypeError',
+ message: 'custom message'
+});
+
+Object.prototype.get = common.mustNotCall();
+assert.throws(() => assert.fail(''), { code: 'ERR_ASSERTION' });
+delete Object.prototype.get;
diff --git a/tests/node_compat/test/parallel/test-assert-strict-exists.js b/tests/node_compat/test/parallel/test-assert-strict-exists.js
new file mode 100644
index 000000000..49499c3f6
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-assert-strict-exists.js
@@ -0,0 +1,13 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+require('../common');
+const assert = require('assert');
+
+assert.strictEqual(require('assert/strict'), assert.strict);
diff --git a/tests/node_compat/test/parallel/test-assert.js b/tests/node_compat/test/parallel/test-assert.js
new file mode 100644
index 000000000..58b95068c
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-assert.js
@@ -0,0 +1,1615 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 15.5.1
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// Flags: --expose-internals
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+
+const common = require('../common');
+const assert = require('assert');
+const { inspect } = require('util');
+// TODO(kt3k): Enable these when "vm" is ready.
+// const vm = require('vm');
+// TODO(kt3k): Enable these when "internal/test/binding" is ready.
+// const { internalBinding } = require('internal/test/binding');
+const a = assert;
+
+// Disable colored output to prevent color codes from breaking assertion
+// message comparisons. This should only be an issue when process.stdout
+// is a TTY.
+if (process.stdout.isTTY)
+ process.env.NODE_DISABLE_COLORS = '1';
+
+const strictEqualMessageStart = 'Expected values to be strictly equal:\n';
+const start = 'Expected values to be strictly deep-equal:';
+const actExp = '+ actual - expected';
+
+assert.ok(a.AssertionError.prototype instanceof Error,
+ 'a.AssertionError instanceof Error');
+
+assert.throws(() => a(false), a.AssertionError, 'ok(false)');
+assert.throws(() => a.ok(false), a.AssertionError, 'ok(false)');
+
+// Throw message if the message is instanceof Error.
+{
+ let threw = false;
+ try {
+ assert.ok(false, new Error('ok(false)'));
+ } catch (e) {
+ threw = true;
+ assert.ok(e instanceof Error);
+ }
+ assert.ok(threw, 'Error: ok(false)');
+}
+
+
+a(true);
+a('test', 'ok(\'test\')');
+a.ok(true);
+a.ok('test');
+
+assert.throws(() => a.equal(true, false),
+ a.AssertionError, 'equal(true, false)');
+
+a.equal(null, null);
+a.equal(undefined, undefined);
+a.equal(null, undefined);
+a.equal(true, true);
+a.equal(2, '2');
+a.notEqual(true, false);
+
+assert.throws(() => a.notEqual(true, true),
+ a.AssertionError, 'notEqual(true, true)');
+
+assert.throws(() => a.strictEqual(2, '2'),
+ a.AssertionError, 'strictEqual(2, \'2\')');
+
+assert.throws(() => a.strictEqual(null, undefined),
+ a.AssertionError, 'strictEqual(null, undefined)');
+
+assert.throws(
+ () => a.notStrictEqual(2, 2),
+ {
+ message: 'Expected "actual" to be strictly unequal to: 2\n',
+ name: 'AssertionError'
+ }
+);
+
+assert.throws(
+ () => a.notStrictEqual('a '.repeat(30), 'a '.repeat(30)),
+ {
+ message: 'Expected "actual" to be strictly unequal to: ' +
+ `"${'a '.repeat(30)}"\n`,
+ name: 'AssertionError'
+ }
+);
+
+assert.throws(
+ () => a.notEqual(1, 1),
+ {
+ message: '1 != 1',
+ operator: '!='
+ }
+);
+
+a.notStrictEqual(2, '2');
+
+// Testing the throwing.
+function thrower(errorConstructor) {
+ throw new errorConstructor({});
+}
+
+// The basic calls work.
+assert.throws(() => thrower(a.AssertionError), a.AssertionError, 'message');
+assert.throws(() => thrower(a.AssertionError), a.AssertionError);
+assert.throws(() => thrower(a.AssertionError));
+
+// If not passing an error, catch all.
+assert.throws(() => thrower(TypeError));
+
+// When passing a type, only catch errors of the appropriate type.
+assert.throws(
+ () => a.throws(() => thrower(TypeError), a.AssertionError),
+ {
+ // generatedMessage: true,
+ // actual: new TypeError({}),
+ expected: a.AssertionError,
+ code: 'ERR_ASSERTION',
+ name: 'AssertionError',
+ operator: 'throws',
+ message: 'The error is expected to be an instance of "AssertionError". ' +
+ 'Received "TypeError"\n\nError message:\n\n[object Object]'
+ }
+);
+
+// doesNotThrow should pass through all errors.
+{
+ let threw = false;
+ try {
+ a.doesNotThrow(() => thrower(TypeError), a.AssertionError);
+ } catch (e) {
+ threw = true;
+ assert.ok(e instanceof TypeError);
+ }
+ assert(threw, 'a.doesNotThrow with an explicit error is eating extra errors');
+}
+
+// Key difference is that throwing our correct error makes an assertion error.
+{
+ let threw = false;
+ try {
+ a.doesNotThrow(() => thrower(TypeError), TypeError);
+ } catch (e) {
+ threw = true;
+ assert.ok(e instanceof a.AssertionError);
+ // Commented out the following assertion
+ // assert.ok(!e.stack.includes('at Function.doesNotThrow'));
+ }
+ assert.ok(threw, 'a.doesNotThrow is not catching type matching errors');
+}
+
+assert.throws(
+ () => a.doesNotThrow(() => thrower(Error), 'user message'),
+ {
+ name: 'AssertionError',
+ code: 'ERR_ASSERTION',
+ operator: 'doesNotThrow',
+ message: 'Got unwanted exception: user message\n' +
+ 'Actual message: "[object Object]"'
+ }
+);
+
+assert.throws(
+ () => a.doesNotThrow(() => thrower(Error)),
+ {
+ code: 'ERR_ASSERTION',
+ message: 'Got unwanted exception.\nActual message: "[object Object]"'
+ }
+);
+
+assert.throws(
+ () => a.doesNotThrow(() => thrower(Error), /\[[a-z]{6}\s[A-z]{6}\]/g, 'user message'),
+ {
+ name: 'AssertionError',
+ code: 'ERR_ASSERTION',
+ operator: 'doesNotThrow',
+ message: 'Got unwanted exception: user message\n' +
+ 'Actual message: "[object Object]"'
+ }
+);
+
+// Make sure that validating using constructor really works.
+{
+ let threw = false;
+ try {
+ assert.throws(
+ () => {
+ throw ({});
+ },
+ Array
+ );
+ } catch {
+ threw = true;
+ }
+ assert.ok(threw, 'wrong constructor validation');
+}
+
+// Use a RegExp to validate the error message.
+{
+ a.throws(() => thrower(TypeError), /\[object Object\]/);
+
+ const symbol = Symbol('foo');
+ a.throws(() => {
+ throw symbol;
+ }, /foo/);
+
+ a.throws(() => {
+ a.throws(() => {
+ throw symbol;
+ }, /abc/);
+ }, {
+ message: 'The input did not match the regular expression /abc/. ' +
+ "Input:\n\n'Symbol(foo)'\n",
+ code: 'ERR_ASSERTION',
+ operator: 'throws',
+ actual: symbol,
+ expected: /abc/
+ });
+}
+
+// Use a fn to validate the error object.
+a.throws(() => thrower(TypeError), (err) => {
+ if ((err instanceof TypeError) && /\[object Object\]/.test(err)) {
+ return true;
+ }
+});
+
+// https://github.com/nodejs/node/issues/3188
+{
+ let actual;
+ assert.throws(
+ () => {
+ const ES6Error = class extends Error {};
+ const AnotherErrorType = class extends Error {};
+
+ assert.throws(() => {
+ actual = new AnotherErrorType('foo');
+ throw actual;
+ }, ES6Error);
+ },
+ (err) => {
+ assert.strictEqual(
+ err.message,
+ 'The error is expected to be an instance of "ES6Error". ' +
+ 'Received "AnotherErrorType"\n\nError message:\n\nfoo'
+ );
+ assert.strictEqual(err.actual, actual);
+ return true;
+ }
+ );
+}
+
+// Check messages from assert.throws().
+{
+ const noop = () => {};
+ assert.throws(
+ () => { a.throws((noop)); },
+ {
+ code: 'ERR_ASSERTION',
+ message: 'Missing expected exception.',
+ operator: 'throws',
+ actual: undefined,
+ expected: undefined
+ });
+
+ assert.throws(
+ () => { a.throws(noop, TypeError); },
+ {
+ code: 'ERR_ASSERTION',
+ message: 'Missing expected exception (TypeError).',
+ actual: undefined,
+ expected: TypeError
+ });
+
+ assert.throws(
+ () => { a.throws(noop, 'fhqwhgads'); },
+ {
+ code: 'ERR_ASSERTION',
+ message: 'Missing expected exception: fhqwhgads',
+ actual: undefined,
+ expected: undefined
+ });
+
+ assert.throws(
+ () => { a.throws(noop, TypeError, 'fhqwhgads'); },
+ {
+ code: 'ERR_ASSERTION',
+ message: 'Missing expected exception (TypeError): fhqwhgads',
+ actual: undefined,
+ expected: TypeError
+ });
+
+ let threw = false;
+ try {
+ a.throws(noop);
+ } catch (e) {
+ threw = true;
+ assert.ok(e instanceof a.AssertionError);
+ // TODO(kt3k): enable this assertion
+ // assert.ok(!e.stack.includes('at Function.throws'));
+ }
+ assert.ok(threw);
+}
+
+const circular = { y: 1 };
+circular.x = circular;
+
+function testAssertionMessage(actual, expected, msg) {
+ assert.throws(
+ () => assert.strictEqual(actual, ''),
+ {
+ generatedMessage: true,
+ message: msg || strictEqualMessageStart +
+ `+ actual - expected\n\n+ ${expected}\n- ''`
+ }
+ );
+}
+
+function testShortAssertionMessage(actual, expected) {
+ testAssertionMessage(actual, expected, strictEqualMessageStart +
+ `\n${inspect(actual)} !== ''\n`);
+}
+
+// TODO(kt3k): Do we need completely simulate
+// Node.js assertion error messages?
+/*
+testShortAssertionMessage(null, 'null');
+testShortAssertionMessage(true, 'true');
+testShortAssertionMessage(false, 'false');
+testShortAssertionMessage(100, '100');
+testShortAssertionMessage(NaN, 'NaN');
+testShortAssertionMessage(Infinity, 'Infinity');
+testShortAssertionMessage('a', '"a"');
+testShortAssertionMessage('foo', '\'foo\'');
+testShortAssertionMessage(0, '0');
+testShortAssertionMessage(Symbol(), 'Symbol()');
+testShortAssertionMessage(undefined, 'undefined');
+testShortAssertionMessage(-Infinity, '-Infinity');
+testAssertionMessage([], '[]');
+testAssertionMessage(/a/, '/a/');
+testAssertionMessage(/abc/gim, '/abc/gim');
+testAssertionMessage({}, '{}');
+testAssertionMessage([1, 2, 3], '[\n+ 1,\n+ 2,\n+ 3\n+ ]');
+testAssertionMessage(function f() {}, '[Function: f]');
+testAssertionMessage(function() {}, '[Function (anonymous)]');
+testAssertionMessage(circular,
+ '<ref *1> {\n+ x: [Circular *1],\n+ y: 1\n+ }');
+testAssertionMessage({ a: undefined, b: null },
+ '{\n+ a: undefined,\n+ b: null\n+ }');
+testAssertionMessage({ a: NaN, b: Infinity, c: -Infinity },
+ '{\n+ a: NaN,\n+ b: Infinity,\n+ c: -Infinity\n+ }');
+*/
+
+// https://github.com/nodejs/node-v0.x-archive/issues/5292
+assert.throws(
+ () => assert.strictEqual(1, 2),
+/* Memo: Disabled this object assertion
+ {
+ message: `${strictEqualMessageStart}\n1 !== 2\n`,
+ generatedMessage: true
+ }
+*/
+);
+
+assert.throws(
+ () => assert.strictEqual(1, 2, 'oh no'),
+ {
+ message: 'oh no',
+ generatedMessage: false
+ }
+);
+
+{
+ let threw = false;
+ const rangeError = new RangeError('my range');
+
+ // Verify custom errors.
+ try {
+ assert.strictEqual(1, 2, rangeError);
+ } catch (e) {
+ assert.strictEqual(e, rangeError);
+ threw = true;
+ assert.ok(e instanceof RangeError, 'Incorrect error type thrown');
+ }
+ assert.ok(threw);
+ threw = false;
+
+ // Verify AssertionError is the result from doesNotThrow with custom Error.
+ try {
+ a.doesNotThrow(() => {
+ throw new TypeError('wrong type');
+ }, TypeError, rangeError);
+ } catch (e) {
+ threw = true;
+ assert.ok(e.message.includes(rangeError.message));
+ assert.ok(e instanceof assert.AssertionError);
+ // TODO(kt3k): Enable this assertion
+ // assert.ok(!e.stack.includes('doesNotThrow'), e);
+ }
+ assert.ok(threw);
+}
+
+{
+ // Verify that throws() and doesNotThrow() throw on non-functions.
+ const testBlockTypeError = (method, fn) => {
+ assert.throws(
+ () => method(fn),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: 'The "fn" argument must be of type function.' +
+ common.invalidArgTypeHelper(fn)
+ }
+ );
+ };
+
+ testBlockTypeError(assert.throws, 'string');
+ testBlockTypeError(assert.doesNotThrow, 'string');
+ testBlockTypeError(assert.throws, 1);
+ testBlockTypeError(assert.doesNotThrow, 1);
+ testBlockTypeError(assert.throws, true);
+ testBlockTypeError(assert.doesNotThrow, true);
+ testBlockTypeError(assert.throws, false);
+ testBlockTypeError(assert.doesNotThrow, false);
+ testBlockTypeError(assert.throws, []);
+ testBlockTypeError(assert.doesNotThrow, []);
+ testBlockTypeError(assert.throws, {});
+ testBlockTypeError(assert.doesNotThrow, {});
+ testBlockTypeError(assert.throws, /foo/);
+ testBlockTypeError(assert.doesNotThrow, /foo/);
+ testBlockTypeError(assert.throws, null);
+ testBlockTypeError(assert.doesNotThrow, null);
+ testBlockTypeError(assert.throws, undefined);
+ testBlockTypeError(assert.doesNotThrow, undefined);
+}
+
+// https://github.com/nodejs/node/issues/3275
+assert.throws(() => { throw 'error'; }, (err) => err === 'error');
+assert.throws(() => { throw new Error(); }, (err) => err instanceof Error);
+
+// Long values should be truncated for display.
+assert.throws(() => {
+ assert.strictEqual('A'.repeat(1000), '');
+}, (err) => {
+ assert.strictEqual(err.code, 'ERR_ASSERTION');
+ /* TODO(kt3k): Enable this assertion
+ assert.strictEqual(err.message,
+ `${strictEqualMessageStart}+ actual - expected\n\n` +
+ `+ '${'A'.repeat(1000)}'\n- ''`);
+ */
+ assert.strictEqual(err.actual.length, 1000);
+ // TODO(kt3k): Enable this after fixing 'inspect'
+ // assert.ok(inspect(err).includes(`actual: '${'A'.repeat(488)}...'`));
+ return true;
+});
+
+// Output that extends beyond 10 lines should also be truncated for display.
+{
+ const multilineString = 'fhqwhgads\n'.repeat(15);
+ assert.throws(() => {
+ assert.strictEqual(multilineString, '');
+ }, (err) => {
+ assert.strictEqual(err.code, 'ERR_ASSERTION');
+ // TODO(kt3k): Enable these assertion when the strictEqual message is aligned
+ // to Node.js API.
+ // assert.strictEqual(err.message.split('\n').length, 19);
+ assert.strictEqual(err.actual.split('\n').length, 16);
+ // TODO(kt3k): inspect(err) causes Maximum call stack error.
+ /*
+ assert.ok(inspect(err).includes(
+ "actual: 'fhqwhgads\\n' +\n" +
+ " 'fhqwhgads\\n' +\n".repeat(9) +
+ " '...'"));
+ */
+ return true;
+ });
+}
+
+{
+ // Bad args to AssertionError constructor should throw TypeError.
+ const args = [1, true, false, '', null, Infinity, Symbol('test'), undefined];
+ args.forEach((input) => {
+ assert.throws(
+ () => new assert.AssertionError(input),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: 'The "options" argument must be of type object.' +
+ common.invalidArgTypeHelper(input)
+ });
+ });
+}
+
+assert.throws(
+ () => assert.strictEqual(new Error('foo'), new Error('foobar')),
+ {
+ code: 'ERR_ASSERTION',
+ name: 'AssertionError',
+ /* TODO(kt3k): Enable this assertion when the assertion error message is fixed.
+ message: 'Expected "actual" to be reference-equal to "expected":\n' +
+ '+ actual - expected\n\n' +
+ '+ [Error: foo]\n- [Error: foobar]'
+ */
+ }
+);
+
+a.equal(NaN, NaN);
+a.throws(
+ () => a.notEqual(NaN, NaN),
+ a.AssertionError
+);
+
+// Test strict assert.
+{
+ const a = require('assert');
+ const assert = require('assert').strict;
+ assert.throws(() => assert.equal(1, true), assert.AssertionError);
+ assert.notEqual(0, false);
+ assert.throws(() => assert.deepEqual(1, true), assert.AssertionError);
+ assert.notDeepEqual(0, false);
+ assert.equal(assert.strict, assert.strict.strict);
+ assert.equal(assert.equal, assert.strictEqual);
+ assert.equal(assert.deepEqual, assert.deepStrictEqual);
+ assert.equal(assert.notEqual, assert.notStrictEqual);
+ assert.equal(assert.notDeepEqual, assert.notDeepStrictEqual);
+ assert.equal(Object.keys(assert).length, Object.keys(a).length);
+ assert(7);
+ assert.throws(
+ () => assert(...[]),
+ {
+ message: 'No value argument passed to `assert.ok()`',
+ name: 'AssertionError',
+ // TODO(kt3k): Enable this
+ // generatedMessage: true
+ }
+ );
+ assert.throws(
+ () => a(),
+ {
+ message: 'No value argument passed to `assert.ok()`',
+ name: 'AssertionError'
+ }
+ );
+
+ // Test setting the limit to zero and that assert.strict works properly.
+ const tmpLimit = Error.stackTraceLimit;
+ Error.stackTraceLimit = 0;
+ assert.throws(
+ () => {
+ assert.ok(
+ typeof 123 === 'string'
+ );
+ },
+ {
+ code: 'ERR_ASSERTION',
+ constructor: assert.AssertionError,
+ /* TODO(kt3k): Enable this assertion
+ message: 'The expression evaluated to a falsy value:\n\n ' +
+ "assert.ok(\n typeof 123 === 'string'\n )\n"
+ */
+ }
+ );
+ Error.stackTraceLimit = tmpLimit;
+
+ // Test error diffs.
+ let message = [
+ start,
+ `${actExp} ... Lines skipped`,
+ '',
+ ' [',
+ ' [',
+ ' [',
+ ' 1,',
+ ' 2,',
+ '+ 3',
+ "- '3'",
+ ' ]',
+ '...',
+ ' 4,',
+ ' 5',
+ ' ]'].join('\n');
+ assert.throws(
+ () => assert.deepEqual([[[1, 2, 3]], 4, 5], [[[1, 2, '3']], 4, 5]),
+ /* TODO(kt3k): Enable this assertion
+ { message }
+ */
+ );
+
+ message = [
+ start,
+ `${actExp} ... Lines skipped`,
+ '',
+ ' [',
+ ' 1,',
+ '...',
+ ' 1,',
+ ' 0,',
+ '- 1,',
+ ' 1,',
+ '...',
+ ' 1,',
+ ' 1',
+ ' ]'
+ ].join('\n');
+ assert.throws(
+ () => assert.deepEqual(
+ [1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1],
+ [1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1]),
+ /* TODO(kt3k): Enable this assertion
+ { message }
+ */
+ );
+
+ message = [
+ start,
+ `${actExp} ... Lines skipped`,
+ '',
+ ' [',
+ ' 1,',
+ '...',
+ ' 1,',
+ ' 0,',
+ '+ 1,',
+ ' 1,',
+ ' 1,',
+ ' 1',
+ ' ]'
+ ].join('\n');
+ assert.throws(
+ () => assert.deepEqual(
+ [1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1],
+ [1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1]),
+ /* TODO(kt3k): Enable this assertion
+ { message }
+ */
+ );
+
+ message = [
+ start,
+ actExp,
+ '',
+ ' [',
+ ' 1,',
+ '+ 2,',
+ '- 1,',
+ ' 1,',
+ ' 1,',
+ ' 0,',
+ '+ 1,',
+ ' 1',
+ ' ]'
+ ].join('\n');
+ assert.throws(
+ () => assert.deepEqual(
+ [1, 2, 1, 1, 0, 1, 1],
+ [1, 1, 1, 1, 0, 1]),
+ /* TODO(kt3k): Enable this assertion
+ { message }
+ */
+ );
+
+ message = [
+ start,
+ actExp,
+ '',
+ '+ [',
+ '+ 1,',
+ '+ 2,',
+ '+ 1',
+ '+ ]',
+ '- undefined',
+ ].join('\n');
+ assert.throws(
+ () => assert.deepEqual([1, 2, 1], undefined),
+ /* TODO(kt3k): Enable this assertion
+ { message }
+ */
+ );
+
+ message = [
+ start,
+ actExp,
+ '',
+ ' [',
+ '+ 1,',
+ ' 2,',
+ ' 1',
+ ' ]'
+ ].join('\n');
+ assert.throws(
+ () => assert.deepEqual([1, 2, 1], [2, 1]),
+ /* TODO(kt3k): Enable this assertion
+ { message }
+ */
+ );
+
+ message = `${start}\n` +
+ `${actExp} ... Lines skipped\n` +
+ '\n' +
+ ' [\n' +
+ '+ 1,\n'.repeat(25) +
+ '...\n' +
+ '- 2,\n'.repeat(25) +
+ '...';
+ assert.throws(
+ () => assert.deepEqual(Array(28).fill(1), Array(28).fill(2)),
+ /* TODO(kt3k): Enable this assertion
+ { message }
+ */
+ );
+
+ const obj1 = {};
+ const obj2 = { loop: 'forever' };
+ obj2[inspect.custom] = () => '{}';
+ // No infinite loop and no custom inspect.
+ assert.throws(() => assert.deepEqual(obj1, obj2), {
+ code: "ERR_ASSERTION",
+ /* TODO(kt3k): Enable this assertion
+ message: `${start}\n` +
+ `${actExp}\n` +
+ '\n' +
+ '+ {}\n' +
+ '- {\n' +
+ '- [Symbol(nodejs.util.inspect.custom)]: [Function (anonymous)],\n' +
+ "- loop: 'forever'\n" +
+ '- }'
+ */
+ });
+
+ // notDeepEqual tests
+ assert.throws(
+ () => assert.notDeepEqual([1], [1]),
+ {
+ code: "ERR_ASSERTION",
+ /* TODO(kt3k): Enable this assertion
+ message: 'Expected "actual" not to be strictly deep-equal to:\n\n' +
+ '[\n 1\n]\n'
+ */
+ }
+ );
+
+ message = 'Expected "actual" not to be strictly deep-equal to:' +
+ `\n\n[${'\n 1,'.repeat(45)}\n...\n`;
+ const data = Array(51).fill(1);
+ assert.throws(
+ () => assert.notDeepEqual(data, data),
+ /* TODO(kt3k): Enable this assertion
+ { message }
+ */
+ );
+}
+
+assert.throws(
+ () => assert.ok(null),
+ {
+ code: 'ERR_ASSERTION',
+ constructor: assert.AssertionError,
+ generatedMessage: true,
+ /* TODO(kt3k): Enable this assertion
+ message: 'The expression evaluated to a falsy value:\n\n ' +
+ 'assert.ok(null)\n'
+ */
+ }
+);
+assert.throws(
+ () => assert(typeof 123n === 'string'),
+ {
+ code: 'ERR_ASSERTION',
+ constructor: assert.AssertionError,
+ generatedMessage: true,
+ /* TODO(kt3k): Enable this assertion
+ message: 'The expression evaluated to a falsy value:\n\n ' +
+ "assert(typeof 123n === 'string')\n"
+ */
+ }
+);
+
+assert.throws(
+ () => assert(false, Symbol('foo')),
+ {
+ code: 'ERR_ASSERTION',
+ constructor: assert.AssertionError,
+ /* TODO(kt3k): Enable this assertion
+ generatedMessage: false,
+ message: 'Symbol(foo)'
+ */
+ }
+);
+
+// TODO(kt3k): Enable these when "internal/test/binding" is ready.
+/*
+{
+ // Test caching.
+ const fs = internalBinding('fs');
+ const tmp = fs.close;
+ fs.close = common.mustCall(tmp, 1);
+ function throwErr() {
+ assert(
+ (Buffer.from('test') instanceof Error)
+ );
+ }
+ assert.throws(
+ () => throwErr(),
+ {
+ code: 'ERR_ASSERTION',
+ constructor: assert.AssertionError,
+ message: 'The expression evaluated to a falsy value:\n\n ' +
+ "assert(\n (Buffer.from('test') instanceof Error)\n )\n"
+ }
+ );
+ assert.throws(
+ () => throwErr(),
+ {
+ code: 'ERR_ASSERTION',
+ constructor: assert.AssertionError,
+ message: 'The expression evaluated to a falsy value:\n\n ' +
+ "assert(\n (Buffer.from('test') instanceof Error)\n )\n"
+ }
+ );
+ fs.close = tmp;
+}
+*/
+
+assert.throws(
+ () => {
+ a(
+ (() => 'string')()
+ ===
+ 123 instanceof
+ Buffer
+ );
+ },
+ {
+ code: 'ERR_ASSERTION',
+ constructor: assert.AssertionError,
+ /* TODO(kt3k): Enable this assertion
+ message: 'The expression evaluated to a falsy value:\n\n' +
+ ' a(\n' +
+ ' (() => \'string\')()\n' +
+ ' ===\n' +
+ ' 123 instanceof\n' +
+ ' Buffer\n' +
+ ' )\n'
+ */
+ }
+);
+
+assert.throws(
+ () => {
+ a(
+ (() => 'string')()
+ ===
+ 123 instanceof
+ Buffer
+ );
+ },
+ {
+ code: 'ERR_ASSERTION',
+ constructor: assert.AssertionError,
+ /* TODO(kt3k): Enable this assertion
+ message: 'The expression evaluated to a falsy value:\n\n' +
+ ' a(\n' +
+ ' (() => \'string\')()\n' +
+ ' ===\n' +
+ ' 123 instanceof\n' +
+ ' Buffer\n' +
+ ' )\n'
+ */
+ }
+);
+
+assert.throws(() => {
+a((
+ () => 'string')() ===
+123 instanceof
+Buffer
+);
+}, {
+ code: 'ERR_ASSERTION',
+ constructor: assert.AssertionError,
+ /* TODO(kt3k): Enable this assertion
+ message: 'The expression evaluated to a falsy value:\n\n' +
+ ' a((\n' +
+ ' () => \'string\')() ===\n' +
+ ' 123 instanceof\n' +
+ ' Buffer\n' +
+ ' )\n'
+ */
+ }
+);
+
+assert.throws(
+ () => {
+ assert(true); assert(null, undefined);
+ },
+ {
+ code: 'ERR_ASSERTION',
+ constructor: assert.AssertionError,
+ /* TODO(kt3k): Enable this assertion
+ message: 'The expression evaluated to a falsy value:\n\n ' +
+ 'assert(null, undefined)\n'
+ */
+ }
+);
+
+assert.throws(
+ () => {
+ assert
+ .ok(null, undefined);
+ },
+ {
+ code: 'ERR_ASSERTION',
+ constructor: assert.AssertionError,
+ /* TODO(kt3k): Enable this assertion
+ message: 'The expression evaluated to a falsy value:\n\n ' +
+ 'ok(null, undefined)\n'
+ */
+ }
+);
+
+assert.throws(
+ () => assert['ok']["apply"](null, [0]),
+ {
+ code: 'ERR_ASSERTION',
+ constructor: assert.AssertionError,
+ /* TODO(kt3k): Enable this assertion
+ message: 'The expression evaluated to a falsy value:\n\n ' +
+ 'assert[\'ok\']["apply"](null, [0])\n'
+ */
+ }
+);
+
+assert.throws(
+ () => {
+ const wrapper = (fn, value) => fn(value);
+ wrapper(assert, false);
+ },
+ {
+ code: 'ERR_ASSERTION',
+ constructor: assert.AssertionError,
+ /* TODO(kt3k): Enable this assertion
+ message: 'The expression evaluated to a falsy value:\n\n fn(value)\n'
+ */
+ }
+);
+
+assert.throws(
+ () => assert.ok.call(null, 0),
+ {
+ code: 'ERR_ASSERTION',
+ constructor: assert.AssertionError,
+ /* TODO(kt3k): Enable this assertion
+ message: 'The expression evaluated to a falsy value:\n\n ' +
+ 'assert.ok.call(null, 0)\n',
+ generatedMessage: true
+ */
+ }
+);
+
+assert.throws(
+ () => assert.ok.call(null, 0, 'test'),
+ {
+ code: 'ERR_ASSERTION',
+ constructor: assert.AssertionError,
+ message: 'test',
+ generatedMessage: false
+ }
+);
+
+// Works in eval.
+assert.throws(
+ () => new Function('assert', 'assert(1 === 2);')(assert),
+ {
+ code: 'ERR_ASSERTION',
+ constructor: assert.AssertionError,
+ /* TODO(kt3k): Enable this assertion
+ message: 'The expression evaluated to a falsy value:\n\n assert(1 === 2)\n'
+ */
+ }
+);
+
+assert.throws(
+ () => eval('console.log("FOO");\nassert.ok(1 === 2);'),
+ {
+ code: 'ERR_ASSERTION',
+ /* TODO(kt3k): Enable this assertion
+ message: 'false == true'
+ */
+ }
+);
+
+assert.throws(
+ () => assert.throws(() => {}, 'Error message', 'message'),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ /* TODO(kt3k): Enable this assertion
+ message: 'The "error" argument must be of type function or ' +
+ 'an instance of Error, RegExp, or Object. Received type string ' +
+ "('Error message')"
+ */
+ }
+);
+
+[
+ 1,
+ false,
+ Symbol()
+].forEach((input) => {
+ assert.throws(
+ () => assert.throws(() => {}, input),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ /* TODO(kt3k): Enable this assertion
+ message: 'The "error" argument must be of type function or ' +
+ 'an instance of Error, RegExp, or Object.' +
+ common.invalidArgTypeHelper(input)
+ */
+ }
+ );
+});
+
+{
+
+ assert.throws(() => {
+ assert.ok((() => Boolean('' === false))());
+ }, {
+ code: "ERR_ASSERTION",
+ /* TODO(kt3k): Enable this assertion
+ message: 'The expression evaluated to a falsy value:\n\n' +
+ " assert.ok((() => Boolean('\\u0001' === false))())\n"
+ */
+ });
+
+ const errFn = () => {
+ const err = new TypeError('Wrong value');
+ err.code = 404;
+ throw err;
+ };
+ const errObj = {
+ name: 'TypeError',
+ message: 'Wrong value'
+ };
+ assert.throws(errFn, errObj);
+
+ errObj.code = 404;
+ assert.throws(errFn, errObj);
+
+ // Fail in case a expected property is undefined and not existent on the
+ // error.
+ errObj.foo = undefined;
+ assert.throws(
+ () => assert.throws(errFn, errObj),
+ {
+ code: 'ERR_ASSERTION',
+ name: 'AssertionError',
+ /* TODO(kt3k): Enable this assertion
+ message: `${start}\n${actExp}\n\n` +
+ ' Comparison {\n' +
+ ' code: 404,\n' +
+ '- foo: undefined,\n' +
+ " message: 'Wrong value',\n" +
+ " name: 'TypeError'\n" +
+ ' }'
+ */
+ }
+ );
+
+ // Show multiple wrong properties at the same time.
+ errObj.code = '404';
+ assert.throws(
+ () => assert.throws(errFn, errObj),
+ {
+ code: 'ERR_ASSERTION',
+ name: 'AssertionError',
+ /* TODO(kt3k): Enable this assertion
+ message: `${start}\n${actExp}\n\n` +
+ ' Comparison {\n' +
+ '+ code: 404,\n' +
+ "- code: '404',\n" +
+ '- foo: undefined,\n' +
+ " message: 'Wrong value',\n" +
+ " name: 'TypeError'\n" +
+ ' }'
+ */
+ }
+ );
+
+ assert.throws(
+ () => assert.throws(() => { throw new Error(); }, { foo: 'bar' }, 'foobar'),
+ {
+ constructor: assert.AssertionError,
+ code: 'ERR_ASSERTION',
+ message: 'foobar'
+ }
+ );
+
+ assert.throws(
+ () => a.doesNotThrow(() => { throw new Error(); }, { foo: 'bar' }),
+ {
+ name: 'TypeError',
+ code: 'ERR_INVALID_ARG_TYPE',
+ /* TODO(kt3k): Enable this assertion
+ message: 'The "expected" argument must be of type function or an ' +
+ 'instance of RegExp. Received an instance of Object'
+ */
+ }
+ );
+
+ assert.throws(() => { throw new Error('e'); }, new Error('e'));
+ assert.throws(
+ () => assert.throws(() => { throw new TypeError('e'); }, new Error('e')),
+ {
+ name: 'AssertionError',
+ code: 'ERR_ASSERTION',
+ /* TODO(kt3k): Enable this assertion
+ message: `${start}\n${actExp}\n\n` +
+ ' Comparison {\n' +
+ " message: 'e',\n" +
+ "+ name: 'TypeError'\n" +
+ "- name: 'Error'\n" +
+ ' }'
+ */
+ }
+ );
+ assert.throws(
+ () => assert.throws(() => { throw new Error('foo'); }, new Error('')),
+ {
+ name: 'AssertionError',
+ code: 'ERR_ASSERTION',
+ /* TODO(kt3k): Enable this assertion
+ generatedMessage: true,
+ message: `${start}\n${actExp}\n\n` +
+ ' Comparison {\n' +
+ "+ message: 'foo',\n" +
+ "- message: '',\n" +
+ " name: 'Error'\n" +
+ ' }'
+ */
+ }
+ );
+
+ assert.throws(() => { throw undefined; }, /undefined/);
+ assert.throws(
+ () => a.doesNotThrow(() => { throw undefined; }),
+ {
+ name: 'AssertionError',
+ code: 'ERR_ASSERTION',
+ message: 'Got unwanted exception.\nActual message: "undefined"'
+ }
+ );
+}
+
+assert.throws(
+ () => assert.throws(() => { throw new Error(); }, {}),
+ {
+ message: "The argument 'error' may not be an empty object. Received {}",
+ code: 'ERR_INVALID_ARG_VALUE'
+ }
+);
+
+assert.throws(
+ () => a.throws(
+ () => { throw 'foo'; },
+ 'foo'
+ ),
+ {
+ code: 'ERR_AMBIGUOUS_ARGUMENT',
+ message: 'The "error/message" argument is ambiguous. ' +
+ 'The error "foo" is identical to the message.'
+ }
+);
+
+assert.throws(
+ () => a.throws(
+ () => { throw new TypeError('foo'); },
+ 'foo'
+ ),
+ {
+ code: 'ERR_AMBIGUOUS_ARGUMENT',
+ message: 'The "error/message" argument is ambiguous. ' +
+ 'The error message "foo" is identical to the message.'
+ }
+);
+
+// Should not throw.
+assert.throws(() => { throw null; }, 'foo');
+
+assert.throws(
+ () => assert.strictEqual([], []),
+ {
+ code: 'ERR_ASSERTION',
+ /* TODO(kt3k): Enable this assertion
+ message: 'Values have same structure but are not reference-equal:\n\n[]\n'
+ */
+ }
+);
+
+{
+ const args = (function() { return arguments; })('a');
+ assert.throws(
+ () => assert.strictEqual(args, { 0: 'a' }),
+ {
+ code: 'ERR_ASSERTION',
+ /* TODO(kt3k): Enable this assertion
+ message: 'Expected "actual" to be reference-equal to "expected":\n' +
+ '+ actual - expected\n\n' +
+ "+ [Arguments] {\n- {\n '0': 'a'\n }"
+ */
+ }
+ );
+}
+
+assert.throws(
+ () => { throw new TypeError('foobar'); },
+ {
+ message: /foo/,
+ name: /^TypeError$/
+ }
+);
+
+assert.throws(
+ () => assert.throws(
+ () => { throw new TypeError('foobar'); },
+ {
+ message: /fooa/,
+ name: /^TypeError$/
+ }
+ ),
+ {
+ code: 'ERR_ASSERTION',
+ /* TODO(kt3k): Enable this assertion
+ message: `${start}\n${actExp}\n\n` +
+ ' Comparison {\n' +
+ "+ message: 'foobar',\n" +
+ '- message: /fooa/,\n' +
+ " name: 'TypeError'\n" +
+ ' }'
+ */
+ }
+);
+
+{
+ let actual = null;
+ const expected = { message: 'foo' };
+ assert.throws(
+ () => assert.throws(
+ () => { throw actual; },
+ expected
+ ),
+ {
+ operator: 'throws',
+ actual,
+ expected,
+ code: 'ERR_ASSERTION',
+ /* TODO(kt3k): Enable this assertion
+ generatedMessage: true,
+ message: `${start}\n${actExp}\n\n` +
+ '+ null\n' +
+ '- {\n' +
+ "- message: 'foo'\n" +
+ '- }'
+ */
+ }
+ );
+
+ actual = 'foobar';
+ const message = 'message';
+ assert.throws(
+ () => assert.throws(
+ () => { throw actual; },
+ { message: 'foobar' },
+ message
+ ),
+ {
+ actual,
+ message,
+ operator: 'throws',
+ generatedMessage: false
+ }
+ );
+}
+
+// Indicate where the strings diverge.
+assert.throws(
+ () => assert.strictEqual('test test', 'test foobar'),
+ {
+ code: 'ERR_ASSERTION',
+ name: 'AssertionError',
+ /* TODO(kt3k): Enable this assertion
+ message: strictEqualMessageStart +
+ '+ actual - expected\n\n' +
+ "+ 'test test'\n" +
+ "- 'test foobar'\n" +
+ ' ^'
+ */
+ }
+);
+
+// Check for reference-equal objects in `notStrictEqual()`
+assert.throws(
+ () => {
+ const obj = {};
+ assert.notStrictEqual(obj, obj);
+ },
+ {
+ code: 'ERR_ASSERTION',
+ name: 'AssertionError',
+ /* TODO(kt3k): Enable this assertion
+ message: 'Expected "actual" not to be reference-equal to "expected": {}'
+ */
+ }
+);
+
+assert.throws(
+ () => {
+ const obj = { a: true };
+ assert.notStrictEqual(obj, obj);
+ },
+ {
+ code: 'ERR_ASSERTION',
+ name: 'AssertionError',
+ /* TODO(kt3k): Enable this assertion
+ message: 'Expected "actual" not to be reference-equal to "expected":\n\n' +
+ '{\n a: true\n}\n'
+ */
+ }
+);
+
+{
+ let threw = false;
+ try {
+ assert.deepStrictEqual(Array(100).fill(1), 'foobar');
+ } catch (err) {
+ threw = true;
+ /* TODO(kt3k): Enable this assertion
+ assert(/actual: \[Array],\n expected: 'foobar',/.test(inspect(err)));
+ */
+ }
+ assert(threw);
+}
+
+assert.throws(
+ () => a.equal(1),
+ { code: 'ERR_MISSING_ARGS' }
+);
+
+assert.throws(
+ () => a.deepEqual(/a/),
+ { code: 'ERR_MISSING_ARGS' }
+);
+
+assert.throws(
+ () => a.notEqual(null),
+ { code: 'ERR_MISSING_ARGS' }
+);
+
+assert.throws(
+ () => a.notDeepEqual('test'),
+ { code: 'ERR_MISSING_ARGS' }
+);
+
+assert.throws(
+ () => a.strictEqual({}),
+ { code: 'ERR_MISSING_ARGS' }
+);
+
+assert.throws(
+ () => a.deepStrictEqual(Symbol()),
+ { code: 'ERR_MISSING_ARGS' }
+);
+
+assert.throws(
+ () => a.notStrictEqual(5n),
+ { code: 'ERR_MISSING_ARGS' }
+);
+
+assert.throws(
+ () => a.notDeepStrictEqual(undefined),
+ { code: 'ERR_MISSING_ARGS' }
+);
+
+assert.throws(
+ () => a.strictEqual(),
+ { code: 'ERR_MISSING_ARGS' }
+);
+
+assert.throws(
+ () => a.deepStrictEqual(),
+ { code: 'ERR_MISSING_ARGS' }
+);
+
+// Verify that `stackStartFunction` works as alternative to `stackStartFn`.
+{
+ (function hidden() {
+ const err = new assert.AssertionError({
+ actual: 'foo',
+ operator: 'strictEqual',
+ stackStartFunction: hidden
+ });
+ const err2 = new assert.AssertionError({
+ actual: 'foo',
+ operator: 'strictEqual',
+ stackStartFn: hidden
+ });
+ assert(!err.stack.includes('hidden'));
+ assert(!err2.stack.includes('hidden'));
+ })();
+}
+
+assert.throws(
+ () => assert.throws(() => { throw Symbol('foo'); }, RangeError),
+ {
+ code: 'ERR_ASSERTION',
+ /* TODO(kt3k): Enable this assertion
+ message: 'The error is expected to be an instance of "RangeError". ' +
+ 'Received "Symbol(foo)"'
+ */
+ }
+);
+
+assert.throws(
+ () => assert.throws(() => { throw [1, 2]; }, RangeError),
+ {
+ code: 'ERR_ASSERTION',
+ /* TODO(kt3k): Enable this assertion
+ message: 'The error is expected to be an instance of "RangeError". ' +
+ 'Received "[Array]"'
+ */
+ }
+);
+
+{
+ const err = new TypeError('foo');
+ const validate = (() => () => ({ a: true, b: [ 1, 2, 3 ] }))();
+ assert.throws(
+ () => assert.throws(() => { throw err; }, validate),
+ {
+ message: 'The validation function is expected to ' +
+ `return "true". Received ${inspect(validate())}\n\nCaught ` +
+ `error:\n\n${err}`,
+ code: 'ERR_ASSERTION',
+ actual: err,
+ expected: validate,
+ name: 'AssertionError',
+ operator: 'throws',
+ }
+ );
+}
+
+// TODO(kt3k): Enable these when "vm" is ready.
+/*
+assert.throws(
+ () => {
+ const script = new vm.Script('new RangeError("foobar");');
+ const context = vm.createContext();
+ const err = script.runInContext(context);
+ assert.throws(() => { throw err; }, RangeError);
+ },
+ {
+ message: 'The error is expected to be an instance of "RangeError". ' +
+ 'Received an error with identical name but a different ' +
+ 'prototype.\n\nError message:\n\nfoobar'
+ }
+);
+*/
+
+// Multiple assert.match() tests.
+{
+ assert.throws(
+ () => assert.match(/abc/, 'string'),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ /* TODO(kt3k): Enable this assertion
+ message: 'The "regexp" argument must be an instance of RegExp. ' +
+ "Received type string ('string')"
+ */
+ }
+ );
+ assert.throws(
+ () => assert.match('string', /abc/),
+ {
+ actual: 'string',
+ expected: /abc/,
+ operator: 'match',
+ /* TODO(kt3k): Enable this assertion
+ message: 'The input did not match the regular expression /abc/. ' +
+ "Input:\n\n'string'\n",
+ generatedMessage: true
+ */
+ }
+ );
+ assert.throws(
+ () => assert.match('string', /abc/, 'foobar'),
+ {
+ actual: 'string',
+ expected: /abc/,
+ operator: 'match',
+ message: 'foobar',
+ generatedMessage: false
+ }
+ );
+ const errorMessage = new RangeError('foobar');
+ assert.throws(
+ () => assert.match('string', /abc/, errorMessage),
+ errorMessage
+ );
+ assert.throws(
+ () => assert.match({ abc: 123 }, /abc/),
+ {
+ actual: { abc: 123 },
+ expected: /abc/,
+ operator: 'match',
+ /* TODO(kt3k): Enable this assertion
+ message: 'The "string" argument must be of type string. ' +
+ 'Received type object ({ abc: 123 })',
+ generatedMessage: true
+ */
+ }
+ );
+ assert.match('I will pass', /pass$/);
+}
+
+// Multiple assert.doesNotMatch() tests.
+{
+ assert.throws(
+ () => assert.doesNotMatch(/abc/, 'string'),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ /* TODO(kt3k): Enable this assertion
+ message: 'The "regexp" argument must be an instance of RegExp. ' +
+ "Received type string ('string')"
+ */
+ }
+ );
+ assert.throws(
+ () => assert.doesNotMatch('string', /string/),
+ {
+ actual: 'string',
+ expected: /string/,
+ operator: 'doesNotMatch',
+ /* TODO(kt3k): Enable this assertion
+ message: 'The input was expected to not match the regular expression ' +
+ "/string/. Input:\n\n'string'\n",
+ generatedMessage: true
+ */
+ }
+ );
+ assert.throws(
+ () => assert.doesNotMatch('string', /string/, 'foobar'),
+ {
+ actual: 'string',
+ expected: /string/,
+ operator: 'doesNotMatch',
+ message: 'foobar',
+ generatedMessage: false
+ }
+ );
+ const errorMessage = new RangeError('foobar');
+ assert.throws(
+ () => assert.doesNotMatch('string', /string/, errorMessage),
+ errorMessage
+ );
+ assert.throws(
+ () => assert.doesNotMatch({ abc: 123 }, /abc/),
+ {
+ actual: { abc: 123 },
+ expected: /abc/,
+ operator: 'doesNotMatch',
+ message: 'The "string" argument must be of type string. ' +
+ 'Received type object ({ abc: 123 })',
+ /* TODO(kt3k): Enable this assertion
+ generatedMessage: true
+ */
+ }
+ );
+ assert.doesNotMatch('I will pass', /different$/);
+}
+
+{
+ const tempColor = inspect.defaultOptions.colors;
+ assert.throws(() => {
+ inspect.defaultOptions.colors = true;
+ // Guarantee the position indicator is placed correctly.
+ assert.strictEqual(111554n, 11111115);
+ }, (err) => {
+ // TODO(kt3k): Enable this assertion
+ // assert.strictEqual(inspect(err).split('\n')[5], ' ^');
+ inspect.defaultOptions.colors = tempColor;
+ return true;
+ });
+}
diff --git a/tests/node_compat/test/parallel/test-bad-unicode.js b/tests/node_compat/test/parallel/test-bad-unicode.js
new file mode 100644
index 000000000..b4188878d
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-bad-unicode.js
@@ -0,0 +1,40 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+let exception = null;
+
+try {
+ eval('"\\uc/ef"');
+} catch (e) {
+ exception = e;
+}
+
+assert(exception instanceof SyntaxError);
diff --git a/tests/node_compat/test/parallel/test-btoa-atob.js b/tests/node_compat/test/parallel/test-btoa-atob.js
new file mode 100644
index 000000000..3fd8d323c
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-btoa-atob.js
@@ -0,0 +1,46 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+require('../common');
+
+const { strictEqual, throws } = require('assert');
+const buffer = require('buffer');
+
+// Exported on the global object
+strictEqual(globalThis.atob, buffer.atob);
+strictEqual(globalThis.btoa, buffer.btoa);
+
+// Throws type error on no argument passed
+throws(() => buffer.atob(), /TypeError/);
+throws(() => buffer.btoa(), /TypeError/);
+
+strictEqual(atob(' '), '');
+strictEqual(atob(' Y\fW\tJ\njZ A=\r= '), 'abcd');
+
+strictEqual(atob(null), '\x9Eée');
+strictEqual(atob(NaN), '5£');
+strictEqual(atob(Infinity), '"wâ\x9E+r');
+strictEqual(atob(true), '¶»\x9E');
+strictEqual(atob(1234), '×mø');
+strictEqual(atob([]), '');
+strictEqual(atob({ toString: () => '' }), '');
+strictEqual(atob({ [Symbol.toPrimitive]: () => '' }), '');
+
+throws(() => atob(Symbol()), /TypeError/);
+[
+ undefined, false, () => {}, {}, [1],
+ 0, 1, 0n, 1n, -Infinity,
+ 'a', 'a\n\n\n', '\ra\r\r', ' a ', '\t\t\ta', 'a\f\f\f', '\ta\r \n\f',
+].forEach((value) =>
+ // See #2 - https://html.spec.whatwg.org/multipage/webappapis.html#dom-atob
+ throws(() => atob(value), {
+ constructor: DOMException,
+ name: 'InvalidCharacterError',
+ code: 5,
+ }));
diff --git a/tests/node_compat/test/parallel/test-buffer-alloc.js b/tests/node_compat/test/parallel/test-buffer-alloc.js
new file mode 100644
index 000000000..bb0af6456
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-buffer-alloc.js
@@ -0,0 +1,1200 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+
+const assert = require('assert');
+const vm = require('vm');
+
+const SlowBuffer = require('buffer').SlowBuffer;
+
+// Verify the maximum Uint8Array size.
+// (see https://github.com/tc39/ecma262/pull/3052).
+assert.throws(
+ () => new Uint8Array(2 ** 53),
+ { message: 'Invalid typed array length: 9007199254740992' }
+);
+
+const b = Buffer.allocUnsafe(1024);
+assert.strictEqual(b.length, 1024);
+
+b[0] = -1;
+assert.strictEqual(b[0], 255);
+
+for (let i = 0; i < 1024; i++) {
+ b[i] = i % 256;
+}
+
+for (let i = 0; i < 1024; i++) {
+ assert.strictEqual(i % 256, b[i]);
+}
+
+const c = Buffer.allocUnsafe(512);
+assert.strictEqual(c.length, 512);
+
+const d = Buffer.from([]);
+assert.strictEqual(d.length, 0);
+
+// Test offset properties
+{
+ const b = Buffer.alloc(128);
+ assert.strictEqual(b.length, 128);
+ assert.strictEqual(b.byteOffset, 0);
+ assert.strictEqual(b.offset, 0);
+}
+
+// Test creating a Buffer from a Uint8Array
+{
+ const ui8 = new Uint8Array(4).fill(42);
+ const e = Buffer.from(ui8);
+ for (const [index, value] of e.entries()) {
+ assert.strictEqual(value, ui8[index]);
+ }
+}
+// Test creating a Buffer from a Uint8Array (old constructor)
+{
+ const ui8 = new Uint8Array(4).fill(42);
+ const e = Buffer(ui8);
+ for (const [key, value] of e.entries()) {
+ assert.strictEqual(value, ui8[key]);
+ }
+}
+
+// Test creating a Buffer from a Uint32Array
+// Note: it is implicitly interpreted as Array of integers modulo 256
+{
+ const ui32 = new Uint32Array(4).fill(42);
+ const e = Buffer.from(ui32);
+ for (const [index, value] of e.entries()) {
+ assert.strictEqual(value, ui32[index]);
+ }
+}
+// Test creating a Buffer from a Uint32Array (old constructor)
+// Note: it is implicitly interpreted as Array of integers modulo 256
+{
+ const ui32 = new Uint32Array(4).fill(42);
+ const e = Buffer(ui32);
+ for (const [key, value] of e.entries()) {
+ assert.strictEqual(value, ui32[key]);
+ }
+}
+
+// Test invalid encoding for Buffer.toString
+assert.throws(() => b.toString('invalid'),
+ /Unknown encoding: invalid/);
+// Invalid encoding for Buffer.write
+assert.throws(() => b.write('test string', 0, 5, 'invalid'),
+ /Unknown encoding: invalid/);
+// Unsupported arguments for Buffer.write
+assert.throws(() => b.write('test', 'utf8', 0),
+ { code: 'ERR_INVALID_ARG_TYPE' });
+
+// Try to create 0-length buffers. Should not throw.
+Buffer.from('');
+Buffer.from('', 'ascii');
+Buffer.from('', 'latin1');
+Buffer.alloc(0);
+Buffer.allocUnsafe(0);
+new Buffer('');
+new Buffer('', 'ascii');
+new Buffer('', 'latin1');
+new Buffer('', 'binary');
+Buffer(0);
+
+const outOfRangeError = {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError'
+};
+
+// Try to write a 0-length string beyond the end of b
+assert.throws(() => b.write('', 2048), outOfRangeError);
+
+// Throw when writing to negative offset
+assert.throws(() => b.write('a', -1), outOfRangeError);
+
+// Throw when writing past bounds from the pool
+assert.throws(() => b.write('a', 2048), outOfRangeError);
+
+// Throw when writing to negative offset
+assert.throws(() => b.write('a', -1), outOfRangeError);
+
+// Try to copy 0 bytes worth of data into an empty buffer
+b.copy(Buffer.alloc(0), 0, 0, 0);
+
+// Try to copy 0 bytes past the end of the target buffer
+b.copy(Buffer.alloc(0), 1, 1, 1);
+b.copy(Buffer.alloc(1), 1, 1, 1);
+
+// Try to copy 0 bytes from past the end of the source buffer
+b.copy(Buffer.alloc(1), 0, 1024, 1024);
+
+// Testing for smart defaults and ability to pass string values as offset
+{
+ const writeTest = Buffer.from('abcdes');
+ writeTest.write('n', 'ascii');
+ assert.throws(
+ () => writeTest.write('o', '1', 'ascii'),
+ { code: 'ERR_INVALID_ARG_TYPE' }
+ );
+ writeTest.write('o', 1, 'ascii');
+ writeTest.write('d', 2, 'ascii');
+ writeTest.write('e', 3, 'ascii');
+ writeTest.write('j', 4, 'ascii');
+ assert.strictEqual(writeTest.toString(), 'nodejs');
+}
+
+// Offset points to the end of the buffer and does not throw.
+// (see https://github.com/nodejs/node/issues/8127).
+Buffer.alloc(1).write('', 1, 0);
+
+// ASCII slice test
+{
+ const asciiString = 'hello world';
+
+ for (let i = 0; i < asciiString.length; i++) {
+ b[i] = asciiString.charCodeAt(i);
+ }
+ const asciiSlice = b.toString('ascii', 0, asciiString.length);
+ assert.strictEqual(asciiString, asciiSlice);
+}
+
+{
+ const asciiString = 'hello world';
+ const offset = 100;
+
+ assert.strictEqual(asciiString.length, b.write(asciiString, offset, 'ascii'));
+ const asciiSlice = b.toString('ascii', offset, offset + asciiString.length);
+ assert.strictEqual(asciiString, asciiSlice);
+}
+
+{
+ const asciiString = 'hello world';
+ const offset = 100;
+
+ const sliceA = b.slice(offset, offset + asciiString.length);
+ const sliceB = b.slice(offset, offset + asciiString.length);
+ for (let i = 0; i < asciiString.length; i++) {
+ assert.strictEqual(sliceA[i], sliceB[i]);
+ }
+}
+
+// UTF-8 slice test
+{
+ const utf8String = '¡hέlló wôrld!';
+ const offset = 100;
+
+ b.write(utf8String, 0, Buffer.byteLength(utf8String), 'utf8');
+ let utf8Slice = b.toString('utf8', 0, Buffer.byteLength(utf8String));
+ assert.strictEqual(utf8String, utf8Slice);
+
+ assert.strictEqual(Buffer.byteLength(utf8String),
+ b.write(utf8String, offset, 'utf8'));
+ utf8Slice = b.toString('utf8', offset,
+ offset + Buffer.byteLength(utf8String));
+ assert.strictEqual(utf8String, utf8Slice);
+
+ const sliceA = b.slice(offset, offset + Buffer.byteLength(utf8String));
+ const sliceB = b.slice(offset, offset + Buffer.byteLength(utf8String));
+ for (let i = 0; i < Buffer.byteLength(utf8String); i++) {
+ assert.strictEqual(sliceA[i], sliceB[i]);
+ }
+}
+
+{
+ const slice = b.slice(100, 150);
+ assert.strictEqual(slice.length, 50);
+ for (let i = 0; i < 50; i++) {
+ assert.strictEqual(b[100 + i], slice[i]);
+ }
+}
+
+{
+ // Make sure only top level parent propagates from allocPool
+ const b = Buffer.allocUnsafe(5);
+ const c = b.slice(0, 4);
+ const d = c.slice(0, 2);
+ assert.strictEqual(b.parent, c.parent);
+ assert.strictEqual(b.parent, d.parent);
+}
+
+{
+ // Also from a non-pooled instance
+ const b = Buffer.allocUnsafeSlow(5);
+ const c = b.slice(0, 4);
+ const d = c.slice(0, 2);
+ assert.strictEqual(c.parent, d.parent);
+}
+
+{
+ // Bug regression test
+ const testValue = '\u00F6\u65E5\u672C\u8A9E'; // ö日本語
+ const buffer = Buffer.allocUnsafe(32);
+ const size = buffer.write(testValue, 0, 'utf8');
+ const slice = buffer.toString('utf8', 0, size);
+ assert.strictEqual(slice, testValue);
+}
+
+{
+ // Test triple slice
+ const a = Buffer.allocUnsafe(8);
+ for (let i = 0; i < 8; i++) a[i] = i;
+ const b = a.slice(4, 8);
+ assert.strictEqual(b[0], 4);
+ assert.strictEqual(b[1], 5);
+ assert.strictEqual(b[2], 6);
+ assert.strictEqual(b[3], 7);
+ const c = b.slice(2, 4);
+ assert.strictEqual(c[0], 6);
+ assert.strictEqual(c[1], 7);
+}
+
+{
+ const d = Buffer.from([23, 42, 255]);
+ assert.strictEqual(d.length, 3);
+ assert.strictEqual(d[0], 23);
+ assert.strictEqual(d[1], 42);
+ assert.strictEqual(d[2], 255);
+ assert.deepStrictEqual(d, Buffer.from(d));
+}
+
+{
+ // Test for proper UTF-8 Encoding
+ const e = Buffer.from('über');
+ assert.deepStrictEqual(e, Buffer.from([195, 188, 98, 101, 114]));
+}
+
+{
+ // Test for proper ascii Encoding, length should be 4
+ const f = Buffer.from('über', 'ascii');
+ assert.deepStrictEqual(f, Buffer.from([252, 98, 101, 114]));
+}
+
+['ucs2', 'ucs-2', 'utf16le', 'utf-16le'].forEach((encoding) => {
+ {
+ // Test for proper UTF16LE encoding, length should be 8
+ const f = Buffer.from('über', encoding);
+ assert.deepStrictEqual(f, Buffer.from([252, 0, 98, 0, 101, 0, 114, 0]));
+ }
+
+ {
+ // Length should be 12
+ const f = Buffer.from('привет', encoding);
+ assert.deepStrictEqual(
+ f, Buffer.from([63, 4, 64, 4, 56, 4, 50, 4, 53, 4, 66, 4])
+ );
+ assert.strictEqual(f.toString(encoding), 'привет');
+ }
+
+ {
+ const f = Buffer.from([0, 0, 0, 0, 0]);
+ assert.strictEqual(f.length, 5);
+ const size = f.write('あいうえお', encoding);
+ assert.strictEqual(size, 4);
+ assert.deepStrictEqual(f, Buffer.from([0x42, 0x30, 0x44, 0x30, 0x00]));
+ }
+});
+
+{
+ const f = Buffer.from('\uD83D\uDC4D', 'utf-16le'); // THUMBS UP SIGN (U+1F44D)
+ assert.strictEqual(f.length, 4);
+ assert.deepStrictEqual(f, Buffer.from('3DD84DDC', 'hex'));
+}
+
+// Test construction from arrayish object
+{
+ const arrayIsh = { 0: 0, 1: 1, 2: 2, 3: 3, length: 4 };
+ let g = Buffer.from(arrayIsh);
+ assert.deepStrictEqual(g, Buffer.from([0, 1, 2, 3]));
+ const strArrayIsh = { 0: '0', 1: '1', 2: '2', 3: '3', length: 4 };
+ g = Buffer.from(strArrayIsh);
+ assert.deepStrictEqual(g, Buffer.from([0, 1, 2, 3]));
+}
+
+//
+// Test toString('base64')
+//
+assert.strictEqual((Buffer.from('Man')).toString('base64'), 'TWFu');
+assert.strictEqual((Buffer.from('Woman')).toString('base64'), 'V29tYW4=');
+
+//
+// Test toString('base64url')
+//
+assert.strictEqual((Buffer.from('Man')).toString('base64url'), 'TWFu');
+assert.strictEqual((Buffer.from('Woman')).toString('base64url'), 'V29tYW4');
+
+{
+ // Test that regular and URL-safe base64 both work both ways
+ const expected = [0xff, 0xff, 0xbe, 0xff, 0xef, 0xbf, 0xfb, 0xef, 0xff];
+ assert.deepStrictEqual(Buffer.from('//++/++/++//', 'base64'),
+ Buffer.from(expected));
+ assert.deepStrictEqual(Buffer.from('__--_--_--__', 'base64'),
+ Buffer.from(expected));
+ assert.deepStrictEqual(Buffer.from('//++/++/++//', 'base64url'),
+ Buffer.from(expected));
+ assert.deepStrictEqual(Buffer.from('__--_--_--__', 'base64url'),
+ Buffer.from(expected));
+}
+
+const base64flavors = ['base64', 'base64url'];
+
+{
+ // Test that regular and URL-safe base64 both work both ways with padding
+ const expected = [0xff, 0xff, 0xbe, 0xff, 0xef, 0xbf, 0xfb, 0xef, 0xff, 0xfb];
+ assert.deepStrictEqual(Buffer.from('//++/++/++//+w==', 'base64'),
+ Buffer.from(expected));
+ assert.deepStrictEqual(Buffer.from('//++/++/++//+w==', 'base64'),
+ Buffer.from(expected));
+ assert.deepStrictEqual(Buffer.from('//++/++/++//+w==', 'base64url'),
+ Buffer.from(expected));
+ assert.deepStrictEqual(Buffer.from('//++/++/++//+w==', 'base64url'),
+ Buffer.from(expected));
+}
+
+{
+ // big example
+ const quote = 'Man is distinguished, not only by his reason, but by this ' +
+ 'singular passion from other animals, which is a lust ' +
+ 'of the mind, that by a perseverance of delight in the ' +
+ 'continued and indefatigable generation of knowledge, ' +
+ 'exceeds the short vehemence of any carnal pleasure.';
+ const expected = 'TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb' +
+ '24sIGJ1dCBieSB0aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlci' +
+ 'BhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2YgdGhlIG1pbmQsIHRoYXQ' +
+ 'gYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGlu' +
+ 'dWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZ' +
+ 'GdlLCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm' +
+ '5hbCBwbGVhc3VyZS4=';
+ assert.strictEqual(Buffer.from(quote).toString('base64'), expected);
+ assert.strictEqual(
+ Buffer.from(quote).toString('base64url'),
+ expected.replaceAll('+', '-').replaceAll('/', '_').replaceAll('=', '')
+ );
+
+ base64flavors.forEach((encoding) => {
+ let b = Buffer.allocUnsafe(1024);
+ let bytesWritten = b.write(expected, 0, encoding);
+ assert.strictEqual(quote.length, bytesWritten);
+ assert.strictEqual(quote, b.toString('ascii', 0, quote.length));
+
+ // Check that the base64 decoder ignores whitespace
+ const expectedWhite = `${expected.slice(0, 60)} \n` +
+ `${expected.slice(60, 120)} \n` +
+ `${expected.slice(120, 180)} \n` +
+ `${expected.slice(180, 240)} \n` +
+ `${expected.slice(240, 300)}\n` +
+ `${expected.slice(300, 360)}\n`;
+ b = Buffer.allocUnsafe(1024);
+ bytesWritten = b.write(expectedWhite, 0, encoding);
+ assert.strictEqual(quote.length, bytesWritten);
+ assert.strictEqual(quote, b.toString('ascii', 0, quote.length));
+
+ // Check that the base64 decoder on the constructor works
+ // even in the presence of whitespace.
+ b = Buffer.from(expectedWhite, encoding);
+ assert.strictEqual(quote.length, b.length);
+ assert.strictEqual(quote, b.toString('ascii', 0, quote.length));
+
+ // Check that the base64 decoder ignores illegal chars
+ const expectedIllegal = expected.slice(0, 60) + ' \x80' +
+ expected.slice(60, 120) + ' \xff' +
+ expected.slice(120, 180) + ' \x00' +
+ expected.slice(180, 240) + ' \x98' +
+ expected.slice(240, 300) + '\x03' +
+ expected.slice(300, 360);
+ b = Buffer.from(expectedIllegal, encoding);
+ assert.strictEqual(quote.length, b.length);
+ assert.strictEqual(quote, b.toString('ascii', 0, quote.length));
+ });
+}
+
+base64flavors.forEach((encoding) => {
+ assert.strictEqual(Buffer.from('', encoding).toString(), '');
+ assert.strictEqual(Buffer.from('K', encoding).toString(), '');
+
+ // multiple-of-4 with padding
+ assert.strictEqual(Buffer.from('Kg==', encoding).toString(), '*');
+ assert.strictEqual(Buffer.from('Kio=', encoding).toString(), '*'.repeat(2));
+ assert.strictEqual(Buffer.from('Kioq', encoding).toString(), '*'.repeat(3));
+ assert.strictEqual(
+ Buffer.from('KioqKg==', encoding).toString(), '*'.repeat(4));
+ assert.strictEqual(
+ Buffer.from('KioqKio=', encoding).toString(), '*'.repeat(5));
+ assert.strictEqual(
+ Buffer.from('KioqKioq', encoding).toString(), '*'.repeat(6));
+ assert.strictEqual(Buffer.from('KioqKioqKg==', encoding).toString(),
+ '*'.repeat(7));
+ assert.strictEqual(Buffer.from('KioqKioqKio=', encoding).toString(),
+ '*'.repeat(8));
+ assert.strictEqual(Buffer.from('KioqKioqKioq', encoding).toString(),
+ '*'.repeat(9));
+ assert.strictEqual(Buffer.from('KioqKioqKioqKg==', encoding).toString(),
+ '*'.repeat(10));
+ assert.strictEqual(Buffer.from('KioqKioqKioqKio=', encoding).toString(),
+ '*'.repeat(11));
+ assert.strictEqual(Buffer.from('KioqKioqKioqKioq', encoding).toString(),
+ '*'.repeat(12));
+ assert.strictEqual(Buffer.from('KioqKioqKioqKioqKg==', encoding).toString(),
+ '*'.repeat(13));
+ assert.strictEqual(Buffer.from('KioqKioqKioqKioqKio=', encoding).toString(),
+ '*'.repeat(14));
+ assert.strictEqual(Buffer.from('KioqKioqKioqKioqKioq', encoding).toString(),
+ '*'.repeat(15));
+ assert.strictEqual(
+ Buffer.from('KioqKioqKioqKioqKioqKg==', encoding).toString(),
+ '*'.repeat(16));
+ assert.strictEqual(
+ Buffer.from('KioqKioqKioqKioqKioqKio=', encoding).toString(),
+ '*'.repeat(17));
+ assert.strictEqual(
+ Buffer.from('KioqKioqKioqKioqKioqKioq', encoding).toString(),
+ '*'.repeat(18));
+ assert.strictEqual(Buffer.from('KioqKioqKioqKioqKioqKioqKg==',
+ encoding).toString(),
+ '*'.repeat(19));
+ assert.strictEqual(Buffer.from('KioqKioqKioqKioqKioqKioqKio=',
+ encoding).toString(),
+ '*'.repeat(20));
+
+ // No padding, not a multiple of 4
+ assert.strictEqual(Buffer.from('Kg', encoding).toString(), '*');
+ assert.strictEqual(Buffer.from('Kio', encoding).toString(), '*'.repeat(2));
+ assert.strictEqual(Buffer.from('KioqKg', encoding).toString(), '*'.repeat(4));
+ assert.strictEqual(
+ Buffer.from('KioqKio', encoding).toString(), '*'.repeat(5));
+ assert.strictEqual(Buffer.from('KioqKioqKg', encoding).toString(),
+ '*'.repeat(7));
+ assert.strictEqual(Buffer.from('KioqKioqKio', encoding).toString(),
+ '*'.repeat(8));
+ assert.strictEqual(Buffer.from('KioqKioqKioqKg', encoding).toString(),
+ '*'.repeat(10));
+ assert.strictEqual(Buffer.from('KioqKioqKioqKio', encoding).toString(),
+ '*'.repeat(11));
+ assert.strictEqual(Buffer.from('KioqKioqKioqKioqKg', encoding).toString(),
+ '*'.repeat(13));
+ assert.strictEqual(Buffer.from('KioqKioqKioqKioqKio', encoding).toString(),
+ '*'.repeat(14));
+ assert.strictEqual(Buffer.from('KioqKioqKioqKioqKioqKg', encoding).toString(),
+ '*'.repeat(16));
+ assert.strictEqual(
+ Buffer.from('KioqKioqKioqKioqKioqKio', encoding).toString(),
+ '*'.repeat(17));
+ assert.strictEqual(
+ Buffer.from('KioqKioqKioqKioqKioqKioqKg', encoding).toString(),
+ '*'.repeat(19));
+ assert.strictEqual(
+ Buffer.from('KioqKioqKioqKioqKioqKioqKio', encoding).toString(),
+ '*'.repeat(20));
+});
+
+// Handle padding graciously, multiple-of-4 or not
+assert.strictEqual(
+ Buffer.from('72INjkR5fchcxk9+VgdGPFJDxUBFR5/rMFsghgxADiw==', 'base64').length,
+ 32
+);
+assert.strictEqual(
+ Buffer.from('72INjkR5fchcxk9-VgdGPFJDxUBFR5_rMFsghgxADiw==', 'base64url')
+ .length,
+ 32
+);
+assert.strictEqual(
+ Buffer.from('72INjkR5fchcxk9+VgdGPFJDxUBFR5/rMFsghgxADiw=', 'base64').length,
+ 32
+);
+assert.strictEqual(
+ Buffer.from('72INjkR5fchcxk9-VgdGPFJDxUBFR5_rMFsghgxADiw=', 'base64url')
+ .length,
+ 32
+);
+assert.strictEqual(
+ Buffer.from('72INjkR5fchcxk9+VgdGPFJDxUBFR5/rMFsghgxADiw', 'base64').length,
+ 32
+);
+assert.strictEqual(
+ Buffer.from('72INjkR5fchcxk9-VgdGPFJDxUBFR5_rMFsghgxADiw', 'base64url')
+ .length,
+ 32
+);
+assert.strictEqual(
+ Buffer.from('w69jACy6BgZmaFvv96HG6MYksWytuZu3T1FvGnulPg==', 'base64').length,
+ 31
+);
+assert.strictEqual(
+ Buffer.from('w69jACy6BgZmaFvv96HG6MYksWytuZu3T1FvGnulPg==', 'base64url')
+ .length,
+ 31
+);
+assert.strictEqual(
+ Buffer.from('w69jACy6BgZmaFvv96HG6MYksWytuZu3T1FvGnulPg=', 'base64').length,
+ 31
+);
+assert.strictEqual(
+ Buffer.from('w69jACy6BgZmaFvv96HG6MYksWytuZu3T1FvGnulPg=', 'base64url')
+ .length,
+ 31
+);
+assert.strictEqual(
+ Buffer.from('w69jACy6BgZmaFvv96HG6MYksWytuZu3T1FvGnulPg', 'base64').length,
+ 31
+);
+assert.strictEqual(
+ Buffer.from('w69jACy6BgZmaFvv96HG6MYksWytuZu3T1FvGnulPg', 'base64url').length,
+ 31
+);
+
+{
+// This string encodes single '.' character in UTF-16
+ const dot = Buffer.from('//4uAA==', 'base64');
+ assert.strictEqual(dot[0], 0xff);
+ assert.strictEqual(dot[1], 0xfe);
+ assert.strictEqual(dot[2], 0x2e);
+ assert.strictEqual(dot[3], 0x00);
+ assert.strictEqual(dot.toString('base64'), '//4uAA==');
+}
+
+{
+// This string encodes single '.' character in UTF-16
+ const dot = Buffer.from('//4uAA', 'base64url');
+ assert.strictEqual(dot[0], 0xff);
+ assert.strictEqual(dot[1], 0xfe);
+ assert.strictEqual(dot[2], 0x2e);
+ assert.strictEqual(dot[3], 0x00);
+ assert.strictEqual(dot.toString('base64url'), '__4uAA');
+}
+
+{
+ // Writing base64 at a position > 0 should not mangle the result.
+ //
+ // https://github.com/joyent/node/issues/402
+ const segments = ['TWFkbmVzcz8h', 'IFRoaXM=', 'IGlz', 'IG5vZGUuanMh'];
+ const b = Buffer.allocUnsafe(64);
+ let pos = 0;
+
+ for (let i = 0; i < segments.length; ++i) {
+ pos += b.write(segments[i], pos, 'base64');
+ }
+ assert.strictEqual(b.toString('latin1', 0, pos),
+ 'Madness?! This is node.js!');
+}
+
+{
+ // Writing base64url at a position > 0 should not mangle the result.
+ //
+ // https://github.com/joyent/node/issues/402
+ const segments = ['TWFkbmVzcz8h', 'IFRoaXM', 'IGlz', 'IG5vZGUuanMh'];
+ const b = Buffer.allocUnsafe(64);
+ let pos = 0;
+
+ for (let i = 0; i < segments.length; ++i) {
+ pos += b.write(segments[i], pos, 'base64url');
+ }
+ assert.strictEqual(b.toString('latin1', 0, pos),
+ 'Madness?! This is node.js!');
+}
+
+// Regression test for https://github.com/nodejs/node/issues/3496.
+assert.strictEqual(Buffer.from('=bad'.repeat(1e4), 'base64').length, 0);
+
+// Regression test for https://github.com/nodejs/node/issues/11987.
+assert.deepStrictEqual(Buffer.from('w0 ', 'base64'),
+ Buffer.from('w0', 'base64'));
+
+// Regression test for https://github.com/nodejs/node/issues/13657.
+assert.deepStrictEqual(Buffer.from(' YWJvcnVtLg', 'base64'),
+ Buffer.from('YWJvcnVtLg', 'base64'));
+
+{
+ // Creating buffers larger than pool size.
+ const l = Buffer.poolSize + 5;
+ const s = 'h'.repeat(l);
+ const b = Buffer.from(s);
+
+ for (let i = 0; i < l; i++) {
+ assert.strictEqual(b[i], 'h'.charCodeAt(0));
+ }
+
+ const sb = b.toString();
+ assert.strictEqual(sb.length, s.length);
+ assert.strictEqual(sb, s);
+}
+
+{
+ // test hex toString
+ const hexb = Buffer.allocUnsafe(256);
+ for (let i = 0; i < 256; i++) {
+ hexb[i] = i;
+ }
+ const hexStr = hexb.toString('hex');
+ assert.strictEqual(hexStr,
+ '000102030405060708090a0b0c0d0e0f' +
+ '101112131415161718191a1b1c1d1e1f' +
+ '202122232425262728292a2b2c2d2e2f' +
+ '303132333435363738393a3b3c3d3e3f' +
+ '404142434445464748494a4b4c4d4e4f' +
+ '505152535455565758595a5b5c5d5e5f' +
+ '606162636465666768696a6b6c6d6e6f' +
+ '707172737475767778797a7b7c7d7e7f' +
+ '808182838485868788898a8b8c8d8e8f' +
+ '909192939495969798999a9b9c9d9e9f' +
+ 'a0a1a2a3a4a5a6a7a8a9aaabacadaeaf' +
+ 'b0b1b2b3b4b5b6b7b8b9babbbcbdbebf' +
+ 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf' +
+ 'd0d1d2d3d4d5d6d7d8d9dadbdcdddedf' +
+ 'e0e1e2e3e4e5e6e7e8e9eaebecedeeef' +
+ 'f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff');
+
+ const hexb2 = Buffer.from(hexStr, 'hex');
+ for (let i = 0; i < 256; i++) {
+ assert.strictEqual(hexb2[i], hexb[i]);
+ }
+}
+
+// Test single hex character is discarded.
+assert.strictEqual(Buffer.from('A', 'hex').length, 0);
+
+// Test that if a trailing character is discarded, rest of string is processed.
+assert.deepStrictEqual(Buffer.from('Abx', 'hex'), Buffer.from('Ab', 'hex'));
+
+// Test single base64 char encodes as 0.
+assert.strictEqual(Buffer.from('A', 'base64').length, 0);
+
+
+{
+ // Test an invalid slice end.
+ const b = Buffer.from([1, 2, 3, 4, 5]);
+ const b2 = b.toString('hex', 1, 10000);
+ const b3 = b.toString('hex', 1, 5);
+ const b4 = b.toString('hex', 1);
+ assert.strictEqual(b2, b3);
+ assert.strictEqual(b2, b4);
+}
+
+function buildBuffer(data) {
+ if (Array.isArray(data)) {
+ const buffer = Buffer.allocUnsafe(data.length);
+ data.forEach((v, k) => buffer[k] = v);
+ return buffer;
+ }
+ return null;
+}
+
+const x = buildBuffer([0x81, 0xa3, 0x66, 0x6f, 0x6f, 0xa3, 0x62, 0x61, 0x72]);
+
+assert.strictEqual(x.inspect(), '<Buffer 81 a3 66 6f 6f a3 62 61 72>');
+
+{
+ const z = x.slice(4);
+ assert.strictEqual(z.length, 5);
+ assert.strictEqual(z[0], 0x6f);
+ assert.strictEqual(z[1], 0xa3);
+ assert.strictEqual(z[2], 0x62);
+ assert.strictEqual(z[3], 0x61);
+ assert.strictEqual(z[4], 0x72);
+}
+
+{
+ const z = x.slice(0);
+ assert.strictEqual(z.length, x.length);
+}
+
+{
+ const z = x.slice(0, 4);
+ assert.strictEqual(z.length, 4);
+ assert.strictEqual(z[0], 0x81);
+ assert.strictEqual(z[1], 0xa3);
+}
+
+{
+ const z = x.slice(0, 9);
+ assert.strictEqual(z.length, 9);
+}
+
+{
+ const z = x.slice(1, 4);
+ assert.strictEqual(z.length, 3);
+ assert.strictEqual(z[0], 0xa3);
+}
+
+{
+ const z = x.slice(2, 4);
+ assert.strictEqual(z.length, 2);
+ assert.strictEqual(z[0], 0x66);
+ assert.strictEqual(z[1], 0x6f);
+}
+
+['ucs2', 'ucs-2', 'utf16le', 'utf-16le'].forEach((encoding) => {
+ const b = Buffer.allocUnsafe(10);
+ b.write('あいうえお', encoding);
+ assert.strictEqual(b.toString(encoding), 'あいうえお');
+});
+
+['ucs2', 'ucs-2', 'utf16le', 'utf-16le'].forEach((encoding) => {
+ const b = Buffer.allocUnsafe(11);
+ b.write('あいうえお', 1, encoding);
+ assert.strictEqual(b.toString(encoding, 1), 'あいうえお');
+});
+
+{
+ // latin1 encoding should write only one byte per character.
+ const b = Buffer.from([0xde, 0xad, 0xbe, 0xef]);
+ let s = String.fromCharCode(0xffff);
+ b.write(s, 0, 'latin1');
+ assert.strictEqual(b[0], 0xff);
+ assert.strictEqual(b[1], 0xad);
+ assert.strictEqual(b[2], 0xbe);
+ assert.strictEqual(b[3], 0xef);
+ s = String.fromCharCode(0xaaee);
+ b.write(s, 0, 'latin1');
+ assert.strictEqual(b[0], 0xee);
+ assert.strictEqual(b[1], 0xad);
+ assert.strictEqual(b[2], 0xbe);
+ assert.strictEqual(b[3], 0xef);
+}
+
+{
+ // Binary encoding should write only one byte per character.
+ const b = Buffer.from([0xde, 0xad, 0xbe, 0xef]);
+ let s = String.fromCharCode(0xffff);
+ b.write(s, 0, 'latin1');
+ assert.strictEqual(b[0], 0xff);
+ assert.strictEqual(b[1], 0xad);
+ assert.strictEqual(b[2], 0xbe);
+ assert.strictEqual(b[3], 0xef);
+ s = String.fromCharCode(0xaaee);
+ b.write(s, 0, 'latin1');
+ assert.strictEqual(b[0], 0xee);
+ assert.strictEqual(b[1], 0xad);
+ assert.strictEqual(b[2], 0xbe);
+ assert.strictEqual(b[3], 0xef);
+}
+
+{
+ // https://github.com/nodejs/node-v0.x-archive/pull/1210
+ // Test UTF-8 string includes null character
+ let buf = Buffer.from('\0');
+ assert.strictEqual(buf.length, 1);
+ buf = Buffer.from('\0\0');
+ assert.strictEqual(buf.length, 2);
+}
+
+{
+ const buf = Buffer.allocUnsafe(2);
+ assert.strictEqual(buf.write(''), 0); // 0bytes
+ assert.strictEqual(buf.write('\0'), 1); // 1byte (v8 adds null terminator)
+ assert.strictEqual(buf.write('a\0'), 2); // 1byte * 2
+ assert.strictEqual(buf.write('あ'), 0); // 3bytes
+ assert.strictEqual(buf.write('\0あ'), 1); // 1byte + 3bytes
+ assert.strictEqual(buf.write('\0\0あ'), 2); // 1byte * 2 + 3bytes
+}
+
+{
+ const buf = Buffer.allocUnsafe(10);
+ assert.strictEqual(buf.write('あいう'), 9); // 3bytes * 3 (v8 adds null term.)
+ assert.strictEqual(buf.write('あいう\0'), 10); // 3bytes * 3 + 1byte
+}
+
+{
+ // https://github.com/nodejs/node-v0.x-archive/issues/243
+ // Test write() with maxLength
+ const buf = Buffer.allocUnsafe(4);
+ buf.fill(0xFF);
+ assert.strictEqual(buf.write('abcd', 1, 2, 'utf8'), 2);
+ assert.strictEqual(buf[0], 0xFF);
+ assert.strictEqual(buf[1], 0x61);
+ assert.strictEqual(buf[2], 0x62);
+ assert.strictEqual(buf[3], 0xFF);
+
+ buf.fill(0xFF);
+ assert.strictEqual(buf.write('abcd', 1, 4), 3);
+ assert.strictEqual(buf[0], 0xFF);
+ assert.strictEqual(buf[1], 0x61);
+ assert.strictEqual(buf[2], 0x62);
+ assert.strictEqual(buf[3], 0x63);
+
+ buf.fill(0xFF);
+ assert.strictEqual(buf.write('abcd', 1, 2, 'utf8'), 2);
+ assert.strictEqual(buf[0], 0xFF);
+ assert.strictEqual(buf[1], 0x61);
+ assert.strictEqual(buf[2], 0x62);
+ assert.strictEqual(buf[3], 0xFF);
+
+ buf.fill(0xFF);
+ assert.strictEqual(buf.write('abcdef', 1, 2, 'hex'), 2);
+ assert.strictEqual(buf[0], 0xFF);
+ assert.strictEqual(buf[1], 0xAB);
+ assert.strictEqual(buf[2], 0xCD);
+ assert.strictEqual(buf[3], 0xFF);
+
+ ['ucs2', 'ucs-2', 'utf16le', 'utf-16le'].forEach((encoding) => {
+ buf.fill(0xFF);
+ assert.strictEqual(buf.write('abcd', 0, 2, encoding), 2);
+ assert.strictEqual(buf[0], 0x61);
+ assert.strictEqual(buf[1], 0x00);
+ assert.strictEqual(buf[2], 0xFF);
+ assert.strictEqual(buf[3], 0xFF);
+ });
+}
+
+{
+ // Test offset returns are correct
+ const b = Buffer.allocUnsafe(16);
+ assert.strictEqual(b.writeUInt32LE(0, 0), 4);
+ assert.strictEqual(b.writeUInt16LE(0, 4), 6);
+ assert.strictEqual(b.writeUInt8(0, 6), 7);
+ assert.strictEqual(b.writeInt8(0, 7), 8);
+ assert.strictEqual(b.writeDoubleLE(0, 8), 16);
+}
+
+{
+ // Test unmatched surrogates not producing invalid utf8 output
+ // ef bf bd = utf-8 representation of unicode replacement character
+ // see https://codereview.chromium.org/121173009/
+ const buf = Buffer.from('ab\ud800cd', 'utf8');
+ assert.strictEqual(buf[0], 0x61);
+ assert.strictEqual(buf[1], 0x62);
+ assert.strictEqual(buf[2], 0xef);
+ assert.strictEqual(buf[3], 0xbf);
+ assert.strictEqual(buf[4], 0xbd);
+ assert.strictEqual(buf[5], 0x63);
+ assert.strictEqual(buf[6], 0x64);
+}
+
+{
+ // Test for buffer overrun
+ const buf = Buffer.from([0, 0, 0, 0, 0]); // length: 5
+ const sub = buf.slice(0, 4); // length: 4
+ assert.strictEqual(sub.write('12345', 'latin1'), 4);
+ assert.strictEqual(buf[4], 0);
+ assert.strictEqual(sub.write('12345', 'binary'), 4);
+ assert.strictEqual(buf[4], 0);
+}
+
+{
+ // Test alloc with fill option
+ const buf = Buffer.alloc(5, '800A', 'hex');
+ assert.strictEqual(buf[0], 128);
+ assert.strictEqual(buf[1], 10);
+ assert.strictEqual(buf[2], 128);
+ assert.strictEqual(buf[3], 10);
+ assert.strictEqual(buf[4], 128);
+}
+
+
+// Check for fractional length args, junk length args, etc.
+// https://github.com/joyent/node/issues/1758
+
+// Call .fill() first, stops valgrind warning about uninitialized memory reads.
+Buffer.allocUnsafe(3.3).fill().toString();
+// Throws bad argument error in commit 43cb4ec
+Buffer.alloc(3.3).fill().toString();
+assert.strictEqual(Buffer.allocUnsafe(3.3).length, 3);
+assert.strictEqual(Buffer.from({ length: 3.3 }).length, 3);
+assert.strictEqual(Buffer.from({ length: 'BAM' }).length, 0);
+
+// Make sure that strings are not coerced to numbers.
+assert.strictEqual(Buffer.from('99').length, 2);
+assert.strictEqual(Buffer.from('13.37').length, 5);
+
+// Ensure that the length argument is respected.
+['ascii', 'utf8', 'hex', 'base64', 'latin1', 'binary'].forEach((enc) => {
+ assert.strictEqual(Buffer.allocUnsafe(1).write('aaaaaa', 0, 1, enc), 1);
+});
+
+{
+ // Regression test, guard against buffer overrun in the base64 decoder.
+ const a = Buffer.allocUnsafe(3);
+ const b = Buffer.from('xxx');
+ a.write('aaaaaaaa', 'base64');
+ assert.strictEqual(b.toString(), 'xxx');
+}
+
+// issue GH-3416
+Buffer.from(Buffer.allocUnsafe(0), 0, 0);
+
+// issue GH-5587
+assert.throws(
+ () => Buffer.alloc(8).writeFloatLE(0, 5),
+ outOfRangeError
+);
+assert.throws(
+ () => Buffer.alloc(16).writeDoubleLE(0, 9),
+ outOfRangeError
+);
+
+// Attempt to overflow buffers, similar to previous bug in array buffers
+assert.throws(
+ () => Buffer.allocUnsafe(8).writeFloatLE(0.0, 0xffffffff),
+ outOfRangeError
+);
+assert.throws(
+ () => Buffer.allocUnsafe(8).writeFloatLE(0.0, 0xffffffff),
+ outOfRangeError
+);
+
+// Ensure negative values can't get past offset
+assert.throws(
+ () => Buffer.allocUnsafe(8).writeFloatLE(0.0, -1),
+ outOfRangeError
+);
+assert.throws(
+ () => Buffer.allocUnsafe(8).writeFloatLE(0.0, -1),
+ outOfRangeError
+);
+
+// Test for common write(U)IntLE/BE
+{
+ let buf = Buffer.allocUnsafe(3);
+ buf.writeUIntLE(0x123456, 0, 3);
+ assert.deepStrictEqual(buf.toJSON().data, [0x56, 0x34, 0x12]);
+ assert.strictEqual(buf.readUIntLE(0, 3), 0x123456);
+
+ buf.fill(0xFF);
+ buf.writeUIntBE(0x123456, 0, 3);
+ assert.deepStrictEqual(buf.toJSON().data, [0x12, 0x34, 0x56]);
+ assert.strictEqual(buf.readUIntBE(0, 3), 0x123456);
+
+ buf.fill(0xFF);
+ buf.writeIntLE(0x123456, 0, 3);
+ assert.deepStrictEqual(buf.toJSON().data, [0x56, 0x34, 0x12]);
+ assert.strictEqual(buf.readIntLE(0, 3), 0x123456);
+
+ buf.fill(0xFF);
+ buf.writeIntBE(0x123456, 0, 3);
+ assert.deepStrictEqual(buf.toJSON().data, [0x12, 0x34, 0x56]);
+ assert.strictEqual(buf.readIntBE(0, 3), 0x123456);
+
+ buf.fill(0xFF);
+ buf.writeIntLE(-0x123456, 0, 3);
+ assert.deepStrictEqual(buf.toJSON().data, [0xaa, 0xcb, 0xed]);
+ assert.strictEqual(buf.readIntLE(0, 3), -0x123456);
+
+ buf.fill(0xFF);
+ buf.writeIntBE(-0x123456, 0, 3);
+ assert.deepStrictEqual(buf.toJSON().data, [0xed, 0xcb, 0xaa]);
+ assert.strictEqual(buf.readIntBE(0, 3), -0x123456);
+
+ buf.fill(0xFF);
+ buf.writeIntLE(-0x123400, 0, 3);
+ assert.deepStrictEqual(buf.toJSON().data, [0x00, 0xcc, 0xed]);
+ assert.strictEqual(buf.readIntLE(0, 3), -0x123400);
+
+ buf.fill(0xFF);
+ buf.writeIntBE(-0x123400, 0, 3);
+ assert.deepStrictEqual(buf.toJSON().data, [0xed, 0xcc, 0x00]);
+ assert.strictEqual(buf.readIntBE(0, 3), -0x123400);
+
+ buf.fill(0xFF);
+ buf.writeIntLE(-0x120000, 0, 3);
+ assert.deepStrictEqual(buf.toJSON().data, [0x00, 0x00, 0xee]);
+ assert.strictEqual(buf.readIntLE(0, 3), -0x120000);
+
+ buf.fill(0xFF);
+ buf.writeIntBE(-0x120000, 0, 3);
+ assert.deepStrictEqual(buf.toJSON().data, [0xee, 0x00, 0x00]);
+ assert.strictEqual(buf.readIntBE(0, 3), -0x120000);
+
+ buf = Buffer.allocUnsafe(5);
+ buf.writeUIntLE(0x1234567890, 0, 5);
+ assert.deepStrictEqual(buf.toJSON().data, [0x90, 0x78, 0x56, 0x34, 0x12]);
+ assert.strictEqual(buf.readUIntLE(0, 5), 0x1234567890);
+
+ buf.fill(0xFF);
+ buf.writeUIntBE(0x1234567890, 0, 5);
+ assert.deepStrictEqual(buf.toJSON().data, [0x12, 0x34, 0x56, 0x78, 0x90]);
+ assert.strictEqual(buf.readUIntBE(0, 5), 0x1234567890);
+
+ buf.fill(0xFF);
+ buf.writeIntLE(0x1234567890, 0, 5);
+ assert.deepStrictEqual(buf.toJSON().data, [0x90, 0x78, 0x56, 0x34, 0x12]);
+ assert.strictEqual(buf.readIntLE(0, 5), 0x1234567890);
+
+ buf.fill(0xFF);
+ buf.writeIntBE(0x1234567890, 0, 5);
+ assert.deepStrictEqual(buf.toJSON().data, [0x12, 0x34, 0x56, 0x78, 0x90]);
+ assert.strictEqual(buf.readIntBE(0, 5), 0x1234567890);
+
+ buf.fill(0xFF);
+ buf.writeIntLE(-0x1234567890, 0, 5);
+ assert.deepStrictEqual(buf.toJSON().data, [0x70, 0x87, 0xa9, 0xcb, 0xed]);
+ assert.strictEqual(buf.readIntLE(0, 5), -0x1234567890);
+
+ buf.fill(0xFF);
+ buf.writeIntBE(-0x1234567890, 0, 5);
+ assert.deepStrictEqual(buf.toJSON().data, [0xed, 0xcb, 0xa9, 0x87, 0x70]);
+ assert.strictEqual(buf.readIntBE(0, 5), -0x1234567890);
+
+ buf.fill(0xFF);
+ buf.writeIntLE(-0x0012000000, 0, 5);
+ assert.deepStrictEqual(buf.toJSON().data, [0x00, 0x00, 0x00, 0xee, 0xff]);
+ assert.strictEqual(buf.readIntLE(0, 5), -0x0012000000);
+
+ buf.fill(0xFF);
+ buf.writeIntBE(-0x0012000000, 0, 5);
+ assert.deepStrictEqual(buf.toJSON().data, [0xff, 0xee, 0x00, 0x00, 0x00]);
+ assert.strictEqual(buf.readIntBE(0, 5), -0x0012000000);
+}
+
+// Regression test for https://github.com/nodejs/node-v0.x-archive/issues/5482:
+// should throw but not assert in C++ land.
+assert.throws(
+ () => Buffer.from('', 'buffer'),
+ {
+ code: 'ERR_UNKNOWN_ENCODING',
+ name: 'TypeError',
+ message: 'Unknown encoding: buffer'
+ }
+);
+
+// Regression test for https://github.com/nodejs/node-v0.x-archive/issues/6111.
+// Constructing a buffer from another buffer should a) work, and b) not corrupt
+// the source buffer.
+{
+ const a = [...Array(128).keys()]; // [0, 1, 2, 3, ... 126, 127]
+ const b = Buffer.from(a);
+ const c = Buffer.from(b);
+ assert.strictEqual(b.length, a.length);
+ assert.strictEqual(c.length, a.length);
+ for (let i = 0, k = a.length; i < k; ++i) {
+ assert.strictEqual(a[i], i);
+ assert.strictEqual(b[i], i);
+ assert.strictEqual(c[i], i);
+ }
+}
+
+if (common.hasCrypto) { // eslint-disable-line node-core/crypto-check
+ // Test truncation after decode
+ const crypto = require('crypto');
+
+ const b1 = Buffer.from('YW55=======', 'base64');
+ const b2 = Buffer.from('YW55', 'base64');
+
+ assert.strictEqual(
+ crypto.createHash('sha1').update(b1).digest('hex'),
+ crypto.createHash('sha1').update(b2).digest('hex')
+ );
+} else {
+ common.printSkipMessage('missing crypto');
+}
+
+const ps = Buffer.poolSize;
+Buffer.poolSize = 0;
+assert(Buffer.allocUnsafe(1).parent instanceof ArrayBuffer);
+Buffer.poolSize = ps;
+
+assert.throws(
+ () => Buffer.allocUnsafe(10).copy(),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: 'The "target" argument must be an instance of Buffer or ' +
+ 'Uint8Array. Received undefined'
+ });
+
+assert.throws(() => Buffer.from(), {
+ name: 'TypeError',
+ message: 'The first argument must be of type string or an instance of ' +
+ 'Buffer, ArrayBuffer, or Array or an Array-like Object. Received undefined'
+});
+assert.throws(() => Buffer.from(null), {
+ name: 'TypeError',
+ message: 'The first argument must be of type string or an instance of ' +
+ 'Buffer, ArrayBuffer, or Array or an Array-like Object. Received null'
+});
+
+// Test prototype getters don't throw
+assert.strictEqual(Buffer.prototype.parent, undefined);
+assert.strictEqual(Buffer.prototype.offset, undefined);
+assert.strictEqual(SlowBuffer.prototype.parent, undefined);
+assert.strictEqual(SlowBuffer.prototype.offset, undefined);
+
+
+{
+ // Test that large negative Buffer length inputs don't affect the pool offset.
+ // Use the fromArrayLike() variant here because it's more lenient
+ // about its input and passes the length directly to allocate().
+ assert.deepStrictEqual(Buffer.from({ length: -Buffer.poolSize }),
+ Buffer.from(''));
+ assert.deepStrictEqual(Buffer.from({ length: -100 }),
+ Buffer.from(''));
+
+ // Check pool offset after that by trying to write string into the pool.
+ Buffer.from('abc');
+}
+
+
+// Test that ParseArrayIndex handles full uint32
+{
+ const errMsg = common.expectsError({
+ code: 'ERR_BUFFER_OUT_OF_BOUNDS',
+ name: 'RangeError',
+ message: '"offset" is outside of buffer bounds'
+ });
+ assert.throws(() => Buffer.from(new ArrayBuffer(0), -1 >>> 0), errMsg);
+}
+
+// ParseArrayIndex() should reject values that don't fit in a 32 bits size_t.
+assert.throws(() => {
+ const a = Buffer.alloc(1);
+ const b = Buffer.alloc(1);
+ a.copy(b, 0, 0x100000000, 0x100000001);
+}, outOfRangeError);
+
+// Unpooled buffer (replaces SlowBuffer)
+{
+ const ubuf = Buffer.allocUnsafeSlow(10);
+ assert(ubuf);
+ assert(ubuf.buffer);
+ assert.strictEqual(ubuf.buffer.byteLength, 10);
+}
+
+// Regression test to verify that an empty ArrayBuffer does not throw.
+Buffer.from(new ArrayBuffer());
+
+
+// Test that ArrayBuffer from a different context is detected correctly.
+const arrayBuf = vm.runInNewContext('new ArrayBuffer()');
+Buffer.from(arrayBuf);
+Buffer.from({ buffer: arrayBuf });
+
+assert.throws(() => Buffer.alloc({ valueOf: () => 1 }),
+ /"size" argument must be of type number/);
+assert.throws(() => Buffer.alloc({ valueOf: () => -1 }),
+ /"size" argument must be of type number/);
+
+assert.strictEqual(Buffer.prototype.toLocaleString, Buffer.prototype.toString);
+{
+ const buf = Buffer.from('test');
+ assert.strictEqual(buf.toLocaleString(), buf.toString());
+}
+
+assert.throws(() => {
+ Buffer.alloc(0x1000, 'This is not correctly encoded', 'hex');
+}, {
+ code: 'ERR_INVALID_ARG_VALUE',
+ name: 'TypeError'
+});
+
+assert.throws(() => {
+ Buffer.alloc(0x1000, 'c', 'hex');
+}, {
+ code: 'ERR_INVALID_ARG_VALUE',
+ name: 'TypeError'
+});
+
+assert.throws(() => {
+ Buffer.alloc(1, Buffer.alloc(0));
+}, {
+ code: 'ERR_INVALID_ARG_VALUE',
+ name: 'TypeError'
+});
+
+assert.throws(() => {
+ Buffer.alloc(40, 'x', 20);
+}, {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError'
+});
diff --git a/tests/node_compat/test/parallel/test-buffer-arraybuffer.js b/tests/node_compat/test/parallel/test-buffer-arraybuffer.js
new file mode 100644
index 000000000..286481758
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-buffer-arraybuffer.js
@@ -0,0 +1,159 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+require('../common');
+const assert = require('assert');
+
+const LENGTH = 16;
+
+const ab = new ArrayBuffer(LENGTH);
+const dv = new DataView(ab);
+const ui = new Uint8Array(ab);
+const buf = Buffer.from(ab);
+
+
+assert.ok(buf instanceof Buffer);
+assert.strictEqual(buf.parent, buf.buffer);
+assert.strictEqual(buf.buffer, ab);
+assert.strictEqual(buf.length, ab.byteLength);
+
+
+buf.fill(0xC);
+for (let i = 0; i < LENGTH; i++) {
+ assert.strictEqual(ui[i], 0xC);
+ ui[i] = 0xF;
+ assert.strictEqual(buf[i], 0xF);
+}
+
+buf.writeUInt32LE(0xF00, 0);
+buf.writeUInt32BE(0xB47, 4);
+buf.writeDoubleLE(3.1415, 8);
+
+assert.strictEqual(dv.getUint32(0, true), 0xF00);
+assert.strictEqual(dv.getUint32(4), 0xB47);
+assert.strictEqual(dv.getFloat64(8, true), 3.1415);
+
+
+// Now test protecting users from doing stupid things
+
+assert.throws(function() {
+ function AB() { }
+ Object.setPrototypeOf(AB, ArrayBuffer);
+ Object.setPrototypeOf(AB.prototype, ArrayBuffer.prototype);
+ Buffer.from(new AB());
+}, {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: 'The first argument must be of type string or an instance of ' +
+ 'Buffer, ArrayBuffer, or Array or an Array-like Object. Received ' +
+ 'an instance of AB'
+});
+
+// Test the byteOffset and length arguments
+{
+ const ab = new Uint8Array(5);
+ ab[0] = 1;
+ ab[1] = 2;
+ ab[2] = 3;
+ ab[3] = 4;
+ ab[4] = 5;
+ const buf = Buffer.from(ab.buffer, 1, 3);
+ assert.strictEqual(buf.length, 3);
+ assert.strictEqual(buf[0], 2);
+ assert.strictEqual(buf[1], 3);
+ assert.strictEqual(buf[2], 4);
+ buf[0] = 9;
+ assert.strictEqual(ab[1], 9);
+
+ assert.throws(() => Buffer.from(ab.buffer, 6), {
+ code: 'ERR_BUFFER_OUT_OF_BOUNDS',
+ name: 'RangeError',
+ message: '"offset" is outside of buffer bounds'
+ });
+ assert.throws(() => Buffer.from(ab.buffer, 3, 6), {
+ code: 'ERR_BUFFER_OUT_OF_BOUNDS',
+ name: 'RangeError',
+ message: '"length" is outside of buffer bounds'
+ });
+}
+
+// Test the deprecated Buffer() version also
+{
+ const ab = new Uint8Array(5);
+ ab[0] = 1;
+ ab[1] = 2;
+ ab[2] = 3;
+ ab[3] = 4;
+ ab[4] = 5;
+ const buf = Buffer(ab.buffer, 1, 3);
+ assert.strictEqual(buf.length, 3);
+ assert.strictEqual(buf[0], 2);
+ assert.strictEqual(buf[1], 3);
+ assert.strictEqual(buf[2], 4);
+ buf[0] = 9;
+ assert.strictEqual(ab[1], 9);
+
+ assert.throws(() => Buffer(ab.buffer, 6), {
+ code: 'ERR_BUFFER_OUT_OF_BOUNDS',
+ name: 'RangeError',
+ message: '"offset" is outside of buffer bounds'
+ });
+ assert.throws(() => Buffer(ab.buffer, 3, 6), {
+ code: 'ERR_BUFFER_OUT_OF_BOUNDS',
+ name: 'RangeError',
+ message: '"length" is outside of buffer bounds'
+ });
+}
+
+{
+ // If byteOffset is not numeric, it defaults to 0.
+ const ab = new ArrayBuffer(10);
+ const expected = Buffer.from(ab, 0);
+ assert.deepStrictEqual(Buffer.from(ab, 'fhqwhgads'), expected);
+ assert.deepStrictEqual(Buffer.from(ab, NaN), expected);
+ assert.deepStrictEqual(Buffer.from(ab, {}), expected);
+ assert.deepStrictEqual(Buffer.from(ab, []), expected);
+
+ // If byteOffset can be converted to a number, it will be.
+ assert.deepStrictEqual(Buffer.from(ab, [1]), Buffer.from(ab, 1));
+
+ // If byteOffset is Infinity, throw.
+ assert.throws(() => {
+ Buffer.from(ab, Infinity);
+ }, {
+ code: 'ERR_BUFFER_OUT_OF_BOUNDS',
+ name: 'RangeError',
+ message: '"offset" is outside of buffer bounds'
+ });
+}
+
+{
+ // If length is not numeric, it defaults to 0.
+ const ab = new ArrayBuffer(10);
+ const expected = Buffer.from(ab, 0, 0);
+ assert.deepStrictEqual(Buffer.from(ab, 0, 'fhqwhgads'), expected);
+ assert.deepStrictEqual(Buffer.from(ab, 0, NaN), expected);
+ assert.deepStrictEqual(Buffer.from(ab, 0, {}), expected);
+ assert.deepStrictEqual(Buffer.from(ab, 0, []), expected);
+
+ // If length can be converted to a number, it will be.
+ assert.deepStrictEqual(Buffer.from(ab, 0, [1]), Buffer.from(ab, 0, 1));
+
+ // If length is Infinity, throw.
+ assert.throws(() => {
+ Buffer.from(ab, 0, Infinity);
+ }, {
+ code: 'ERR_BUFFER_OUT_OF_BOUNDS',
+ name: 'RangeError',
+ message: '"length" is outside of buffer bounds'
+ });
+}
+
+// Test an array like entry with the length set to NaN.
+assert.deepStrictEqual(Buffer.from({ length: NaN }), Buffer.alloc(0));
diff --git a/tests/node_compat/test/parallel/test-buffer-ascii.js b/tests/node_compat/test/parallel/test-buffer-ascii.js
new file mode 100644
index 000000000..08e4e6543
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-buffer-ascii.js
@@ -0,0 +1,53 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+
+// ASCII conversion in node.js simply masks off the high bits,
+// it doesn't do transliteration.
+assert.strictEqual(Buffer.from('hérité').toString('ascii'), 'hC)ritC)');
+
+// 71 characters, 78 bytes. The ’ character is a triple-byte sequence.
+const input = 'C’est, graphiquement, la réunion d’un accent aigu ' +
+ 'et d’un accent grave.';
+
+const expected = 'Cb\u0000\u0019est, graphiquement, la rC)union ' +
+ 'db\u0000\u0019un accent aigu et db\u0000\u0019un ' +
+ 'accent grave.';
+
+const buf = Buffer.from(input);
+
+for (let i = 0; i < expected.length; ++i) {
+ assert.strictEqual(buf.slice(i).toString('ascii'), expected.slice(i));
+
+ // Skip remainder of multi-byte sequence.
+ if (input.charCodeAt(i) > 65535) ++i;
+ if (input.charCodeAt(i) > 127) ++i;
+}
diff --git a/tests/node_compat/test/parallel/test-buffer-badhex.js b/tests/node_compat/test/parallel/test-buffer-badhex.js
new file mode 100644
index 000000000..cafaa0887
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-buffer-badhex.js
@@ -0,0 +1,55 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+
+// Test hex strings and bad hex strings
+{
+ const buf = Buffer.alloc(4);
+ assert.strictEqual(buf.length, 4);
+ assert.deepStrictEqual(buf, Buffer.from([0, 0, 0, 0]));
+ assert.strictEqual(buf.write('abcdxx', 0, 'hex'), 2);
+ assert.deepStrictEqual(buf, Buffer.from([0xab, 0xcd, 0x00, 0x00]));
+ assert.strictEqual(buf.toString('hex'), 'abcd0000');
+ assert.strictEqual(buf.write('abcdef01', 0, 'hex'), 4);
+ assert.deepStrictEqual(buf, Buffer.from([0xab, 0xcd, 0xef, 0x01]));
+ assert.strictEqual(buf.toString('hex'), 'abcdef01');
+
+ const copy = Buffer.from(buf.toString('hex'), 'hex');
+ assert.strictEqual(buf.toString('hex'), copy.toString('hex'));
+}
+
+{
+ const buf = Buffer.alloc(5);
+ assert.strictEqual(buf.write('abcdxx', 1, 'hex'), 2);
+ assert.strictEqual(buf.toString('hex'), '00abcd0000');
+}
+
+{
+ const buf = Buffer.alloc(4);
+ assert.deepStrictEqual(buf, Buffer.from([0, 0, 0, 0]));
+ assert.strictEqual(buf.write('xxabcd', 0, 'hex'), 0);
+ assert.deepStrictEqual(buf, Buffer.from([0, 0, 0, 0]));
+ assert.strictEqual(buf.write('xxab', 1, 'hex'), 0);
+ assert.deepStrictEqual(buf, Buffer.from([0, 0, 0, 0]));
+ assert.strictEqual(buf.write('cdxxab', 0, 'hex'), 1);
+ assert.deepStrictEqual(buf, Buffer.from([0xcd, 0, 0, 0]));
+}
+
+{
+ const buf = Buffer.alloc(256);
+ for (let i = 0; i < 256; i++)
+ buf[i] = i;
+
+ const hex = buf.toString('hex');
+ assert.deepStrictEqual(Buffer.from(hex, 'hex'), buf);
+
+ const badHex = `${hex.slice(0, 256)}xx${hex.slice(256, 510)}`;
+ assert.deepStrictEqual(Buffer.from(badHex, 'hex'), buf.slice(0, 128));
+}
diff --git a/tests/node_compat/test/parallel/test-buffer-bigint64.js b/tests/node_compat/test/parallel/test-buffer-bigint64.js
new file mode 100644
index 000000000..7aa391f0a
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-buffer-bigint64.js
@@ -0,0 +1,62 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+
+const buf = Buffer.allocUnsafe(8);
+
+['LE', 'BE'].forEach(function(endianness) {
+ // Should allow simple BigInts to be written and read
+ let val = 123456789n;
+ buf[`writeBigInt64${endianness}`](val, 0);
+ let rtn = buf[`readBigInt64${endianness}`](0);
+ assert.strictEqual(val, rtn);
+
+ // Should allow INT64_MAX to be written and read
+ val = 0x7fffffffffffffffn;
+ buf[`writeBigInt64${endianness}`](val, 0);
+ rtn = buf[`readBigInt64${endianness}`](0);
+ assert.strictEqual(val, rtn);
+
+ // Should read and write a negative signed 64-bit integer
+ val = -123456789n;
+ buf[`writeBigInt64${endianness}`](val, 0);
+ assert.strictEqual(val, buf[`readBigInt64${endianness}`](0));
+
+ // Should read and write an unsigned 64-bit integer
+ val = 123456789n;
+ buf[`writeBigUInt64${endianness}`](val, 0);
+ assert.strictEqual(val, buf[`readBigUInt64${endianness}`](0));
+
+ // Should throw a RangeError upon INT64_MAX+1 being written
+ assert.throws(function() {
+ const val = 0x8000000000000000n;
+ buf[`writeBigInt64${endianness}`](val, 0);
+ }, RangeError);
+
+ // Should throw a RangeError upon UINT64_MAX+1 being written
+ assert.throws(function() {
+ const val = 0x10000000000000000n;
+ buf[`writeBigUInt64${endianness}`](val, 0);
+ }, {
+ code: 'ERR_OUT_OF_RANGE',
+ message: 'The value of "value" is out of range. It must be ' +
+ '>= 0n and < 2n ** 64n. Received 18_446_744_073_709_551_616n'
+ });
+
+ // Should throw a TypeError upon invalid input
+ assert.throws(function() {
+ buf[`writeBigInt64${endianness}`]('bad', 0);
+ }, TypeError);
+
+ // Should throw a TypeError upon invalid input
+ assert.throws(function() {
+ buf[`writeBigUInt64${endianness}`]('bad', 0);
+ }, TypeError);
+});
diff --git a/tests/node_compat/test/parallel/test-buffer-bytelength.js b/tests/node_compat/test/parallel/test-buffer-bytelength.js
new file mode 100644
index 000000000..4f10596a2
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-buffer-bytelength.js
@@ -0,0 +1,139 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const assert = require('assert');
+const SlowBuffer = require('buffer').SlowBuffer;
+const vm = require('vm');
+
+[
+ [32, 'latin1'],
+ [NaN, 'utf8'],
+ [{}, 'latin1'],
+ [],
+].forEach((args) => {
+ assert.throws(
+ () => Buffer.byteLength(...args),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: 'The "string" argument must be of type string or an instance ' +
+ 'of Buffer or ArrayBuffer.' +
+ common.invalidArgTypeHelper(args[0])
+ }
+ );
+});
+
+assert(ArrayBuffer.isView(new Buffer(10)));
+assert(ArrayBuffer.isView(new SlowBuffer(10)));
+assert(ArrayBuffer.isView(Buffer.alloc(10)));
+assert(ArrayBuffer.isView(Buffer.allocUnsafe(10)));
+assert(ArrayBuffer.isView(Buffer.allocUnsafeSlow(10)));
+assert(ArrayBuffer.isView(Buffer.from('')));
+
+// buffer
+const incomplete = Buffer.from([0xe4, 0xb8, 0xad, 0xe6, 0x96]);
+assert.strictEqual(Buffer.byteLength(incomplete), 5);
+const ascii = Buffer.from('abc');
+assert.strictEqual(Buffer.byteLength(ascii), 3);
+
+// ArrayBuffer
+const buffer = new ArrayBuffer(8);
+assert.strictEqual(Buffer.byteLength(buffer), 8);
+
+// TypedArray
+const int8 = new Int8Array(8);
+assert.strictEqual(Buffer.byteLength(int8), 8);
+const uint8 = new Uint8Array(8);
+assert.strictEqual(Buffer.byteLength(uint8), 8);
+const uintc8 = new Uint8ClampedArray(2);
+assert.strictEqual(Buffer.byteLength(uintc8), 2);
+const int16 = new Int16Array(8);
+assert.strictEqual(Buffer.byteLength(int16), 16);
+const uint16 = new Uint16Array(8);
+assert.strictEqual(Buffer.byteLength(uint16), 16);
+const int32 = new Int32Array(8);
+assert.strictEqual(Buffer.byteLength(int32), 32);
+const uint32 = new Uint32Array(8);
+assert.strictEqual(Buffer.byteLength(uint32), 32);
+const float32 = new Float32Array(8);
+assert.strictEqual(Buffer.byteLength(float32), 32);
+const float64 = new Float64Array(8);
+assert.strictEqual(Buffer.byteLength(float64), 64);
+
+// DataView
+const dv = new DataView(new ArrayBuffer(2));
+assert.strictEqual(Buffer.byteLength(dv), 2);
+
+// Special case: zero length string
+assert.strictEqual(Buffer.byteLength('', 'ascii'), 0);
+assert.strictEqual(Buffer.byteLength('', 'HeX'), 0);
+
+// utf8
+assert.strictEqual(Buffer.byteLength('∑éllö wørl∂!', 'utf-8'), 19);
+assert.strictEqual(Buffer.byteLength('κλμνξο', 'utf8'), 12);
+assert.strictEqual(Buffer.byteLength('挵挶挷挸挹', 'utf-8'), 15);
+assert.strictEqual(Buffer.byteLength('𠝹𠱓𠱸', 'UTF8'), 12);
+// Without an encoding, utf8 should be assumed
+assert.strictEqual(Buffer.byteLength('hey there'), 9);
+assert.strictEqual(Buffer.byteLength('𠱸挶νξ#xx :)'), 17);
+assert.strictEqual(Buffer.byteLength('hello world', ''), 11);
+// It should also be assumed with unrecognized encoding
+assert.strictEqual(Buffer.byteLength('hello world', 'abc'), 11);
+assert.strictEqual(Buffer.byteLength('ßœ∑≈', 'unkn0wn enc0ding'), 10);
+
+// base64
+assert.strictEqual(Buffer.byteLength('aGVsbG8gd29ybGQ=', 'base64'), 11);
+assert.strictEqual(Buffer.byteLength('aGVsbG8gd29ybGQ=', 'BASE64'), 11);
+assert.strictEqual(Buffer.byteLength('bm9kZS5qcyByb2NrcyE=', 'base64'), 14);
+assert.strictEqual(Buffer.byteLength('aGkk', 'base64'), 3);
+assert.strictEqual(
+ Buffer.byteLength('bHNrZGZsa3NqZmtsc2xrZmFqc2RsZmtqcw==', 'base64'), 25
+);
+// base64url
+assert.strictEqual(Buffer.byteLength('aGVsbG8gd29ybGQ', 'base64url'), 11);
+assert.strictEqual(Buffer.byteLength('aGVsbG8gd29ybGQ', 'BASE64URL'), 11);
+assert.strictEqual(Buffer.byteLength('bm9kZS5qcyByb2NrcyE', 'base64url'), 14);
+assert.strictEqual(Buffer.byteLength('aGkk', 'base64url'), 3);
+assert.strictEqual(
+ Buffer.byteLength('bHNrZGZsa3NqZmtsc2xrZmFqc2RsZmtqcw', 'base64url'), 25
+);
+// special padding
+assert.strictEqual(Buffer.byteLength('aaa=', 'base64'), 2);
+assert.strictEqual(Buffer.byteLength('aaaa==', 'base64'), 3);
+assert.strictEqual(Buffer.byteLength('aaa=', 'base64url'), 2);
+assert.strictEqual(Buffer.byteLength('aaaa==', 'base64url'), 3);
+
+assert.strictEqual(Buffer.byteLength('Il était tué'), 14);
+assert.strictEqual(Buffer.byteLength('Il était tué', 'utf8'), 14);
+
+['ascii', 'latin1', 'binary']
+ .reduce((es, e) => es.concat(e, e.toUpperCase()), [])
+ .forEach((encoding) => {
+ assert.strictEqual(Buffer.byteLength('Il était tué', encoding), 12);
+ });
+
+['ucs2', 'ucs-2', 'utf16le', 'utf-16le']
+ .reduce((es, e) => es.concat(e, e.toUpperCase()), [])
+ .forEach((encoding) => {
+ assert.strictEqual(Buffer.byteLength('Il était tué', encoding), 24);
+ });
+
+// Test that ArrayBuffer from a different context is detected correctly
+const arrayBuf = vm.runInNewContext('new ArrayBuffer()');
+assert.strictEqual(Buffer.byteLength(arrayBuf), 0);
+
+// Verify that invalid encodings are treated as utf8
+for (let i = 1; i < 10; i++) {
+ const encoding = String(i).repeat(i);
+
+ assert.ok(!Buffer.isEncoding(encoding));
+ assert.strictEqual(Buffer.byteLength('foo', encoding),
+ Buffer.byteLength('foo', 'utf8'));
+}
diff --git a/tests/node_compat/test/parallel/test-buffer-compare-offset.js b/tests/node_compat/test/parallel/test-buffer-compare-offset.js
new file mode 100644
index 000000000..bb7ba2998
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-buffer-compare-offset.js
@@ -0,0 +1,101 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+require('../common');
+const assert = require('assert');
+
+const a = Buffer.from([1, 2, 3, 4, 5, 6, 7, 8, 9, 0]);
+const b = Buffer.from([5, 6, 7, 8, 9, 0, 1, 2, 3, 4]);
+
+assert.strictEqual(a.compare(b), -1);
+
+// Equivalent to a.compare(b).
+assert.strictEqual(a.compare(b, 0), -1);
+assert.throws(() => a.compare(b, '0'), { code: 'ERR_INVALID_ARG_TYPE' });
+assert.strictEqual(a.compare(b, undefined), -1);
+
+// Equivalent to a.compare(b).
+assert.strictEqual(a.compare(b, 0, undefined, 0), -1);
+
+// Zero-length target, return 1
+assert.strictEqual(a.compare(b, 0, 0, 0), 1);
+assert.throws(
+ () => a.compare(b, 0, '0', '0'),
+ { code: 'ERR_INVALID_ARG_TYPE' }
+);
+
+// Equivalent to Buffer.compare(a, b.slice(6, 10))
+assert.strictEqual(a.compare(b, 6, 10), 1);
+
+// Zero-length source, return -1
+assert.strictEqual(a.compare(b, 6, 10, 0, 0), -1);
+
+// Zero-length source and target, return 0
+assert.strictEqual(a.compare(b, 0, 0, 0, 0), 0);
+assert.strictEqual(a.compare(b, 1, 1, 2, 2), 0);
+
+// Equivalent to Buffer.compare(a.slice(4), b.slice(0, 5))
+assert.strictEqual(a.compare(b, 0, 5, 4), 1);
+
+// Equivalent to Buffer.compare(a.slice(1), b.slice(5))
+assert.strictEqual(a.compare(b, 5, undefined, 1), 1);
+
+// Equivalent to Buffer.compare(a.slice(2), b.slice(2, 4))
+assert.strictEqual(a.compare(b, 2, 4, 2), -1);
+
+// Equivalent to Buffer.compare(a.slice(4), b.slice(0, 7))
+assert.strictEqual(a.compare(b, 0, 7, 4), -1);
+
+// Equivalent to Buffer.compare(a.slice(4, 6), b.slice(0, 7));
+assert.strictEqual(a.compare(b, 0, 7, 4, 6), -1);
+
+// Null is ambiguous.
+assert.throws(
+ () => a.compare(b, 0, null),
+ { code: 'ERR_INVALID_ARG_TYPE' }
+);
+
+// Values do not get coerced.
+assert.throws(
+ () => a.compare(b, 0, { valueOf: () => 5 }),
+ { code: 'ERR_INVALID_ARG_TYPE' }
+);
+
+// Infinity should not be coerced.
+assert.throws(
+ () => a.compare(b, Infinity, -Infinity),
+ { code: 'ERR_OUT_OF_RANGE' }
+);
+
+// Zero length target because default for targetEnd <= targetSource
+assert.strictEqual(a.compare(b, 0xff), 1);
+
+assert.throws(
+ () => a.compare(b, '0xff'),
+ { code: 'ERR_INVALID_ARG_TYPE' }
+);
+assert.throws(
+ () => a.compare(b, 0, '0xff'),
+ { code: 'ERR_INVALID_ARG_TYPE' }
+);
+
+const oor = { code: 'ERR_OUT_OF_RANGE' };
+
+assert.throws(() => a.compare(b, 0, 100, 0), oor);
+assert.throws(() => a.compare(b, 0, 1, 0, 100), oor);
+assert.throws(() => a.compare(b, -1), oor);
+assert.throws(() => a.compare(b, 0, Infinity), oor);
+assert.throws(() => a.compare(b, 0, 1, -1), oor);
+assert.throws(() => a.compare(b, -Infinity, Infinity), oor);
+assert.throws(() => a.compare(), {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: 'The "target" argument must be an instance of ' +
+ 'Buffer or Uint8Array. Received undefined'
+});
diff --git a/tests/node_compat/test/parallel/test-buffer-concat.js b/tests/node_compat/test/parallel/test-buffer-concat.js
new file mode 100644
index 000000000..5d2e2c4a5
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-buffer-concat.js
@@ -0,0 +1,107 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+
+const zero = [];
+const one = [ Buffer.from('asdf') ];
+const long = [];
+for (let i = 0; i < 10; i++) long.push(Buffer.from('asdf'));
+
+const flatZero = Buffer.concat(zero);
+const flatOne = Buffer.concat(one);
+const flatLong = Buffer.concat(long);
+const flatLongLen = Buffer.concat(long, 40);
+
+assert.strictEqual(flatZero.length, 0);
+assert.strictEqual(flatOne.toString(), 'asdf');
+
+const check = 'asdf'.repeat(10);
+
+// A special case where concat used to return the first item,
+// if the length is one. This check is to make sure that we don't do that.
+assert.notStrictEqual(flatOne, one[0]);
+assert.strictEqual(flatLong.toString(), check);
+assert.strictEqual(flatLongLen.toString(), check);
+
+[undefined, null, Buffer.from('hello')].forEach((value) => {
+ assert.throws(() => {
+ Buffer.concat(value);
+ }, {
+ code: 'ERR_INVALID_ARG_TYPE',
+ message: 'The "list" argument must be an instance of Array.' +
+ `${common.invalidArgTypeHelper(value)}`
+ });
+});
+
+[[42], ['hello', Buffer.from('world')]].forEach((value) => {
+ assert.throws(() => {
+ Buffer.concat(value);
+ }, {
+ code: 'ERR_INVALID_ARG_TYPE',
+ message: 'The "list[0]" argument must be an instance of Buffer ' +
+ `or Uint8Array.${common.invalidArgTypeHelper(value[0])}`
+ });
+});
+
+assert.throws(() => {
+ Buffer.concat([Buffer.from('hello'), 3]);
+}, {
+ code: 'ERR_INVALID_ARG_TYPE',
+ message: 'The "list[1]" argument must be an instance of Buffer ' +
+ 'or Uint8Array. Received type number (3)'
+});
+
+// eslint-disable-next-line node-core/crypto-check
+const random10 = common.hasCrypto ?
+ require('crypto').randomBytes(10) :
+ Buffer.alloc(10, 1);
+const empty = Buffer.alloc(0);
+
+assert.notDeepStrictEqual(random10, empty);
+assert.notDeepStrictEqual(random10, Buffer.alloc(10));
+
+assert.deepStrictEqual(Buffer.concat([], 100), empty);
+assert.deepStrictEqual(Buffer.concat([random10], 0), empty);
+assert.deepStrictEqual(Buffer.concat([random10], 10), random10);
+assert.deepStrictEqual(Buffer.concat([random10, random10], 10), random10);
+assert.deepStrictEqual(Buffer.concat([empty, random10]), random10);
+assert.deepStrictEqual(Buffer.concat([random10, empty, empty]), random10);
+
+// The tail should be zero-filled
+assert.deepStrictEqual(Buffer.concat([empty], 100), Buffer.alloc(100));
+assert.deepStrictEqual(Buffer.concat([empty], 4096), Buffer.alloc(4096));
+assert.deepStrictEqual(
+ Buffer.concat([random10], 40),
+ Buffer.concat([random10, Buffer.alloc(30)]));
+
+assert.deepStrictEqual(Buffer.concat([new Uint8Array([0x41, 0x42]),
+ new Uint8Array([0x43, 0x44])]),
+ Buffer.from('ABCD'));
diff --git a/tests/node_compat/test/parallel/test-buffer-constants.js b/tests/node_compat/test/parallel/test-buffer-constants.js
new file mode 100644
index 000000000..0c4f6e21b
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-buffer-constants.js
@@ -0,0 +1,25 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+
+const { kMaxLength, kStringMaxLength } = require('buffer');
+const { MAX_LENGTH, MAX_STRING_LENGTH } = require('buffer').constants;
+
+assert.strictEqual(typeof MAX_LENGTH, 'number');
+assert.strictEqual(typeof MAX_STRING_LENGTH, 'number');
+assert(MAX_STRING_LENGTH <= MAX_LENGTH);
+assert.throws(() => ' '.repeat(MAX_STRING_LENGTH + 1),
+ /^RangeError: Invalid string length$/);
+
+' '.repeat(MAX_STRING_LENGTH); // Should not throw.
+
+// Legacy values match:
+assert.strictEqual(kMaxLength, MAX_LENGTH);
+assert.strictEqual(kStringMaxLength, MAX_STRING_LENGTH);
diff --git a/tests/node_compat/test/parallel/test-buffer-copy.js b/tests/node_compat/test/parallel/test-buffer-copy.js
new file mode 100644
index 000000000..a10bfebc5
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-buffer-copy.js
@@ -0,0 +1,243 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+require('../common');
+const assert = require('assert');
+
+const b = Buffer.allocUnsafe(1024);
+const c = Buffer.allocUnsafe(512);
+
+let cntr = 0;
+
+{
+ // copy 512 bytes, from 0 to 512.
+ b.fill(++cntr);
+ c.fill(++cntr);
+ const copied = b.copy(c, 0, 0, 512);
+ assert.strictEqual(copied, 512);
+ for (let i = 0; i < c.length; i++) {
+ assert.strictEqual(c[i], b[i]);
+ }
+}
+
+{
+ // Current behavior is to coerce values to integers.
+ b.fill(++cntr);
+ c.fill(++cntr);
+ const copied = b.copy(c, '0', '0', '512');
+ assert.strictEqual(copied, 512);
+ for (let i = 0; i < c.length; i++) {
+ assert.strictEqual(c[i], b[i]);
+ }
+}
+
+{
+ // Floats will be converted to integers via `Math.floor`
+ b.fill(++cntr);
+ c.fill(++cntr);
+ const copied = b.copy(c, 0, 0, 512.5);
+ assert.strictEqual(copied, 512);
+ for (let i = 0; i < c.length; i++) {
+ assert.strictEqual(c[i], b[i]);
+ }
+}
+
+{
+ // Copy c into b, without specifying sourceEnd
+ b.fill(++cntr);
+ c.fill(++cntr);
+ const copied = c.copy(b, 0, 0);
+ assert.strictEqual(copied, c.length);
+ for (let i = 0; i < c.length; i++) {
+ assert.strictEqual(b[i], c[i]);
+ }
+}
+
+{
+ // Copy c into b, without specifying sourceStart
+ b.fill(++cntr);
+ c.fill(++cntr);
+ const copied = c.copy(b, 0);
+ assert.strictEqual(copied, c.length);
+ for (let i = 0; i < c.length; i++) {
+ assert.strictEqual(b[i], c[i]);
+ }
+}
+
+{
+ // Copied source range greater than source length
+ b.fill(++cntr);
+ c.fill(++cntr);
+ const copied = c.copy(b, 0, 0, c.length + 1);
+ assert.strictEqual(copied, c.length);
+ for (let i = 0; i < c.length; i++) {
+ assert.strictEqual(b[i], c[i]);
+ }
+}
+
+{
+ // Copy longer buffer b to shorter c without targetStart
+ b.fill(++cntr);
+ c.fill(++cntr);
+ const copied = b.copy(c);
+ assert.strictEqual(copied, c.length);
+ for (let i = 0; i < c.length; i++) {
+ assert.strictEqual(c[i], b[i]);
+ }
+}
+
+{
+ // Copy starting near end of b to c
+ b.fill(++cntr);
+ c.fill(++cntr);
+ const copied = b.copy(c, 0, b.length - Math.floor(c.length / 2));
+ assert.strictEqual(copied, Math.floor(c.length / 2));
+ for (let i = 0; i < Math.floor(c.length / 2); i++) {
+ assert.strictEqual(c[i], b[b.length - Math.floor(c.length / 2) + i]);
+ }
+ for (let i = Math.floor(c.length / 2) + 1; i < c.length; i++) {
+ assert.strictEqual(c[c.length - 1], c[i]);
+ }
+}
+
+{
+ // Try to copy 513 bytes, and check we don't overrun c
+ b.fill(++cntr);
+ c.fill(++cntr);
+ const copied = b.copy(c, 0, 0, 513);
+ assert.strictEqual(copied, c.length);
+ for (let i = 0; i < c.length; i++) {
+ assert.strictEqual(c[i], b[i]);
+ }
+}
+
+{
+ // copy 768 bytes from b into b
+ b.fill(++cntr);
+ b.fill(++cntr, 256);
+ const copied = b.copy(b, 0, 256, 1024);
+ assert.strictEqual(copied, 768);
+ for (let i = 0; i < b.length; i++) {
+ assert.strictEqual(b[i], cntr);
+ }
+}
+
+// Copy string longer than buffer length (failure will segfault)
+const bb = Buffer.allocUnsafe(10);
+bb.fill('hello crazy world');
+
+
+// Try to copy from before the beginning of b. Should not throw.
+b.copy(c, 0, 100, 10);
+
+// Throw with invalid source type
+assert.throws(
+ () => Buffer.prototype.copy.call(0),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ }
+);
+
+// Copy throws at negative targetStart
+assert.throws(
+ () => Buffer.allocUnsafe(5).copy(Buffer.allocUnsafe(5), -1, 0),
+ {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError',
+ message: 'The value of "targetStart" is out of range. ' +
+ 'It must be >= 0. Received -1'
+ }
+);
+
+// Copy throws at negative sourceStart
+assert.throws(
+ () => Buffer.allocUnsafe(5).copy(Buffer.allocUnsafe(5), 0, -1),
+ {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError',
+ }
+);
+
+// Copy throws if sourceStart is greater than length of source
+assert.throws(
+ () => Buffer.allocUnsafe(5).copy(Buffer.allocUnsafe(5), 0, 100),
+ {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError',
+ }
+);
+
+{
+ // Check sourceEnd resets to targetEnd if former is greater than the latter
+ b.fill(++cntr);
+ c.fill(++cntr);
+ b.copy(c, 0, 0, 1025);
+ for (let i = 0; i < c.length; i++) {
+ assert.strictEqual(c[i], b[i]);
+ }
+}
+
+// Throw with negative sourceEnd
+assert.throws(
+ () => b.copy(c, 0, 0, -1),
+ {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError',
+ message: 'The value of "sourceEnd" is out of range. ' +
+ 'It must be >= 0. Received -1'
+ }
+);
+
+// When sourceStart is greater than sourceEnd, zero copied
+assert.strictEqual(b.copy(c, 0, 100, 10), 0);
+
+// When targetStart > targetLength, zero copied
+assert.strictEqual(b.copy(c, 512, 0, 10), 0);
+
+// Test that the `target` can be a Uint8Array.
+{
+ const d = new Uint8Array(c);
+ // copy 512 bytes, from 0 to 512.
+ b.fill(++cntr);
+ d.fill(++cntr);
+ const copied = b.copy(d, 0, 0, 512);
+ assert.strictEqual(copied, 512);
+ for (let i = 0; i < d.length; i++) {
+ assert.strictEqual(d[i], b[i]);
+ }
+}
+
+// Test that the source can be a Uint8Array, too.
+{
+ const e = new Uint8Array(b);
+ // copy 512 bytes, from 0 to 512.
+ e.fill(++cntr);
+ c.fill(++cntr);
+ const copied = Buffer.prototype.copy.call(e, c, 0, 0, 512);
+ assert.strictEqual(copied, 512);
+ for (let i = 0; i < c.length; i++) {
+ assert.strictEqual(c[i], e[i]);
+ }
+}
+
+// https://github.com/nodejs/node/issues/23668: Do not crash for invalid input.
+c.fill('c');
+b.copy(c, 'not a valid offset');
+// Make sure this acted like a regular copy with `0` offset.
+assert.deepStrictEqual(c, b.slice(0, c.length));
+
+{
+ c.fill('C');
+ assert.throws(() => {
+ b.copy(c, { [Symbol.toPrimitive]() { throw new Error('foo'); } });
+ }, /foo/);
+ // No copying took place:
+ assert.deepStrictEqual(c.toString(), 'C'.repeat(c.length));
+}
diff --git a/tests/node_compat/test/parallel/test-buffer-equals.js b/tests/node_compat/test/parallel/test-buffer-equals.js
new file mode 100644
index 000000000..3d22fae84
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-buffer-equals.js
@@ -0,0 +1,32 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+require('../common');
+const assert = require('assert');
+
+const b = Buffer.from('abcdf');
+const c = Buffer.from('abcdf');
+const d = Buffer.from('abcde');
+const e = Buffer.from('abcdef');
+
+assert.ok(b.equals(c));
+assert.ok(!c.equals(d));
+assert.ok(!d.equals(e));
+assert.ok(d.equals(d));
+assert.ok(d.equals(new Uint8Array([0x61, 0x62, 0x63, 0x64, 0x65])));
+
+assert.throws(
+ () => Buffer.alloc(1).equals('abc'),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: 'The "otherBuffer" argument must be an instance of ' +
+ "Buffer or Uint8Array. Received type string ('abc')"
+ }
+);
diff --git a/tests/node_compat/test/parallel/test-buffer-failed-alloc-typed-arrays.js b/tests/node_compat/test/parallel/test-buffer-failed-alloc-typed-arrays.js
new file mode 100644
index 000000000..fc822ec86
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-buffer-failed-alloc-typed-arrays.js
@@ -0,0 +1,40 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+require('../common');
+const assert = require('assert');
+const SlowBuffer = require('buffer').SlowBuffer;
+
+// Test failed or zero-sized Buffer allocations not affecting typed arrays.
+// This test exists because of a regression that occurred. Because Buffer
+// instances are allocated with the same underlying allocator as TypedArrays,
+// but Buffer's can optional be non-zero filled, there was a regression that
+// occurred when a Buffer allocated failed, the internal flag specifying
+// whether or not to zero-fill was not being reset, causing TypedArrays to
+// allocate incorrectly.
+const zeroArray = new Uint32Array(10).fill(0);
+const sizes = [1e10, 0, 0.1, -1, 'a', undefined, null, NaN];
+const allocators = [
+ Buffer,
+ SlowBuffer,
+ Buffer.alloc,
+ Buffer.allocUnsafe,
+ Buffer.allocUnsafeSlow,
+];
+for (const allocator of allocators) {
+ for (const size of sizes) {
+ try {
+ // Some of these allocations are known to fail. If they do,
+ // Uint32Array should still produce a zeroed out result.
+ allocator(size);
+ } catch {
+ assert.deepStrictEqual(zeroArray, new Uint32Array(10));
+ }
+ }
+}
diff --git a/tests/node_compat/test/parallel/test-buffer-fakes.js b/tests/node_compat/test/parallel/test-buffer-fakes.js
new file mode 100644
index 000000000..2e25d6219
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-buffer-fakes.js
@@ -0,0 +1,61 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+require('../common');
+const assert = require('assert');
+
+function FakeBuffer() { }
+Object.setPrototypeOf(FakeBuffer, Buffer);
+Object.setPrototypeOf(FakeBuffer.prototype, Buffer.prototype);
+
+const fb = new FakeBuffer();
+
+assert.throws(function() {
+ Buffer.from(fb);
+}, TypeError);
+
+assert.throws(function() {
+ +Buffer.prototype; // eslint-disable-line no-unused-expressions
+}, TypeError);
+
+assert.throws(function() {
+ Buffer.compare(fb, Buffer.alloc(0));
+}, TypeError);
+
+assert.throws(function() {
+ fb.write('foo');
+}, TypeError);
+
+assert.throws(function() {
+ Buffer.concat([fb, fb]);
+}, TypeError);
+
+assert.throws(function() {
+ fb.toString();
+}, TypeError);
+
+assert.throws(function() {
+ fb.equals(Buffer.alloc(0));
+}, TypeError);
+
+assert.throws(function() {
+ fb.indexOf(5);
+}, TypeError);
+
+assert.throws(function() {
+ fb.readFloatLE(0);
+}, TypeError);
+
+assert.throws(function() {
+ fb.writeFloatLE(0);
+}, TypeError);
+
+assert.throws(function() {
+ fb.fill(0);
+}, TypeError);
diff --git a/tests/node_compat/test/parallel/test-buffer-from.js b/tests/node_compat/test/parallel/test-buffer-from.js
new file mode 100644
index 000000000..6483e2a63
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-buffer-from.js
@@ -0,0 +1,73 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const { deepStrictEqual, throws } = require('assert');
+// const { runInNewContext } = require('vm');
+
+const checkString = 'test';
+
+const check = Buffer.from(checkString);
+
+class MyString extends String {
+ constructor() {
+ super(checkString);
+ }
+}
+
+class MyPrimitive {
+ [Symbol.toPrimitive]() {
+ return checkString;
+ }
+}
+
+class MyBadPrimitive {
+ [Symbol.toPrimitive]() {
+ return 1;
+ }
+}
+
+deepStrictEqual(Buffer.from(new String(checkString)), check);
+deepStrictEqual(Buffer.from(new MyString()), check);
+deepStrictEqual(Buffer.from(new MyPrimitive()), check);
+// TODO(Soremwar)
+// Enable once again when vm works correctly
+// deepStrictEqual(
+// Buffer.from(runInNewContext('new String(checkString)', { checkString })),
+// check
+// );
+
+[
+ {},
+ new Boolean(true),
+ { valueOf() { return null; } },
+ { valueOf() { return undefined; } },
+ { valueOf: null },
+ Object.create(null),
+ new Number(true),
+ new MyBadPrimitive(),
+ Symbol(),
+ 5n,
+ (one, two, three) => {},
+ undefined,
+ null,
+].forEach((input) => {
+ const errObj = {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: 'The first argument must be of type string or an instance of ' +
+ 'Buffer, ArrayBuffer, or Array or an Array-like Object.' +
+ common.invalidArgTypeHelper(input)
+ };
+ throws(() => Buffer.from(input), errObj);
+ throws(() => Buffer.from(input, 'hex'), errObj);
+});
+
+Buffer.allocUnsafe(10); // Should not throw.
+Buffer.from('deadbeaf', 'hex'); // Should not throw.
diff --git a/tests/node_compat/test/parallel/test-buffer-includes.js b/tests/node_compat/test/parallel/test-buffer-includes.js
new file mode 100644
index 000000000..797ec8246
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-buffer-includes.js
@@ -0,0 +1,317 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+
+const b = Buffer.from('abcdef');
+const buf_a = Buffer.from('a');
+const buf_bc = Buffer.from('bc');
+const buf_f = Buffer.from('f');
+const buf_z = Buffer.from('z');
+const buf_empty = Buffer.from('');
+
+assert(b.includes('a'));
+assert(!b.includes('a', 1));
+assert(!b.includes('a', -1));
+assert(!b.includes('a', -4));
+assert(b.includes('a', -b.length));
+assert(b.includes('a', NaN));
+assert(b.includes('a', -Infinity));
+assert(!b.includes('a', Infinity));
+assert(b.includes('bc'));
+assert(!b.includes('bc', 2));
+assert(!b.includes('bc', -1));
+assert(!b.includes('bc', -3));
+assert(b.includes('bc', -5));
+assert(b.includes('bc', NaN));
+assert(b.includes('bc', -Infinity));
+assert(!b.includes('bc', Infinity));
+assert(b.includes('f'), b.length - 1);
+assert(!b.includes('z'));
+assert(b.includes(''));
+assert(b.includes('', 1));
+assert(b.includes('', b.length + 1));
+assert(b.includes('', Infinity));
+assert(b.includes(buf_a));
+assert(!b.includes(buf_a, 1));
+assert(!b.includes(buf_a, -1));
+assert(!b.includes(buf_a, -4));
+assert(b.includes(buf_a, -b.length));
+assert(b.includes(buf_a, NaN));
+assert(b.includes(buf_a, -Infinity));
+assert(!b.includes(buf_a, Infinity));
+assert(b.includes(buf_bc));
+assert(!b.includes(buf_bc, 2));
+assert(!b.includes(buf_bc, -1));
+assert(!b.includes(buf_bc, -3));
+assert(b.includes(buf_bc, -5));
+assert(b.includes(buf_bc, NaN));
+assert(b.includes(buf_bc, -Infinity));
+assert(!b.includes(buf_bc, Infinity));
+assert(b.includes(buf_f), b.length - 1);
+assert(!b.includes(buf_z));
+assert(b.includes(buf_empty));
+assert(b.includes(buf_empty, 1));
+assert(b.includes(buf_empty, b.length + 1));
+assert(b.includes(buf_empty, Infinity));
+assert(b.includes(0x61));
+assert(!b.includes(0x61, 1));
+assert(!b.includes(0x61, -1));
+assert(!b.includes(0x61, -4));
+assert(b.includes(0x61, -b.length));
+assert(b.includes(0x61, NaN));
+assert(b.includes(0x61, -Infinity));
+assert(!b.includes(0x61, Infinity));
+assert(!b.includes(0x0));
+
+// test offsets
+assert(b.includes('d', 2));
+assert(b.includes('f', 5));
+assert(b.includes('f', -1));
+assert(!b.includes('f', 6));
+
+assert(b.includes(Buffer.from('d'), 2));
+assert(b.includes(Buffer.from('f'), 5));
+assert(b.includes(Buffer.from('f'), -1));
+assert(!b.includes(Buffer.from('f'), 6));
+
+// TODO(Soremwar)
+// Enable again once encoding is taking into account when evaluating indexOf
+// assert(!Buffer.from('ff').includes(Buffer.from('f'), 1, 'ucs2'));
+
+// test hex encoding
+assert.strictEqual(
+ Buffer.from(b.toString('hex'), 'hex')
+ .includes('64', 0, 'hex'),
+ true
+);
+assert.strictEqual(
+ Buffer.from(b.toString('hex'), 'hex')
+ .includes(Buffer.from('64', 'hex'), 0, 'hex'),
+ true
+);
+
+// Test base64 encoding
+assert.strictEqual(
+ Buffer.from(b.toString('base64'), 'base64')
+ .includes('ZA==', 0, 'base64'),
+ true
+);
+assert.strictEqual(
+ Buffer.from(b.toString('base64'), 'base64')
+ .includes(Buffer.from('ZA==', 'base64'), 0, 'base64'),
+ true
+);
+
+// test ascii encoding
+assert.strictEqual(
+ Buffer.from(b.toString('ascii'), 'ascii')
+ .includes('d', 0, 'ascii'),
+ true
+);
+assert.strictEqual(
+ Buffer.from(b.toString('ascii'), 'ascii')
+ .includes(Buffer.from('d', 'ascii'), 0, 'ascii'),
+ true
+);
+
+// Test latin1 encoding
+assert.strictEqual(
+ Buffer.from(b.toString('latin1'), 'latin1')
+ .includes('d', 0, 'latin1'),
+ true
+);
+assert.strictEqual(
+ Buffer.from(b.toString('latin1'), 'latin1')
+ .includes(Buffer.from('d', 'latin1'), 0, 'latin1'),
+ true
+);
+
+// Test binary encoding
+assert.strictEqual(
+ Buffer.from(b.toString('binary'), 'binary')
+ .includes('d', 0, 'binary'),
+ true
+);
+assert.strictEqual(
+ Buffer.from(b.toString('binary'), 'binary')
+ .includes(Buffer.from('d', 'binary'), 0, 'binary'),
+ true
+);
+
+
+// test ucs2 encoding
+let twoByteString = Buffer.from('\u039a\u0391\u03a3\u03a3\u0395', 'ucs2');
+
+assert(twoByteString.includes('\u0395', 4, 'ucs2'));
+assert(twoByteString.includes('\u03a3', -4, 'ucs2'));
+assert(twoByteString.includes('\u03a3', -6, 'ucs2'));
+assert(twoByteString.includes(
+ Buffer.from('\u03a3', 'ucs2'), -6, 'ucs2'));
+assert(!twoByteString.includes('\u03a3', -2, 'ucs2'));
+
+const mixedByteStringUcs2 =
+ Buffer.from('\u039a\u0391abc\u03a3\u03a3\u0395', 'ucs2');
+assert(mixedByteStringUcs2.includes('bc', 0, 'ucs2'));
+assert(mixedByteStringUcs2.includes('\u03a3', 0, 'ucs2'));
+assert(!mixedByteStringUcs2.includes('\u0396', 0, 'ucs2'));
+
+assert.ok(
+ mixedByteStringUcs2.includes(Buffer.from('bc', 'ucs2'), 0, 'ucs2'));
+assert.ok(
+ mixedByteStringUcs2.includes(Buffer.from('\u03a3', 'ucs2'), 0, 'ucs2'));
+assert.ok(
+ !mixedByteStringUcs2.includes(Buffer.from('\u0396', 'ucs2'), 0, 'ucs2'));
+
+twoByteString = Buffer.from('\u039a\u0391\u03a3\u03a3\u0395', 'ucs2');
+
+// Test single char pattern
+assert(twoByteString.includes('\u039a', 0, 'ucs2'));
+assert(twoByteString.includes('\u0391', 0, 'ucs2'), 'Alpha');
+assert(twoByteString.includes('\u03a3', 0, 'ucs2'), 'First Sigma');
+assert(twoByteString.includes('\u03a3', 6, 'ucs2'), 'Second Sigma');
+assert(twoByteString.includes('\u0395', 0, 'ucs2'), 'Epsilon');
+assert(!twoByteString.includes('\u0392', 0, 'ucs2'), 'Not beta');
+
+// Test multi-char pattern
+assert(twoByteString.includes('\u039a\u0391', 0, 'ucs2'), 'Lambda Alpha');
+assert(twoByteString.includes('\u0391\u03a3', 0, 'ucs2'), 'Alpha Sigma');
+assert(twoByteString.includes('\u03a3\u03a3', 0, 'ucs2'), 'Sigma Sigma');
+assert(twoByteString.includes('\u03a3\u0395', 0, 'ucs2'), 'Sigma Epsilon');
+
+const mixedByteStringUtf8 = Buffer.from('\u039a\u0391abc\u03a3\u03a3\u0395');
+assert(mixedByteStringUtf8.includes('bc'));
+assert(mixedByteStringUtf8.includes('bc', 5));
+assert(mixedByteStringUtf8.includes('bc', -8));
+assert(mixedByteStringUtf8.includes('\u03a3'));
+assert(!mixedByteStringUtf8.includes('\u0396'));
+
+
+// Test complex string includes algorithms. Only trigger for long strings.
+// Long string that isn't a simple repeat of a shorter string.
+let longString = 'A';
+for (let i = 66; i < 76; i++) { // from 'B' to 'K'
+ longString = longString + String.fromCharCode(i) + longString;
+}
+
+const longBufferString = Buffer.from(longString);
+
+// Pattern of 15 chars, repeated every 16 chars in long
+let pattern = 'ABACABADABACABA';
+for (let i = 0; i < longBufferString.length - pattern.length; i += 7) {
+ const includes = longBufferString.includes(pattern, i);
+ assert(includes, `Long ABACABA...-string at index ${i}`);
+}
+assert(longBufferString.includes('AJABACA'), 'Long AJABACA, First J');
+assert(longBufferString.includes('AJABACA', 511), 'Long AJABACA, Second J');
+
+pattern = 'JABACABADABACABA';
+assert(longBufferString.includes(pattern), 'Long JABACABA..., First J');
+assert(longBufferString.includes(pattern, 512), 'Long JABACABA..., Second J');
+
+// Search for a non-ASCII string in a pure ASCII string.
+const asciiString = Buffer.from(
+ 'arglebargleglopglyfarglebargleglopglyfarglebargleglopglyf');
+assert(!asciiString.includes('\x2061'));
+assert(asciiString.includes('leb', 0));
+
+// Search in string containing many non-ASCII chars.
+const allCodePoints = [];
+for (let i = 0; i < 65534; i++) allCodePoints[i] = i;
+const allCharsString = String.fromCharCode.apply(String, allCodePoints) +
+ String.fromCharCode(65534, 65535);
+const allCharsBufferUtf8 = Buffer.from(allCharsString);
+const allCharsBufferUcs2 = Buffer.from(allCharsString, 'ucs2');
+
+// Search for string long enough to trigger complex search with ASCII pattern
+// and UC16 subject.
+assert(!allCharsBufferUtf8.includes('notfound'));
+assert(!allCharsBufferUcs2.includes('notfound'));
+
+// Find substrings in Utf8.
+let lengths = [1, 3, 15]; // Single char, simple and complex.
+let indices = [0x5, 0x60, 0x400, 0x680, 0x7ee, 0xFF02, 0x16610, 0x2f77b];
+for (let lengthIndex = 0; lengthIndex < lengths.length; lengthIndex++) {
+ for (let i = 0; i < indices.length; i++) {
+ const index = indices[i];
+ let length = lengths[lengthIndex];
+
+ if (index + length > 0x7F) {
+ length = 2 * length;
+ }
+
+ if (index + length > 0x7FF) {
+ length = 3 * length;
+ }
+
+ if (index + length > 0xFFFF) {
+ length = 4 * length;
+ }
+
+ const patternBufferUtf8 = allCharsBufferUtf8.slice(index, index + length);
+ assert(index, allCharsBufferUtf8.includes(patternBufferUtf8));
+
+ const patternStringUtf8 = patternBufferUtf8.toString();
+ assert(index, allCharsBufferUtf8.includes(patternStringUtf8));
+ }
+}
+
+// Find substrings in Usc2.
+lengths = [2, 4, 16]; // Single char, simple and complex.
+indices = [0x5, 0x65, 0x105, 0x205, 0x285, 0x2005, 0x2085, 0xfff0];
+for (let lengthIndex = 0; lengthIndex < lengths.length; lengthIndex++) {
+ for (let i = 0; i < indices.length; i++) {
+ const index = indices[i] * 2;
+ const length = lengths[lengthIndex];
+
+ const patternBufferUcs2 =
+ allCharsBufferUcs2.slice(index, index + length);
+ assert.ok(
+ allCharsBufferUcs2.includes(patternBufferUcs2, 0, 'ucs2'));
+
+ const patternStringUcs2 = patternBufferUcs2.toString('ucs2');
+ assert.ok(
+ allCharsBufferUcs2.includes(patternStringUcs2, 0, 'ucs2'));
+ }
+}
+
+[
+ () => { },
+ {},
+ [],
+].forEach((val) => {
+ assert.throws(
+ () => b.includes(val),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: 'The "value" argument must be one of type number or string ' +
+ 'or an instance of Buffer or Uint8Array.' +
+ common.invalidArgTypeHelper(val)
+ }
+ );
+});
+
+// Test truncation of Number arguments to uint8
+// TODO(Soremwar)
+// Enable once multi byte number search is available
+// {
+// const buf = Buffer.from('this is a test');
+// assert.ok(buf.includes(0x6973));
+// assert.ok(buf.includes(0x697320));
+// assert.ok(buf.includes(0x69732069));
+// assert.ok(buf.includes(0x697374657374));
+// assert.ok(buf.includes(0x69737374));
+// assert.ok(buf.includes(0x69737465));
+// assert.ok(buf.includes(0x69737465));
+// assert.ok(buf.includes(-140));
+// assert.ok(buf.includes(-152));
+// assert.ok(!buf.includes(0xff));
+// assert.ok(!buf.includes(0xffff));
+// }
diff --git a/tests/node_compat/test/parallel/test-buffer-indexof.js b/tests/node_compat/test/parallel/test-buffer-indexof.js
new file mode 100644
index 000000000..802e0208b
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-buffer-indexof.js
@@ -0,0 +1,646 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+
+const b = Buffer.from('abcdef');
+const buf_a = Buffer.from('a');
+const buf_bc = Buffer.from('bc');
+const buf_f = Buffer.from('f');
+const buf_z = Buffer.from('z');
+const buf_empty = Buffer.from('');
+
+const s = 'abcdef';
+
+assert.strictEqual(b.indexOf('a'), 0);
+assert.strictEqual(b.indexOf('a', 1), -1);
+assert.strictEqual(b.indexOf('a', -1), -1);
+assert.strictEqual(b.indexOf('a', -4), -1);
+assert.strictEqual(b.indexOf('a', -b.length), 0);
+assert.strictEqual(b.indexOf('a', NaN), 0);
+assert.strictEqual(b.indexOf('a', -Infinity), 0);
+assert.strictEqual(b.indexOf('a', Infinity), -1);
+assert.strictEqual(b.indexOf('bc'), 1);
+assert.strictEqual(b.indexOf('bc', 2), -1);
+assert.strictEqual(b.indexOf('bc', -1), -1);
+assert.strictEqual(b.indexOf('bc', -3), -1);
+assert.strictEqual(b.indexOf('bc', -5), 1);
+assert.strictEqual(b.indexOf('bc', NaN), 1);
+assert.strictEqual(b.indexOf('bc', -Infinity), 1);
+assert.strictEqual(b.indexOf('bc', Infinity), -1);
+assert.strictEqual(b.indexOf('f'), b.length - 1);
+assert.strictEqual(b.indexOf('z'), -1);
+assert.strictEqual(b.indexOf(''), 0);
+assert.strictEqual(b.indexOf('', 1), 1);
+assert.strictEqual(b.indexOf('', b.length + 1), b.length);
+assert.strictEqual(b.indexOf('', Infinity), b.length);
+assert.strictEqual(b.indexOf(buf_a), 0);
+assert.strictEqual(b.indexOf(buf_a, 1), -1);
+assert.strictEqual(b.indexOf(buf_a, -1), -1);
+assert.strictEqual(b.indexOf(buf_a, -4), -1);
+assert.strictEqual(b.indexOf(buf_a, -b.length), 0);
+assert.strictEqual(b.indexOf(buf_a, NaN), 0);
+assert.strictEqual(b.indexOf(buf_a, -Infinity), 0);
+assert.strictEqual(b.indexOf(buf_a, Infinity), -1);
+assert.strictEqual(b.indexOf(buf_bc), 1);
+assert.strictEqual(b.indexOf(buf_bc, 2), -1);
+assert.strictEqual(b.indexOf(buf_bc, -1), -1);
+assert.strictEqual(b.indexOf(buf_bc, -3), -1);
+assert.strictEqual(b.indexOf(buf_bc, -5), 1);
+assert.strictEqual(b.indexOf(buf_bc, NaN), 1);
+assert.strictEqual(b.indexOf(buf_bc, -Infinity), 1);
+assert.strictEqual(b.indexOf(buf_bc, Infinity), -1);
+assert.strictEqual(b.indexOf(buf_f), b.length - 1);
+assert.strictEqual(b.indexOf(buf_z), -1);
+assert.strictEqual(b.indexOf(buf_empty), 0);
+assert.strictEqual(b.indexOf(buf_empty, 1), 1);
+assert.strictEqual(b.indexOf(buf_empty, b.length + 1), b.length);
+assert.strictEqual(b.indexOf(buf_empty, Infinity), b.length);
+assert.strictEqual(b.indexOf(0x61), 0);
+assert.strictEqual(b.indexOf(0x61, 1), -1);
+assert.strictEqual(b.indexOf(0x61, -1), -1);
+assert.strictEqual(b.indexOf(0x61, -4), -1);
+assert.strictEqual(b.indexOf(0x61, -b.length), 0);
+assert.strictEqual(b.indexOf(0x61, NaN), 0);
+assert.strictEqual(b.indexOf(0x61, -Infinity), 0);
+assert.strictEqual(b.indexOf(0x61, Infinity), -1);
+assert.strictEqual(b.indexOf(0x0), -1);
+
+// test offsets
+assert.strictEqual(b.indexOf('d', 2), 3);
+assert.strictEqual(b.indexOf('f', 5), 5);
+assert.strictEqual(b.indexOf('f', -1), 5);
+assert.strictEqual(b.indexOf('f', 6), -1);
+
+assert.strictEqual(b.indexOf(Buffer.from('d'), 2), 3);
+assert.strictEqual(b.indexOf(Buffer.from('f'), 5), 5);
+assert.strictEqual(b.indexOf(Buffer.from('f'), -1), 5);
+assert.strictEqual(b.indexOf(Buffer.from('f'), 6), -1);
+
+// TODO(Soremwar)
+// Enable again once encoding is taking into account when evaluating indexOf
+// assert.strictEqual(Buffer.from('ff').indexOf(Buffer.from('f'), 1, 'ucs2'), -1);
+
+// Test invalid and uppercase encoding
+assert.strictEqual(b.indexOf('b', 'utf8'), 1);
+assert.strictEqual(b.indexOf('b', 'UTF8'), 1);
+assert.strictEqual(b.indexOf('62', 'HEX'), 1);
+assert.throws(() => b.indexOf('bad', 'enc'), /Unknown encoding: enc/);
+
+// test hex encoding
+assert.strictEqual(
+ Buffer.from(b.toString('hex'), 'hex')
+ .indexOf('64', 0, 'hex'),
+ 3
+);
+assert.strictEqual(
+ Buffer.from(b.toString('hex'), 'hex')
+ .indexOf(Buffer.from('64', 'hex'), 0, 'hex'),
+ 3
+);
+
+// Test base64 encoding
+assert.strictEqual(
+ Buffer.from(b.toString('base64'), 'base64')
+ .indexOf('ZA==', 0, 'base64'),
+ 3
+);
+assert.strictEqual(
+ Buffer.from(b.toString('base64'), 'base64')
+ .indexOf(Buffer.from('ZA==', 'base64'), 0, 'base64'),
+ 3
+);
+
+// Test base64url encoding
+assert.strictEqual(
+ Buffer.from(b.toString('base64url'), 'base64url')
+ .indexOf('ZA==', 0, 'base64url'),
+ 3
+);
+
+// test ascii encoding
+assert.strictEqual(
+ Buffer.from(b.toString('ascii'), 'ascii')
+ .indexOf('d', 0, 'ascii'),
+ 3
+);
+assert.strictEqual(
+ Buffer.from(b.toString('ascii'), 'ascii')
+ .indexOf(Buffer.from('d', 'ascii'), 0, 'ascii'),
+ 3
+);
+
+// Test latin1 encoding
+assert.strictEqual(
+ Buffer.from(b.toString('latin1'), 'latin1')
+ .indexOf('d', 0, 'latin1'),
+ 3
+);
+assert.strictEqual(
+ Buffer.from(b.toString('latin1'), 'latin1')
+ .indexOf(Buffer.from('d', 'latin1'), 0, 'latin1'),
+ 3
+);
+assert.strictEqual(
+ Buffer.from('aa\u00e8aa', 'latin1')
+ .indexOf('\u00e8', 'latin1'),
+ 2
+);
+assert.strictEqual(
+ Buffer.from('\u00e8', 'latin1')
+ .indexOf('\u00e8', 'latin1'),
+ 0
+);
+assert.strictEqual(
+ Buffer.from('\u00e8', 'latin1')
+ .indexOf(Buffer.from('\u00e8', 'latin1'), 'latin1'),
+ 0
+);
+
+// Test binary encoding
+assert.strictEqual(
+ Buffer.from(b.toString('binary'), 'binary')
+ .indexOf('d', 0, 'binary'),
+ 3
+);
+assert.strictEqual(
+ Buffer.from(b.toString('binary'), 'binary')
+ .indexOf(Buffer.from('d', 'binary'), 0, 'binary'),
+ 3
+);
+assert.strictEqual(
+ Buffer.from('aa\u00e8aa', 'binary')
+ .indexOf('\u00e8', 'binary'),
+ 2
+);
+assert.strictEqual(
+ Buffer.from('\u00e8', 'binary')
+ .indexOf('\u00e8', 'binary'),
+ 0
+);
+assert.strictEqual(
+ Buffer.from('\u00e8', 'binary')
+ .indexOf(Buffer.from('\u00e8', 'binary'), 'binary'),
+ 0
+);
+
+
+// Test optional offset with passed encoding
+assert.strictEqual(Buffer.from('aaaa0').indexOf('30', 'hex'), 4);
+assert.strictEqual(Buffer.from('aaaa00a').indexOf('3030', 'hex'), 4);
+
+{
+ // Test usc2 and utf16le encoding
+ ['ucs2', 'utf16le'].forEach((encoding) => {
+ const twoByteString = Buffer.from(
+ '\u039a\u0391\u03a3\u03a3\u0395', encoding);
+
+ assert.strictEqual(twoByteString.indexOf('\u0395', 4, encoding), 8);
+ assert.strictEqual(twoByteString.indexOf('\u03a3', -4, encoding), 6);
+ assert.strictEqual(twoByteString.indexOf('\u03a3', -6, encoding), 4);
+ assert.strictEqual(twoByteString.indexOf(
+ Buffer.from('\u03a3', encoding), -6, encoding), 4);
+ assert.strictEqual(-1, twoByteString.indexOf('\u03a3', -2, encoding));
+ });
+}
+
+const mixedByteStringUcs2 =
+ Buffer.from('\u039a\u0391abc\u03a3\u03a3\u0395', 'ucs2');
+assert.strictEqual(mixedByteStringUcs2.indexOf('bc', 0, 'ucs2'), 6);
+assert.strictEqual(mixedByteStringUcs2.indexOf('\u03a3', 0, 'ucs2'), 10);
+assert.strictEqual(-1, mixedByteStringUcs2.indexOf('\u0396', 0, 'ucs2'));
+
+assert.strictEqual(
+ mixedByteStringUcs2.indexOf(Buffer.from('bc', 'ucs2'), 0, 'ucs2'), 6);
+assert.strictEqual(
+ mixedByteStringUcs2.indexOf(Buffer.from('\u03a3', 'ucs2'), 0, 'ucs2'), 10);
+assert.strictEqual(
+ -1, mixedByteStringUcs2.indexOf(Buffer.from('\u0396', 'ucs2'), 0, 'ucs2'));
+
+{
+ const twoByteString = Buffer.from('\u039a\u0391\u03a3\u03a3\u0395', 'ucs2');
+
+ // Test single char pattern
+ assert.strictEqual(twoByteString.indexOf('\u039a', 0, 'ucs2'), 0);
+ let index = twoByteString.indexOf('\u0391', 0, 'ucs2');
+ assert.strictEqual(index, 2, `Alpha - at index ${index}`);
+ index = twoByteString.indexOf('\u03a3', 0, 'ucs2');
+ assert.strictEqual(index, 4, `First Sigma - at index ${index}`);
+ index = twoByteString.indexOf('\u03a3', 6, 'ucs2');
+ assert.strictEqual(index, 6, `Second Sigma - at index ${index}`);
+ index = twoByteString.indexOf('\u0395', 0, 'ucs2');
+ assert.strictEqual(index, 8, `Epsilon - at index ${index}`);
+ index = twoByteString.indexOf('\u0392', 0, 'ucs2');
+ assert.strictEqual(-1, index, `Not beta - at index ${index}`);
+
+ // Test multi-char pattern
+ index = twoByteString.indexOf('\u039a\u0391', 0, 'ucs2');
+ assert.strictEqual(index, 0, `Lambda Alpha - at index ${index}`);
+ index = twoByteString.indexOf('\u0391\u03a3', 0, 'ucs2');
+ assert.strictEqual(index, 2, `Alpha Sigma - at index ${index}`);
+ index = twoByteString.indexOf('\u03a3\u03a3', 0, 'ucs2');
+ assert.strictEqual(index, 4, `Sigma Sigma - at index ${index}`);
+ index = twoByteString.indexOf('\u03a3\u0395', 0, 'ucs2');
+ assert.strictEqual(index, 6, `Sigma Epsilon - at index ${index}`);
+}
+
+const mixedByteStringUtf8 = Buffer.from('\u039a\u0391abc\u03a3\u03a3\u0395');
+assert.strictEqual(mixedByteStringUtf8.indexOf('bc'), 5);
+assert.strictEqual(mixedByteStringUtf8.indexOf('bc', 5), 5);
+assert.strictEqual(mixedByteStringUtf8.indexOf('bc', -8), 5);
+assert.strictEqual(mixedByteStringUtf8.indexOf('\u03a3'), 7);
+assert.strictEqual(mixedByteStringUtf8.indexOf('\u0396'), -1);
+
+
+// Test complex string indexOf algorithms. Only trigger for long strings.
+// Long string that isn't a simple repeat of a shorter string.
+let longString = 'A';
+for (let i = 66; i < 76; i++) { // from 'B' to 'K'
+ longString = longString + String.fromCharCode(i) + longString;
+}
+
+const longBufferString = Buffer.from(longString);
+
+// Pattern of 15 chars, repeated every 16 chars in long
+let pattern = 'ABACABADABACABA';
+for (let i = 0; i < longBufferString.length - pattern.length; i += 7) {
+ const index = longBufferString.indexOf(pattern, i);
+ assert.strictEqual((i + 15) & ~0xf, index,
+ `Long ABACABA...-string at index ${i}`);
+}
+
+let index = longBufferString.indexOf('AJABACA');
+assert.strictEqual(index, 510, `Long AJABACA, First J - at index ${index}`);
+index = longBufferString.indexOf('AJABACA', 511);
+assert.strictEqual(index, 1534, `Long AJABACA, Second J - at index ${index}`);
+
+pattern = 'JABACABADABACABA';
+index = longBufferString.indexOf(pattern);
+assert.strictEqual(index, 511, `Long JABACABA..., First J - at index ${index}`);
+index = longBufferString.indexOf(pattern, 512);
+assert.strictEqual(
+ index, 1535, `Long JABACABA..., Second J - at index ${index}`);
+
+// Search for a non-ASCII string in a pure ASCII string.
+const asciiString = Buffer.from(
+ 'arglebargleglopglyfarglebargleglopglyfarglebargleglopglyf');
+assert.strictEqual(-1, asciiString.indexOf('\x2061'));
+assert.strictEqual(asciiString.indexOf('leb', 0), 3);
+
+// Search in string containing many non-ASCII chars.
+const allCodePoints = [];
+for (let i = 0; i < 65534; i++) allCodePoints[i] = i;
+const allCharsString = String.fromCharCode.apply(String, allCodePoints) +
+ String.fromCharCode(65534, 65535);
+const allCharsBufferUtf8 = Buffer.from(allCharsString);
+const allCharsBufferUcs2 = Buffer.from(allCharsString, 'ucs2');
+
+// Search for string long enough to trigger complex search with ASCII pattern
+// and UC16 subject.
+assert.strictEqual(-1, allCharsBufferUtf8.indexOf('notfound'));
+assert.strictEqual(-1, allCharsBufferUcs2.indexOf('notfound'));
+
+// Needle is longer than haystack, but only because it's encoded as UTF-16
+assert.strictEqual(Buffer.from('aaaa').indexOf('a'.repeat(4), 'ucs2'), -1);
+
+assert.strictEqual(Buffer.from('aaaa').indexOf('a'.repeat(4), 'utf8'), 0);
+assert.strictEqual(Buffer.from('aaaa').indexOf('你好', 'ucs2'), -1);
+
+// Haystack has odd length, but the needle is UCS2.
+assert.strictEqual(Buffer.from('aaaaa').indexOf('b', 'ucs2'), -1);
+
+{
+ // Find substrings in Utf8.
+ const lengths = [1, 3, 15]; // Single char, simple and complex.
+ const indices = [0x5, 0x60, 0x400, 0x680, 0x7ee, 0xFF02, 0x16610, 0x2f77b];
+ for (let lengthIndex = 0; lengthIndex < lengths.length; lengthIndex++) {
+ for (let i = 0; i < indices.length; i++) {
+ const index = indices[i];
+ let length = lengths[lengthIndex];
+
+ if (index + length > 0x7F) {
+ length = 2 * length;
+ }
+
+ if (index + length > 0x7FF) {
+ length = 3 * length;
+ }
+
+ if (index + length > 0xFFFF) {
+ length = 4 * length;
+ }
+
+ const patternBufferUtf8 = allCharsBufferUtf8.slice(index, index + length);
+ assert.strictEqual(index, allCharsBufferUtf8.indexOf(patternBufferUtf8));
+
+ const patternStringUtf8 = patternBufferUtf8.toString();
+ assert.strictEqual(index, allCharsBufferUtf8.indexOf(patternStringUtf8));
+ }
+ }
+}
+
+// TODO(Soremwar)
+// Enable again once encoding is taking into account when evaluating indexOf
+// {
+// // Find substrings in Usc2.
+// const lengths = [2, 4, 16]; // Single char, simple and complex.
+// const indices = [0x5, 0x65, 0x105, 0x205, 0x285, 0x2005, 0x2085, 0xfff0];
+// for (let lengthIndex = 0; lengthIndex < lengths.length; lengthIndex++) {
+// for (let i = 0; i < indices.length; i++) {
+// const index = indices[i] * 2;
+// const length = lengths[lengthIndex];
+
+// const patternBufferUcs2 =
+// allCharsBufferUcs2.slice(index, index + length);
+// assert.strictEqual(
+// index, allCharsBufferUcs2.indexOf(patternBufferUcs2, 0, 'ucs2'));
+
+// const patternStringUcs2 = patternBufferUcs2.toString('ucs2');
+// assert.strictEqual(
+// index, allCharsBufferUcs2.indexOf(patternStringUcs2, 0, 'ucs2'));
+// }
+// }
+// }
+
+[
+ () => {},
+ {},
+ [],
+].forEach((val) => {
+ assert.throws(
+ () => b.indexOf(val),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: 'The "value" argument must be one of type number or string ' +
+ 'or an instance of Buffer or Uint8Array.' +
+ common.invalidArgTypeHelper(val)
+ }
+ );
+});
+
+// Test weird offset arguments.
+// The following offsets coerce to NaN or 0, searching the whole Buffer
+assert.strictEqual(b.indexOf('b', undefined), 1);
+assert.strictEqual(b.indexOf('b', {}), 1);
+assert.strictEqual(b.indexOf('b', 0), 1);
+assert.strictEqual(b.indexOf('b', null), 1);
+assert.strictEqual(b.indexOf('b', []), 1);
+
+// The following offset coerces to 2, in other words +[2] === 2
+assert.strictEqual(b.indexOf('b', [2]), -1);
+
+// Behavior should match String.indexOf()
+assert.strictEqual(
+ b.indexOf('b', undefined),
+ s.indexOf('b', undefined));
+assert.strictEqual(
+ b.indexOf('b', {}),
+ s.indexOf('b', {}));
+assert.strictEqual(
+ b.indexOf('b', 0),
+ s.indexOf('b', 0));
+assert.strictEqual(
+ b.indexOf('b', null),
+ s.indexOf('b', null));
+assert.strictEqual(
+ b.indexOf('b', []),
+ s.indexOf('b', []));
+assert.strictEqual(
+ b.indexOf('b', [2]),
+ s.indexOf('b', [2]));
+
+// All code for handling encodings is shared between Buffer.indexOf and
+// Buffer.lastIndexOf, so only testing the separate lastIndexOf semantics.
+
+// Test lastIndexOf basic functionality; Buffer b contains 'abcdef'.
+// lastIndexOf string:
+assert.strictEqual(b.lastIndexOf('a'), 0);
+assert.strictEqual(b.lastIndexOf('a', 1), 0);
+assert.strictEqual(b.lastIndexOf('b', 1), 1);
+assert.strictEqual(b.lastIndexOf('c', 1), -1);
+assert.strictEqual(b.lastIndexOf('a', -1), 0);
+assert.strictEqual(b.lastIndexOf('a', -4), 0);
+assert.strictEqual(b.lastIndexOf('a', -b.length), 0);
+assert.strictEqual(b.lastIndexOf('a', -b.length - 1), -1);
+assert.strictEqual(b.lastIndexOf('a', NaN), 0);
+assert.strictEqual(b.lastIndexOf('a', -Infinity), -1);
+assert.strictEqual(b.lastIndexOf('a', Infinity), 0);
+// lastIndexOf Buffer:
+assert.strictEqual(b.lastIndexOf(buf_a), 0);
+assert.strictEqual(b.lastIndexOf(buf_a, 1), 0);
+assert.strictEqual(b.lastIndexOf(buf_a, -1), 0);
+assert.strictEqual(b.lastIndexOf(buf_a, -4), 0);
+assert.strictEqual(b.lastIndexOf(buf_a, -b.length), 0);
+assert.strictEqual(b.lastIndexOf(buf_a, -b.length - 1), -1);
+assert.strictEqual(b.lastIndexOf(buf_a, NaN), 0);
+assert.strictEqual(b.lastIndexOf(buf_a, -Infinity), -1);
+assert.strictEqual(b.lastIndexOf(buf_a, Infinity), 0);
+assert.strictEqual(b.lastIndexOf(buf_bc), 1);
+assert.strictEqual(b.lastIndexOf(buf_bc, 2), 1);
+assert.strictEqual(b.lastIndexOf(buf_bc, -1), 1);
+assert.strictEqual(b.lastIndexOf(buf_bc, -3), 1);
+assert.strictEqual(b.lastIndexOf(buf_bc, -5), 1);
+assert.strictEqual(b.lastIndexOf(buf_bc, -6), -1);
+assert.strictEqual(b.lastIndexOf(buf_bc, NaN), 1);
+assert.strictEqual(b.lastIndexOf(buf_bc, -Infinity), -1);
+assert.strictEqual(b.lastIndexOf(buf_bc, Infinity), 1);
+assert.strictEqual(b.lastIndexOf(buf_f), b.length - 1);
+assert.strictEqual(b.lastIndexOf(buf_z), -1);
+assert.strictEqual(b.lastIndexOf(buf_empty), b.length);
+assert.strictEqual(b.lastIndexOf(buf_empty, 1), 1);
+assert.strictEqual(b.lastIndexOf(buf_empty, b.length + 1), b.length);
+assert.strictEqual(b.lastIndexOf(buf_empty, Infinity), b.length);
+// lastIndexOf number:
+assert.strictEqual(b.lastIndexOf(0x61), 0);
+assert.strictEqual(b.lastIndexOf(0x61, 1), 0);
+assert.strictEqual(b.lastIndexOf(0x61, -1), 0);
+assert.strictEqual(b.lastIndexOf(0x61, -4), 0);
+assert.strictEqual(b.lastIndexOf(0x61, -b.length), 0);
+assert.strictEqual(b.lastIndexOf(0x61, -b.length - 1), -1);
+assert.strictEqual(b.lastIndexOf(0x61, NaN), 0);
+assert.strictEqual(b.lastIndexOf(0x61, -Infinity), -1);
+assert.strictEqual(b.lastIndexOf(0x61, Infinity), 0);
+assert.strictEqual(b.lastIndexOf(0x0), -1);
+
+// Test weird offset arguments.
+// The following offsets coerce to NaN, searching the whole Buffer
+assert.strictEqual(b.lastIndexOf('b', undefined), 1);
+assert.strictEqual(b.lastIndexOf('b', {}), 1);
+
+// The following offsets coerce to 0
+assert.strictEqual(b.lastIndexOf('b', 0), -1);
+assert.strictEqual(b.lastIndexOf('b', null), -1);
+assert.strictEqual(b.lastIndexOf('b', []), -1);
+
+// The following offset coerces to 2, in other words +[2] === 2
+assert.strictEqual(b.lastIndexOf('b', [2]), 1);
+
+// Behavior should match String.lastIndexOf()
+assert.strictEqual(
+ b.lastIndexOf('b', undefined),
+ s.lastIndexOf('b', undefined));
+assert.strictEqual(
+ b.lastIndexOf('b', {}),
+ s.lastIndexOf('b', {}));
+assert.strictEqual(
+ b.lastIndexOf('b', 0),
+ s.lastIndexOf('b', 0));
+assert.strictEqual(
+ b.lastIndexOf('b', null),
+ s.lastIndexOf('b', null));
+assert.strictEqual(
+ b.lastIndexOf('b', []),
+ s.lastIndexOf('b', []));
+assert.strictEqual(
+ b.lastIndexOf('b', [2]),
+ s.lastIndexOf('b', [2]));
+
+// Test needles longer than the haystack.
+assert.strictEqual(b.lastIndexOf('aaaaaaaaaaaaaaa', 'ucs2'), -1);
+assert.strictEqual(b.lastIndexOf('aaaaaaaaaaaaaaa', 'utf8'), -1);
+assert.strictEqual(b.lastIndexOf('aaaaaaaaaaaaaaa', 'latin1'), -1);
+assert.strictEqual(b.lastIndexOf('aaaaaaaaaaaaaaa', 'binary'), -1);
+assert.strictEqual(b.lastIndexOf(Buffer.from('aaaaaaaaaaaaaaa')), -1);
+assert.strictEqual(b.lastIndexOf('aaaaaaaaaaaaaaa', 2, 'ucs2'), -1);
+assert.strictEqual(b.lastIndexOf('aaaaaaaaaaaaaaa', 3, 'utf8'), -1);
+assert.strictEqual(b.lastIndexOf('aaaaaaaaaaaaaaa', 5, 'latin1'), -1);
+assert.strictEqual(b.lastIndexOf('aaaaaaaaaaaaaaa', 5, 'binary'), -1);
+assert.strictEqual(b.lastIndexOf(Buffer.from('aaaaaaaaaaaaaaa'), 7), -1);
+
+// 你好 expands to a total of 6 bytes using UTF-8 and 4 bytes using UTF-16
+assert.strictEqual(buf_bc.lastIndexOf('你好', 'ucs2'), -1);
+assert.strictEqual(buf_bc.lastIndexOf('你好', 'utf8'), -1);
+assert.strictEqual(buf_bc.lastIndexOf('你好', 'latin1'), -1);
+assert.strictEqual(buf_bc.lastIndexOf('你好', 'binary'), -1);
+assert.strictEqual(buf_bc.lastIndexOf(Buffer.from('你好')), -1);
+assert.strictEqual(buf_bc.lastIndexOf('你好', 2, 'ucs2'), -1);
+assert.strictEqual(buf_bc.lastIndexOf('你好', 3, 'utf8'), -1);
+assert.strictEqual(buf_bc.lastIndexOf('你好', 5, 'latin1'), -1);
+assert.strictEqual(buf_bc.lastIndexOf('你好', 5, 'binary'), -1);
+assert.strictEqual(buf_bc.lastIndexOf(Buffer.from('你好'), 7), -1);
+
+// Test lastIndexOf on a longer buffer:
+const bufferString = Buffer.from('a man a plan a canal panama');
+assert.strictEqual(bufferString.lastIndexOf('canal'), 15);
+assert.strictEqual(bufferString.lastIndexOf('panama'), 21);
+assert.strictEqual(bufferString.lastIndexOf('a man a plan a canal panama'), 0);
+assert.strictEqual(-1, bufferString.lastIndexOf('a man a plan a canal mexico'));
+assert.strictEqual(-1, bufferString
+ .lastIndexOf('a man a plan a canal mexico city'));
+assert.strictEqual(-1, bufferString.lastIndexOf(Buffer.from('a'.repeat(1000))));
+assert.strictEqual(bufferString.lastIndexOf('a man a plan', 4), 0);
+assert.strictEqual(bufferString.lastIndexOf('a '), 13);
+assert.strictEqual(bufferString.lastIndexOf('a ', 13), 13);
+assert.strictEqual(bufferString.lastIndexOf('a ', 12), 6);
+assert.strictEqual(bufferString.lastIndexOf('a ', 5), 0);
+assert.strictEqual(bufferString.lastIndexOf('a ', -1), 13);
+assert.strictEqual(bufferString.lastIndexOf('a ', -27), 0);
+assert.strictEqual(-1, bufferString.lastIndexOf('a ', -28));
+
+// Test lastIndexOf for the case that the first character can be found,
+// but in a part of the buffer that does not make search to search
+// due do length constraints.
+const abInUCS2 = Buffer.from('ab', 'ucs2');
+assert.strictEqual(-1, Buffer.from('µaaaa¶bbbb', 'latin1').lastIndexOf('µ'));
+assert.strictEqual(-1, Buffer.from('µaaaa¶bbbb', 'binary').lastIndexOf('µ'));
+assert.strictEqual(-1, Buffer.from('bc').lastIndexOf('ab'));
+assert.strictEqual(-1, Buffer.from('abc').lastIndexOf('qa'));
+assert.strictEqual(-1, Buffer.from('abcdef').lastIndexOf('qabc'));
+assert.strictEqual(-1, Buffer.from('bc').lastIndexOf(Buffer.from('ab')));
+assert.strictEqual(-1, Buffer.from('bc', 'ucs2').lastIndexOf('ab', 'ucs2'));
+assert.strictEqual(-1, Buffer.from('bc', 'ucs2').lastIndexOf(abInUCS2));
+
+assert.strictEqual(Buffer.from('abc').lastIndexOf('ab'), 0);
+assert.strictEqual(Buffer.from('abc').lastIndexOf('ab', 1), 0);
+assert.strictEqual(Buffer.from('abc').lastIndexOf('ab', 2), 0);
+assert.strictEqual(Buffer.from('abc').lastIndexOf('ab', 3), 0);
+
+// The above tests test the LINEAR and SINGLE-CHAR strategies.
+// Now, we test the BOYER-MOORE-HORSPOOL strategy.
+// Test lastIndexOf on a long buffer w multiple matches:
+pattern = 'JABACABADABACABA';
+assert.strictEqual(longBufferString.lastIndexOf(pattern), 1535);
+assert.strictEqual(longBufferString.lastIndexOf(pattern, 1535), 1535);
+assert.strictEqual(longBufferString.lastIndexOf(pattern, 1534), 511);
+
+// Finally, give it a really long input to trigger fallback from BMH to
+// regular BOYER-MOORE (which has better worst-case complexity).
+
+// Generate a really long Thue-Morse sequence of 'yolo' and 'swag',
+// "yolo swag swag yolo swag yolo yolo swag" ..., goes on for about 5MB.
+// This is hard to search because it all looks similar, but never repeats.
+
+// countBits returns the number of bits in the binary representation of n.
+function countBits(n) {
+ let count;
+ for (count = 0; n > 0; count++) {
+ n = n & (n - 1); // remove top bit
+ }
+ return count;
+}
+const parts = [];
+for (let i = 0; i < 1000000; i++) {
+ parts.push((countBits(i) % 2 === 0) ? 'yolo' : 'swag');
+}
+const reallyLong = Buffer.from(parts.join(' '));
+assert.strictEqual(reallyLong.slice(0, 19).toString(), 'yolo swag swag yolo');
+
+// Expensive reverse searches. Stress test lastIndexOf:
+pattern = reallyLong.slice(0, 100000); // First 1/50th of the pattern.
+assert.strictEqual(reallyLong.lastIndexOf(pattern), 4751360);
+assert.strictEqual(reallyLong.lastIndexOf(pattern, 4000000), 3932160);
+assert.strictEqual(reallyLong.lastIndexOf(pattern, 3000000), 2949120);
+pattern = reallyLong.slice(100000, 200000); // Second 1/50th.
+assert.strictEqual(reallyLong.lastIndexOf(pattern), 4728480);
+pattern = reallyLong.slice(0, 1000000); // First 1/5th.
+assert.strictEqual(reallyLong.lastIndexOf(pattern), 3932160);
+pattern = reallyLong.slice(0, 2000000); // first 2/5ths.
+assert.strictEqual(reallyLong.lastIndexOf(pattern), 0);
+
+// Test truncation of Number arguments to uint8
+// TODO(Soremwar)
+// Enable once multi byte number search is available
+// {
+// const buf = Buffer.from('this is a test');
+// assert.strictEqual(buf.indexOf(0x6973), 3);
+// assert.strictEqual(buf.indexOf(0x697320), 4);
+// assert.strictEqual(buf.indexOf(0x69732069), 2);
+// assert.strictEqual(buf.indexOf(0x697374657374), 0);
+// assert.strictEqual(buf.indexOf(0x69737374), 0);
+// assert.strictEqual(buf.indexOf(0x69737465), 11);
+// assert.strictEqual(buf.indexOf(0x69737465), 11);
+// assert.strictEqual(buf.indexOf(-140), 0);
+// assert.strictEqual(buf.indexOf(-152), 1);
+// assert.strictEqual(buf.indexOf(0xff), -1);
+// assert.strictEqual(buf.indexOf(0xffff), -1);
+// }
+
+// Test that Uint8Array arguments are okay.
+{
+ const needle = new Uint8Array([ 0x66, 0x6f, 0x6f ]);
+ const haystack = Buffer.from('a foo b foo');
+ assert.strictEqual(haystack.indexOf(needle), 2);
+ assert.strictEqual(haystack.lastIndexOf(needle), haystack.length - 3);
+}
+
+// Avoid abort because of invalid usage
+// see https://github.com/nodejs/node/issues/32753
+{
+ assert.throws(() => {
+ const buffer = require('buffer');
+ new buffer.Buffer.prototype.lastIndexOf(1, 'str');
+ }, {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: 'The "buffer" argument must be an instance of Buffer, ' +
+ 'TypedArray, or DataView. ' +
+ 'Received an instance of lastIndexOf'
+ });
+}
diff --git a/tests/node_compat/test/parallel/test-buffer-inheritance.js b/tests/node_compat/test/parallel/test-buffer-inheritance.js
new file mode 100644
index 000000000..6440a84cb
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-buffer-inheritance.js
@@ -0,0 +1,46 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+require('../common');
+const assert = require('assert');
+
+
+function T(n) {
+ const ui8 = new Uint8Array(n);
+ Object.setPrototypeOf(ui8, T.prototype);
+ return ui8;
+}
+Object.setPrototypeOf(T.prototype, Buffer.prototype);
+Object.setPrototypeOf(T, Buffer);
+
+T.prototype.sum = function sum() {
+ let cntr = 0;
+ for (let i = 0; i < this.length; i++)
+ cntr += this[i];
+ return cntr;
+};
+
+
+const vals = [new T(4), T(4)];
+
+vals.forEach(function(t) {
+ assert.strictEqual(t.constructor, T);
+ assert.strictEqual(Object.getPrototypeOf(t), T.prototype);
+ assert.strictEqual(Object.getPrototypeOf(Object.getPrototypeOf(t)),
+ Buffer.prototype);
+
+ t.fill(5);
+ let cntr = 0;
+ for (let i = 0; i < t.length; i++)
+ cntr += t[i];
+ assert.strictEqual(cntr, t.length * 5);
+
+ // Check this does not throw
+ t.toString();
+});
diff --git a/tests/node_compat/test/parallel/test-buffer-isencoding.js b/tests/node_compat/test/parallel/test-buffer-isencoding.js
new file mode 100644
index 000000000..439e6860a
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-buffer-isencoding.js
@@ -0,0 +1,45 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+require('../common');
+const assert = require('assert');
+
+[
+ 'hex',
+ 'utf8',
+ 'utf-8',
+ 'ascii',
+ 'latin1',
+ 'binary',
+ 'base64',
+ 'base64url',
+ 'ucs2',
+ 'ucs-2',
+ 'utf16le',
+ 'utf-16le',
+].forEach((enc) => {
+ assert.strictEqual(Buffer.isEncoding(enc), true);
+});
+
+[
+ 'utf9',
+ 'utf-7',
+ 'Unicode-FTW',
+ 'new gnu gun',
+ false,
+ NaN,
+ {},
+ Infinity,
+ [],
+ 1,
+ 0,
+ -1,
+].forEach((enc) => {
+ assert.strictEqual(Buffer.isEncoding(enc), false);
+});
diff --git a/tests/node_compat/test/parallel/test-buffer-iterator.js b/tests/node_compat/test/parallel/test-buffer-iterator.js
new file mode 100644
index 000000000..8ac97e259
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-buffer-iterator.js
@@ -0,0 +1,69 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+
+const buffer = Buffer.from([1, 2, 3, 4, 5]);
+let arr;
+let b;
+
+// Buffers should be iterable
+
+arr = [];
+
+for (b of buffer)
+ arr.push(b);
+
+assert.deepStrictEqual(arr, [1, 2, 3, 4, 5]);
+
+
+// Buffer iterators should be iterable
+
+arr = [];
+
+for (b of buffer[Symbol.iterator]())
+ arr.push(b);
+
+assert.deepStrictEqual(arr, [1, 2, 3, 4, 5]);
+
+
+// buffer#values() should return iterator for values
+
+arr = [];
+
+for (b of buffer.values())
+ arr.push(b);
+
+assert.deepStrictEqual(arr, [1, 2, 3, 4, 5]);
+
+
+// buffer#keys() should return iterator for keys
+
+arr = [];
+
+for (b of buffer.keys())
+ arr.push(b);
+
+assert.deepStrictEqual(arr, [0, 1, 2, 3, 4]);
+
+
+// buffer#entries() should return iterator for entries
+
+arr = [];
+
+for (b of buffer.entries())
+ arr.push(b);
+
+assert.deepStrictEqual(arr, [
+ [0, 1],
+ [1, 2],
+ [2, 3],
+ [3, 4],
+ [4, 5],
+]);
diff --git a/tests/node_compat/test/parallel/test-buffer-new.js b/tests/node_compat/test/parallel/test-buffer-new.js
new file mode 100644
index 000000000..d15138327
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-buffer-new.js
@@ -0,0 +1,18 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+require('../common');
+const assert = require('assert');
+
+assert.throws(() => new Buffer(42, 'utf8'), {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: 'The "string" argument must be of type string. Received type ' +
+ 'number (42)'
+});
diff --git a/tests/node_compat/test/parallel/test-buffer-no-negative-allocation.js b/tests/node_compat/test/parallel/test-buffer-no-negative-allocation.js
new file mode 100644
index 000000000..df4a6cb52
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-buffer-no-negative-allocation.js
@@ -0,0 +1,45 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+require('../common');
+const assert = require('assert');
+const { SlowBuffer } = require('buffer');
+
+const msg = {
+ code: 'ERR_INVALID_ARG_VALUE',
+ name: 'RangeError',
+ message: /^The argument 'size' is invalid\. Received [^"]*$/
+};
+
+// Test that negative Buffer length inputs throw errors.
+
+assert.throws(() => Buffer(-Buffer.poolSize), msg);
+assert.throws(() => Buffer(-100), msg);
+assert.throws(() => Buffer(-1), msg);
+assert.throws(() => Buffer(NaN), msg);
+
+assert.throws(() => Buffer.alloc(-Buffer.poolSize), msg);
+assert.throws(() => Buffer.alloc(-100), msg);
+assert.throws(() => Buffer.alloc(-1), msg);
+assert.throws(() => Buffer.alloc(NaN), msg);
+
+assert.throws(() => Buffer.allocUnsafe(-Buffer.poolSize), msg);
+assert.throws(() => Buffer.allocUnsafe(-100), msg);
+assert.throws(() => Buffer.allocUnsafe(-1), msg);
+assert.throws(() => Buffer.allocUnsafe(NaN), msg);
+
+assert.throws(() => Buffer.allocUnsafeSlow(-Buffer.poolSize), msg);
+assert.throws(() => Buffer.allocUnsafeSlow(-100), msg);
+assert.throws(() => Buffer.allocUnsafeSlow(-1), msg);
+assert.throws(() => Buffer.allocUnsafeSlow(NaN), msg);
+
+assert.throws(() => SlowBuffer(-Buffer.poolSize), msg);
+assert.throws(() => SlowBuffer(-100), msg);
+assert.throws(() => SlowBuffer(-1), msg);
+assert.throws(() => SlowBuffer(NaN), msg);
diff --git a/tests/node_compat/test/parallel/test-buffer-nopendingdep-map.js b/tests/node_compat/test/parallel/test-buffer-nopendingdep-map.js
new file mode 100644
index 000000000..a6320d0b0
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-buffer-nopendingdep-map.js
@@ -0,0 +1,20 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Flags: --no-warnings --pending-deprecation
+'use strict';
+
+const common = require('../common');
+
+process.on('warning', common.mustNotCall('A warning should not be emitted'));
+
+// With the --pending-deprecation flag, the deprecation warning for
+// new Buffer() should not be emitted when Uint8Array methods are called.
+
+Buffer.from('abc').map((i) => i);
+Buffer.from('abc').filter((i) => i);
+Buffer.from('abc').slice(1, 2);
diff --git a/tests/node_compat/test/parallel/test-buffer-of-no-deprecation.js b/tests/node_compat/test/parallel/test-buffer-of-no-deprecation.js
new file mode 100644
index 000000000..b2b48d51d
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-buffer-of-no-deprecation.js
@@ -0,0 +1,14 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+
+process.on('warning', common.mustNotCall());
+
+Buffer.of(0, 1);
diff --git a/tests/node_compat/test/parallel/test-buffer-over-max-length.js b/tests/node_compat/test/parallel/test-buffer-over-max-length.js
new file mode 100644
index 000000000..c10c1e9d1
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-buffer-over-max-length.js
@@ -0,0 +1,37 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+require('../common');
+
+const assert = require('assert');
+
+const buffer = require('buffer');
+const SlowBuffer = buffer.SlowBuffer;
+
+const kMaxLength = buffer.kMaxLength;
+const bufferMaxSizeMsg = {
+ code: 'ERR_INVALID_ARG_VALUE',
+ name: 'RangeError',
+ message: /^The argument 'size' is invalid\. Received [^"]*$/
+};
+
+assert.throws(() => Buffer((-1 >>> 0) + 2), bufferMaxSizeMsg);
+assert.throws(() => SlowBuffer((-1 >>> 0) + 2), bufferMaxSizeMsg);
+assert.throws(() => Buffer.alloc((-1 >>> 0) + 2), bufferMaxSizeMsg);
+assert.throws(() => Buffer.allocUnsafe((-1 >>> 0) + 2), bufferMaxSizeMsg);
+assert.throws(() => Buffer.allocUnsafeSlow((-1 >>> 0) + 2), bufferMaxSizeMsg);
+
+assert.throws(() => Buffer(kMaxLength + 1), bufferMaxSizeMsg);
+assert.throws(() => SlowBuffer(kMaxLength + 1), bufferMaxSizeMsg);
+assert.throws(() => Buffer.alloc(kMaxLength + 1), bufferMaxSizeMsg);
+assert.throws(() => Buffer.allocUnsafe(kMaxLength + 1), bufferMaxSizeMsg);
+assert.throws(() => Buffer.allocUnsafeSlow(kMaxLength + 1), bufferMaxSizeMsg);
+
+// issue GH-4331
+assert.throws(() => Buffer.allocUnsafe(0x100000001), bufferMaxSizeMsg);
+assert.throws(() => Buffer.allocUnsafe(0xFFFFFFFFF), bufferMaxSizeMsg);
diff --git a/tests/node_compat/test/parallel/test-buffer-parent-property.js b/tests/node_compat/test/parallel/test-buffer-parent-property.js
new file mode 100644
index 000000000..6efc42d06
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-buffer-parent-property.js
@@ -0,0 +1,28 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+// Fix for https://github.com/nodejs/node/issues/8266
+//
+// Zero length Buffer objects should expose the `buffer` property of the
+// TypedArrays, via the `parent` property.
+require('../common');
+const assert = require('assert');
+
+// If the length of the buffer object is zero
+assert((new Buffer(0)).parent instanceof ArrayBuffer);
+
+// If the length of the buffer object is equal to the underlying ArrayBuffer
+assert((new Buffer(Buffer.poolSize)).parent instanceof ArrayBuffer);
+
+// Same as the previous test, but with user created buffer
+const arrayBuffer = new ArrayBuffer(0);
+assert.strictEqual(new Buffer(arrayBuffer).parent, arrayBuffer);
+assert.strictEqual(new Buffer(arrayBuffer).buffer, arrayBuffer);
+assert.strictEqual(Buffer.from(arrayBuffer).parent, arrayBuffer);
+assert.strictEqual(Buffer.from(arrayBuffer).buffer, arrayBuffer);
diff --git a/tests/node_compat/test/parallel/test-buffer-read.js b/tests/node_compat/test/parallel/test-buffer-read.js
new file mode 100644
index 000000000..391b309a8
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-buffer-read.js
@@ -0,0 +1,113 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+
+// Testing basic buffer read functions
+const buf = Buffer.from([0xa4, 0xfd, 0x48, 0xea, 0xcf, 0xff, 0xd9, 0x01, 0xde]);
+
+function read(buff, funx, args, expected) {
+ assert.strictEqual(buff[funx](...args), expected);
+ assert.throws(
+ () => buff[funx](-1, args[1]),
+ { code: 'ERR_OUT_OF_RANGE' }
+ );
+}
+
+// Testing basic functionality of readDoubleBE() and readDoubleLE()
+read(buf, 'readDoubleBE', [1], -3.1827727774563287e+295);
+read(buf, 'readDoubleLE', [1], -6.966010051009108e+144);
+
+// Testing basic functionality of readFloatBE() and readFloatLE()
+read(buf, 'readFloatBE', [1], -1.6691549692541768e+37);
+read(buf, 'readFloatLE', [1], -7861303808);
+
+// Testing basic functionality of readInt8()
+read(buf, 'readInt8', [1], -3);
+
+// Testing basic functionality of readInt16BE() and readInt16LE()
+read(buf, 'readInt16BE', [1], -696);
+read(buf, 'readInt16LE', [1], 0x48fd);
+
+// Testing basic functionality of readInt32BE() and readInt32LE()
+read(buf, 'readInt32BE', [1], -45552945);
+read(buf, 'readInt32LE', [1], -806729475);
+
+// Testing basic functionality of readIntBE() and readIntLE()
+read(buf, 'readIntBE', [1, 1], -3);
+read(buf, 'readIntLE', [2, 1], 0x48);
+
+// Testing basic functionality of readUInt8()
+read(buf, 'readUInt8', [1], 0xfd);
+
+// Testing basic functionality of readUInt16BE() and readUInt16LE()
+read(buf, 'readUInt16BE', [2], 0x48ea);
+read(buf, 'readUInt16LE', [2], 0xea48);
+
+// Testing basic functionality of readUInt32BE() and readUInt32LE()
+read(buf, 'readUInt32BE', [1], 0xfd48eacf);
+read(buf, 'readUInt32LE', [1], 0xcfea48fd);
+
+// Testing basic functionality of readUIntBE() and readUIntLE()
+read(buf, 'readUIntBE', [2, 2], 0x48ea);
+read(buf, 'readUIntLE', [2, 2], 0xea48);
+
+// Error name and message
+const OOR_ERROR =
+{
+ name: 'RangeError'
+};
+
+const OOB_ERROR =
+{
+ name: 'RangeError',
+ message: 'Attempt to access memory outside buffer bounds'
+};
+
+// Attempt to overflow buffers, similar to previous bug in array buffers
+assert.throws(
+ () => Buffer.allocUnsafe(8).readFloatBE(0xffffffff), OOR_ERROR);
+
+assert.throws(
+ () => Buffer.allocUnsafe(8).readFloatLE(0xffffffff), OOR_ERROR);
+
+// Ensure negative values can't get past offset
+assert.throws(
+ () => Buffer.allocUnsafe(8).readFloatBE(-1), OOR_ERROR);
+assert.throws(
+ () => Buffer.allocUnsafe(8).readFloatLE(-1), OOR_ERROR);
+
+// Offset checks
+{
+ const buf = Buffer.allocUnsafe(0);
+
+ assert.throws(
+ () => buf.readUInt8(0), OOB_ERROR);
+ assert.throws(
+ () => buf.readInt8(0), OOB_ERROR);
+}
+
+[16, 32].forEach((bit) => {
+ const buf = Buffer.allocUnsafe(bit / 8 - 1);
+ [`Int${bit}B`, `Int${bit}L`, `UInt${bit}B`, `UInt${bit}L`].forEach((fn) => {
+ assert.throws(
+ () => buf[`read${fn}E`](0), OOB_ERROR);
+ });
+});
+
+[16, 32].forEach((bits) => {
+ const buf = Buffer.from([0xFF, 0xFF, 0xFF, 0xFF]);
+ ['LE', 'BE'].forEach((endian) => {
+ assert.strictEqual(buf[`readUInt${bits}${endian}`](0),
+ (0xFFFFFFFF >>> (32 - bits)));
+
+ assert.strictEqual(buf[`readInt${bits}${endian}`](0),
+ (0xFFFFFFFF >> (32 - bits)));
+ });
+});
diff --git a/tests/node_compat/test/parallel/test-buffer-readdouble.js b/tests/node_compat/test/parallel/test-buffer-readdouble.js
new file mode 100644
index 000000000..f4ab9ba88
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-buffer-readdouble.js
@@ -0,0 +1,151 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+require('../common');
+const assert = require('assert');
+
+// Test (64 bit) double
+const buffer = Buffer.allocUnsafe(8);
+
+buffer[0] = 0x55;
+buffer[1] = 0x55;
+buffer[2] = 0x55;
+buffer[3] = 0x55;
+buffer[4] = 0x55;
+buffer[5] = 0x55;
+buffer[6] = 0xd5;
+buffer[7] = 0x3f;
+assert.strictEqual(buffer.readDoubleBE(0), 1.1945305291680097e+103);
+assert.strictEqual(buffer.readDoubleLE(0), 0.3333333333333333);
+
+buffer[0] = 1;
+buffer[1] = 0;
+buffer[2] = 0;
+buffer[3] = 0;
+buffer[4] = 0;
+buffer[5] = 0;
+buffer[6] = 0xf0;
+buffer[7] = 0x3f;
+assert.strictEqual(buffer.readDoubleBE(0), 7.291122019655968e-304);
+assert.strictEqual(buffer.readDoubleLE(0), 1.0000000000000002);
+
+buffer[0] = 2;
+assert.strictEqual(buffer.readDoubleBE(0), 4.778309726801735e-299);
+assert.strictEqual(buffer.readDoubleLE(0), 1.0000000000000004);
+
+buffer[0] = 1;
+buffer[6] = 0;
+buffer[7] = 0;
+// eslint-disable-next-line no-loss-of-precision
+assert.strictEqual(buffer.readDoubleBE(0), 7.291122019556398e-304);
+assert.strictEqual(buffer.readDoubleLE(0), 5e-324);
+
+buffer[0] = 0xff;
+buffer[1] = 0xff;
+buffer[2] = 0xff;
+buffer[3] = 0xff;
+buffer[4] = 0xff;
+buffer[5] = 0xff;
+buffer[6] = 0x0f;
+buffer[7] = 0x00;
+assert.ok(Number.isNaN(buffer.readDoubleBE(0)));
+assert.strictEqual(buffer.readDoubleLE(0), 2.225073858507201e-308);
+
+buffer[6] = 0xef;
+buffer[7] = 0x7f;
+assert.ok(Number.isNaN(buffer.readDoubleBE(0)));
+assert.strictEqual(buffer.readDoubleLE(0), 1.7976931348623157e+308);
+
+buffer[0] = 0;
+buffer[1] = 0;
+buffer[2] = 0;
+buffer[3] = 0;
+buffer[4] = 0;
+buffer[5] = 0;
+buffer[6] = 0xf0;
+buffer[7] = 0x3f;
+assert.strictEqual(buffer.readDoubleBE(0), 3.03865e-319);
+assert.strictEqual(buffer.readDoubleLE(0), 1);
+
+buffer[6] = 0;
+buffer[7] = 0x40;
+assert.strictEqual(buffer.readDoubleBE(0), 3.16e-322);
+assert.strictEqual(buffer.readDoubleLE(0), 2);
+
+buffer[7] = 0xc0;
+assert.strictEqual(buffer.readDoubleBE(0), 9.5e-322);
+assert.strictEqual(buffer.readDoubleLE(0), -2);
+
+buffer[6] = 0x10;
+buffer[7] = 0;
+assert.strictEqual(buffer.readDoubleBE(0), 2.0237e-320);
+assert.strictEqual(buffer.readDoubleLE(0), 2.2250738585072014e-308);
+
+buffer[6] = 0;
+assert.strictEqual(buffer.readDoubleBE(0), 0);
+assert.strictEqual(buffer.readDoubleLE(0), 0);
+assert.ok(1 / buffer.readDoubleLE(0) >= 0);
+
+buffer[7] = 0x80;
+assert.strictEqual(buffer.readDoubleBE(0), 6.3e-322);
+assert.strictEqual(buffer.readDoubleLE(0), -0);
+assert.ok(1 / buffer.readDoubleLE(0) < 0);
+
+buffer[6] = 0xf0;
+buffer[7] = 0x7f;
+assert.strictEqual(buffer.readDoubleBE(0), 3.0418e-319);
+assert.strictEqual(buffer.readDoubleLE(0), Infinity);
+
+buffer[7] = 0xff;
+assert.strictEqual(buffer.readDoubleBE(0), 3.04814e-319);
+assert.strictEqual(buffer.readDoubleLE(0), -Infinity);
+
+['readDoubleLE', 'readDoubleBE'].forEach((fn) => {
+
+ // Verify that default offset works fine.
+ buffer[fn](undefined);
+ buffer[fn]();
+
+ ['', '0', null, {}, [], () => {}, true, false].forEach((off) => {
+ assert.throws(
+ () => buffer[fn](off),
+ { code: 'ERR_INVALID_ARG_TYPE' }
+ );
+ });
+
+ [Infinity, -1, 1].forEach((offset) => {
+ assert.throws(
+ () => buffer[fn](offset),
+ {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError',
+ message: 'The value of "offset" is out of range. ' +
+ `It must be >= 0 and <= 0. Received ${offset}`
+ });
+ });
+
+ assert.throws(
+ () => Buffer.alloc(1)[fn](1),
+ {
+ code: 'ERR_BUFFER_OUT_OF_BOUNDS',
+ name: 'RangeError',
+ message: 'Attempt to access memory outside buffer bounds'
+ });
+
+ [NaN, 1.01].forEach((offset) => {
+ assert.throws(
+ () => buffer[fn](offset),
+ {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError',
+ message: 'The value of "offset" is out of range. ' +
+ `It must be an integer. Received ${offset}`
+ });
+ });
+});
diff --git a/tests/node_compat/test/parallel/test-buffer-readfloat.js b/tests/node_compat/test/parallel/test-buffer-readfloat.js
new file mode 100644
index 000000000..780d3a6ac
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-buffer-readfloat.js
@@ -0,0 +1,113 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+require('../common');
+const assert = require('assert');
+
+// Test 32 bit float
+const buffer = Buffer.alloc(4);
+
+buffer[0] = 0;
+buffer[1] = 0;
+buffer[2] = 0x80;
+buffer[3] = 0x3f;
+assert.strictEqual(buffer.readFloatBE(0), 4.600602988224807e-41);
+assert.strictEqual(buffer.readFloatLE(0), 1);
+
+buffer[0] = 0;
+buffer[1] = 0;
+buffer[2] = 0;
+buffer[3] = 0xc0;
+assert.strictEqual(buffer.readFloatBE(0), 2.6904930515036488e-43);
+assert.strictEqual(buffer.readFloatLE(0), -2);
+
+buffer[0] = 0xff;
+buffer[1] = 0xff;
+buffer[2] = 0x7f;
+buffer[3] = 0x7f;
+assert.ok(Number.isNaN(buffer.readFloatBE(0)));
+assert.strictEqual(buffer.readFloatLE(0), 3.4028234663852886e+38);
+
+buffer[0] = 0xab;
+buffer[1] = 0xaa;
+buffer[2] = 0xaa;
+buffer[3] = 0x3e;
+assert.strictEqual(buffer.readFloatBE(0), -1.2126478207002966e-12);
+assert.strictEqual(buffer.readFloatLE(0), 0.3333333432674408);
+
+buffer[0] = 0;
+buffer[1] = 0;
+buffer[2] = 0;
+buffer[3] = 0;
+assert.strictEqual(buffer.readFloatBE(0), 0);
+assert.strictEqual(buffer.readFloatLE(0), 0);
+assert.ok(1 / buffer.readFloatLE(0) >= 0);
+
+buffer[3] = 0x80;
+assert.strictEqual(buffer.readFloatBE(0), 1.793662034335766e-43);
+assert.strictEqual(buffer.readFloatLE(0), -0);
+assert.ok(1 / buffer.readFloatLE(0) < 0);
+
+buffer[0] = 0;
+buffer[1] = 0;
+buffer[2] = 0x80;
+buffer[3] = 0x7f;
+assert.strictEqual(buffer.readFloatBE(0), 4.609571298396486e-41);
+assert.strictEqual(buffer.readFloatLE(0), Infinity);
+
+buffer[0] = 0;
+buffer[1] = 0;
+buffer[2] = 0x80;
+buffer[3] = 0xff;
+assert.strictEqual(buffer.readFloatBE(0), 4.627507918739843e-41);
+assert.strictEqual(buffer.readFloatLE(0), -Infinity);
+
+['readFloatLE', 'readFloatBE'].forEach((fn) => {
+
+ // Verify that default offset works fine.
+ buffer[fn](undefined);
+ buffer[fn]();
+
+ ['', '0', null, {}, [], () => {}, true, false].forEach((off) => {
+ assert.throws(
+ () => buffer[fn](off),
+ { code: 'ERR_INVALID_ARG_TYPE' }
+ );
+ });
+
+ [Infinity, -1, 1].forEach((offset) => {
+ assert.throws(
+ () => buffer[fn](offset),
+ {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError',
+ message: 'The value of "offset" is out of range. ' +
+ `It must be >= 0 and <= 0. Received ${offset}`
+ });
+ });
+
+ assert.throws(
+ () => Buffer.alloc(1)[fn](1),
+ {
+ code: 'ERR_BUFFER_OUT_OF_BOUNDS',
+ name: 'RangeError',
+ message: 'Attempt to access memory outside buffer bounds'
+ });
+
+ [NaN, 1.01].forEach((offset) => {
+ assert.throws(
+ () => buffer[fn](offset),
+ {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError',
+ message: 'The value of "offset" is out of range. ' +
+ `It must be an integer. Received ${offset}`
+ });
+ });
+});
diff --git a/tests/node_compat/test/parallel/test-buffer-readint.js b/tests/node_compat/test/parallel/test-buffer-readint.js
new file mode 100644
index 000000000..0c865eb92
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-buffer-readint.js
@@ -0,0 +1,204 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+require('../common');
+const assert = require('assert');
+
+// Test OOB
+{
+ const buffer = Buffer.alloc(4);
+
+ ['Int8', 'Int16BE', 'Int16LE', 'Int32BE', 'Int32LE'].forEach((fn) => {
+
+ // Verify that default offset works fine.
+ buffer[`read${fn}`](undefined);
+ buffer[`read${fn}`]();
+
+ ['', '0', null, {}, [], () => {}, true, false].forEach((o) => {
+ assert.throws(
+ () => buffer[`read${fn}`](o),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError'
+ });
+ });
+
+ [Infinity, -1, -4294967295].forEach((offset) => {
+ assert.throws(
+ () => buffer[`read${fn}`](offset),
+ {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError'
+ });
+ });
+
+ [NaN, 1.01].forEach((offset) => {
+ assert.throws(
+ () => buffer[`read${fn}`](offset),
+ {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError',
+ message: 'The value of "offset" is out of range. ' +
+ `It must be an integer. Received ${offset}`
+ });
+ });
+ });
+}
+
+// Test 8 bit signed integers
+{
+ const data = Buffer.from([0x23, 0xab, 0x7c, 0xef]);
+
+ assert.strictEqual(data.readInt8(0), 0x23);
+
+ data[0] = 0xff;
+ assert.strictEqual(data.readInt8(0), -1);
+
+ data[0] = 0x87;
+ assert.strictEqual(data.readInt8(0), -121);
+ assert.strictEqual(data.readInt8(1), -85);
+ assert.strictEqual(data.readInt8(2), 124);
+ assert.strictEqual(data.readInt8(3), -17);
+}
+
+// Test 16 bit integers
+{
+ const buffer = Buffer.from([0x16, 0x79, 0x65, 0x6e, 0x69, 0x78]);
+
+ assert.strictEqual(buffer.readInt16BE(0), 0x1679);
+ assert.strictEqual(buffer.readInt16LE(0), 0x7916);
+
+ buffer[0] = 0xff;
+ buffer[1] = 0x80;
+ assert.strictEqual(buffer.readInt16BE(0), -128);
+ assert.strictEqual(buffer.readInt16LE(0), -32513);
+
+ buffer[0] = 0x77;
+ buffer[1] = 0x65;
+ assert.strictEqual(buffer.readInt16BE(0), 0x7765);
+ assert.strictEqual(buffer.readInt16BE(1), 0x6565);
+ assert.strictEqual(buffer.readInt16BE(2), 0x656e);
+ assert.strictEqual(buffer.readInt16BE(3), 0x6e69);
+ assert.strictEqual(buffer.readInt16BE(4), 0x6978);
+ assert.strictEqual(buffer.readInt16LE(0), 0x6577);
+ assert.strictEqual(buffer.readInt16LE(1), 0x6565);
+ assert.strictEqual(buffer.readInt16LE(2), 0x6e65);
+ assert.strictEqual(buffer.readInt16LE(3), 0x696e);
+ assert.strictEqual(buffer.readInt16LE(4), 0x7869);
+}
+
+// Test 32 bit integers
+{
+ const buffer = Buffer.from([0x43, 0x53, 0x16, 0x79, 0x36, 0x17]);
+
+ assert.strictEqual(buffer.readInt32BE(0), 0x43531679);
+ assert.strictEqual(buffer.readInt32LE(0), 0x79165343);
+
+ buffer[0] = 0xff;
+ buffer[1] = 0xfe;
+ buffer[2] = 0xef;
+ buffer[3] = 0xfa;
+ assert.strictEqual(buffer.readInt32BE(0), -69638);
+ assert.strictEqual(buffer.readInt32LE(0), -84934913);
+
+ buffer[0] = 0x42;
+ buffer[1] = 0xc3;
+ buffer[2] = 0x95;
+ buffer[3] = 0xa9;
+ assert.strictEqual(buffer.readInt32BE(0), 0x42c395a9);
+ assert.strictEqual(buffer.readInt32BE(1), -1013601994);
+ assert.strictEqual(buffer.readInt32BE(2), -1784072681);
+ assert.strictEqual(buffer.readInt32LE(0), -1449802942);
+ assert.strictEqual(buffer.readInt32LE(1), 917083587);
+ assert.strictEqual(buffer.readInt32LE(2), 389458325);
+}
+
+// Test Int
+{
+ const buffer = Buffer.from([0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]);
+
+ assert.strictEqual(buffer.readIntLE(0, 1), 0x01);
+ assert.strictEqual(buffer.readIntBE(0, 1), 0x01);
+ assert.strictEqual(buffer.readIntLE(0, 3), 0x030201);
+ assert.strictEqual(buffer.readIntBE(0, 3), 0x010203);
+ assert.strictEqual(buffer.readIntLE(0, 5), 0x0504030201);
+ assert.strictEqual(buffer.readIntBE(0, 5), 0x0102030405);
+ assert.strictEqual(buffer.readIntLE(0, 6), 0x060504030201);
+ assert.strictEqual(buffer.readIntBE(0, 6), 0x010203040506);
+ assert.strictEqual(buffer.readIntLE(1, 6), 0x070605040302);
+ assert.strictEqual(buffer.readIntBE(1, 6), 0x020304050607);
+ assert.strictEqual(buffer.readIntLE(2, 6), 0x080706050403);
+ assert.strictEqual(buffer.readIntBE(2, 6), 0x030405060708);
+
+ // Check byteLength.
+ ['readIntBE', 'readIntLE'].forEach((fn) => {
+ ['', '0', null, {}, [], () => {}, true, false, undefined].forEach((len) => {
+ assert.throws(
+ () => buffer[fn](0, len),
+ { code: 'ERR_INVALID_ARG_TYPE' });
+ });
+
+ [Infinity, -1].forEach((byteLength) => {
+ assert.throws(
+ () => buffer[fn](0, byteLength),
+ {
+ code: 'ERR_OUT_OF_RANGE',
+ message: 'The value of "byteLength" is out of range. ' +
+ `It must be >= 1 and <= 6. Received ${byteLength}`
+ });
+ });
+
+ [NaN, 1.01].forEach((byteLength) => {
+ assert.throws(
+ () => buffer[fn](0, byteLength),
+ {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError',
+ message: 'The value of "byteLength" is out of range. ' +
+ `It must be an integer. Received ${byteLength}`
+ });
+ });
+ });
+
+ // Test 1 to 6 bytes.
+ for (let i = 1; i <= 6; i++) {
+ ['readIntBE', 'readIntLE'].forEach((fn) => {
+ ['', '0', null, {}, [], () => {}, true, false, undefined].forEach((o) => {
+ assert.throws(
+ () => buffer[fn](o, i),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError'
+ });
+ });
+
+ [Infinity, -1, -4294967295].forEach((offset) => {
+ assert.throws(
+ () => buffer[fn](offset, i),
+ {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError',
+ message: 'The value of "offset" is out of range. ' +
+ `It must be >= 0 and <= ${8 - i}. Received ${offset}`
+ });
+ });
+
+ [NaN, 1.01].forEach((offset) => {
+ assert.throws(
+ () => buffer[fn](offset, i),
+ {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError',
+ message: 'The value of "offset" is out of range. ' +
+ `It must be an integer. Received ${offset}`
+ });
+ });
+ });
+ }
+}
diff --git a/tests/node_compat/test/parallel/test-buffer-readuint.js b/tests/node_compat/test/parallel/test-buffer-readuint.js
new file mode 100644
index 000000000..bbef6f49a
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-buffer-readuint.js
@@ -0,0 +1,172 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+require('../common');
+const assert = require('assert');
+
+// Test OOB
+{
+ const buffer = Buffer.alloc(4);
+
+ ['UInt8', 'UInt16BE', 'UInt16LE', 'UInt32BE', 'UInt32LE'].forEach((fn) => {
+
+ // Verify that default offset works fine.
+ buffer[`read${fn}`](undefined);
+ buffer[`read${fn}`]();
+
+ ['', '0', null, {}, [], () => {}, true, false].forEach((o) => {
+ assert.throws(
+ () => buffer[`read${fn}`](o),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError'
+ });
+ });
+
+ [Infinity, -1, -4294967295].forEach((offset) => {
+ assert.throws(
+ () => buffer[`read${fn}`](offset),
+ {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError'
+ });
+ });
+
+ [NaN, 1.01].forEach((offset) => {
+ assert.throws(
+ () => buffer[`read${fn}`](offset),
+ {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError',
+ message: 'The value of "offset" is out of range. ' +
+ `It must be an integer. Received ${offset}`
+ });
+ });
+ });
+}
+
+// Test 8 bit unsigned integers
+{
+ const data = Buffer.from([0xff, 0x2a, 0x2a, 0x2a]);
+ assert.strictEqual(data.readUInt8(0), 255);
+ assert.strictEqual(data.readUInt8(1), 42);
+ assert.strictEqual(data.readUInt8(2), 42);
+ assert.strictEqual(data.readUInt8(3), 42);
+}
+
+// Test 16 bit unsigned integers
+{
+ const data = Buffer.from([0x00, 0x2a, 0x42, 0x3f]);
+ assert.strictEqual(data.readUInt16BE(0), 0x2a);
+ assert.strictEqual(data.readUInt16BE(1), 0x2a42);
+ assert.strictEqual(data.readUInt16BE(2), 0x423f);
+ assert.strictEqual(data.readUInt16LE(0), 0x2a00);
+ assert.strictEqual(data.readUInt16LE(1), 0x422a);
+ assert.strictEqual(data.readUInt16LE(2), 0x3f42);
+
+ data[0] = 0xfe;
+ data[1] = 0xfe;
+ assert.strictEqual(data.readUInt16BE(0), 0xfefe);
+ assert.strictEqual(data.readUInt16LE(0), 0xfefe);
+}
+
+// Test 32 bit unsigned integers
+{
+ const data = Buffer.from([0x32, 0x65, 0x42, 0x56, 0x23, 0xff]);
+ assert.strictEqual(data.readUInt32BE(0), 0x32654256);
+ assert.strictEqual(data.readUInt32BE(1), 0x65425623);
+ assert.strictEqual(data.readUInt32BE(2), 0x425623ff);
+ assert.strictEqual(data.readUInt32LE(0), 0x56426532);
+ assert.strictEqual(data.readUInt32LE(1), 0x23564265);
+ assert.strictEqual(data.readUInt32LE(2), 0xff235642);
+}
+
+// Test UInt
+{
+ const buffer = Buffer.from([0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]);
+
+ assert.strictEqual(buffer.readUIntLE(0, 1), 0x01);
+ assert.strictEqual(buffer.readUIntBE(0, 1), 0x01);
+ assert.strictEqual(buffer.readUIntLE(0, 3), 0x030201);
+ assert.strictEqual(buffer.readUIntBE(0, 3), 0x010203);
+ assert.strictEqual(buffer.readUIntLE(0, 5), 0x0504030201);
+ assert.strictEqual(buffer.readUIntBE(0, 5), 0x0102030405);
+ assert.strictEqual(buffer.readUIntLE(0, 6), 0x060504030201);
+ assert.strictEqual(buffer.readUIntBE(0, 6), 0x010203040506);
+ assert.strictEqual(buffer.readUIntLE(1, 6), 0x070605040302);
+ assert.strictEqual(buffer.readUIntBE(1, 6), 0x020304050607);
+ assert.strictEqual(buffer.readUIntLE(2, 6), 0x080706050403);
+ assert.strictEqual(buffer.readUIntBE(2, 6), 0x030405060708);
+
+ // Check byteLength.
+ ['readUIntBE', 'readUIntLE'].forEach((fn) => {
+ ['', '0', null, {}, [], () => {}, true, false, undefined].forEach((len) => {
+ assert.throws(
+ () => buffer[fn](0, len),
+ { code: 'ERR_INVALID_ARG_TYPE' });
+ });
+
+ [Infinity, -1].forEach((byteLength) => {
+ assert.throws(
+ () => buffer[fn](0, byteLength),
+ {
+ code: 'ERR_OUT_OF_RANGE',
+ message: 'The value of "byteLength" is out of range. ' +
+ `It must be >= 1 and <= 6. Received ${byteLength}`
+ });
+ });
+
+ [NaN, 1.01].forEach((byteLength) => {
+ assert.throws(
+ () => buffer[fn](0, byteLength),
+ {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError',
+ message: 'The value of "byteLength" is out of range. ' +
+ `It must be an integer. Received ${byteLength}`
+ });
+ });
+ });
+
+ // Test 1 to 6 bytes.
+ for (let i = 1; i <= 6; i++) {
+ ['readUIntBE', 'readUIntLE'].forEach((fn) => {
+ ['', '0', null, {}, [], () => {}, true, false, undefined].forEach((o) => {
+ assert.throws(
+ () => buffer[fn](o, i),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError'
+ });
+ });
+
+ [Infinity, -1, -4294967295].forEach((offset) => {
+ assert.throws(
+ () => buffer[fn](offset, i),
+ {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError',
+ message: 'The value of "offset" is out of range. ' +
+ `It must be >= 0 and <= ${8 - i}. Received ${offset}`
+ });
+ });
+
+ [NaN, 1.01].forEach((offset) => {
+ assert.throws(
+ () => buffer[fn](offset, i),
+ {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError',
+ message: 'The value of "offset" is out of range. ' +
+ `It must be an integer. Received ${offset}`
+ });
+ });
+ });
+ }
+}
diff --git a/tests/node_compat/test/parallel/test-buffer-safe-unsafe.js b/tests/node_compat/test/parallel/test-buffer-safe-unsafe.js
new file mode 100644
index 000000000..180af8993
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-buffer-safe-unsafe.js
@@ -0,0 +1,31 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+require('../common');
+const assert = require('assert');
+
+const safe = Buffer.alloc(10);
+
+function isZeroFilled(buf) {
+ for (let n = 0; n < buf.length; n++)
+ if (buf[n] !== 0) return false;
+ return true;
+}
+
+assert(isZeroFilled(safe));
+
+// Test that unsafe allocations doesn't affect subsequent safe allocations
+Buffer.allocUnsafe(10);
+assert(isZeroFilled(new Float64Array(10)));
+
+new Buffer(10);
+assert(isZeroFilled(new Float64Array(10)));
+
+Buffer.allocUnsafe(10);
+assert(isZeroFilled(Buffer.alloc(10)));
diff --git a/tests/node_compat/test/parallel/test-buffer-slice.js b/tests/node_compat/test/parallel/test-buffer-slice.js
new file mode 100644
index 000000000..518618d8d
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-buffer-slice.js
@@ -0,0 +1,136 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+
+require('../common');
+const assert = require('assert');
+
+assert.strictEqual(Buffer.from('hello', 'utf8').slice(0, 0).length, 0);
+assert.strictEqual(Buffer('hello', 'utf8').slice(0, 0).length, 0);
+
+const buf = Buffer.from('0123456789', 'utf8');
+const expectedSameBufs = [
+ [buf.slice(-10, 10), Buffer.from('0123456789', 'utf8')],
+ [buf.slice(-20, 10), Buffer.from('0123456789', 'utf8')],
+ [buf.slice(-20, -10), Buffer.from('', 'utf8')],
+ [buf.slice(), Buffer.from('0123456789', 'utf8')],
+ [buf.slice(0), Buffer.from('0123456789', 'utf8')],
+ [buf.slice(0, 0), Buffer.from('', 'utf8')],
+ [buf.slice(undefined), Buffer.from('0123456789', 'utf8')],
+ [buf.slice('foobar'), Buffer.from('0123456789', 'utf8')],
+ [buf.slice(undefined, undefined), Buffer.from('0123456789', 'utf8')],
+ [buf.slice(2), Buffer.from('23456789', 'utf8')],
+ [buf.slice(5), Buffer.from('56789', 'utf8')],
+ [buf.slice(10), Buffer.from('', 'utf8')],
+ [buf.slice(5, 8), Buffer.from('567', 'utf8')],
+ [buf.slice(8, -1), Buffer.from('8', 'utf8')],
+ [buf.slice(-10), Buffer.from('0123456789', 'utf8')],
+ [buf.slice(0, -9), Buffer.from('0', 'utf8')],
+ [buf.slice(0, -10), Buffer.from('', 'utf8')],
+ [buf.slice(0, -1), Buffer.from('012345678', 'utf8')],
+ [buf.slice(2, -2), Buffer.from('234567', 'utf8')],
+ [buf.slice(0, 65536), Buffer.from('0123456789', 'utf8')],
+ [buf.slice(65536, 0), Buffer.from('', 'utf8')],
+ [buf.slice(-5, -8), Buffer.from('', 'utf8')],
+ [buf.slice(-5, -3), Buffer.from('56', 'utf8')],
+ [buf.slice(-10, 10), Buffer.from('0123456789', 'utf8')],
+ [buf.slice('0', '1'), Buffer.from('0', 'utf8')],
+ [buf.slice('-5', '10'), Buffer.from('56789', 'utf8')],
+ [buf.slice('-10', '10'), Buffer.from('0123456789', 'utf8')],
+ [buf.slice('-10', '-5'), Buffer.from('01234', 'utf8')],
+ [buf.slice('-10', '-0'), Buffer.from('', 'utf8')],
+ [buf.slice('111'), Buffer.from('', 'utf8')],
+ [buf.slice('0', '-111'), Buffer.from('', 'utf8')],
+];
+
+for (let i = 0, s = buf.toString(); i < buf.length; ++i) {
+ expectedSameBufs.push(
+ [buf.slice(i), Buffer.from(s.slice(i))],
+ [buf.slice(0, i), Buffer.from(s.slice(0, i))],
+ [buf.slice(-i), Buffer.from(s.slice(-i))],
+ [buf.slice(0, -i), Buffer.from(s.slice(0, -i))]
+ );
+}
+
+expectedSameBufs.forEach(([buf1, buf2]) => {
+ assert.strictEqual(Buffer.compare(buf1, buf2), 0);
+});
+
+const utf16Buf = Buffer.from('0123456789', 'utf16le');
+assert.deepStrictEqual(utf16Buf.slice(0, 6), Buffer.from('012', 'utf16le'));
+// Try to slice a zero length Buffer.
+// See https://github.com/joyent/node/issues/5881
+assert.strictEqual(Buffer.alloc(0).slice(0, 1).length, 0);
+
+{
+ // Single argument slice
+ assert.strictEqual(Buffer.from('abcde', 'utf8').slice(1).toString('utf8'),
+ 'bcde');
+}
+
+// slice(0,0).length === 0
+assert.strictEqual(Buffer.from('hello', 'utf8').slice(0, 0).length, 0);
+
+{
+ // Regression tests for https://github.com/nodejs/node/issues/9096
+ const buf = Buffer.from('abcd', 'utf8');
+ assert.strictEqual(buf.slice(buf.length / 3).toString('utf8'), 'bcd');
+ assert.strictEqual(
+ buf.slice(buf.length / 3, buf.length).toString(),
+ 'bcd'
+ );
+}
+
+{
+ const buf = Buffer.from('abcdefg', 'utf8');
+ assert.strictEqual(buf.slice(-(-1 >>> 0) - 1).toString('utf8'),
+ buf.toString('utf8'));
+}
+
+{
+ const buf = Buffer.from('abc', 'utf8');
+ assert.strictEqual(buf.slice(-0.5).toString('utf8'), buf.toString('utf8'));
+}
+
+{
+ const buf = Buffer.from([
+ 1, 29, 0, 0, 1, 143, 216, 162, 92, 254, 248, 63, 0,
+ 0, 0, 18, 184, 6, 0, 175, 29, 0, 8, 11, 1, 0, 0,
+ ]);
+ const chunk1 = Buffer.from([
+ 1, 29, 0, 0, 1, 143, 216, 162, 92, 254, 248, 63, 0,
+ ]);
+ const chunk2 = Buffer.from([
+ 0, 0, 18, 184, 6, 0, 175, 29, 0, 8, 11, 1, 0, 0,
+ ]);
+ const middle = buf.length / 2;
+
+ assert.deepStrictEqual(buf.slice(0, middle), chunk1);
+ assert.deepStrictEqual(buf.slice(middle), chunk2);
+}
diff --git a/tests/node_compat/test/parallel/test-buffer-slow.js b/tests/node_compat/test/parallel/test-buffer-slow.js
new file mode 100644
index 000000000..eed2898c5
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-buffer-slow.js
@@ -0,0 +1,69 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+require('../common');
+const assert = require('assert');
+const buffer = require('buffer');
+const SlowBuffer = buffer.SlowBuffer;
+
+const ones = [1, 1, 1, 1];
+
+// Should create a Buffer
+let sb = SlowBuffer(4);
+assert(sb instanceof Buffer);
+assert.strictEqual(sb.length, 4);
+sb.fill(1);
+for (const [key, value] of sb.entries()) {
+ assert.deepStrictEqual(value, ones[key]);
+}
+
+// underlying ArrayBuffer should have the same length
+assert.strictEqual(sb.buffer.byteLength, 4);
+
+// Should work without new
+sb = SlowBuffer(4);
+assert(sb instanceof Buffer);
+assert.strictEqual(sb.length, 4);
+sb.fill(1);
+for (const [key, value] of sb.entries()) {
+ assert.deepStrictEqual(value, ones[key]);
+}
+
+// Should work with edge cases
+assert.strictEqual(SlowBuffer(0).length, 0);
+try {
+ assert.strictEqual(
+ SlowBuffer(buffer.kMaxLength).length, buffer.kMaxLength);
+} catch (e) {
+ // Don't match on message as it is from the JavaScript engine. V8 and
+ // ChakraCore provide different messages.
+ assert.strictEqual(e.name, 'RangeError');
+}
+
+// Should throw with invalid length type
+const bufferInvalidTypeMsg = {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: /^The "size" argument must be of type number/,
+};
+assert.throws(() => SlowBuffer(), bufferInvalidTypeMsg);
+assert.throws(() => SlowBuffer({}), bufferInvalidTypeMsg);
+assert.throws(() => SlowBuffer('6'), bufferInvalidTypeMsg);
+assert.throws(() => SlowBuffer(true), bufferInvalidTypeMsg);
+
+// Should throw with invalid length value
+const bufferMaxSizeMsg = {
+ code: 'ERR_INVALID_ARG_VALUE',
+ name: 'RangeError',
+ message: /^The argument 'size' is invalid\. Received [^"]*$/
+};
+assert.throws(() => SlowBuffer(NaN), bufferMaxSizeMsg);
+assert.throws(() => SlowBuffer(Infinity), bufferMaxSizeMsg);
+assert.throws(() => SlowBuffer(-1), bufferMaxSizeMsg);
+assert.throws(() => SlowBuffer(buffer.kMaxLength + 1), bufferMaxSizeMsg);
diff --git a/tests/node_compat/test/parallel/test-buffer-swap.js b/tests/node_compat/test/parallel/test-buffer-swap.js
new file mode 100644
index 000000000..8e1315601
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-buffer-swap.js
@@ -0,0 +1,159 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+require('../common');
+const assert = require('assert');
+
+// Test buffers small enough to use the JS implementation
+{
+ const buf = Buffer.from([0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
+ 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10]);
+
+ assert.strictEqual(buf, buf.swap16());
+ assert.deepStrictEqual(buf, Buffer.from([0x02, 0x01, 0x04, 0x03, 0x06, 0x05,
+ 0x08, 0x07, 0x0a, 0x09, 0x0c, 0x0b,
+ 0x0e, 0x0d, 0x10, 0x0f]));
+ buf.swap16(); // restore
+
+ assert.strictEqual(buf, buf.swap32());
+ assert.deepStrictEqual(buf, Buffer.from([0x04, 0x03, 0x02, 0x01, 0x08, 0x07,
+ 0x06, 0x05, 0x0c, 0x0b, 0x0a, 0x09,
+ 0x10, 0x0f, 0x0e, 0x0d]));
+ buf.swap32(); // restore
+
+ assert.strictEqual(buf, buf.swap64());
+ assert.deepStrictEqual(buf, Buffer.from([0x08, 0x07, 0x06, 0x05, 0x04, 0x03,
+ 0x02, 0x01, 0x10, 0x0f, 0x0e, 0x0d,
+ 0x0c, 0x0b, 0x0a, 0x09]));
+}
+
+// Operates in-place
+{
+ const buf = Buffer.from([0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7]);
+ buf.slice(1, 5).swap32();
+ assert.deepStrictEqual(buf, Buffer.from([0x1, 0x5, 0x4, 0x3, 0x2, 0x6, 0x7]));
+ buf.slice(1, 5).swap16();
+ assert.deepStrictEqual(buf, Buffer.from([0x1, 0x4, 0x5, 0x2, 0x3, 0x6, 0x7]));
+
+ // Length assertions
+ const re16 = /Buffer size must be a multiple of 16-bits/;
+ const re32 = /Buffer size must be a multiple of 32-bits/;
+ const re64 = /Buffer size must be a multiple of 64-bits/;
+
+ assert.throws(() => Buffer.from(buf).swap16(), re16);
+ assert.throws(() => Buffer.alloc(1025).swap16(), re16);
+ assert.throws(() => Buffer.from(buf).swap32(), re32);
+ assert.throws(() => buf.slice(1, 3).swap32(), re32);
+ assert.throws(() => Buffer.alloc(1025).swap32(), re32);
+ assert.throws(() => buf.slice(1, 3).swap64(), re64);
+ assert.throws(() => Buffer.alloc(1025).swap64(), re64);
+}
+
+{
+ const buf = Buffer.from([0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10]);
+
+ buf.slice(2, 18).swap64();
+
+ assert.deepStrictEqual(buf, Buffer.from([0x01, 0x02, 0x0a, 0x09, 0x08, 0x07,
+ 0x06, 0x05, 0x04, 0x03, 0x02, 0x01,
+ 0x10, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b,
+ 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
+ 0x0f, 0x10]));
+}
+
+// Force use of native code (Buffer size above threshold limit for js impl)
+{
+ const bufData = new Uint32Array(256).fill(0x04030201);
+ const buf = Buffer.from(bufData.buffer, bufData.byteOffset);
+ const otherBufData = new Uint32Array(256).fill(0x03040102);
+ const otherBuf = Buffer.from(otherBufData.buffer, otherBufData.byteOffset);
+ buf.swap16();
+ assert.deepStrictEqual(buf, otherBuf);
+}
+
+{
+ const bufData = new Uint32Array(256).fill(0x04030201);
+ const buf = Buffer.from(bufData.buffer);
+ const otherBufData = new Uint32Array(256).fill(0x01020304);
+ const otherBuf = Buffer.from(otherBufData.buffer, otherBufData.byteOffset);
+ buf.swap32();
+ assert.deepStrictEqual(buf, otherBuf);
+}
+
+{
+ const bufData = new Uint8Array(256 * 8);
+ const otherBufData = new Uint8Array(256 * 8);
+ for (let i = 0; i < bufData.length; i++) {
+ bufData[i] = i % 8;
+ otherBufData[otherBufData.length - i - 1] = i % 8;
+ }
+ const buf = Buffer.from(bufData.buffer, bufData.byteOffset);
+ const otherBuf = Buffer.from(otherBufData.buffer, otherBufData.byteOffset);
+ buf.swap64();
+ assert.deepStrictEqual(buf, otherBuf);
+}
+
+// Test native code with buffers that are not memory-aligned
+{
+ const bufData = new Uint8Array(256 * 8);
+ const otherBufData = new Uint8Array(256 * 8 - 2);
+ for (let i = 0; i < bufData.length; i++) {
+ bufData[i] = i % 2;
+ }
+ for (let i = 1; i < otherBufData.length; i++) {
+ otherBufData[otherBufData.length - i] = (i + 1) % 2;
+ }
+ const buf = Buffer.from(bufData.buffer, bufData.byteOffset);
+ // 0|1 0|1 0|1...
+ const otherBuf = Buffer.from(otherBufData.buffer, otherBufData.byteOffset);
+ // 0|0 1|0 1|0...
+
+ buf.slice(1, buf.length - 1).swap16();
+ assert.deepStrictEqual(buf.slice(0, otherBuf.length), otherBuf);
+}
+
+{
+ const bufData = new Uint8Array(256 * 8);
+ const otherBufData = new Uint8Array(256 * 8 - 4);
+ for (let i = 0; i < bufData.length; i++) {
+ bufData[i] = i % 4;
+ }
+ for (let i = 1; i < otherBufData.length; i++) {
+ otherBufData[otherBufData.length - i] = (i + 1) % 4;
+ }
+ const buf = Buffer.from(bufData.buffer, bufData.byteOffset);
+ // 0|1 2 3 0|1 2 3...
+ const otherBuf = Buffer.from(otherBufData.buffer, otherBufData.byteOffset);
+ // 0|0 3 2 1|0 3 2...
+
+ buf.slice(1, buf.length - 3).swap32();
+ assert.deepStrictEqual(buf.slice(0, otherBuf.length), otherBuf);
+}
+
+{
+ const bufData = new Uint8Array(256 * 8);
+ const otherBufData = new Uint8Array(256 * 8 - 8);
+ for (let i = 0; i < bufData.length; i++) {
+ bufData[i] = i % 8;
+ }
+ for (let i = 1; i < otherBufData.length; i++) {
+ otherBufData[otherBufData.length - i] = (i + 1) % 8;
+ }
+ const buf = Buffer.from(bufData.buffer, bufData.byteOffset);
+ // 0|1 2 3 4 5 6 7 0|1 2 3 4...
+ const otherBuf = Buffer.from(otherBufData.buffer, otherBufData.byteOffset);
+ // 0|0 7 6 5 4 3 2 1|0 7 6 5...
+
+ buf.slice(1, buf.length - 7).swap64();
+ assert.deepStrictEqual(buf.slice(0, otherBuf.length), otherBuf);
+}
diff --git a/tests/node_compat/test/parallel/test-buffer-tojson.js b/tests/node_compat/test/parallel/test-buffer-tojson.js
new file mode 100644
index 000000000..d21786c37
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-buffer-tojson.js
@@ -0,0 +1,42 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+require('../common');
+const assert = require('assert');
+
+{
+ assert.strictEqual(JSON.stringify(Buffer.alloc(0)),
+ '{"type":"Buffer","data":[]}');
+ assert.strictEqual(JSON.stringify(Buffer.from([1, 2, 3, 4])),
+ '{"type":"Buffer","data":[1,2,3,4]}');
+}
+
+// issue GH-7849
+{
+ const buf = Buffer.from('test');
+ const json = JSON.stringify(buf);
+ const obj = JSON.parse(json);
+ const copy = Buffer.from(obj);
+
+ assert.deepStrictEqual(buf, copy);
+}
+
+// GH-5110
+{
+ const buffer = Buffer.from('test');
+ const string = JSON.stringify(buffer);
+
+ assert.strictEqual(string, '{"type":"Buffer","data":[116,101,115,116]}');
+
+ function receiver(key, value) {
+ return value && value.type === 'Buffer' ? Buffer.from(value.data) : value;
+ }
+
+ assert.deepStrictEqual(buffer, JSON.parse(string, receiver));
+}
diff --git a/tests/node_compat/test/parallel/test-buffer-tostring-range.js b/tests/node_compat/test/parallel/test-buffer-tostring-range.js
new file mode 100644
index 000000000..9fa199bd5
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-buffer-tostring-range.js
@@ -0,0 +1,107 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+require('../common');
+const assert = require('assert');
+
+const rangeBuffer = Buffer.from('abc');
+
+// If start >= buffer's length, empty string will be returned
+assert.strictEqual(rangeBuffer.toString('ascii', 3), '');
+assert.strictEqual(rangeBuffer.toString('ascii', +Infinity), '');
+assert.strictEqual(rangeBuffer.toString('ascii', 3.14, 3), '');
+assert.strictEqual(rangeBuffer.toString('ascii', 'Infinity', 3), '');
+
+// If end <= 0, empty string will be returned
+assert.strictEqual(rangeBuffer.toString('ascii', 1, 0), '');
+assert.strictEqual(rangeBuffer.toString('ascii', 1, -1.2), '');
+assert.strictEqual(rangeBuffer.toString('ascii', 1, -100), '');
+assert.strictEqual(rangeBuffer.toString('ascii', 1, -Infinity), '');
+
+// If start < 0, start will be taken as zero
+assert.strictEqual(rangeBuffer.toString('ascii', -1, 3), 'abc');
+assert.strictEqual(rangeBuffer.toString('ascii', -1.99, 3), 'abc');
+assert.strictEqual(rangeBuffer.toString('ascii', -Infinity, 3), 'abc');
+assert.strictEqual(rangeBuffer.toString('ascii', '-1', 3), 'abc');
+assert.strictEqual(rangeBuffer.toString('ascii', '-1.99', 3), 'abc');
+assert.strictEqual(rangeBuffer.toString('ascii', '-Infinity', 3), 'abc');
+
+// If start is an invalid integer, start will be taken as zero
+assert.strictEqual(rangeBuffer.toString('ascii', 'node.js', 3), 'abc');
+assert.strictEqual(rangeBuffer.toString('ascii', {}, 3), 'abc');
+assert.strictEqual(rangeBuffer.toString('ascii', [], 3), 'abc');
+assert.strictEqual(rangeBuffer.toString('ascii', NaN, 3), 'abc');
+assert.strictEqual(rangeBuffer.toString('ascii', null, 3), 'abc');
+assert.strictEqual(rangeBuffer.toString('ascii', undefined, 3), 'abc');
+assert.strictEqual(rangeBuffer.toString('ascii', false, 3), 'abc');
+assert.strictEqual(rangeBuffer.toString('ascii', '', 3), 'abc');
+
+// But, if start is an integer when coerced, then it will be coerced and used.
+assert.strictEqual(rangeBuffer.toString('ascii', '-1', 3), 'abc');
+assert.strictEqual(rangeBuffer.toString('ascii', '1', 3), 'bc');
+assert.strictEqual(rangeBuffer.toString('ascii', '-Infinity', 3), 'abc');
+assert.strictEqual(rangeBuffer.toString('ascii', '3', 3), '');
+assert.strictEqual(rangeBuffer.toString('ascii', Number(3), 3), '');
+assert.strictEqual(rangeBuffer.toString('ascii', '3.14', 3), '');
+assert.strictEqual(rangeBuffer.toString('ascii', '1.99', 3), 'bc');
+assert.strictEqual(rangeBuffer.toString('ascii', '-1.99', 3), 'abc');
+assert.strictEqual(rangeBuffer.toString('ascii', 1.99, 3), 'bc');
+assert.strictEqual(rangeBuffer.toString('ascii', true, 3), 'bc');
+
+// If end > buffer's length, end will be taken as buffer's length
+assert.strictEqual(rangeBuffer.toString('ascii', 0, 5), 'abc');
+assert.strictEqual(rangeBuffer.toString('ascii', 0, 6.99), 'abc');
+assert.strictEqual(rangeBuffer.toString('ascii', 0, Infinity), 'abc');
+assert.strictEqual(rangeBuffer.toString('ascii', 0, '5'), 'abc');
+assert.strictEqual(rangeBuffer.toString('ascii', 0, '6.99'), 'abc');
+assert.strictEqual(rangeBuffer.toString('ascii', 0, 'Infinity'), 'abc');
+
+// If end is an invalid integer, end will be taken as buffer's length
+assert.strictEqual(rangeBuffer.toString('ascii', 0, 'node.js'), '');
+assert.strictEqual(rangeBuffer.toString('ascii', 0, {}), '');
+assert.strictEqual(rangeBuffer.toString('ascii', 0, NaN), '');
+assert.strictEqual(rangeBuffer.toString('ascii', 0, undefined), 'abc');
+assert.strictEqual(rangeBuffer.toString('ascii', 0), 'abc');
+assert.strictEqual(rangeBuffer.toString('ascii', 0, null), '');
+assert.strictEqual(rangeBuffer.toString('ascii', 0, []), '');
+assert.strictEqual(rangeBuffer.toString('ascii', 0, false), '');
+assert.strictEqual(rangeBuffer.toString('ascii', 0, ''), '');
+
+// But, if end is an integer when coerced, then it will be coerced and used.
+assert.strictEqual(rangeBuffer.toString('ascii', 0, '-1'), '');
+assert.strictEqual(rangeBuffer.toString('ascii', 0, '1'), 'a');
+assert.strictEqual(rangeBuffer.toString('ascii', 0, '-Infinity'), '');
+assert.strictEqual(rangeBuffer.toString('ascii', 0, '3'), 'abc');
+assert.strictEqual(rangeBuffer.toString('ascii', 0, Number(3)), 'abc');
+assert.strictEqual(rangeBuffer.toString('ascii', 0, '3.14'), 'abc');
+assert.strictEqual(rangeBuffer.toString('ascii', 0, '1.99'), 'a');
+assert.strictEqual(rangeBuffer.toString('ascii', 0, '-1.99'), '');
+assert.strictEqual(rangeBuffer.toString('ascii', 0, 1.99), 'a');
+assert.strictEqual(rangeBuffer.toString('ascii', 0, true), 'a');
+
+// Try toString() with an object as an encoding
+assert.strictEqual(rangeBuffer.toString({ toString: function() {
+ return 'ascii';
+} }), 'abc');
+
+// Try toString() with 0 and null as the encoding
+assert.throws(() => {
+ rangeBuffer.toString(0, 1, 2);
+}, {
+ code: 'ERR_UNKNOWN_ENCODING',
+ name: 'TypeError',
+ message: 'Unknown encoding: 0'
+});
+assert.throws(() => {
+ rangeBuffer.toString(null, 1, 2);
+}, {
+ code: 'ERR_UNKNOWN_ENCODING',
+ name: 'TypeError',
+ message: 'Unknown encoding: null'
+});
diff --git a/tests/node_compat/test/parallel/test-buffer-tostring-rangeerror.js b/tests/node_compat/test/parallel/test-buffer-tostring-rangeerror.js
new file mode 100644
index 000000000..793d2d891
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-buffer-tostring-rangeerror.js
@@ -0,0 +1,28 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+require('../common');
+
+// This test ensures that Node.js throws a RangeError when trying to convert a
+// gigantic buffer into a string.
+// Regression test for https://github.com/nodejs/node/issues/649.
+
+const assert = require('assert');
+const SlowBuffer = require('buffer').SlowBuffer;
+
+const len = 1422561062959;
+const message = {
+ code: 'ERR_INVALID_ARG_VALUE',
+ name: 'RangeError',
+ message: /^The argument 'size' is invalid\. Received [^"]*$/
+};
+assert.throws(() => Buffer(len).toString('utf8'), message);
+assert.throws(() => SlowBuffer(len).toString('utf8'), message);
+assert.throws(() => Buffer.alloc(len).toString('utf8'), message);
+assert.throws(() => Buffer.allocUnsafe(len).toString('utf8'), message);
+assert.throws(() => Buffer.allocUnsafeSlow(len).toString('utf8'), message);
diff --git a/tests/node_compat/test/parallel/test-buffer-tostring.js b/tests/node_compat/test/parallel/test-buffer-tostring.js
new file mode 100644
index 000000000..a6f5cabe0
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-buffer-tostring.js
@@ -0,0 +1,44 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const assert = require('assert');
+
+// utf8, ucs2, ascii, latin1, utf16le
+const encodings = ['utf8', 'utf-8', 'ucs2', 'ucs-2', 'ascii', 'latin1',
+ 'binary', 'utf16le', 'utf-16le'];
+
+encodings
+ .reduce((es, e) => es.concat(e, e.toUpperCase()), [])
+ .forEach((encoding) => {
+ assert.strictEqual(Buffer.from('foo', encoding).toString(encoding), 'foo');
+ });
+
+// base64
+['base64', 'BASE64'].forEach((encoding) => {
+ assert.strictEqual(Buffer.from('Zm9v', encoding).toString(encoding), 'Zm9v');
+});
+
+// hex
+['hex', 'HEX'].forEach((encoding) => {
+ assert.strictEqual(Buffer.from('666f6f', encoding).toString(encoding),
+ '666f6f');
+});
+
+// Invalid encodings
+for (let i = 1; i < 10; i++) {
+ const encoding = String(i).repeat(i);
+ const error = common.expectsError({
+ code: 'ERR_UNKNOWN_ENCODING',
+ name: 'TypeError',
+ message: `Unknown encoding: ${encoding}`
+ });
+ assert.ok(!Buffer.isEncoding(encoding));
+ assert.throws(() => Buffer.from('foo').toString(encoding), error);
+}
diff --git a/tests/node_compat/test/parallel/test-buffer-writedouble.js b/tests/node_compat/test/parallel/test-buffer-writedouble.js
new file mode 100644
index 000000000..3e4d4e676
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-buffer-writedouble.js
@@ -0,0 +1,140 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+// Tests to verify doubles are correctly written
+
+require('../common');
+const assert = require('assert');
+
+const buffer = Buffer.allocUnsafe(16);
+
+buffer.writeDoubleBE(2.225073858507201e-308, 0);
+buffer.writeDoubleLE(2.225073858507201e-308, 8);
+assert.ok(buffer.equals(new Uint8Array([
+ 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00,
+])));
+
+buffer.writeDoubleBE(1.0000000000000004, 0);
+buffer.writeDoubleLE(1.0000000000000004, 8);
+assert.ok(buffer.equals(new Uint8Array([
+ 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f,
+])));
+
+buffer.writeDoubleBE(-2, 0);
+buffer.writeDoubleLE(-2, 8);
+assert.ok(buffer.equals(new Uint8Array([
+ 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
+])));
+
+buffer.writeDoubleBE(1.7976931348623157e+308, 0);
+buffer.writeDoubleLE(1.7976931348623157e+308, 8);
+assert.ok(buffer.equals(new Uint8Array([
+ 0x7f, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0x7f,
+])));
+
+buffer.writeDoubleBE(0 * -1, 0);
+buffer.writeDoubleLE(0 * -1, 8);
+assert.ok(buffer.equals(new Uint8Array([
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+])));
+
+buffer.writeDoubleBE(Infinity, 0);
+buffer.writeDoubleLE(Infinity, 8);
+
+assert.ok(buffer.equals(new Uint8Array([
+ 0x7F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x7F,
+])));
+
+assert.strictEqual(buffer.readDoubleBE(0), Infinity);
+assert.strictEqual(buffer.readDoubleLE(8), Infinity);
+
+buffer.writeDoubleBE(-Infinity, 0);
+buffer.writeDoubleLE(-Infinity, 8);
+
+assert.ok(buffer.equals(new Uint8Array([
+ 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF,
+])));
+
+assert.strictEqual(buffer.readDoubleBE(0), -Infinity);
+assert.strictEqual(buffer.readDoubleLE(8), -Infinity);
+
+buffer.writeDoubleBE(NaN, 0);
+buffer.writeDoubleLE(NaN, 8);
+
+// JS only knows a single NaN but there exist two platform specific
+// implementations. Therefore, allow both quiet and signalling NaNs.
+if (buffer[1] === 0xF7) {
+ assert.ok(buffer.equals(new Uint8Array([
+ 0x7F, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0x7F,
+ ])));
+} else {
+ assert.ok(buffer.equals(new Uint8Array([
+ 0x7F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x7F,
+ ])));
+}
+
+assert.ok(Number.isNaN(buffer.readDoubleBE(0)));
+assert.ok(Number.isNaN(buffer.readDoubleLE(8)));
+
+// OOB in writeDouble{LE,BE} should throw.
+{
+ const small = Buffer.allocUnsafe(1);
+
+ ['writeDoubleLE', 'writeDoubleBE'].forEach((fn) => {
+
+ // Verify that default offset works fine.
+ buffer[fn](23, undefined);
+ buffer[fn](23);
+
+ assert.throws(
+ () => small[fn](11.11, 0),
+ {
+ code: 'ERR_BUFFER_OUT_OF_BOUNDS',
+ name: 'RangeError',
+ message: 'Attempt to access memory outside buffer bounds'
+ });
+
+ ['', '0', null, {}, [], () => {}, true, false].forEach((off) => {
+ assert.throws(
+ () => small[fn](23, off),
+ { code: 'ERR_INVALID_ARG_TYPE' });
+ });
+
+ [Infinity, -1, 9].forEach((offset) => {
+ assert.throws(
+ () => buffer[fn](23, offset),
+ {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError',
+ message: 'The value of "offset" is out of range. ' +
+ `It must be >= 0 and <= 8. Received ${offset}`
+ });
+ });
+
+ [NaN, 1.01].forEach((offset) => {
+ assert.throws(
+ () => buffer[fn](42, offset),
+ {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError',
+ message: 'The value of "offset" is out of range. ' +
+ `It must be an integer. Received ${offset}`
+ });
+ });
+ });
+}
diff --git a/tests/node_compat/test/parallel/test-buffer-writefloat.js b/tests/node_compat/test/parallel/test-buffer-writefloat.js
new file mode 100644
index 000000000..4dd75f83e
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-buffer-writefloat.js
@@ -0,0 +1,124 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+// Tests to verify floats are correctly written
+
+require('../common');
+const assert = require('assert');
+
+const buffer = Buffer.allocUnsafe(8);
+
+buffer.writeFloatBE(1, 0);
+buffer.writeFloatLE(1, 4);
+assert.ok(buffer.equals(
+ new Uint8Array([ 0x3f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f ])));
+
+buffer.writeFloatBE(1 / 3, 0);
+buffer.writeFloatLE(1 / 3, 4);
+assert.ok(buffer.equals(
+ new Uint8Array([ 0x3e, 0xaa, 0xaa, 0xab, 0xab, 0xaa, 0xaa, 0x3e ])));
+
+buffer.writeFloatBE(3.4028234663852886e+38, 0);
+buffer.writeFloatLE(3.4028234663852886e+38, 4);
+assert.ok(buffer.equals(
+ new Uint8Array([ 0x7f, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x7f ])));
+
+buffer.writeFloatLE(1.1754943508222875e-38, 0);
+buffer.writeFloatBE(1.1754943508222875e-38, 4);
+assert.ok(buffer.equals(
+ new Uint8Array([ 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00 ])));
+
+buffer.writeFloatBE(0 * -1, 0);
+buffer.writeFloatLE(0 * -1, 4);
+assert.ok(buffer.equals(
+ new Uint8Array([ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 ])));
+
+buffer.writeFloatBE(Infinity, 0);
+buffer.writeFloatLE(Infinity, 4);
+assert.ok(buffer.equals(
+ new Uint8Array([ 0x7F, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x7F ])));
+
+assert.strictEqual(buffer.readFloatBE(0), Infinity);
+assert.strictEqual(buffer.readFloatLE(4), Infinity);
+
+buffer.writeFloatBE(-Infinity, 0);
+buffer.writeFloatLE(-Infinity, 4);
+assert.ok(buffer.equals(
+ new Uint8Array([ 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF ])));
+
+assert.strictEqual(buffer.readFloatBE(0), -Infinity);
+assert.strictEqual(buffer.readFloatLE(4), -Infinity);
+
+buffer.writeFloatBE(NaN, 0);
+buffer.writeFloatLE(NaN, 4);
+
+// JS only knows a single NaN but there exist two platform specific
+// implementations. Therefore, allow both quiet and signalling NaNs.
+if (buffer[1] === 0xBF) {
+ assert.ok(
+ buffer.equals(new Uint8Array(
+ [ 0x7F, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0x7F ])));
+} else {
+ assert.ok(
+ buffer.equals(new Uint8Array(
+ [ 0x7F, 0xC0, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x7F ])));
+}
+
+assert.ok(Number.isNaN(buffer.readFloatBE(0)));
+assert.ok(Number.isNaN(buffer.readFloatLE(4)));
+
+// OOB in writeFloat{LE,BE} should throw.
+{
+ const small = Buffer.allocUnsafe(1);
+
+ ['writeFloatLE', 'writeFloatBE'].forEach((fn) => {
+
+ // Verify that default offset works fine.
+ buffer[fn](23, undefined);
+ buffer[fn](23);
+
+ assert.throws(
+ () => small[fn](11.11, 0),
+ {
+ code: 'ERR_BUFFER_OUT_OF_BOUNDS',
+ name: 'RangeError',
+ message: 'Attempt to access memory outside buffer bounds'
+ });
+
+ ['', '0', null, {}, [], () => {}, true, false].forEach((off) => {
+ assert.throws(
+ () => small[fn](23, off),
+ { code: 'ERR_INVALID_ARG_TYPE' }
+ );
+ });
+
+ [Infinity, -1, 5].forEach((offset) => {
+ assert.throws(
+ () => buffer[fn](23, offset),
+ {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError',
+ message: 'The value of "offset" is out of range. ' +
+ `It must be >= 0 and <= 4. Received ${offset}`
+ }
+ );
+ });
+
+ [NaN, 1.01].forEach((offset) => {
+ assert.throws(
+ () => buffer[fn](42, offset),
+ {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError',
+ message: 'The value of "offset" is out of range. ' +
+ `It must be an integer. Received ${offset}`
+ });
+ });
+ });
+}
diff --git a/tests/node_compat/test/parallel/test-buffer-writeint.js b/tests/node_compat/test/parallel/test-buffer-writeint.js
new file mode 100644
index 000000000..117ba47c0
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-buffer-writeint.js
@@ -0,0 +1,277 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+// Tests to verify signed integers are correctly written
+
+require('../common');
+const assert = require('assert');
+const errorOutOfBounds = {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError',
+ message: new RegExp('^The value of "value" is out of range\\. ' +
+ 'It must be >= -\\d+ and <= \\d+\\. Received .+$')
+};
+
+// Test 8 bit
+{
+ const buffer = Buffer.alloc(2);
+
+ buffer.writeInt8(0x23, 0);
+ buffer.writeInt8(-5, 1);
+ assert.ok(buffer.equals(new Uint8Array([ 0x23, 0xfb ])));
+
+ /* Make sure we handle min/max correctly */
+ buffer.writeInt8(0x7f, 0);
+ buffer.writeInt8(-0x80, 1);
+ assert.ok(buffer.equals(new Uint8Array([ 0x7f, 0x80 ])));
+
+ assert.throws(() => {
+ buffer.writeInt8(0x7f + 1, 0);
+ }, errorOutOfBounds);
+ assert.throws(() => {
+ buffer.writeInt8(-0x80 - 1, 0);
+ }, errorOutOfBounds);
+
+ // Verify that default offset works fine.
+ buffer.writeInt8(23, undefined);
+ buffer.writeInt8(23);
+
+ ['', '0', null, {}, [], () => {}, true, false].forEach((off) => {
+ assert.throws(
+ () => buffer.writeInt8(23, off),
+ { code: 'ERR_INVALID_ARG_TYPE' });
+ });
+
+ [NaN, Infinity, -1, 1.01].forEach((off) => {
+ assert.throws(
+ () => buffer.writeInt8(23, off),
+ { code: 'ERR_OUT_OF_RANGE' });
+ });
+}
+
+// Test 16 bit
+{
+ const buffer = Buffer.alloc(4);
+
+ buffer.writeInt16BE(0x0023, 0);
+ buffer.writeInt16LE(0x0023, 2);
+ assert.ok(buffer.equals(new Uint8Array([ 0x00, 0x23, 0x23, 0x00 ])));
+
+ buffer.writeInt16BE(-5, 0);
+ buffer.writeInt16LE(-5, 2);
+ assert.ok(buffer.equals(new Uint8Array([ 0xff, 0xfb, 0xfb, 0xff ])));
+
+ buffer.writeInt16BE(-1679, 0);
+ buffer.writeInt16LE(-1679, 2);
+ assert.ok(buffer.equals(new Uint8Array([ 0xf9, 0x71, 0x71, 0xf9 ])));
+
+ /* Make sure we handle min/max correctly */
+ buffer.writeInt16BE(0x7fff, 0);
+ buffer.writeInt16BE(-0x8000, 2);
+ assert.ok(buffer.equals(new Uint8Array([ 0x7f, 0xff, 0x80, 0x00 ])));
+
+ buffer.writeInt16LE(0x7fff, 0);
+ buffer.writeInt16LE(-0x8000, 2);
+ assert.ok(buffer.equals(new Uint8Array([ 0xff, 0x7f, 0x00, 0x80 ])));
+
+ ['writeInt16BE', 'writeInt16LE'].forEach((fn) => {
+
+ // Verify that default offset works fine.
+ buffer[fn](23, undefined);
+ buffer[fn](23);
+
+ assert.throws(() => {
+ buffer[fn](0x7fff + 1, 0);
+ }, errorOutOfBounds);
+ assert.throws(() => {
+ buffer[fn](-0x8000 - 1, 0);
+ }, errorOutOfBounds);
+
+ ['', '0', null, {}, [], () => {}, true, false].forEach((off) => {
+ assert.throws(
+ () => buffer[fn](23, off),
+ { code: 'ERR_INVALID_ARG_TYPE' });
+ });
+
+ [NaN, Infinity, -1, 1.01].forEach((off) => {
+ assert.throws(
+ () => buffer[fn](23, off),
+ { code: 'ERR_OUT_OF_RANGE' });
+ });
+ });
+}
+
+// Test 32 bit
+{
+ const buffer = Buffer.alloc(8);
+
+ buffer.writeInt32BE(0x23, 0);
+ buffer.writeInt32LE(0x23, 4);
+ assert.ok(buffer.equals(new Uint8Array([
+ 0x00, 0x00, 0x00, 0x23, 0x23, 0x00, 0x00, 0x00,
+ ])));
+
+ buffer.writeInt32BE(-5, 0);
+ buffer.writeInt32LE(-5, 4);
+ assert.ok(buffer.equals(new Uint8Array([
+ 0xff, 0xff, 0xff, 0xfb, 0xfb, 0xff, 0xff, 0xff,
+ ])));
+
+ buffer.writeInt32BE(-805306713, 0);
+ buffer.writeInt32LE(-805306713, 4);
+ assert.ok(buffer.equals(new Uint8Array([
+ 0xcf, 0xff, 0xfe, 0xa7, 0xa7, 0xfe, 0xff, 0xcf,
+ ])));
+
+ /* Make sure we handle min/max correctly */
+ buffer.writeInt32BE(0x7fffffff, 0);
+ buffer.writeInt32BE(-0x80000000, 4);
+ assert.ok(buffer.equals(new Uint8Array([
+ 0x7f, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00,
+ ])));
+
+ buffer.writeInt32LE(0x7fffffff, 0);
+ buffer.writeInt32LE(-0x80000000, 4);
+ assert.ok(buffer.equals(new Uint8Array([
+ 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x80,
+ ])));
+
+ ['writeInt32BE', 'writeInt32LE'].forEach((fn) => {
+
+ // Verify that default offset works fine.
+ buffer[fn](23, undefined);
+ buffer[fn](23);
+
+ assert.throws(() => {
+ buffer[fn](0x7fffffff + 1, 0);
+ }, errorOutOfBounds);
+ assert.throws(() => {
+ buffer[fn](-0x80000000 - 1, 0);
+ }, errorOutOfBounds);
+
+ ['', '0', null, {}, [], () => {}, true, false].forEach((off) => {
+ assert.throws(
+ () => buffer[fn](23, off),
+ { code: 'ERR_INVALID_ARG_TYPE' });
+ });
+
+ [NaN, Infinity, -1, 1.01].forEach((off) => {
+ assert.throws(
+ () => buffer[fn](23, off),
+ { code: 'ERR_OUT_OF_RANGE' });
+ });
+ });
+}
+
+// Test 48 bit
+{
+ const value = 0x1234567890ab;
+ const buffer = Buffer.allocUnsafe(6);
+ buffer.writeIntBE(value, 0, 6);
+ assert.ok(buffer.equals(new Uint8Array([
+ 0x12, 0x34, 0x56, 0x78, 0x90, 0xab,
+ ])));
+
+ buffer.writeIntLE(value, 0, 6);
+ assert.ok(buffer.equals(new Uint8Array([
+ 0xab, 0x90, 0x78, 0x56, 0x34, 0x12,
+ ])));
+}
+
+// Test Int
+{
+ const data = Buffer.alloc(8);
+
+ // Check byteLength.
+ ['writeIntBE', 'writeIntLE'].forEach((fn) => {
+ ['', '0', null, {}, [], () => {}, true, false, undefined].forEach((bl) => {
+ assert.throws(
+ () => data[fn](23, 0, bl),
+ { code: 'ERR_INVALID_ARG_TYPE' });
+ });
+
+ [Infinity, -1].forEach((byteLength) => {
+ assert.throws(
+ () => data[fn](23, 0, byteLength),
+ {
+ code: 'ERR_OUT_OF_RANGE',
+ message: 'The value of "byteLength" is out of range. ' +
+ `It must be >= 1 and <= 6. Received ${byteLength}`
+ }
+ );
+ });
+
+ [NaN, 1.01].forEach((byteLength) => {
+ assert.throws(
+ () => data[fn](42, 0, byteLength),
+ {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError',
+ message: 'The value of "byteLength" is out of range. ' +
+ `It must be an integer. Received ${byteLength}`
+ });
+ });
+ });
+
+ // Test 1 to 6 bytes.
+ for (let i = 1; i <= 6; i++) {
+ ['writeIntBE', 'writeIntLE'].forEach((fn) => {
+ const min = -(2 ** (i * 8 - 1));
+ const max = 2 ** (i * 8 - 1) - 1;
+ let range = `>= ${min} and <= ${max}`;
+ if (i > 4) {
+ range = `>= -(2 ** ${i * 8 - 1}) and < 2 ** ${i * 8 - 1}`;
+ }
+ [min - 1, max + 1].forEach((val) => {
+ const received = i > 4 ?
+ String(val).replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1_') :
+ val;
+ assert.throws(() => {
+ data[fn](val, 0, i);
+ }, {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError',
+ message: 'The value of "value" is out of range. ' +
+ `It must be ${range}. Received ${received}`
+ });
+ });
+
+ ['', '0', null, {}, [], () => {}, true, false, undefined].forEach((o) => {
+ assert.throws(
+ () => data[fn](min, o, i),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError'
+ });
+ });
+
+ [Infinity, -1, -4294967295].forEach((offset) => {
+ assert.throws(
+ () => data[fn](min, offset, i),
+ {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError',
+ message: 'The value of "offset" is out of range. ' +
+ `It must be >= 0 and <= ${8 - i}. Received ${offset}`
+ });
+ });
+
+ [NaN, 1.01].forEach((offset) => {
+ assert.throws(
+ () => data[fn](max, offset, i),
+ {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError',
+ message: 'The value of "offset" is out of range. ' +
+ `It must be an integer. Received ${offset}`
+ });
+ });
+ });
+ }
+}
diff --git a/tests/node_compat/test/parallel/test-buffer-writeuint.js b/tests/node_compat/test/parallel/test-buffer-writeuint.js
new file mode 100644
index 000000000..1c954bb9f
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-buffer-writeuint.js
@@ -0,0 +1,237 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+require('../common');
+const assert = require('assert');
+
+// We need to check the following things:
+// - We are correctly resolving big endian (doesn't mean anything for 8 bit)
+// - Correctly resolving little endian (doesn't mean anything for 8 bit)
+// - Correctly using the offsets
+// - Correctly interpreting values that are beyond the signed range as unsigned
+
+{ // OOB
+ const data = Buffer.alloc(8);
+ ['UInt8', 'UInt16BE', 'UInt16LE', 'UInt32BE', 'UInt32LE'].forEach((fn) => {
+
+ // Verify that default offset works fine.
+ data[`write${fn}`](23, undefined);
+ data[`write${fn}`](23);
+
+ ['', '0', null, {}, [], () => {}, true, false].forEach((o) => {
+ assert.throws(
+ () => data[`write${fn}`](23, o),
+ { code: 'ERR_INVALID_ARG_TYPE' });
+ });
+
+ [NaN, Infinity, -1, 1.01].forEach((o) => {
+ assert.throws(
+ () => data[`write${fn}`](23, o),
+ { code: 'ERR_OUT_OF_RANGE' });
+ });
+ });
+}
+
+{ // Test 8 bit
+ const data = Buffer.alloc(4);
+
+ data.writeUInt8(23, 0);
+ data.writeUInt8(23, 1);
+ data.writeUInt8(23, 2);
+ data.writeUInt8(23, 3);
+ assert.ok(data.equals(new Uint8Array([23, 23, 23, 23])));
+
+ data.writeUInt8(23, 0);
+ data.writeUInt8(23, 1);
+ data.writeUInt8(23, 2);
+ data.writeUInt8(23, 3);
+ assert.ok(data.equals(new Uint8Array([23, 23, 23, 23])));
+
+ data.writeUInt8(255, 0);
+ assert.strictEqual(data[0], 255);
+
+ data.writeUInt8(255, 0);
+ assert.strictEqual(data[0], 255);
+}
+
+// Test 16 bit
+{
+ let value = 0x2343;
+ const data = Buffer.alloc(4);
+
+ data.writeUInt16BE(value, 0);
+ assert.ok(data.equals(new Uint8Array([0x23, 0x43, 0, 0])));
+
+ data.writeUInt16BE(value, 1);
+ assert.ok(data.equals(new Uint8Array([0x23, 0x23, 0x43, 0])));
+
+ data.writeUInt16BE(value, 2);
+ assert.ok(data.equals(new Uint8Array([0x23, 0x23, 0x23, 0x43])));
+
+ data.writeUInt16LE(value, 0);
+ assert.ok(data.equals(new Uint8Array([0x43, 0x23, 0x23, 0x43])));
+
+ data.writeUInt16LE(value, 1);
+ assert.ok(data.equals(new Uint8Array([0x43, 0x43, 0x23, 0x43])));
+
+ data.writeUInt16LE(value, 2);
+ assert.ok(data.equals(new Uint8Array([0x43, 0x43, 0x43, 0x23])));
+
+ value = 0xff80;
+ data.writeUInt16LE(value, 0);
+ assert.ok(data.equals(new Uint8Array([0x80, 0xff, 0x43, 0x23])));
+
+ data.writeUInt16BE(value, 0);
+ assert.ok(data.equals(new Uint8Array([0xff, 0x80, 0x43, 0x23])));
+
+ value = 0xfffff;
+ ['writeUInt16BE', 'writeUInt16LE'].forEach((fn) => {
+ assert.throws(
+ () => data[fn](value, 0),
+ {
+ code: 'ERR_OUT_OF_RANGE',
+ message: 'The value of "value" is out of range. ' +
+ `It must be >= 0 and <= 65535. Received ${value}`
+ }
+ );
+ });
+}
+
+// Test 32 bit
+{
+ const data = Buffer.alloc(6);
+ const value = 0xe7f90a6d;
+
+ data.writeUInt32BE(value, 0);
+ assert.ok(data.equals(new Uint8Array([0xe7, 0xf9, 0x0a, 0x6d, 0, 0])));
+
+ data.writeUInt32BE(value, 1);
+ assert.ok(data.equals(new Uint8Array([0xe7, 0xe7, 0xf9, 0x0a, 0x6d, 0])));
+
+ data.writeUInt32BE(value, 2);
+ assert.ok(data.equals(new Uint8Array([0xe7, 0xe7, 0xe7, 0xf9, 0x0a, 0x6d])));
+
+ data.writeUInt32LE(value, 0);
+ assert.ok(data.equals(new Uint8Array([0x6d, 0x0a, 0xf9, 0xe7, 0x0a, 0x6d])));
+
+ data.writeUInt32LE(value, 1);
+ assert.ok(data.equals(new Uint8Array([0x6d, 0x6d, 0x0a, 0xf9, 0xe7, 0x6d])));
+
+ data.writeUInt32LE(value, 2);
+ assert.ok(data.equals(new Uint8Array([0x6d, 0x6d, 0x6d, 0x0a, 0xf9, 0xe7])));
+}
+
+// Test 48 bit
+{
+ const value = 0x1234567890ab;
+ const data = Buffer.allocUnsafe(6);
+ data.writeUIntBE(value, 0, 6);
+ assert.ok(data.equals(new Uint8Array([0x12, 0x34, 0x56, 0x78, 0x90, 0xab])));
+
+ data.writeUIntLE(value, 0, 6);
+ assert.ok(data.equals(new Uint8Array([0xab, 0x90, 0x78, 0x56, 0x34, 0x12])));
+}
+
+// Test UInt
+{
+ const data = Buffer.alloc(8);
+ let val = 0x100;
+
+ // Check byteLength.
+ ['writeUIntBE', 'writeUIntLE'].forEach((fn) => {
+ ['', '0', null, {}, [], () => {}, true, false, undefined].forEach((bl) => {
+ assert.throws(
+ () => data[fn](23, 0, bl),
+ { code: 'ERR_INVALID_ARG_TYPE' });
+ });
+
+ [Infinity, -1].forEach((byteLength) => {
+ assert.throws(
+ () => data[fn](23, 0, byteLength),
+ {
+ code: 'ERR_OUT_OF_RANGE',
+ message: 'The value of "byteLength" is out of range. ' +
+ `It must be >= 1 and <= 6. Received ${byteLength}`
+ }
+ );
+ });
+
+ [NaN, 1.01].forEach((byteLength) => {
+ assert.throws(
+ () => data[fn](42, 0, byteLength),
+ {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError',
+ message: 'The value of "byteLength" is out of range. ' +
+ `It must be an integer. Received ${byteLength}`
+ });
+ });
+ });
+
+ // Test 1 to 6 bytes.
+ for (let i = 1; i <= 6; i++) {
+ const range = i < 5 ? `= ${val - 1}` : ` 2 ** ${i * 8}`;
+ const received = i > 4 ?
+ String(val).replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1_') :
+ val;
+ ['writeUIntBE', 'writeUIntLE'].forEach((fn) => {
+ assert.throws(() => {
+ data[fn](val, 0, i);
+ }, {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError',
+ message: 'The value of "value" is out of range. ' +
+ `It must be >= 0 and <${range}. Received ${received}`
+ });
+
+ ['', '0', null, {}, [], () => {}, true, false].forEach((o) => {
+ assert.throws(
+ () => data[fn](23, o, i),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError'
+ });
+ });
+
+ [Infinity, -1, -4294967295].forEach((offset) => {
+ assert.throws(
+ () => data[fn](val - 1, offset, i),
+ {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError',
+ message: 'The value of "offset" is out of range. ' +
+ `It must be >= 0 and <= ${8 - i}. Received ${offset}`
+ });
+ });
+
+ [NaN, 1.01].forEach((offset) => {
+ assert.throws(
+ () => data[fn](val - 1, offset, i),
+ {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError',
+ message: 'The value of "offset" is out of range. ' +
+ `It must be an integer. Received ${offset}`
+ });
+ });
+ });
+
+ val *= 0x100;
+ }
+}
+
+for (const fn of [
+ 'UInt8', 'UInt16LE', 'UInt16BE', 'UInt32LE', 'UInt32BE', 'UIntLE', 'UIntBE',
+ 'BigUInt64LE', 'BigUInt64BE',
+]) {
+ const p = Buffer.prototype;
+ const lowerFn = fn.replace(/UInt/, 'Uint');
+ assert.strictEqual(p[`write${fn}`], p[`write${lowerFn}`]);
+ assert.strictEqual(p[`read${fn}`], p[`read${lowerFn}`]);
+}
diff --git a/tests/node_compat/test/parallel/test-buffer-zero-fill-cli.js b/tests/node_compat/test/parallel/test-buffer-zero-fill-cli.js
new file mode 100644
index 000000000..c3250b870
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-buffer-zero-fill-cli.js
@@ -0,0 +1,39 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+// Flags: --zero-fill-buffers
+
+// when using --zero-fill-buffers, every Buffer and SlowBuffer
+// instance must be zero filled upon creation
+
+require('../common');
+const SlowBuffer = require('buffer').SlowBuffer;
+const assert = require('assert');
+
+function isZeroFilled(buf) {
+ for (const n of buf)
+ if (n > 0) return false;
+ return true;
+}
+
+// This can be somewhat unreliable because the
+// allocated memory might just already happen to
+// contain all zeroes. The test is run multiple
+// times to improve the reliability.
+for (let i = 0; i < 50; i++) {
+ const bufs = [
+ Buffer.alloc(20),
+ Buffer.allocUnsafe(20),
+ SlowBuffer(20),
+ Buffer(20),
+ new SlowBuffer(20),
+ ];
+ for (const buf of bufs) {
+ assert(isZeroFilled(buf));
+ }
+}
diff --git a/tests/node_compat/test/parallel/test-buffer-zero-fill-reset.js b/tests/node_compat/test/parallel/test-buffer-zero-fill-reset.js
new file mode 100644
index 000000000..1f1baed66
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-buffer-zero-fill-reset.js
@@ -0,0 +1,26 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+require('../common');
+const assert = require('assert');
+
+
+function testUint8Array(ui) {
+ const length = ui.length;
+ for (let i = 0; i < length; i++)
+ if (ui[i] !== 0) return false;
+ return true;
+}
+
+
+for (let i = 0; i < 100; i++) {
+ Buffer.alloc(0);
+ const ui = new Uint8Array(65);
+ assert.ok(testUint8Array(ui), `Uint8Array is not zero-filled: ${ui}`);
+}
diff --git a/tests/node_compat/test/parallel/test-buffer-zero-fill.js b/tests/node_compat/test/parallel/test-buffer-zero-fill.js
new file mode 100644
index 000000000..be8ce1412
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-buffer-zero-fill.js
@@ -0,0 +1,21 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+require('../common');
+const assert = require('assert');
+
+// Tests deprecated Buffer API on purpose
+const buf1 = Buffer(100);
+const buf2 = new Buffer(100);
+
+for (let n = 0; n < buf1.length; n++)
+ assert.strictEqual(buf1[n], 0);
+
+for (let n = 0; n < buf2.length; n++)
+ assert.strictEqual(buf2[n], 0);
diff --git a/tests/node_compat/test/parallel/test-child-process-default-options.js b/tests/node_compat/test/parallel/test-child-process-default-options.js
new file mode 100644
index 000000000..265cfe22f
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-child-process-default-options.js
@@ -0,0 +1,58 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const { isWindows } = require('../common');
+const assert = require('assert');
+
+const spawn = require('child_process').spawn;
+const debug = require('util').debuglog('test');
+
+process.env.HELLO = 'WORLD';
+
+let child;
+if (isWindows) {
+ child = spawn('cmd.exe', ['/c', 'set'], {});
+} else {
+ child = spawn('/usr/bin/env', [], {});
+}
+
+let response = '';
+
+child.stdout.setEncoding('utf8');
+
+child.stdout.on('data', function(chunk) {
+ debug(`stdout: ${chunk}`);
+ response += chunk;
+});
+
+process.on('exit', function() {
+ assert.ok(response.includes('HELLO=WORLD'),
+ 'spawn did not use process.env as default ' +
+ `(process.env.HELLO = ${process.env.HELLO})`);
+});
diff --git a/tests/node_compat/test/parallel/test-child-process-double-pipe.js b/tests/node_compat/test/parallel/test-child-process-double-pipe.js
new file mode 100644
index 000000000..bd31d1038
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-child-process-double-pipe.js
@@ -0,0 +1,129 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const {
+ isWindows,
+ mustCall,
+ mustCallAtLeast,
+} = require('../common');
+const assert = require('assert');
+const os = require('os');
+const spawn = require('child_process').spawn;
+const debug = require('util').debuglog('test');
+
+// We're trying to reproduce:
+// $ echo "hello\nnode\nand\nworld" | grep o | sed s/o/a/
+
+let grep, sed, echo;
+
+if (isWindows) {
+ grep = spawn('grep', ['--binary', 'o']);
+ sed = spawn('sed', ['--binary', 's/o/O/']);
+ echo = spawn('cmd.exe',
+ ['/c', 'echo', 'hello&&', 'echo',
+ 'node&&', 'echo', 'and&&', 'echo', 'world']);
+} else {
+ grep = spawn('grep', ['o']);
+ sed = spawn('sed', ['s/o/O/']);
+ echo = spawn('echo', ['hello\nnode\nand\nworld\n']);
+}
+
+// If the spawn function leaks file descriptors to subprocesses, grep and sed
+// hang.
+// This happens when calling pipe(2) and then forgetting to set the
+// FD_CLOEXEC flag on the resulting file descriptors.
+//
+// This test checks child processes exit, meaning they don't hang like
+// explained above.
+
+
+// pipe echo | grep
+echo.stdout.on('data', mustCallAtLeast((data) => {
+ debug(`grep stdin write ${data.length}`);
+ if (!grep.stdin.write(data)) {
+ echo.stdout.pause();
+ }
+}));
+
+// TODO(@jasnell): This does not appear to ever be
+// emitted. It's not clear if it is necessary.
+grep.stdin.on('drain', (data) => {
+ echo.stdout.resume();
+});
+
+// Propagate end from echo to grep
+echo.stdout.on('end', mustCall((code) => {
+ grep.stdin.end();
+}));
+
+echo.on('exit', mustCall(() => {
+ debug('echo exit');
+}));
+
+grep.on('exit', mustCall(() => {
+ debug('grep exit');
+}));
+
+sed.on('exit', mustCall(() => {
+ debug('sed exit');
+}));
+
+
+// pipe grep | sed
+grep.stdout.on('data', mustCallAtLeast((data) => {
+ debug(`grep stdout ${data.length}`);
+ if (!sed.stdin.write(data)) {
+ grep.stdout.pause();
+ }
+}));
+
+// TODO(@jasnell): This does not appear to ever be
+// emitted. It's not clear if it is necessary.
+sed.stdin.on('drain', (data) => {
+ grep.stdout.resume();
+});
+
+// Propagate end from grep to sed
+grep.stdout.on('end', mustCall((code) => {
+ debug('grep stdout end');
+ sed.stdin.end();
+}));
+
+
+let result = '';
+
+// print sed's output
+sed.stdout.on('data', mustCallAtLeast((data) => {
+ result += data.toString('utf8', 0, data.length);
+ debug(data);
+}));
+
+sed.stdout.on('end', mustCall((code) => {
+ assert.strictEqual(result, `hellO${os.EOL}nOde${os.EOL}wOrld${os.EOL}`);
+}));
diff --git a/tests/node_compat/test/parallel/test-child-process-exec-abortcontroller-promisified.js b/tests/node_compat/test/parallel/test-child-process-exec-abortcontroller-promisified.js
new file mode 100644
index 000000000..4ba699ba4
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-child-process-exec-abortcontroller-promisified.js
@@ -0,0 +1,54 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.8.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// TODO(PolarETech): The "eval" subcommand passed to execPromisifed() should be the "-e" option.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const exec = require('child_process').exec;
+const { promisify } = require('util');
+
+const execPromisifed = promisify(exec);
+const invalidArgTypeError = {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError'
+};
+
+const waitCommand = common.isLinux ?
+ 'sleep 2m' :
+ `${process.execPath} eval "setInterval(()=>{}, 99)"`;
+
+{
+ const ac = new AbortController();
+ const signal = ac.signal;
+ const promise = execPromisifed(waitCommand, { signal });
+ assert.rejects(promise, /AbortError/, 'post aborted sync signal failed')
+ .then(common.mustCall());
+ ac.abort();
+}
+
+{
+ assert.throws(() => {
+ execPromisifed(waitCommand, { signal: {} });
+ }, invalidArgTypeError);
+}
+
+{
+ function signal() {}
+ assert.throws(() => {
+ execPromisifed(waitCommand, { signal });
+ }, invalidArgTypeError);
+}
+
+{
+ const signal = AbortSignal.abort(); // Abort in advance
+ const promise = execPromisifed(waitCommand, { signal });
+
+ assert.rejects(promise, /AbortError/, 'pre aborted signal failed')
+ .then(common.mustCall());
+}
diff --git a/tests/node_compat/test/parallel/test-child-process-exec-cwd.js b/tests/node_compat/test/parallel/test-child-process-exec-cwd.js
new file mode 100644
index 000000000..4bd394cca
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-child-process-exec-cwd.js
@@ -0,0 +1,46 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const exec = require('child_process').exec;
+
+let pwdcommand, dir;
+
+if (common.isWindows) {
+ pwdcommand = 'echo %cd%';
+ dir = 'c:\\windows';
+} else {
+ pwdcommand = 'pwd';
+ dir = '/dev';
+}
+
+exec(pwdcommand, { cwd: dir }, common.mustSucceed((stdout, stderr) => {
+ assert(stdout.toLowerCase().startsWith(dir));
+}));
diff --git a/tests/node_compat/test/parallel/test-child-process-exec-encoding.js b/tests/node_compat/test/parallel/test-child-process-exec-encoding.js
new file mode 100644
index 000000000..fe03e98d0
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-child-process-exec-encoding.js
@@ -0,0 +1,59 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.8.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// TODO(PolarETech): The process.argv[3] check should be argv[2], and the
+// command passed to exec() should not need to include "run", "-A",
+// and "require.ts".
+
+'use strict';
+const common = require('../common');
+const stdoutData = 'foo';
+const stderrData = 'bar';
+
+if (process.argv[3] === 'child') {
+ // The following console calls are part of the test.
+ console.log(stdoutData);
+ console.error(stderrData);
+} else {
+ const assert = require('assert');
+ const cp = require('child_process');
+ const expectedStdout = `${stdoutData}\n`;
+ const expectedStderr = `${stderrData}\n`;
+ function run(options, callback) {
+ const cmd = `"${process.execPath}" run -A require.ts "${__filename}" child`;
+
+ cp.exec(cmd, options, common.mustSucceed((stdout, stderr) => {
+ callback(stdout, stderr);
+ }));
+ }
+
+ // Test default encoding, which should be utf8.
+ run({}, (stdout, stderr) => {
+ assert.strictEqual(typeof stdout, 'string');
+ assert.strictEqual(typeof stderr, 'string');
+ assert.strictEqual(stdout, expectedStdout);
+ assert.strictEqual(stderr, expectedStderr);
+ });
+
+ // Test explicit utf8 encoding.
+ run({ encoding: 'utf8' }, (stdout, stderr) => {
+ assert.strictEqual(typeof stdout, 'string');
+ assert.strictEqual(typeof stderr, 'string');
+ assert.strictEqual(stdout, expectedStdout);
+ assert.strictEqual(stderr, expectedStderr);
+ });
+
+ // Test cases that result in buffer encodings.
+ [undefined, null, 'buffer', 'invalid'].forEach((encoding) => {
+ run({ encoding }, (stdout, stderr) => {
+ assert(stdout instanceof Buffer);
+ assert(stdout instanceof Buffer);
+ assert.strictEqual(stdout.toString(), expectedStdout);
+ assert.strictEqual(stderr.toString(), expectedStderr);
+ });
+ });
+}
diff --git a/tests/node_compat/test/parallel/test-child-process-exec-env.js b/tests/node_compat/test/parallel/test-child-process-exec-env.js
new file mode 100644
index 000000000..2797b8761
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-child-process-exec-env.js
@@ -0,0 +1,71 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const { isWindows } = require('../common');
+const assert = require('assert');
+const exec = require('child_process').exec;
+const debug = require('util').debuglog('test');
+
+let success_count = 0;
+let error_count = 0;
+let response = '';
+let child;
+
+function after(err, stdout, stderr) {
+ if (err) {
+ error_count++;
+ debug(`error!: ${err.code}`);
+ debug(`stdout: ${JSON.stringify(stdout)}`);
+ debug(`stderr: ${JSON.stringify(stderr)}`);
+ assert.strictEqual(err.killed, false);
+ } else {
+ success_count++;
+ assert.notStrictEqual(stdout, '');
+ }
+}
+
+if (!isWindows) {
+ child = exec('/usr/bin/env', { env: { 'HELLO': 'WORLD' } }, after);
+} else {
+ child = exec('set',
+ { env: { ...process.env, 'HELLO': 'WORLD' } },
+ after);
+}
+
+child.stdout.setEncoding('utf8');
+child.stdout.on('data', function(chunk) {
+ response += chunk;
+});
+
+process.on('exit', function() {
+ debug('response: ', response);
+ assert.strictEqual(success_count, 1);
+ assert.strictEqual(error_count, 0);
+ assert.ok(response.includes('HELLO=WORLD'));
+});
diff --git a/tests/node_compat/test/parallel/test-child-process-exec-error.js b/tests/node_compat/test/parallel/test-child-process-exec-error.js
new file mode 100644
index 000000000..3f809ed18
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-child-process-exec-error.js
@@ -0,0 +1,51 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const child_process = require('child_process');
+
+function test(fn, code, expectPidType = 'number') {
+ const child = fn('does-not-exist', common.mustCall(function(err) {
+ assert.strictEqual(err.code, code);
+ assert(err.cmd.includes('does-not-exist'));
+ }));
+
+ assert.strictEqual(typeof child.pid, expectPidType);
+}
+
+// With `shell: true`, expect pid (of the shell)
+if (common.isWindows) {
+ test(child_process.exec, 1, 'number'); // Exit code of cmd.exe
+} else {
+ test(child_process.exec, 127, 'number'); // Exit code of /bin/sh
+}
+
+// With `shell: false`, expect no pid
+test(child_process.execFile, 'ENOENT', 'undefined');
diff --git a/tests/node_compat/test/parallel/test-child-process-exec-kill-throws.js b/tests/node_compat/test/parallel/test-child-process-exec-kill-throws.js
new file mode 100644
index 000000000..6a28c2a18
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-child-process-exec-kill-throws.js
@@ -0,0 +1,42 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.8.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// TODO(PolarETech): The process.argv[3] check should be argv[2], and the
+// command passed to exec() should not need to include "run", "-A",
+// and "require.ts".
+
+'use strict';
+// Flags: --expose-internals
+const common = require('../common');
+const assert = require('assert');
+const cp = require('child_process');
+
+if (process.argv[3] === 'child') {
+ // Since maxBuffer is 0, this should trigger an error.
+ console.log('foo');
+} else {
+ const internalCp = require('internal/child_process');
+
+ // Monkey patch ChildProcess#kill() to kill the process and then throw.
+ const kill = internalCp.ChildProcess.prototype.kill;
+
+ internalCp.ChildProcess.prototype.kill = function() {
+ kill.apply(this, arguments);
+ throw new Error('mock error');
+ };
+
+ const cmd = `"${process.execPath}" run -A require.ts "${__filename}" child`;
+ const options = { maxBuffer: 0, killSignal: 'SIGKILL' };
+
+ const child = cp.exec(cmd, options, common.mustCall((err, stdout, stderr) => {
+ // Verify that if ChildProcess#kill() throws, the error is reported.
+ assert.strictEqual(err.message, 'mock error', err);
+ assert.strictEqual(stdout, '');
+ assert.strictEqual(stderr, '');
+ assert.strictEqual(child.killed, true);
+ }));
+}
diff --git a/tests/node_compat/test/parallel/test-child-process-exec-maxbuf.js b/tests/node_compat/test/parallel/test-child-process-exec-maxbuf.js
new file mode 100644
index 000000000..2e99855c0
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-child-process-exec-maxbuf.js
@@ -0,0 +1,161 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.8.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// TODO(PolarETech): The "eval" subcommand passed to exec() should be the "-e" option.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const cp = require('child_process');
+
+function runChecks(err, stdio, streamName, expected) {
+ assert.strictEqual(err.message, `${streamName} maxBuffer length exceeded`);
+ assert(err instanceof RangeError);
+ assert.strictEqual(err.code, 'ERR_CHILD_PROCESS_STDIO_MAXBUFFER');
+ assert.deepStrictEqual(stdio[streamName], expected);
+}
+
+// default value
+{
+ const cmd =
+ `"${process.execPath}" eval "console.log('a'.repeat(1024 * 1024))"`;
+
+ cp.exec(cmd, common.mustCall((err) => {
+ assert(err instanceof RangeError);
+ assert.strictEqual(err.message, 'stdout maxBuffer length exceeded');
+ assert.strictEqual(err.code, 'ERR_CHILD_PROCESS_STDIO_MAXBUFFER');
+ }));
+}
+
+// default value
+{
+ const cmd =
+ `${process.execPath} eval "console.log('a'.repeat(1024 * 1024 - 1))"`;
+
+ cp.exec(cmd, common.mustSucceed((stdout, stderr) => {
+ assert.strictEqual(stdout.trim(), 'a'.repeat(1024 * 1024 - 1));
+ assert.strictEqual(stderr, '');
+ }));
+}
+
+{
+ const cmd = `"${process.execPath}" eval "console.log('hello world');"`;
+ const options = { maxBuffer: Infinity };
+
+ cp.exec(cmd, options, common.mustSucceed((stdout, stderr) => {
+ assert.strictEqual(stdout.trim(), 'hello world');
+ assert.strictEqual(stderr, '');
+ }));
+}
+
+{
+ const cmd = 'echo hello world';
+
+ cp.exec(
+ cmd,
+ { maxBuffer: 5 },
+ common.mustCall((err, stdout, stderr) => {
+ runChecks(err, { stdout, stderr }, 'stdout', 'hello');
+ })
+ );
+}
+
+// default value
+{
+ const cmd =
+ `"${process.execPath}" eval "console.log('a'.repeat(1024 * 1024))"`;
+
+ cp.exec(
+ cmd,
+ common.mustCall((err, stdout, stderr) => {
+ runChecks(
+ err,
+ { stdout, stderr },
+ 'stdout',
+ 'a'.repeat(1024 * 1024)
+ );
+ })
+ );
+}
+
+// default value
+{
+ const cmd =
+ `"${process.execPath}" eval "console.log('a'.repeat(1024 * 1024 - 1))"`;
+
+ cp.exec(cmd, common.mustSucceed((stdout, stderr) => {
+ assert.strictEqual(stdout.trim(), 'a'.repeat(1024 * 1024 - 1));
+ assert.strictEqual(stderr, '');
+ }));
+}
+
+const unicode = '中文测试'; // length = 4, byte length = 12
+
+{
+ const cmd = `"${process.execPath}" eval "console.log('${unicode}');"`;
+
+ cp.exec(
+ cmd,
+ { maxBuffer: 10 },
+ common.mustCall((err, stdout, stderr) => {
+ runChecks(err, { stdout, stderr }, 'stdout', '中文测试\n');
+ })
+ );
+}
+
+{
+ const cmd = `"${process.execPath}" eval "console.error('${unicode}');"`;
+
+ cp.exec(
+ cmd,
+ { maxBuffer: 3 },
+ common.mustCall((err, stdout, stderr) => {
+ runChecks(err, { stdout, stderr }, 'stderr', '中文测');
+ })
+ );
+}
+
+{
+ const cmd = `"${process.execPath}" eval "console.log('${unicode}');"`;
+
+ const child = cp.exec(
+ cmd,
+ { encoding: null, maxBuffer: 10 },
+ common.mustCall((err, stdout, stderr) => {
+ runChecks(err, { stdout, stderr }, 'stdout', '中文测试\n');
+ })
+ );
+
+ child.stdout.setEncoding('utf-8');
+}
+
+{
+ const cmd = `"${process.execPath}" eval "console.error('${unicode}');"`;
+
+ const child = cp.exec(
+ cmd,
+ { encoding: null, maxBuffer: 3 },
+ common.mustCall((err, stdout, stderr) => {
+ runChecks(err, { stdout, stderr }, 'stderr', '中文测');
+ })
+ );
+
+ child.stderr.setEncoding('utf-8');
+}
+
+{
+ const cmd = `"${process.execPath}" eval "console.error('${unicode}');"`;
+
+ cp.exec(
+ cmd,
+ { encoding: null, maxBuffer: 5 },
+ common.mustCall((err, stdout, stderr) => {
+ const buf = Buffer.from(unicode).slice(0, 5);
+ runChecks(err, { stdout, stderr }, 'stderr', buf);
+ })
+ );
+}
diff --git a/tests/node_compat/test/parallel/test-child-process-exec-std-encoding.js b/tests/node_compat/test/parallel/test-child-process-exec-std-encoding.js
new file mode 100644
index 000000000..85f3ec2bf
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-child-process-exec-std-encoding.js
@@ -0,0 +1,33 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.8.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// TODO(PolarETech): The process.argv[3] check should be argv[2], and the
+// command passed to exec() should not need to include "run", "-A",
+// and "require.ts".
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const cp = require('child_process');
+const stdoutData = 'foo';
+const stderrData = 'bar';
+const expectedStdout = `${stdoutData}\n`;
+const expectedStderr = `${stderrData}\n`;
+
+if (process.argv[3] === 'child') {
+ // The following console calls are part of the test.
+ console.log(stdoutData);
+ console.error(stderrData);
+} else {
+ const cmd = `"${process.execPath}" run -A require.ts "${__filename}" child`;
+ const child = cp.exec(cmd, common.mustSucceed((stdout, stderr) => {
+ assert.strictEqual(stdout, expectedStdout);
+ assert.strictEqual(stderr, expectedStderr);
+ }));
+ child.stdout.setEncoding('utf-8');
+ child.stderr.setEncoding('utf-8');
+}
diff --git a/tests/node_compat/test/parallel/test-child-process-exec-stdout-stderr-data-string.js b/tests/node_compat/test/parallel/test-child-process-exec-stdout-stderr-data-string.js
new file mode 100644
index 000000000..0e5453926
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-child-process-exec-stdout-stderr-data-string.js
@@ -0,0 +1,20 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+// Refs: https://github.com/nodejs/node/issues/7342
+const common = require('../common');
+const assert = require('assert');
+const exec = require('child_process').exec;
+
+const command = common.isWindows ? 'dir' : 'ls';
+
+exec(command).stdout.on('data', common.mustCallAtLeast());
+
+exec('fhqwhgads').stderr.on('data', common.mustCallAtLeast((data) => {
+ assert.strictEqual(typeof data, 'string');
+}));
diff --git a/tests/node_compat/test/parallel/test-child-process-exec-timeout-not-expired.js b/tests/node_compat/test/parallel/test-child-process-exec-timeout-not-expired.js
new file mode 100644
index 000000000..31fa1f725
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-child-process-exec-timeout-not-expired.js
@@ -0,0 +1,45 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// TODO(PolarETech): The process.argv[3] check should be argv[2], and the
+// command passed to exec() should not need to include "run", "-A",
+// and "require.ts".
+
+'use strict';
+
+// Test exec() when a timeout is set, but not expired.
+
+const common = require('../common');
+const assert = require('assert');
+const cp = require('child_process');
+
+const {
+ cleanupStaleProcess,
+ logAfterTime
+} = require('../common/child_process');
+
+const kTimeoutNotSupposedToExpire = 2 ** 30;
+const childRunTime = common.platformTimeout(100);
+
+// The time spent in the child should be smaller than the timeout below.
+assert(childRunTime < kTimeoutNotSupposedToExpire);
+
+if (process.argv[3] === 'child') {
+ logAfterTime(childRunTime);
+ return;
+}
+
+const cmd = `"${process.execPath}" run -A require.ts "${__filename}" child`;
+
+cp.exec(cmd, {
+ timeout: kTimeoutNotSupposedToExpire
+}, common.mustSucceed((stdout, stderr) => {
+ assert.strictEqual(stdout.trim(), 'child stdout');
+ assert.strictEqual(stderr.trim(), 'child stderr');
+}));
+
+cleanupStaleProcess(__filename);
diff --git a/tests/node_compat/test/parallel/test-child-process-execfile-maxbuf.js b/tests/node_compat/test/parallel/test-child-process-execfile-maxbuf.js
new file mode 100644
index 000000000..729929c78
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-child-process-execfile-maxbuf.js
@@ -0,0 +1,99 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const { execFile } = require('child_process');
+
+function checkFactory(streamName) {
+ return common.mustCall((err) => {
+ assert(err instanceof RangeError);
+ assert.strictEqual(err.message, `${streamName} maxBuffer length exceeded`);
+ assert.strictEqual(err.code, 'ERR_CHILD_PROCESS_STDIO_MAXBUFFER');
+ });
+}
+
+// default value
+{
+ execFile(
+ process.execPath,
+ ['-e', 'console.log("a".repeat(1024 * 1024))'],
+ checkFactory('stdout')
+ );
+}
+
+// default value
+{
+ execFile(
+ process.execPath,
+ ['-e', 'console.log("a".repeat(1024 * 1024 - 1))'],
+ common.mustSucceed((stdout, stderr) => {
+ assert.strictEqual(stdout.trim(), 'a'.repeat(1024 * 1024 - 1));
+ assert.strictEqual(stderr, '');
+ })
+ );
+}
+
+{
+ const options = { maxBuffer: Infinity };
+
+ execFile(
+ process.execPath,
+ ['-e', 'console.log("hello world");'],
+ options,
+ common.mustSucceed((stdout, stderr) => {
+ assert.strictEqual(stdout.trim(), 'hello world');
+ assert.strictEqual(stderr, '');
+ })
+ );
+}
+
+{
+ execFile('echo', ['hello world'], { maxBuffer: 5 }, checkFactory('stdout'));
+}
+
+const unicode = '中文测试'; // length = 4, byte length = 12
+
+{
+ execFile(
+ process.execPath,
+ ['-e', `console.log('${unicode}');`],
+ { maxBuffer: 10 },
+ checkFactory('stdout'));
+}
+
+{
+ execFile(
+ process.execPath,
+ ['-e', `console.error('${unicode}');`],
+ { maxBuffer: 10 },
+ checkFactory('stderr')
+ );
+}
+
+{
+ const child = execFile(
+ process.execPath,
+ ['-e', `console.log('${unicode}');`],
+ { encoding: null, maxBuffer: 10 },
+ checkFactory('stdout')
+ );
+
+ child.stdout.setEncoding('utf-8');
+}
+
+{
+ const child = execFile(
+ process.execPath,
+ ['-e', `console.error('${unicode}');`],
+ { encoding: null, maxBuffer: 10 },
+ checkFactory('stderr')
+ );
+
+ child.stderr.setEncoding('utf-8');
+}
diff --git a/tests/node_compat/test/parallel/test-child-process-execfile.js b/tests/node_compat/test/parallel/test-child-process-execfile.js
new file mode 100644
index 000000000..9f9268407
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-child-process-execfile.js
@@ -0,0 +1,135 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.8.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// TODO(PolarETech): The args passed to execFile() should not need to
+// include "require.ts".
+
+// TODO(cjihrig): See inline TODO comments below.
+
+'use strict';
+
+const common = require('../common');
+const assert = require('assert');
+const { execFile, execFileSync } = require('child_process');
+const { getSystemErrorName } = require('util');
+const fixtures = require('../common/fixtures');
+const os = require('os');
+
+const fixture = fixtures.path('exit.js');
+const echoFixture = fixtures.path('echo.js');
+const execOpts = { encoding: 'utf8', shell: true };
+
+{
+ execFile(
+ process.execPath,
+ ['require.ts', fixture, 42],
+ common.mustCall((e) => {
+ // Check that arguments are included in message
+ assert.strictEqual(e.message.trim(),
+ `Command failed: ${process.execPath} require.ts ${fixture} 42`);
+ assert.strictEqual(e.code, 42);
+ })
+ );
+}
+
+{
+ // Verify that negative exit codes can be translated to UV error names.
+ const errorString = `Error: Command failed: ${process.execPath}`;
+ const code = -1;
+ const callback = common.mustCall((err, stdout, stderr) => {
+ assert.strictEqual(err.toString().trim(), errorString);
+ assert.strictEqual(err.code, getSystemErrorName(code));
+ assert.strictEqual(err.killed, true);
+ assert.strictEqual(err.signal, null);
+ assert.strictEqual(err.cmd, process.execPath);
+ assert.strictEqual(stdout.trim(), '');
+ assert.strictEqual(stderr.trim(), '');
+ });
+ const child = execFile(process.execPath, callback);
+
+ child.kill();
+ child.emit('close', code, null);
+}
+
+{
+ // Verify the shell option works properly
+ execFile(process.execPath, ['require.ts', fixture, 0], execOpts, common.mustSucceed());
+}
+
+{
+ // Verify that the signal option works properly
+ const ac = new AbortController();
+ const { signal } = ac;
+
+ const test = () => {
+ const check = common.mustCall((err) => {
+ assert.strictEqual(err.code, 'ABORT_ERR');
+ assert.strictEqual(err.name, 'AbortError');
+ assert.strictEqual(err.signal, undefined);
+ });
+ execFile(process.execPath, ['require.ts', echoFixture, 0], { signal }, check);
+ };
+
+ // Verify that it still works the same way now that the signal is aborted.
+ test();
+ ac.abort();
+}
+
+{
+ // Verify that does not spawn a child if already aborted
+ const signal = AbortSignal.abort();
+
+ const check = common.mustCall((err) => {
+ assert.strictEqual(err.code, 'ABORT_ERR');
+ assert.strictEqual(err.name, 'AbortError');
+ assert.strictEqual(err.signal, undefined);
+ });
+ execFile(process.execPath, ['require.ts', echoFixture, 0], { signal }, check);
+}
+
+{
+ // Verify that if something different than Abortcontroller.signal
+ // is passed, ERR_INVALID_ARG_TYPE is thrown
+ assert.throws(() => {
+ const callback = common.mustNotCall(() => {});
+
+ execFile(process.execPath, ['require.ts', echoFixture, 0], { signal: 'hello' }, callback);
+ }, { code: 'ERR_INVALID_ARG_TYPE', name: 'TypeError' });
+}
+{
+ // Verify that the process completing removes the abort listener
+ const ac = new AbortController();
+ const { signal } = ac;
+
+ const callback = common.mustCall((err) => {
+ // TODO(cjihrig): The assertion on the next line currently fails because
+ // kEvents is not defined. See TODO comment in _events.mjs.
+ // assert.strictEqual(getEventListeners(ac.signal).length, 0);
+ assert.strictEqual(err, null);
+ });
+ execFile(process.execPath, ['require.ts', fixture, 0], { signal }, callback);
+}
+
+// Verify the execFile() stdout is the same as execFileSync().
+{
+ const file = 'echo';
+ const args = ['foo', 'bar'];
+
+ // Test with and without `{ shell: true }`
+ [
+ // Skipping shell-less test on Windows because its echo command is a shell built-in command.
+ ...(common.isWindows ? [] : [{ encoding: 'utf8' }]),
+ { shell: true, encoding: 'utf8' },
+ ].forEach((options) => {
+ const execFileSyncStdout = execFileSync(file, args, options);
+ assert.strictEqual(execFileSyncStdout, `foo bar${os.EOL}`);
+
+ execFile(file, args, options, common.mustCall((_, stdout) => {
+ assert.strictEqual(stdout, execFileSyncStdout);
+ }));
+ });
+}
diff --git a/tests/node_compat/test/parallel/test-child-process-execfilesync-maxbuf.js b/tests/node_compat/test/parallel/test-child-process-execfilesync-maxbuf.js
new file mode 100644
index 000000000..7ad857a18
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-child-process-execfilesync-maxbuf.js
@@ -0,0 +1,60 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+require('../common');
+
+// This test checks that the maxBuffer option for child_process.execFileSync()
+// works as expected.
+
+const assert = require('assert');
+const { getSystemErrorName } = require('util');
+const { execFileSync } = require('child_process');
+const msgOut = 'this is stdout';
+const msgOutBuf = Buffer.from(`${msgOut}\n`);
+
+const args = [
+ '-e',
+ `console.log("${msgOut}");`,
+];
+
+// Verify that an error is returned if maxBuffer is surpassed.
+{
+ assert.throws(() => {
+ execFileSync(process.execPath, args, { maxBuffer: 1 });
+ }, (e) => {
+ assert.ok(e, 'maxBuffer should error');
+ assert.strictEqual(e.code, 'ENOBUFS');
+ assert.strictEqual(getSystemErrorName(e.errno), 'ENOBUFS');
+ // We can have buffers larger than maxBuffer because underneath we alloc 64k
+ // that matches our read sizes.
+ assert.deepStrictEqual(e.stdout, msgOutBuf);
+ return true;
+ });
+}
+
+// Verify that a maxBuffer size of Infinity works.
+{
+ const ret = execFileSync(process.execPath, args, { maxBuffer: Infinity });
+
+ assert.deepStrictEqual(ret, msgOutBuf);
+}
+
+// Default maxBuffer size is 1024 * 1024.
+{
+ assert.throws(() => {
+ execFileSync(
+ process.execPath,
+ ['-e', "console.log('a'.repeat(1024 * 1024))"]
+ );
+ }, (e) => {
+ assert.ok(e, 'maxBuffer should error');
+ assert.strictEqual(e.code, 'ENOBUFS');
+ assert.strictEqual(getSystemErrorName(e.errno), 'ENOBUFS');
+ return true;
+ });
+}
diff --git a/tests/node_compat/test/parallel/test-child-process-execsync-maxbuf.js b/tests/node_compat/test/parallel/test-child-process-execsync-maxbuf.js
new file mode 100644
index 000000000..703896ef1
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-child-process-execsync-maxbuf.js
@@ -0,0 +1,76 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.8.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// TODO(cjihrig): This should use Node's -e instead of Deno's eval CLI arg.
+
+'use strict';
+require('../common');
+
+// This test checks that the maxBuffer option for child_process.spawnSync()
+// works as expected.
+
+const assert = require('assert');
+const { getSystemErrorName } = require('util');
+const { execSync } = require('child_process');
+const msgOut = 'this is stdout';
+const msgOutBuf = Buffer.from(`${msgOut}\n`);
+
+const args = [
+ 'eval',
+ `"console.log('${msgOut}')";`,
+];
+
+// Verify that an error is returned if maxBuffer is surpassed.
+{
+ assert.throws(() => {
+ execSync(`"${process.execPath}" ${args.join(' ')}`, { maxBuffer: 1 });
+ }, (e) => {
+ assert.ok(e, 'maxBuffer should error');
+ assert.strictEqual(e.code, 'ENOBUFS');
+ assert.strictEqual(getSystemErrorName(e.errno), 'ENOBUFS');
+ // We can have buffers larger than maxBuffer because underneath we alloc 64k
+ // that matches our read sizes.
+ assert.deepStrictEqual(e.stdout, msgOutBuf);
+ return true;
+ });
+}
+
+// Verify that a maxBuffer size of Infinity works.
+{
+ const ret = execSync(
+ `"${process.execPath}" ${args.join(' ')}`,
+ { maxBuffer: Infinity }
+ );
+
+ assert.deepStrictEqual(ret, msgOutBuf);
+}
+
+// Default maxBuffer size is 1024 * 1024.
+{
+ assert.throws(() => {
+ execSync(
+ `"${process.execPath}" eval "console.log('a'.repeat(1024 * 1024))"`
+ );
+ }, (e) => {
+ assert.ok(e, 'maxBuffer should error');
+ assert.strictEqual(e.code, 'ENOBUFS');
+ assert.strictEqual(getSystemErrorName(e.errno), 'ENOBUFS');
+ return true;
+ });
+}
+
+// Default maxBuffer size is 1024 * 1024.
+{
+ const ret = execSync(
+ `"${process.execPath}" eval "console.log('a'.repeat(1024 * 1024 - 1))"`
+ );
+
+ assert.deepStrictEqual(
+ ret.toString().trim(),
+ 'a'.repeat(1024 * 1024 - 1)
+ );
+}
diff --git a/tests/node_compat/test/parallel/test-child-process-exit-code.js b/tests/node_compat/test/parallel/test-child-process-exit-code.js
new file mode 100644
index 000000000..caa57986b
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-child-process-exit-code.js
@@ -0,0 +1,51 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// TODO(PolarETech): The args passed to spawn() should not need to
+// include "require.ts".
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const spawn = require('child_process').spawn;
+const fixtures = require('../common/fixtures');
+
+const exitScript = fixtures.path('exit.js');
+const exitChild = spawn(process.argv[0], ['require.ts', exitScript, 23]);
+exitChild.on('exit', common.mustCall(function(code, signal) {
+ assert.strictEqual(code, 23);
+ assert.strictEqual(signal, null);
+}));
+
+
+const errorScript = fixtures.path('child_process_should_emit_error.js');
+const errorChild = spawn(process.argv[0], ['require.ts', errorScript]);
+errorChild.on('exit', common.mustCall(function(code, signal) {
+ assert.ok(code !== 0);
+ assert.strictEqual(signal, null);
+}));
diff --git a/tests/node_compat/test/parallel/test-child-process-flush-stdio.js b/tests/node_compat/test/parallel/test-child-process-flush-stdio.js
new file mode 100644
index 000000000..c39bcbdbe
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-child-process-flush-stdio.js
@@ -0,0 +1,40 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const cp = require('child_process');
+const assert = require('assert');
+
+// Windows' `echo` command is a built-in shell command and not an external
+// executable like on *nix
+const opts = { shell: common.isWindows };
+
+const p = cp.spawn('echo', [], opts);
+
+p.on('close', common.mustCall((code, signal) => {
+ assert.strictEqual(code, 0);
+ assert.strictEqual(signal, null);
+ spawnWithReadable();
+}));
+
+p.stdout.read();
+
+const spawnWithReadable = () => {
+ const buffer = [];
+ const p = cp.spawn('echo', ['123'], opts);
+ p.on('close', common.mustCall((code, signal) => {
+ assert.strictEqual(code, 0);
+ assert.strictEqual(signal, null);
+ assert.strictEqual(Buffer.concat(buffer).toString().trim(), '123');
+ }));
+ p.stdout.on('readable', () => {
+ let buf;
+ while ((buf = p.stdout.read()) !== null)
+ buffer.push(buf);
+ });
+};
diff --git a/tests/node_compat/test/parallel/test-child-process-fork-ref.js b/tests/node_compat/test/parallel/test-child-process-fork-ref.js
new file mode 100644
index 000000000..37c186af8
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-child-process-fork-ref.js
@@ -0,0 +1,72 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+
+// Ignore on Windows.
+if (process.platform === 'win32') {
+ process.exit(0);
+}
+
+require('../common');
+const assert = require('assert');
+const fork = require('child_process').fork;
+
+if (process.argv[2] === 'child') {
+ process.send('1');
+
+ // Check that child don't instantly die
+ setTimeout(function() {
+ process.send('2');
+ }, 200);
+
+ process.on('disconnect', function() {
+ process.stdout.write('3');
+ });
+
+} else {
+ const child = fork(__filename, ['child'], { silent: true });
+
+ const ipc = [];
+ let stdout = '';
+
+ child.on('message', function(msg) {
+ ipc.push(msg);
+
+ if (msg === '2') child.disconnect();
+ });
+
+ child.stdout.on('data', function(chunk) {
+ stdout += chunk;
+ });
+
+ child.once('exit', function() {
+ assert.deepStrictEqual(ipc, ['1', '2']);
+ assert.strictEqual(stdout, '3');
+ });
+}
diff --git a/tests/node_compat/test/parallel/test-child-process-fork-ref2.js b/tests/node_compat/test/parallel/test-child-process-fork-ref2.js
new file mode 100644
index 000000000..da59d9378
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-child-process-fork-ref2.js
@@ -0,0 +1,63 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+
+// Ignore on Windows.
+if (process.platform === 'win32') {
+ process.exit(0);
+}
+
+const {
+ mustCall,
+ mustNotCall,
+ platformTimeout,
+} = require('../common');
+const fork = require('child_process').fork;
+const debug = require('util').debuglog('test');
+
+if (process.argv[2] === 'child') {
+ debug('child -> call disconnect');
+ process.disconnect();
+
+ setTimeout(() => {
+ debug('child -> will this keep it alive?');
+ process.on('message', mustNotCall());
+ }, platformTimeout(400));
+
+} else {
+ const child = fork(__filename, ['child']);
+
+ child.on('disconnect', mustCall(() => {
+ debug('parent -> disconnect');
+ }));
+
+ child.once('exit', mustCall(() => {
+ debug('parent -> exit');
+ }));
+}
diff --git a/tests/node_compat/test/parallel/test-child-process-ipc-next-tick.js b/tests/node_compat/test/parallel/test-child-process-ipc-next-tick.js
new file mode 100644
index 000000000..d255a0a64
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-child-process-ipc-next-tick.js
@@ -0,0 +1,52 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+// Ignore on Windows.
+if (process.platform === 'win32') {
+ process.exit(0);
+}
+
+const common = require('../common');
+const assert = require('assert');
+const cp = require('child_process');
+const NUM_MESSAGES = 10;
+const values = [];
+
+for (let i = 0; i < NUM_MESSAGES; ++i) {
+ values[i] = i;
+}
+
+if (process.argv[2] === 'child') {
+ const received = values.map(() => { return false; });
+
+ process.on('uncaughtException', common.mustCall((err) => {
+ received[err] = true;
+ const done = received.every((element) => { return element === true; });
+
+ if (done)
+ process.disconnect();
+ }, NUM_MESSAGES));
+
+ process.on('message', (msg) => {
+ // If messages are handled synchronously, throwing should break the IPC
+ // message processing.
+ throw msg;
+ });
+
+ process.send('ready');
+} else {
+ const child = cp.fork(__filename, ['child']);
+
+ child.on('message', common.mustCall((msg) => {
+ assert.strictEqual(msg, 'ready');
+ values.forEach((value) => {
+ child.send(value);
+ });
+ }));
+}
diff --git a/tests/node_compat/test/parallel/test-child-process-ipc.js b/tests/node_compat/test/parallel/test-child-process-ipc.js
new file mode 100644
index 000000000..c1d7bc2b6
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-child-process-ipc.js
@@ -0,0 +1,73 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// TODO(PolarETech): The args passed to spawn() should not need to
+// include "require.ts".
+
+'use strict';
+
+const {
+ mustCall,
+ mustNotCall,
+} = require('../common');
+const assert = require('assert');
+const debug = require('util').debuglog('test');
+
+const { spawn } = require('child_process');
+const fixtures = require('../common/fixtures');
+
+const sub = fixtures.path('echo.js');
+
+const child = spawn(process.argv[0], ['require.ts', sub]);
+
+child.stderr.on('data', mustNotCall());
+
+child.stdout.setEncoding('utf8');
+
+const messages = [
+ 'hello world\r\n',
+ 'echo me\r\n',
+];
+
+child.stdout.on('data', mustCall((data) => {
+ debug(`child said: ${JSON.stringify(data)}`);
+ const test = messages.shift();
+ debug(`testing for '${test}'`);
+ assert.strictEqual(data, test);
+ if (messages.length) {
+ debug(`writing '${messages[0]}'`);
+ child.stdin.write(messages[0]);
+ } else {
+ assert.strictEqual(messages.length, 0);
+ child.stdin.end();
+ }
+}, messages.length));
+
+child.stdout.on('end', mustCall((data) => {
+ debug('child end');
+}));
diff --git a/tests/node_compat/test/parallel/test-child-process-kill.js b/tests/node_compat/test/parallel/test-child-process-kill.js
new file mode 100644
index 000000000..4d4ac3033
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-child-process-kill.js
@@ -0,0 +1,48 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const spawn = require('child_process').spawn;
+const cat = spawn(common.isWindows ? 'cmd' : 'cat');
+
+cat.stdout.on('end', common.mustCall());
+cat.stderr.on('data', common.mustNotCall());
+cat.stderr.on('end', common.mustCall());
+
+cat.on('exit', common.mustCall((code, signal) => {
+ assert.strictEqual(code, null);
+ assert.strictEqual(signal, 'SIGTERM');
+ assert.strictEqual(cat.signalCode, 'SIGTERM');
+}));
+
+assert.strictEqual(cat.signalCode, null);
+assert.strictEqual(cat.killed, false);
+cat.kill();
+assert.strictEqual(cat.killed, true);
diff --git a/tests/node_compat/test/parallel/test-child-process-set-blocking.js b/tests/node_compat/test/parallel/test-child-process-set-blocking.js
new file mode 100644
index 000000000..b43d9ba9c
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-child-process-set-blocking.js
@@ -0,0 +1,43 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const ch = require('child_process');
+
+const SIZE = 100000;
+const python = process.env.PYTHON || (common.isWindows ? 'python' : 'python3');
+
+const cp = ch.spawn(python, ['-c', `print(${SIZE} * "C")`], {
+ stdio: 'inherit'
+});
+
+cp.on('exit', common.mustCall(function(code) {
+ assert.strictEqual(code, 0);
+}));
diff --git a/tests/node_compat/test/parallel/test-child-process-spawn-args.js b/tests/node_compat/test/parallel/test-child-process-spawn-args.js
new file mode 100644
index 000000000..e2597c921
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-child-process-spawn-args.js
@@ -0,0 +1,62 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+// This test confirms that `undefined`, `null`, and `[]`
+// can be used as a placeholder for the second argument (`args`) of `spawn()`.
+// Previously, there was a bug where using `undefined` for the second argument
+// caused the third argument (`options`) to be ignored.
+// See https://github.com/nodejs/node/issues/24912.
+
+const common = require('../common');
+const tmpdir = require('../common/tmpdir');
+
+const assert = require('assert');
+const { spawn } = require('child_process');
+
+tmpdir.refresh();
+
+const command = common.isWindows ? 'cd' : 'pwd';
+const options = { cwd: tmpdir.path };
+
+if (common.isWindows) {
+ // This test is not the case for Windows based systems
+ // unless the `shell` options equals to `true`
+
+ options.shell = true;
+}
+
+const testCases = [
+ undefined,
+ null,
+ [],
+];
+
+const expectedResult = tmpdir.path.trim().toLowerCase();
+
+(async () => {
+ const results = await Promise.all(
+ testCases.map((testCase) => {
+ return new Promise((resolve) => {
+ const subprocess = spawn(command, testCase, options);
+
+ let accumulatedData = Buffer.alloc(0);
+
+ subprocess.stdout.on('data', common.mustCall((data) => {
+ accumulatedData = Buffer.concat([accumulatedData, data]);
+ }));
+
+ subprocess.stdout.on('end', () => {
+ resolve(accumulatedData.toString().trim().toLowerCase());
+ });
+ });
+ })
+ );
+
+ assert.deepStrictEqual([...new Set(results)], [expectedResult]);
+})().then(common.mustCall());
diff --git a/tests/node_compat/test/parallel/test-child-process-spawn-event.js b/tests/node_compat/test/parallel/test-child-process-spawn-event.js
new file mode 100644
index 000000000..315644fd1
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-child-process-spawn-event.js
@@ -0,0 +1,34 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const spawn = require('child_process').spawn;
+const assert = require('assert');
+
+const subprocess = spawn('echo', ['ok']);
+
+let didSpawn = false;
+subprocess.on('spawn', function() {
+ didSpawn = true;
+});
+function mustCallAfterSpawn() {
+ return common.mustCall(function() {
+ assert.ok(didSpawn);
+ });
+}
+
+subprocess.on('error', common.mustNotCall());
+subprocess.on('spawn', common.mustCall());
+subprocess.stdout.on('data', mustCallAfterSpawn());
+subprocess.stdout.on('end', mustCallAfterSpawn());
+subprocess.stdout.on('close', mustCallAfterSpawn());
+subprocess.stderr.on('data', common.mustNotCall());
+subprocess.stderr.on('end', mustCallAfterSpawn());
+subprocess.stderr.on('close', mustCallAfterSpawn());
+subprocess.on('exit', mustCallAfterSpawn());
+subprocess.on('close', mustCallAfterSpawn());
diff --git a/tests/node_compat/test/parallel/test-child-process-spawnsync-args.js b/tests/node_compat/test/parallel/test-child-process-spawnsync-args.js
new file mode 100644
index 000000000..05e04a92e
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-child-process-spawnsync-args.js
@@ -0,0 +1,55 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+// This test confirms that `undefined`, `null`, and `[]` can be used
+// as a placeholder for the second argument (`args`) of `spawnSync()`.
+// Previously, there was a bug where using `undefined` for the second argument
+// caused the third argument (`options`) to be ignored.
+// See https://github.com/nodejs/node/issues/24912.
+
+const common = require('../common');
+const tmpdir = require('../common/tmpdir');
+
+const assert = require('assert');
+const { spawnSync } = require('child_process');
+
+const command = common.isWindows ? 'cd' : 'pwd';
+const options = { cwd: tmpdir.path };
+
+tmpdir.refresh();
+
+if (common.isWindows) {
+ // This test is not the case for Windows based systems
+ // unless the `shell` options equals to `true`
+
+ options.shell = true;
+}
+
+const testCases = [
+ undefined,
+ null,
+ [],
+];
+
+const expectedResult = tmpdir.path.trim().toLowerCase();
+
+const results = testCases.map((testCase) => {
+ const { stdout, stderr, error } = spawnSync(
+ command,
+ testCase,
+ options
+ );
+
+ assert.ifError(error);
+ assert.deepStrictEqual(stderr, Buffer.alloc(0));
+
+ return stdout.toString().trim().toLowerCase();
+});
+
+assert.deepStrictEqual([...new Set(results)], [expectedResult]);
diff --git a/tests/node_compat/test/parallel/test-child-process-spawnsync-env.js b/tests/node_compat/test/parallel/test-child-process-spawnsync-env.js
new file mode 100644
index 000000000..d08ed48d9
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-child-process-spawnsync-env.js
@@ -0,0 +1,47 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.8.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// TODO(cjihrig): The process.argv[3] check should be argv[2], and the
+// arguments array passed to spawnSync() should not need to include
+// "require.ts".
+
+'use strict';
+require('../common');
+const assert = require('assert');
+const cp = require('child_process');
+
+if (process.argv[3] === 'child') {
+ console.log(process.env.foo);
+} else {
+ const expected = 'bar';
+ const child = cp.spawnSync(process.execPath, ["require.ts", __filename, 'child'], {
+ env: Object.assign(process.env, { foo: expected })
+ });
+
+ assert.strictEqual(child.stdout.toString().trim(), expected);
+}
diff --git a/tests/node_compat/test/parallel/test-child-process-spawnsync-maxbuf.js b/tests/node_compat/test/parallel/test-child-process-spawnsync-maxbuf.js
new file mode 100644
index 000000000..62b71c729
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-child-process-spawnsync-maxbuf.js
@@ -0,0 +1,65 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+require('../common');
+
+// This test checks that the maxBuffer option for child_process.spawnSync()
+// works as expected.
+
+const assert = require('assert');
+const spawnSync = require('child_process').spawnSync;
+const { getSystemErrorName } = require('util');
+const msgOut = 'this is stdout';
+const msgOutBuf = Buffer.from(`${msgOut}\n`);
+
+const args = [
+ '-e',
+ `console.log("${msgOut}");`,
+];
+
+// Verify that an error is returned if maxBuffer is surpassed.
+{
+ const ret = spawnSync(process.execPath, args, { maxBuffer: 1 });
+
+ assert.ok(ret.error, 'maxBuffer should error');
+ assert.strictEqual(ret.error.code, 'ENOBUFS');
+ assert.strictEqual(getSystemErrorName(ret.error.errno), 'ENOBUFS');
+ // We can have buffers larger than maxBuffer because underneath we alloc 64k
+ // that matches our read sizes.
+ assert.deepStrictEqual(ret.stdout, msgOutBuf);
+}
+
+// Verify that a maxBuffer size of Infinity works.
+{
+ const ret = spawnSync(process.execPath, args, { maxBuffer: Infinity });
+
+ assert.ifError(ret.error);
+ assert.deepStrictEqual(ret.stdout, msgOutBuf);
+}
+
+// Default maxBuffer size is 1024 * 1024.
+{
+ const args = ['-e', "console.log('a'.repeat(1024 * 1024))"];
+ const ret = spawnSync(process.execPath, args);
+
+ assert.ok(ret.error, 'maxBuffer should error');
+ assert.strictEqual(ret.error.code, 'ENOBUFS');
+ assert.strictEqual(getSystemErrorName(ret.error.errno), 'ENOBUFS');
+}
+
+// Default maxBuffer size is 1024 * 1024.
+{
+ const args = ['-e', "console.log('a'.repeat(1024 * 1024 - 1))"];
+ const ret = spawnSync(process.execPath, args);
+
+ assert.ifError(ret.error);
+ assert.deepStrictEqual(
+ ret.stdout.toString().trim(),
+ 'a'.repeat(1024 * 1024 - 1)
+ );
+}
diff --git a/tests/node_compat/test/parallel/test-child-process-spawnsync-validation-errors.js b/tests/node_compat/test/parallel/test-child-process-spawnsync-validation-errors.js
new file mode 100644
index 000000000..89ff02260
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-child-process-spawnsync-validation-errors.js
@@ -0,0 +1,223 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const spawnSync = require('child_process').spawnSync;
+const signals = require('os').constants.signals;
+const rootUser = common.isWindows ? false :
+ common.isIBMi ? true : process.getuid() === 0;
+
+const invalidArgTypeError = { code: 'ERR_INVALID_ARG_TYPE', name: 'TypeError' };
+const invalidRangeError = { code: 'ERR_OUT_OF_RANGE', name: 'RangeError' };
+
+function pass(option, value) {
+ // Run the command with the specified option. Since it's not a real command,
+ // spawnSync() should run successfully but return an ENOENT error.
+ const child = spawnSync('not_a_real_command', { [option]: value });
+
+ assert.strictEqual(child.error.code, 'ENOENT');
+}
+
+function fail(option, value, message) {
+ assert.throws(() => {
+ spawnSync('not_a_real_command', { [option]: value });
+ }, message);
+}
+
+{
+ // Validate the cwd option
+ pass('cwd', undefined);
+ pass('cwd', null);
+ pass('cwd', __dirname);
+ fail('cwd', 0, invalidArgTypeError);
+ fail('cwd', 1, invalidArgTypeError);
+ fail('cwd', true, invalidArgTypeError);
+ fail('cwd', false, invalidArgTypeError);
+ fail('cwd', [], invalidArgTypeError);
+ fail('cwd', {}, invalidArgTypeError);
+ fail('cwd', common.mustNotCall(), invalidArgTypeError);
+}
+
+{
+ // Validate the detached option
+ pass('detached', undefined);
+ pass('detached', null);
+ pass('detached', true);
+ pass('detached', false);
+ fail('detached', 0, invalidArgTypeError);
+ fail('detached', 1, invalidArgTypeError);
+ fail('detached', __dirname, invalidArgTypeError);
+ fail('detached', [], invalidArgTypeError);
+ fail('detached', {}, invalidArgTypeError);
+ fail('detached', common.mustNotCall(), invalidArgTypeError);
+}
+
+if (!common.isWindows) {
+ {
+ // Validate the uid option
+ if (!rootUser) {
+ pass('uid', undefined);
+ pass('uid', null);
+ pass('uid', process.getuid());
+ fail('uid', __dirname, invalidArgTypeError);
+ fail('uid', true, invalidArgTypeError);
+ fail('uid', false, invalidArgTypeError);
+ fail('uid', [], invalidArgTypeError);
+ fail('uid', {}, invalidArgTypeError);
+ fail('uid', common.mustNotCall(), invalidArgTypeError);
+ fail('uid', NaN, invalidArgTypeError);
+ fail('uid', Infinity, invalidArgTypeError);
+ fail('uid', 3.1, invalidArgTypeError);
+ fail('uid', -3.1, invalidArgTypeError);
+ }
+ }
+
+ {
+ // Validate the gid option
+ if (process.getgid() !== 0) {
+ pass('gid', undefined);
+ pass('gid', null);
+ pass('gid', process.getgid());
+ fail('gid', __dirname, invalidArgTypeError);
+ fail('gid', true, invalidArgTypeError);
+ fail('gid', false, invalidArgTypeError);
+ fail('gid', [], invalidArgTypeError);
+ fail('gid', {}, invalidArgTypeError);
+ fail('gid', common.mustNotCall(), invalidArgTypeError);
+ fail('gid', NaN, invalidArgTypeError);
+ fail('gid', Infinity, invalidArgTypeError);
+ fail('gid', 3.1, invalidArgTypeError);
+ fail('gid', -3.1, invalidArgTypeError);
+ }
+ }
+}
+
+{
+ // Validate the shell option
+ pass('shell', undefined);
+ pass('shell', null);
+ pass('shell', false);
+ fail('shell', 0, invalidArgTypeError);
+ fail('shell', 1, invalidArgTypeError);
+ fail('shell', [], invalidArgTypeError);
+ fail('shell', {}, invalidArgTypeError);
+ fail('shell', common.mustNotCall(), invalidArgTypeError);
+}
+
+{
+ // Validate the argv0 option
+ pass('argv0', undefined);
+ pass('argv0', null);
+ pass('argv0', 'myArgv0');
+ fail('argv0', 0, invalidArgTypeError);
+ fail('argv0', 1, invalidArgTypeError);
+ fail('argv0', true, invalidArgTypeError);
+ fail('argv0', false, invalidArgTypeError);
+ fail('argv0', [], invalidArgTypeError);
+ fail('argv0', {}, invalidArgTypeError);
+ fail('argv0', common.mustNotCall(), invalidArgTypeError);
+}
+
+{
+ // Validate the windowsHide option
+ pass('windowsHide', undefined);
+ pass('windowsHide', null);
+ pass('windowsHide', true);
+ pass('windowsHide', false);
+ fail('windowsHide', 0, invalidArgTypeError);
+ fail('windowsHide', 1, invalidArgTypeError);
+ fail('windowsHide', __dirname, invalidArgTypeError);
+ fail('windowsHide', [], invalidArgTypeError);
+ fail('windowsHide', {}, invalidArgTypeError);
+ fail('windowsHide', common.mustNotCall(), invalidArgTypeError);
+}
+
+{
+ // Validate the windowsVerbatimArguments option
+ pass('windowsVerbatimArguments', undefined);
+ pass('windowsVerbatimArguments', null);
+ pass('windowsVerbatimArguments', true);
+ pass('windowsVerbatimArguments', false);
+ fail('windowsVerbatimArguments', 0, invalidArgTypeError);
+ fail('windowsVerbatimArguments', 1, invalidArgTypeError);
+ fail('windowsVerbatimArguments', __dirname, invalidArgTypeError);
+ fail('windowsVerbatimArguments', [], invalidArgTypeError);
+ fail('windowsVerbatimArguments', {}, invalidArgTypeError);
+ fail('windowsVerbatimArguments', common.mustNotCall(), invalidArgTypeError);
+}
+
+{
+ // Validate the timeout option
+ pass('timeout', undefined);
+ pass('timeout', null);
+ pass('timeout', 1);
+ pass('timeout', 0);
+ fail('timeout', -1, invalidRangeError);
+ fail('timeout', true, invalidRangeError);
+ fail('timeout', false, invalidRangeError);
+ fail('timeout', __dirname, invalidRangeError);
+ fail('timeout', [], invalidRangeError);
+ fail('timeout', {}, invalidRangeError);
+ fail('timeout', common.mustNotCall(), invalidRangeError);
+ fail('timeout', NaN, invalidRangeError);
+ fail('timeout', Infinity, invalidRangeError);
+ fail('timeout', 3.1, invalidRangeError);
+ fail('timeout', -3.1, invalidRangeError);
+}
+
+{
+ // Validate the maxBuffer option
+ pass('maxBuffer', undefined);
+ pass('maxBuffer', null);
+ pass('maxBuffer', 1);
+ pass('maxBuffer', 0);
+ pass('maxBuffer', Infinity);
+ pass('maxBuffer', 3.14);
+ fail('maxBuffer', -1, invalidRangeError);
+ fail('maxBuffer', NaN, invalidRangeError);
+ fail('maxBuffer', -Infinity, invalidRangeError);
+ fail('maxBuffer', true, invalidRangeError);
+ fail('maxBuffer', false, invalidRangeError);
+ fail('maxBuffer', __dirname, invalidRangeError);
+ fail('maxBuffer', [], invalidRangeError);
+ fail('maxBuffer', {}, invalidRangeError);
+ fail('maxBuffer', common.mustNotCall(), invalidRangeError);
+}
+
+{
+ // Validate the killSignal option
+ const unknownSignalErr = { code: 'ERR_UNKNOWN_SIGNAL', name: 'TypeError' };
+
+ pass('killSignal', undefined);
+ pass('killSignal', null);
+ pass('killSignal', 'SIGKILL');
+ fail('killSignal', 'SIGNOTAVALIDSIGNALNAME', unknownSignalErr);
+ fail('killSignal', true, invalidArgTypeError);
+ fail('killSignal', false, invalidArgTypeError);
+ fail('killSignal', [], invalidArgTypeError);
+ fail('killSignal', {}, invalidArgTypeError);
+ fail('killSignal', common.mustNotCall(), invalidArgTypeError);
+
+ // Invalid signal names and numbers should fail
+ fail('killSignal', 500, unknownSignalErr);
+ fail('killSignal', 0, unknownSignalErr);
+ fail('killSignal', -200, unknownSignalErr);
+ fail('killSignal', 3.14, unknownSignalErr);
+
+ Object.getOwnPropertyNames(Object.prototype).forEach((property) => {
+ fail('killSignal', property, unknownSignalErr);
+ });
+
+ // Valid signal names and numbers should pass
+ for (const signalName in signals) {
+ pass('killSignal', signals[signalName]);
+ pass('killSignal', signalName);
+ pass('killSignal', signalName.toLowerCase());
+ }
+}
diff --git a/tests/node_compat/test/parallel/test-child-process-spawnsync.js b/tests/node_compat/test/parallel/test-child-process-spawnsync.js
new file mode 100644
index 000000000..bb60f3bef
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-child-process-spawnsync.js
@@ -0,0 +1,74 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const tmpdir = require('../common/tmpdir');
+tmpdir.refresh();
+
+const assert = require('assert');
+const { spawnSync } = require('child_process');
+const { getSystemErrorName } = require('util');
+
+// `sleep` does different things on Windows and Unix, but in both cases, it does
+// more-or-less nothing if there are no parameters
+const ret = spawnSync('sleep', ['0']);
+assert.strictEqual(ret.status, 0);
+
+// Error test when command does not exist
+const ret_err = spawnSync('command_does_not_exist', ['bar']).error;
+
+assert.strictEqual(ret_err.code, 'ENOENT');
+assert.strictEqual(getSystemErrorName(ret_err.errno), 'ENOENT');
+assert.strictEqual(ret_err.syscall, 'spawnSync command_does_not_exist');
+assert.strictEqual(ret_err.path, 'command_does_not_exist');
+assert.deepStrictEqual(ret_err.spawnargs, ['bar']);
+
+{
+ // Test the cwd option
+ const cwd = tmpdir.path;
+ const response = spawnSync(...common.pwdCommand, { cwd });
+
+ assert.strictEqual(response.stdout.toString().trim(), cwd);
+}
+
+
+{
+ // Assert Buffer is the default encoding
+ const retDefault = spawnSync(...common.pwdCommand);
+ const retBuffer = spawnSync(...common.pwdCommand, { encoding: 'buffer' });
+ assert.deepStrictEqual(retDefault.output, retBuffer.output);
+
+ const retUTF8 = spawnSync(...common.pwdCommand, { encoding: 'utf8' });
+ const stringifiedDefault = [
+ null,
+ retDefault.stdout.toString(),
+ retDefault.stderr.toString(),
+ ];
+ assert.deepStrictEqual(retUTF8.output, stringifiedDefault);
+}
diff --git a/tests/node_compat/test/parallel/test-child-process-stdio-inherit.js b/tests/node_compat/test/parallel/test-child-process-stdio-inherit.js
new file mode 100644
index 000000000..e213dd6b8
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-child-process-stdio-inherit.js
@@ -0,0 +1,66 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// TODO(PolarETech): The process.argv[3] check should be argv[2], and
+// the args passed to spawn() should not need to include "require.ts".
+
+'use strict';
+require('../common');
+const assert = require('assert');
+const spawn = require('child_process').spawn;
+
+if (process.argv[3] === 'parent')
+ parent();
+else
+ grandparent();
+
+function grandparent() {
+ const child = spawn(process.execPath, ['require.ts', __filename, 'parent']);
+ child.stderr.pipe(process.stderr);
+ let output = '';
+ const input = 'asdfasdf';
+
+ child.stdout.on('data', function(chunk) {
+ output += chunk;
+ });
+ child.stdout.setEncoding('utf8');
+
+ child.stdin.end(input);
+
+ child.on('close', function(code, signal) {
+ assert.strictEqual(code, 0);
+ assert.strictEqual(signal, null);
+ // 'cat' on windows adds a \r\n at the end.
+ assert.strictEqual(output.trim(), input.trim());
+ });
+}
+
+function parent() {
+ // Should not immediately exit.
+ spawn('cat', [], { stdio: 'inherit' });
+}
diff --git a/tests/node_compat/test/parallel/test-child-process-stdout-flush-exit.js b/tests/node_compat/test/parallel/test-child-process-stdout-flush-exit.js
new file mode 100644
index 000000000..585cc6084
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-child-process-stdout-flush-exit.js
@@ -0,0 +1,67 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// TODO(PolarETech): The process.argv[3] check should be argv[2],
+// the args passed to spawn() should not need to include "require.ts",
+// and the process.argv[2] passed to spawn() should be argv[1].
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+
+// If child process output to console and exit
+// The console.log statements here are part of the test.
+if (process.argv[3] === 'child') {
+ console.log('hello');
+ for (let i = 0; i < 200; i++) {
+ console.log('filler');
+ }
+ console.log('goodbye');
+ process.exit(0);
+} else {
+ // parent process
+ const spawn = require('child_process').spawn;
+
+ // spawn self as child
+ const child = spawn(process.argv[0], ['require.ts', process.argv[2], 'child']);
+
+ let stdout = '';
+
+ child.stderr.on('data', common.mustNotCall());
+
+ // Check if we receive both 'hello' at start and 'goodbye' at end
+ child.stdout.setEncoding('utf8');
+ child.stdout.on('data', common.mustCallAtLeast((data) => {
+ stdout += data;
+ }));
+
+ child.on('close', common.mustCall(() => {
+ assert.strictEqual(stdout.slice(0, 6), 'hello\n');
+ assert.strictEqual(stdout.slice(stdout.length - 8), 'goodbye\n');
+ }));
+}
diff --git a/tests/node_compat/test/parallel/test-child-process-stdout-flush.js b/tests/node_compat/test/parallel/test-child-process-stdout-flush.js
new file mode 100644
index 000000000..4054d2189
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-child-process-stdout-flush.js
@@ -0,0 +1,58 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// TODO(PolarETech): The args passed to spawn() should not need to
+// include "require.ts".
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const spawn = require('child_process').spawn;
+const fixtures = require('../common/fixtures');
+
+const sub = fixtures.path('print-chars.js');
+
+const n = 500000;
+
+const child = spawn(process.argv[0], ['require.ts', sub, n]);
+
+let count = 0;
+
+child.stderr.setEncoding('utf8');
+child.stderr.on('data', common.mustNotCall());
+
+child.stdout.setEncoding('utf8');
+child.stdout.on('data', (data) => {
+ count += data.length;
+});
+
+child.on('close', common.mustCall((code, signal) => {
+ assert.strictEqual(code, 0);
+ assert.strictEqual(signal, null);
+ assert.strictEqual(n, count);
+}));
diff --git a/tests/node_compat/test/parallel/test-console-async-write-error.js b/tests/node_compat/test/parallel/test-console-async-write-error.js
new file mode 100644
index 000000000..e7591cb9b
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-console-async-write-error.js
@@ -0,0 +1,22 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const { Console } = require('console');
+const { Writable } = require('stream');
+
+for (const method of ['dir', 'log', 'warn']) {
+ const out = new Writable({
+ write: common.mustCall((chunk, enc, callback) => {
+ process.nextTick(callback, new Error('foobar'));
+ })
+ });
+
+ const c = new Console(out, out, true);
+ c[method]('abc'); // Should not throw.
+}
diff --git a/tests/node_compat/test/parallel/test-console-group.js b/tests/node_compat/test/parallel/test-console-group.js
new file mode 100644
index 000000000..f07107cec
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-console-group.js
@@ -0,0 +1,248 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+require('../common');
+const {
+ hijackStdout,
+ hijackStderr,
+ restoreStdout,
+ restoreStderr
+} = require('../common/hijackstdio');
+
+const assert = require('assert');
+const Console = require('console').Console;
+
+let c, stdout, stderr;
+
+function setup(groupIndentation) {
+ stdout = '';
+ hijackStdout(function(data) {
+ stdout += data;
+ });
+
+ stderr = '';
+ hijackStderr(function(data) {
+ stderr += data;
+ });
+
+ c = new Console({ stdout: process.stdout,
+ stderr: process.stderr,
+ colorMode: false,
+ groupIndentation: groupIndentation });
+}
+
+function teardown() {
+ restoreStdout();
+ restoreStderr();
+}
+
+// Basic group() functionality
+{
+ setup();
+ const expectedOut = 'This is the outer level\n' +
+ ' Level 2\n' +
+ ' Level 3\n' +
+ ' Back to level 2\n' +
+ 'Back to the outer level\n' +
+ 'Still at the outer level\n';
+
+
+ const expectedErr = ' More of level 3\n';
+
+ c.log('This is the outer level');
+ c.group();
+ c.log('Level 2');
+ c.group();
+ c.log('Level 3');
+ c.warn('More of level 3');
+ c.groupEnd();
+ c.log('Back to level 2');
+ c.groupEnd();
+ c.log('Back to the outer level');
+ c.groupEnd();
+ c.log('Still at the outer level');
+
+ assert.strictEqual(stdout, expectedOut);
+ assert.strictEqual(stderr, expectedErr);
+ teardown();
+}
+
+// Group indentation is tracked per Console instance.
+{
+ setup();
+ const expectedOut = 'No indentation\n' +
+ 'None here either\n' +
+ ' Now the first console is indenting\n' +
+ 'But the second one does not\n';
+ const expectedErr = '';
+
+ const c2 = new Console(process.stdout, process.stderr);
+ c.log('No indentation');
+ c2.log('None here either');
+ c.group();
+ c.log('Now the first console is indenting');
+ c2.log('But the second one does not');
+
+ assert.strictEqual(stdout, expectedOut);
+ assert.strictEqual(stderr, expectedErr);
+ teardown();
+}
+
+// Make sure labels work.
+{
+ setup();
+ const expectedOut = 'This is a label\n' +
+ ' And this is the data for that label\n';
+ const expectedErr = '';
+
+ c.group('This is a label');
+ c.log('And this is the data for that label');
+
+ assert.strictEqual(stdout, expectedOut);
+ assert.strictEqual(stderr, expectedErr);
+ teardown();
+}
+
+// Check that console.groupCollapsed() is an alias of console.group()
+{
+ setup();
+ const expectedOut = 'Label\n' +
+ ' Level 2\n' +
+ ' Level 3\n';
+ const expectedErr = '';
+
+ c.groupCollapsed('Label');
+ c.log('Level 2');
+ c.groupCollapsed();
+ c.log('Level 3');
+
+ assert.strictEqual(stdout, expectedOut);
+ assert.strictEqual(stderr, expectedErr);
+ teardown();
+}
+
+// Check that multiline strings and object output are indented properly.
+{
+ setup();
+ const expectedOut = 'not indented\n' +
+ ' indented\n' +
+ ' also indented\n' +
+ ' {\n' +
+ " also: 'a',\n" +
+ " multiline: 'object',\n" +
+ " should: 'be',\n" +
+ " indented: 'properly',\n" +
+ " kthx: 'bai'\n" +
+ ' }\n';
+ const expectedErr = '';
+
+ c.log('not indented');
+ c.group();
+ c.log('indented\nalso indented');
+ c.log({ also: 'a',
+ multiline: 'object',
+ should: 'be',
+ indented: 'properly',
+ kthx: 'bai' });
+
+ assert.strictEqual(stdout, expectedOut);
+ assert.strictEqual(stderr, expectedErr);
+ teardown();
+}
+
+// Check that the kGroupIndent symbol property is not enumerable
+{
+ const keys = Reflect.ownKeys(console)
+ .filter((val) => Object.prototype.propertyIsEnumerable.call(console, val))
+ .map((val) => val.toString());
+ assert(!keys.includes('Symbol(groupIndent)'),
+ 'groupIndent should not be enumerable');
+}
+
+// Check custom groupIndentation.
+{
+ setup(3);
+ const expectedOut = 'Set the groupIndentation parameter to 3\n' +
+ 'This is the outer level\n' +
+ ' Level 2\n' +
+ ' Level 3\n' +
+ ' Back to level 2\n' +
+ 'Back to the outer level\n' +
+ 'Still at the outer level\n';
+
+
+ const expectedErr = ' More of level 3\n';
+
+ c.log('Set the groupIndentation parameter to 3');
+ c.log('This is the outer level');
+ c.group();
+ c.log('Level 2');
+ c.group();
+ c.log('Level 3');
+ c.warn('More of level 3');
+ c.groupEnd();
+ c.log('Back to level 2');
+ c.groupEnd();
+ c.log('Back to the outer level');
+ c.groupEnd();
+ c.log('Still at the outer level');
+
+ assert.strictEqual(stdout, expectedOut);
+ assert.strictEqual(stderr, expectedErr);
+ teardown();
+}
+
+// Check the correctness of the groupIndentation parameter.
+{
+ // TypeError
+ [null, 'str', [], false, true, {}].forEach((e) => {
+ assert.throws(
+ () => {
+ new Console({ stdout: process.stdout,
+ stderr: process.stderr,
+ groupIndentation: e });
+ },
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError'
+ }
+ );
+ });
+
+ // RangeError for integer
+ [NaN, 1.01].forEach((e) => {
+ assert.throws(
+ () => {
+ new Console({ stdout: process.stdout,
+ stderr: process.stderr,
+ groupIndentation: e });
+ },
+ {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError',
+ message: /an integer/,
+ }
+ );
+ });
+
+ // RangeError
+ [-1, 1001].forEach((e) => {
+ assert.throws(
+ () => {
+ new Console({ stdout: process.stdout,
+ stderr: process.stderr,
+ groupIndentation: e });
+ },
+ {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError',
+ message: />= 0 && <= 1000/,
+ }
+ );
+ });
+}
diff --git a/tests/node_compat/test/parallel/test-console-instance.js b/tests/node_compat/test/parallel/test-console-instance.js
new file mode 100644
index 000000000..ee561564f
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-console-instance.js
@@ -0,0 +1,156 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 16.13.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const Stream = require('stream');
+const requiredConsole = require('console');
+const Console = requiredConsole.Console;
+
+const out = new Stream();
+const err = new Stream();
+
+// Ensure the Console instance doesn't write to the
+// process' "stdout" or "stderr" streams.
+process.stdout.write = process.stderr.write = common.mustNotCall();
+
+// Make sure that the "Console" function exists.
+assert.strictEqual(typeof Console, 'function');
+
+// Note: We don't replace global console with node.js console
+// assert.strictEqual(requiredConsole, global.console);
+// Make sure the custom instanceof of Console works
+assert.ok(global.console instanceof Console);
+assert.ok(!({} instanceof Console));
+
+// Make sure that the Console constructor throws
+// when not given a writable stream instance.
+assert.throws(
+ () => { new Console(); },
+ {
+ code: 'ERR_CONSOLE_WRITABLE_STREAM',
+ name: 'TypeError',
+ message: /stdout/
+ }
+);
+
+// Console constructor should throw if stderr exists but is not writable.
+assert.throws(
+ () => {
+ out.write = () => {};
+ err.write = undefined;
+ new Console(out, err);
+ },
+ {
+ code: 'ERR_CONSOLE_WRITABLE_STREAM',
+ name: 'TypeError',
+ message: /stderr/
+ }
+);
+
+out.write = err.write = (d) => {};
+
+{
+ const c = new Console(out, err);
+ assert.ok(c instanceof Console);
+
+ out.write = err.write = common.mustCall((d) => {
+ assert.strictEqual(d, 'test\n');
+ }, 2);
+
+ c.log('test');
+ c.error('test');
+
+ out.write = common.mustCall((d) => {
+ assert.strictEqual(d, '{ foo: 1 }\n');
+ });
+
+ c.dir({ foo: 1 });
+
+ // Ensure that the console functions are bound to the console instance.
+ let called = 0;
+ out.write = common.mustCall((d) => {
+ called++;
+ assert.strictEqual(d, `${called} ${called - 1} [ 1, 2, 3 ]\n`);
+ }, 3);
+
+ [1, 2, 3].forEach(c.log);
+}
+
+// Test calling Console without the `new` keyword.
+{
+ const withoutNew = Console(out, err);
+ assert.ok(withoutNew instanceof Console);
+}
+
+// Test extending Console
+{
+ class MyConsole extends Console {
+ hello() {}
+ // See if the methods on Console.prototype are overridable.
+ log() { return 'overridden'; }
+ }
+ const myConsole = new MyConsole(process.stdout);
+ assert.strictEqual(typeof myConsole.hello, 'function');
+ assert.ok(myConsole instanceof Console);
+ assert.strictEqual(myConsole.log(), 'overridden');
+
+ const log = myConsole.log;
+ assert.strictEqual(log(), 'overridden');
+}
+
+// Instance that does not ignore the stream errors.
+{
+ const c2 = new Console(out, err, false);
+
+ out.write = () => { throw new Error('out'); };
+ err.write = () => { throw new Error('err'); };
+
+ assert.throws(() => c2.log('foo'), /^Error: out$/);
+ assert.throws(() => c2.warn('foo'), /^Error: err$/);
+ assert.throws(() => c2.dir('foo'), /^Error: out$/);
+}
+
+// Console constructor throws if inspectOptions is not an object.
+[null, true, false, 'foo', 5, Symbol()].forEach((inspectOptions) => {
+ assert.throws(
+ () => {
+ new Console({
+ stdout: out,
+ stderr: err,
+ inspectOptions
+ });
+ },
+ {
+ message: 'The "options.inspectOptions" property must be of type object.' +
+ common.invalidArgTypeHelper(inspectOptions),
+ code: 'ERR_INVALID_ARG_TYPE'
+ }
+ );
+});
diff --git a/tests/node_compat/test/parallel/test-console-log-stdio-broken-dest.js b/tests/node_compat/test/parallel/test-console-log-stdio-broken-dest.js
new file mode 100644
index 000000000..832e1a510
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-console-log-stdio-broken-dest.js
@@ -0,0 +1,31 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const { Writable } = require('stream');
+const { Console } = require('console');
+const { EventEmitter } = require('events');
+
+const stream = new Writable({
+ write(chunk, enc, cb) {
+ cb();
+ },
+ writev(chunks, cb) {
+ setTimeout(cb, 10, new Error('kaboom'));
+ }
+});
+const myConsole = new Console(stream, stream);
+
+process.on('warning', common.mustNotCall());
+
+stream.cork();
+for (let i = 0; i < EventEmitter.defaultMaxListeners + 1; i++) {
+ myConsole.log('a message');
+}
+stream.uncork();
diff --git a/tests/node_compat/test/parallel/test-console-log-throw-primitive.js b/tests/node_compat/test/parallel/test-console-log-throw-primitive.js
new file mode 100644
index 000000000..760c96399
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-console-log-throw-primitive.js
@@ -0,0 +1,21 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+require('../common');
+const { Writable } = require('stream');
+const { Console } = require('console');
+
+const stream = new Writable({
+ write() {
+ throw null; // eslint-disable-line no-throw-literal
+ }
+});
+
+const console = new Console({ stdout: stream });
+
+console.log('test'); // Should not throw
diff --git a/tests/node_compat/test/parallel/test-console-no-swallow-stack-overflow.js b/tests/node_compat/test/parallel/test-console-no-swallow-stack-overflow.js
new file mode 100644
index 000000000..98621b3ce
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-console-no-swallow-stack-overflow.js
@@ -0,0 +1,26 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const { Console } = require('console');
+const { Writable } = require('stream');
+
+for (const method of ['dir', 'log', 'warn']) {
+ assert.throws(() => {
+ const out = new Writable({
+ write: common.mustCall(function write(...args) {
+ // Exceeds call stack.
+ return write(...args);
+ }),
+ });
+ const c = new Console(out, out, true);
+
+ c[method]('Hello, world!');
+ }, { name: 'RangeError' });
+}
diff --git a/tests/node_compat/test/parallel/test-console-sync-write-error.js b/tests/node_compat/test/parallel/test-console-sync-write-error.js
new file mode 100644
index 000000000..1018a3b54
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-console-sync-write-error.js
@@ -0,0 +1,46 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const { Console } = require('console');
+const { Writable } = require('stream');
+
+for (const method of ['dir', 'log', 'warn']) {
+ {
+ const out = new Writable({
+ write: common.mustCall((chunk, enc, callback) => {
+ callback(new Error('foobar'));
+ })
+ });
+
+ const c = new Console(out, out, true);
+ c[method]('abc'); // Should not throw.
+ }
+
+ {
+ const out = new Writable({
+ write: common.mustCall((chunk, enc, callback) => {
+ throw new Error('foobar');
+ })
+ });
+
+ const c = new Console(out, out, true);
+ c[method]('abc'); // Should not throw.
+ }
+
+ {
+ const out = new Writable({
+ write: common.mustCall((chunk, enc, callback) => {
+ setImmediate(() => callback(new Error('foobar')));
+ })
+ });
+
+ const c = new Console(out, out, true);
+ c[method]('abc'); // Should not throw.
+ }
+}
diff --git a/tests/node_compat/test/parallel/test-console-table.js b/tests/node_compat/test/parallel/test-console-table.js
new file mode 100644
index 000000000..a7fddac1e
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-console-table.js
@@ -0,0 +1,300 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+require('../common');
+
+const assert = require('assert');
+const { Console } = require('console');
+
+const queue = [];
+
+const console = new Console({ write: (x) => {
+ queue.push(x);
+}, removeListener: () => {} }, process.stderr, false);
+
+function test(data, only, expected) {
+ if (arguments.length === 2) {
+ expected = only;
+ only = undefined;
+ }
+ console.table(data, only);
+ assert.deepStrictEqual(
+ queue.shift().split('\n'),
+ expected.trimLeft().split('\n')
+ );
+}
+
+assert.throws(() => console.table([], false), {
+ code: 'ERR_INVALID_ARG_TYPE',
+});
+
+test(null, 'null\n');
+test(undefined, 'undefined\n');
+test(false, 'false\n');
+test('hi', 'hi\n');
+test(Symbol(), 'Symbol()\n');
+test(function() {}, '[Function (anonymous)]\n');
+
+test([1, 2, 3], `
+┌─────────┬────────┐
+│ (index) │ Values │
+├─────────┼────────┤
+│ 0 │ 1 │
+│ 1 │ 2 │
+│ 2 │ 3 │
+└─────────┴────────┘
+`);
+
+test([Symbol(), 5, [10]], `
+┌─────────┬────┬──────────┐
+│ (index) │ 0 │ Values │
+├─────────┼────┼──────────┤
+│ 0 │ │ Symbol() │
+│ 1 │ │ 5 │
+│ 2 │ 10 │ │
+└─────────┴────┴──────────┘
+`);
+
+test([null, 5], `
+┌─────────┬────────┐
+│ (index) │ Values │
+├─────────┼────────┤
+│ 0 │ null │
+│ 1 │ 5 │
+└─────────┴────────┘
+`);
+
+test([undefined, 5], `
+┌─────────┬───────────┐
+│ (index) │ Values │
+├─────────┼───────────┤
+│ 0 │ undefined │
+│ 1 │ 5 │
+└─────────┴───────────┘
+`);
+
+test({ a: 1, b: Symbol(), c: [10] }, `
+┌─────────┬────┬──────────┐
+│ (index) │ 0 │ Values │
+├─────────┼────┼──────────┤
+│ a │ │ 1 │
+│ b │ │ Symbol() │
+│ c │ 10 │ │
+└─────────┴────┴──────────┘
+`);
+
+test(new Map([ ['a', 1], [Symbol(), [2]] ]), `
+┌───────────────────┬──────────┬────────┐
+│ (iteration index) │ Key │ Values │
+├───────────────────┼──────────┼────────┤
+│ 0 │ 'a' │ 1 │
+│ 1 │ Symbol() │ [ 2 ] │
+└───────────────────┴──────────┴────────┘
+`);
+
+test(new Set([1, 2, Symbol()]), `
+┌───────────────────┬──────────┐
+│ (iteration index) │ Values │
+├───────────────────┼──────────┤
+│ 0 │ 1 │
+│ 1 │ 2 │
+│ 2 │ Symbol() │
+└───────────────────┴──────────┘
+`);
+
+test({ a: 1, b: 2 }, ['a'], `
+┌─────────┬───┐
+│ (index) │ a │
+├─────────┼───┤
+│ a │ │
+│ b │ │
+└─────────┴───┘
+`);
+
+test([{ a: 1, b: 2 }, { a: 3, c: 4 }], ['a'], `
+┌─────────┬───┐
+│ (index) │ a │
+├─────────┼───┤
+│ 0 │ 1 │
+│ 1 │ 3 │
+└─────────┴───┘
+`);
+
+test(new Map([[1, 1], [2, 2], [3, 3]]).entries(), `
+┌───────────────────┬─────┬────────┐
+│ (iteration index) │ Key │ Values │
+├───────────────────┼─────┼────────┤
+│ 0 │ 1 │ 1 │
+│ 1 │ 2 │ 2 │
+│ 2 │ 3 │ 3 │
+└───────────────────┴─────┴────────┘
+`);
+
+test(new Map([[1, 1], [2, 2], [3, 3]]).values(), `
+┌───────────────────┬────────┐
+│ (iteration index) │ Values │
+├───────────────────┼────────┤
+│ 0 │ 1 │
+│ 1 │ 2 │
+│ 2 │ 3 │
+└───────────────────┴────────┘
+`);
+
+test(new Map([[1, 1], [2, 2], [3, 3]]).keys(), `
+┌───────────────────┬────────┐
+│ (iteration index) │ Values │
+├───────────────────┼────────┤
+│ 0 │ 1 │
+│ 1 │ 2 │
+│ 2 │ 3 │
+└───────────────────┴────────┘
+`);
+
+test(new Set([1, 2, 3]).values(), `
+┌───────────────────┬────────┐
+│ (iteration index) │ Values │
+├───────────────────┼────────┤
+│ 0 │ 1 │
+│ 1 │ 2 │
+│ 2 │ 3 │
+└───────────────────┴────────┘
+`);
+
+
+test({ a: { a: 1, b: 2, c: 3 } }, `
+┌─────────┬───┬───┬───┐
+│ (index) │ a │ b │ c │
+├─────────┼───┼───┼───┤
+│ a │ 1 │ 2 │ 3 │
+└─────────┴───┴───┴───┘
+`);
+
+test({ a: { a: { a: 1, b: 2, c: 3 } } }, `
+┌─────────┬──────────┐
+│ (index) │ a │
+├─────────┼──────────┤
+│ a │ [Object] │
+└─────────┴──────────┘
+`);
+
+test({ a: [1, 2] }, `
+┌─────────┬───┬───┐
+│ (index) │ 0 │ 1 │
+├─────────┼───┼───┤
+│ a │ 1 │ 2 │
+└─────────┴───┴───┘
+`);
+
+test({ a: [1, 2, 3, 4, 5], b: 5, c: { e: 5 } }, `
+┌─────────┬───┬───┬───┬───┬───┬───┬────────┐
+│ (index) │ 0 │ 1 │ 2 │ 3 │ 4 │ e │ Values │
+├─────────┼───┼───┼───┼───┼───┼───┼────────┤
+│ a │ 1 │ 2 │ 3 │ 4 │ 5 │ │ │
+│ b │ │ │ │ │ │ │ 5 │
+│ c │ │ │ │ │ │ 5 │ │
+└─────────┴───┴───┴───┴───┴───┴───┴────────┘
+`);
+
+test(new Uint8Array([1, 2, 3]), `
+┌─────────┬────────┐
+│ (index) │ Values │
+├─────────┼────────┤
+│ 0 │ 1 │
+│ 1 │ 2 │
+│ 2 │ 3 │
+└─────────┴────────┘
+`);
+
+test(Buffer.from([1, 2, 3]), `
+┌─────────┬────────┐
+│ (index) │ Values │
+├─────────┼────────┤
+│ 0 │ 1 │
+│ 1 │ 2 │
+│ 2 │ 3 │
+└─────────┴────────┘
+`);
+
+test({ a: undefined }, ['x'], `
+┌─────────┬───┐
+│ (index) │ x │
+├─────────┼───┤
+│ a │ │
+└─────────┴───┘
+`);
+
+test([], `
+┌─────────┐
+│ (index) │
+├─────────┤
+└─────────┘
+`);
+
+test(new Map(), `
+┌───────────────────┬─────┬────────┐
+│ (iteration index) │ Key │ Values │
+├───────────────────┼─────┼────────┤
+└───────────────────┴─────┴────────┘
+`);
+
+test([{ a: 1, b: 'Y' }, { a: 'Z', b: 2 }], `
+┌─────────┬─────┬─────┐
+│ (index) │ a │ b │
+├─────────┼─────┼─────┤
+│ 0 │ 1 │ 'Y' │
+│ 1 │ 'Z' │ 2 │
+└─────────┴─────┴─────┘
+`);
+
+{
+ const line = '─'.repeat(79);
+ const header = `${' '.repeat(37)}name${' '.repeat(40)}`;
+ const name = 'very long long long long long long long long long long long ' +
+ 'long long long long';
+ test([{ name }], `
+┌─────────┬──${line}──┐
+│ (index) │ ${header}│
+├─────────┼──${line}──┤
+│ 0 │ '${name}' │
+└─────────┴──${line}──┘
+`);
+}
+
+test({ foo: '¥', bar: '¥' }, `
+┌─────────┬────────┐
+│ (index) │ Values │
+├─────────┼────────┤
+│ foo │ '¥' │
+│ bar │ '¥' │
+└─────────┴────────┘
+`);
+
+test({ foo: '你好', bar: 'hello' }, `
+┌─────────┬─────────┐
+│ (index) │ Values │
+├─────────┼─────────┤
+│ foo │ '你好' │
+│ bar │ 'hello' │
+└─────────┴─────────┘
+`);
+
+// Regression test for prototype pollution via console.table. Earlier versions
+// of Node.js created an object with a non-null prototype within console.table
+// and then wrote to object[column][index], which lead to an error as well as
+// modifications to Object.prototype.
+test([{ foo: 10 }, { foo: 20 }], ['__proto__'], `
+┌─────────┬───────────┐
+│ (index) │ __proto__ │
+├─────────┼───────────┤
+│ 0 │ │
+│ 1 │ │
+└─────────┴───────────┘
+`);
+assert.strictEqual('0' in Object.prototype, false);
+assert.strictEqual('1' in Object.prototype, false);
diff --git a/tests/node_compat/test/parallel/test-console-tty-colors.js b/tests/node_compat/test/parallel/test-console-tty-colors.js
new file mode 100644
index 000000000..6b6886d1f
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-console-tty-colors.js
@@ -0,0 +1,102 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const util = require('util');
+const { Writable } = require('stream');
+const { Console } = require('console');
+
+function check(isTTY, colorMode, expectedColorMode, inspectOptions) {
+ const items = [
+ 1,
+ { a: 2 },
+ [ 'foo' ],
+ { '\\a': '\\bar' },
+ ];
+
+ let i = 0;
+ const stream = new Writable({
+ write: common.mustCall((chunk, enc, cb) => {
+ assert.strictEqual(chunk.trim(),
+ util.inspect(items[i++], {
+ colors: expectedColorMode,
+ ...inspectOptions
+ }));
+ cb();
+ }, items.length),
+ decodeStrings: false
+ });
+ stream.isTTY = isTTY;
+
+ // Set ignoreErrors to `false` here so that we see assertion failures
+ // from the `write()` call happen.
+ const testConsole = new Console({
+ stdout: stream,
+ ignoreErrors: false,
+ colorMode,
+ inspectOptions
+ });
+ for (const item of items) {
+ testConsole.log(item);
+ }
+}
+
+check(true, 'auto', true);
+check(false, 'auto', false);
+check(false, undefined, true, { colors: true, compact: false });
+check(true, 'auto', true, { compact: false });
+check(true, undefined, false, { colors: false });
+check(true, true, true);
+check(false, true, true);
+check(true, false, false);
+check(false, false, false);
+
+// Check invalid options.
+{
+ const stream = new Writable({
+ write: common.mustNotCall()
+ });
+
+ [0, 'true', null, {}, [], () => {}].forEach((colorMode) => {
+ const received = util.inspect(colorMode);
+ assert.throws(
+ () => {
+ new Console({
+ stdout: stream,
+ ignoreErrors: false,
+ colorMode: colorMode
+ });
+ },
+ {
+ message: `The argument 'colorMode' is invalid. Received ${received}`,
+ code: 'ERR_INVALID_ARG_VALUE'
+ }
+ );
+ });
+
+ [true, false, 'auto'].forEach((colorMode) => {
+ assert.throws(
+ () => {
+ new Console({
+ stdout: stream,
+ ignoreErrors: false,
+ colorMode: colorMode,
+ inspectOptions: {
+ colors: false
+ }
+ });
+ },
+ {
+ message: 'Option "options.inspectOptions.color" cannot be used in ' +
+ 'combination with option "colorMode"',
+ code: 'ERR_INCOMPATIBLE_OPTION_PAIR'
+ }
+ );
+ });
+}
diff --git a/tests/node_compat/test/parallel/test-crypto-dh-shared.js b/tests/node_compat/test/parallel/test-crypto-dh-shared.js
new file mode 100644
index 000000000..7266b00b9
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-crypto-dh-shared.js
@@ -0,0 +1,22 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+if (!common.hasCrypto)
+ common.skip('missing crypto');
+
+const assert = require('assert');
+const crypto = require('crypto');
+
+const alice = crypto.createDiffieHellmanGroup('modp5');
+const bob = crypto.createDiffieHellmanGroup('modp5');
+alice.generateKeys();
+bob.generateKeys();
+const aSecret = alice.computeSecret(bob.getPublicKey()).toString('hex');
+const bSecret = bob.computeSecret(alice.getPublicKey()).toString('hex');
+assert.strictEqual(aSecret, bSecret);
diff --git a/tests/node_compat/test/parallel/test-crypto-dh.js b/tests/node_compat/test/parallel/test-crypto-dh.js
new file mode 100644
index 000000000..bcf0c6764
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-crypto-dh.js
@@ -0,0 +1,214 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+'use strict';
+const common = require('../common');
+if (!common.hasCrypto)
+ common.skip('missing crypto');
+
+const assert = require('assert');
+const crypto = require('crypto');
+
+const size = common.hasFipsCrypto || common.hasOpenSSL3 ? 1024 : 256;
+const dh1 = crypto.createDiffieHellman(size);
+const p1 = dh1.getPrime('buffer');
+const dh2 = crypto.createDiffieHellman(p1, 'buffer');
+const key1 = dh1.generateKeys();
+const key2 = dh2.generateKeys('hex');
+const secret1 = dh1.computeSecret(key2, 'hex', 'base64');
+const secret2 = dh2.computeSecret(key1, 'latin1', 'buffer');
+
+// Test Diffie-Hellman with two parties sharing a secret,
+// using various encodings as we go along
+assert.strictEqual(secret2.toString('base64'), secret1);
+assert.strictEqual(dh1.verifyError, 0);
+assert.strictEqual(dh2.verifyError, 0);
+
+// https://github.com/nodejs/node/issues/32738
+// XXX(bnoordhuis) validateInt32() throwing ERR_OUT_OF_RANGE and RangeError
+// instead of ERR_INVALID_ARG_TYPE and TypeError is questionable, IMO.
+assert.throws(() => crypto.createDiffieHellman(13.37), {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError',
+ message: 'The value of "sizeOrKey" is out of range. ' +
+ 'It must be an integer. Received 13.37',
+});
+
+assert.throws(() => crypto.createDiffieHellman('abcdef', 13.37), {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError',
+ message: 'The value of "generator" is out of range. ' +
+ 'It must be an integer. Received 13.37',
+});
+
+for (const bits of [-1, 0, 1]) {
+ if (common.hasOpenSSL3) {
+ assert.throws(() => crypto.createDiffieHellman(bits), {
+ code: 'ERR_OSSL_DH_MODULUS_TOO_SMALL',
+ name: 'Error',
+ message: /modulus too small/,
+ });
+ } else {
+ assert.throws(() => crypto.createDiffieHellman(bits), {
+ code: 'ERR_OSSL_BN_BITS_TOO_SMALL',
+ name: 'Error',
+ message: /bits too small/,
+ });
+ }
+}
+
+// Through a fluke of history, g=0 defaults to DH_GENERATOR (2).
+{
+ const g = 0;
+ crypto.createDiffieHellman('abcdef', g);
+ crypto.createDiffieHellman('abcdef', 'hex', g);
+}
+
+for (const g of [-1, 1]) {
+ const ex = {
+ code: 'ERR_OSSL_DH_BAD_GENERATOR',
+ name: 'Error',
+ message: /bad generator/,
+ };
+ assert.throws(() => crypto.createDiffieHellman('abcdef', g), ex);
+ assert.throws(() => crypto.createDiffieHellman('abcdef', 'hex', g), ex);
+}
+
+crypto.createDiffieHellman('abcdef', Buffer.from([2])); // OK
+
+for (const g of [Buffer.from([]),
+ Buffer.from([0]),
+ Buffer.from([1])]) {
+ const ex = {
+ code: 'ERR_OSSL_DH_BAD_GENERATOR',
+ name: 'Error',
+ message: /bad generator/,
+ };
+ assert.throws(() => crypto.createDiffieHellman('abcdef', g), ex);
+ assert.throws(() => crypto.createDiffieHellman('abcdef', 'hex', g), ex);
+}
+
+[
+ [0x1, 0x2],
+ () => { },
+ /abc/,
+ {},
+].forEach((input) => {
+ assert.throws(
+ () => crypto.createDiffieHellman(input),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ }
+ );
+});
+
+// Create "another dh1" using generated keys from dh1,
+// and compute secret again
+const dh3 = crypto.createDiffieHellman(p1, 'buffer');
+const privkey1 = dh1.getPrivateKey();
+dh3.setPublicKey(key1);
+dh3.setPrivateKey(privkey1);
+
+assert.deepStrictEqual(dh1.getPrime(), dh3.getPrime());
+assert.deepStrictEqual(dh1.getGenerator(), dh3.getGenerator());
+assert.deepStrictEqual(dh1.getPublicKey(), dh3.getPublicKey());
+assert.deepStrictEqual(dh1.getPrivateKey(), dh3.getPrivateKey());
+assert.strictEqual(dh3.verifyError, 0);
+
+const secret3 = dh3.computeSecret(key2, 'hex', 'base64');
+
+assert.strictEqual(secret1, secret3);
+
+// computeSecret works without a public key set at all.
+const dh4 = crypto.createDiffieHellman(p1, 'buffer');
+dh4.setPrivateKey(privkey1);
+
+assert.deepStrictEqual(dh1.getPrime(), dh4.getPrime());
+assert.deepStrictEqual(dh1.getGenerator(), dh4.getGenerator());
+assert.deepStrictEqual(dh1.getPrivateKey(), dh4.getPrivateKey());
+assert.strictEqual(dh4.verifyError, 0);
+
+const secret4 = dh4.computeSecret(key2, 'hex', 'base64');
+
+assert.strictEqual(secret1, secret4);
+
+
+if (false) {
+ let wrongBlockLength;
+ if (common.hasOpenSSL3) {
+ wrongBlockLength = {
+ message: 'error:1C80006B:Provider routines::wrong final block length',
+ code: 'ERR_OSSL_WRONG_FINAL_BLOCK_LENGTH',
+ library: 'Provider routines',
+ reason: 'wrong final block length'
+ };
+ } else {
+ wrongBlockLength = {
+ message: 'error:0606506D:digital envelope' +
+ ' routines:EVP_DecryptFinal_ex:wrong final block length',
+ code: 'ERR_OSSL_EVP_WRONG_FINAL_BLOCK_LENGTH',
+ library: 'digital envelope routines',
+ reason: 'wrong final block length'
+ };
+ }
+
+ // Run this one twice to make sure that the dh3 clears its error properly
+ {
+ const c = crypto.createDecipheriv('aes-128-ecb', crypto.randomBytes(16), '');
+ assert.throws(() => {
+ c.final('utf8');
+ }, wrongBlockLength);
+ }
+
+ {
+ const c = crypto.createDecipheriv('aes-128-ecb', crypto.randomBytes(16), '');
+ assert.throws(() => {
+ c.final('utf8');
+ }, wrongBlockLength);
+ }
+
+ assert.throws(() => {
+ dh3.computeSecret('');
+ }, { message: common.hasOpenSSL3 ?
+ 'error:02800080:Diffie-Hellman routines::invalid secret' :
+ 'Supplied key is too small' });
+
+ // Invalid test: curve argument is undefined
+ assert.throws(
+ () => crypto.createECDH(),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: 'The "curve" argument must be of type string. ' +
+ 'Received undefined'
+ });
+}
+
+assert.throws(
+ function() {
+ crypto.getDiffieHellman('unknown-group');
+ },
+ {
+ name: 'Error',
+ code: 'ERR_CRYPTO_UNKNOWN_DH_GROUP',
+ message: 'Unknown DH group'
+ },
+ 'crypto.getDiffieHellman(\'unknown-group\') ' +
+ 'failed to throw the expected error.'
+);
+
+assert.throws(
+ () => crypto.createDiffieHellman('', true),
+ {
+ code: 'ERR_INVALID_ARG_TYPE'
+ }
+);
+[true, Symbol(), {}, () => {}, []].forEach((generator) => assert.throws(
+ () => crypto.createDiffieHellman('', 'base64', generator),
+ { code: 'ERR_INVALID_ARG_TYPE' }
+));
diff --git a/tests/node_compat/test/parallel/test-crypto-hkdf.js b/tests/node_compat/test/parallel/test-crypto-hkdf.js
new file mode 100644
index 000000000..b5b35e3ce
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-crypto-hkdf.js
@@ -0,0 +1,203 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+
+'use strict';
+
+const common = require('../common');
+
+if (!common.hasCrypto)
+ common.skip('missing crypto');
+
+const { kMaxLength } = require('buffer');
+const assert = require('assert');
+const {
+ createSecretKey,
+ hkdf,
+ hkdfSync
+} = require('crypto');
+
+{
+ assert.throws(() => hkdf(), {
+ code: 'ERR_INVALID_ARG_TYPE',
+ message: /The "digest" argument must be of type string/
+ });
+
+ [1, {}, [], false, Infinity].forEach((i) => {
+ assert.throws(() => hkdf(i, 'a'), {
+ code: 'ERR_INVALID_ARG_TYPE',
+ message: /^The "digest" argument must be of type string/
+ });
+ assert.throws(() => hkdfSync(i, 'a'), {
+ code: 'ERR_INVALID_ARG_TYPE',
+ message: /^The "digest" argument must be of type string/
+ });
+ });
+
+ [1, {}, [], false, Infinity].forEach((i) => {
+ assert.throws(() => hkdf('sha256', i), {
+ code: 'ERR_INVALID_ARG_TYPE',
+ message: /^The "ikm" argument must be /
+ });
+ assert.throws(() => hkdfSync('sha256', i), {
+ code: 'ERR_INVALID_ARG_TYPE',
+ message: /^The "ikm" argument must be /
+ });
+ });
+
+ [1, {}, [], false, Infinity].forEach((i) => {
+ assert.throws(() => hkdf('sha256', 'secret', i), {
+ code: 'ERR_INVALID_ARG_TYPE',
+ message: /^The "salt" argument must be /
+ });
+ assert.throws(() => hkdfSync('sha256', 'secret', i), {
+ code: 'ERR_INVALID_ARG_TYPE',
+ message: /^The "salt" argument must be /
+ });
+ });
+
+ [1, {}, [], false, Infinity].forEach((i) => {
+ assert.throws(() => hkdf('sha256', 'secret', 'salt', i), {
+ code: 'ERR_INVALID_ARG_TYPE',
+ message: /^The "info" argument must be /
+ });
+ assert.throws(() => hkdfSync('sha256', 'secret', 'salt', i), {
+ code: 'ERR_INVALID_ARG_TYPE',
+ message: /^The "info" argument must be /
+ });
+ });
+
+ ['test', {}, [], false].forEach((i) => {
+ assert.throws(() => hkdf('sha256', 'secret', 'salt', 'info', i), {
+ code: 'ERR_INVALID_ARG_TYPE',
+ message: /^The "length" argument must be of type number/
+ });
+ assert.throws(() => hkdfSync('sha256', 'secret', 'salt', 'info', i), {
+ code: 'ERR_INVALID_ARG_TYPE',
+ message: /^The "length" argument must be of type number/
+ });
+ });
+
+ assert.throws(() => hkdf('sha256', 'secret', 'salt', 'info', -1), {
+ code: 'ERR_OUT_OF_RANGE'
+ });
+ assert.throws(() => hkdfSync('sha256', 'secret', 'salt', 'info', -1), {
+ code: 'ERR_OUT_OF_RANGE'
+ });
+ assert.throws(() => hkdf('sha256', 'secret', 'salt', 'info',
+ kMaxLength + 1), {
+ code: 'ERR_OUT_OF_RANGE'
+ });
+ assert.throws(() => hkdfSync('sha256', 'secret', 'salt', 'info',
+ kMaxLength + 1), {
+ code: 'ERR_OUT_OF_RANGE'
+ });
+
+ assert.throws(() => hkdfSync('unknown', 'a', '', '', 10), {
+ code: 'ERR_CRYPTO_INVALID_DIGEST'
+ });
+
+ assert.throws(() => hkdf('unknown', 'a', '', Buffer.alloc(1025), 10,
+ common.mustNotCall()), {
+ code: 'ERR_OUT_OF_RANGE'
+ });
+
+ assert.throws(() => hkdfSync('unknown', 'a', '', Buffer.alloc(1025), 10), {
+ code: 'ERR_OUT_OF_RANGE'
+ });
+}
+
+const algorithms = [
+ ['sha256', 'secret', 'salt', 'info', 10],
+ ['sha256', '', '', '', 10],
+ ['sha256', '', 'salt', '', 10],
+ ['sha512', 'secret', 'salt', '', 15],
+];
+
+algorithms.forEach(([ hash, secret, salt, info, length ]) => {
+ {
+ const syncResult = hkdfSync(hash, secret, salt, info, length);
+ assert(syncResult instanceof ArrayBuffer);
+ let is_async = false;
+ hkdf(hash, secret, salt, info, length,
+ common.mustSucceed((asyncResult) => {
+ assert(is_async);
+ assert(asyncResult instanceof ArrayBuffer);
+ assert.deepStrictEqual(syncResult, asyncResult);
+ }));
+ // Keep this after the hkdf call above. This verifies
+ // that the callback is invoked asynchronously.
+ is_async = true;
+ }
+
+ {
+ const buf_secret = Buffer.from(secret);
+ const buf_salt = Buffer.from(salt);
+ const buf_info = Buffer.from(info);
+
+ const syncResult = hkdfSync(hash, buf_secret, buf_salt, buf_info, length);
+ hkdf(hash, buf_secret, buf_salt, buf_info, length,
+ common.mustSucceed((asyncResult) => {
+ assert.deepStrictEqual(syncResult, asyncResult);
+ }));
+ }
+
+ {
+ const key_secret = createSecretKey(Buffer.from(secret));
+ const buf_salt = Buffer.from(salt);
+ const buf_info = Buffer.from(info);
+
+ const syncResult = hkdfSync(hash, key_secret, buf_salt, buf_info, length);
+ hkdf(hash, key_secret, buf_salt, buf_info, length,
+ common.mustSucceed((asyncResult) => {
+ assert.deepStrictEqual(syncResult, asyncResult);
+ }));
+ }
+
+ {
+ const ta_secret = new Uint8Array(Buffer.from(secret));
+ const ta_salt = new Uint16Array(Buffer.from(salt));
+ const ta_info = new Uint32Array(Buffer.from(info));
+
+ const syncResult = hkdfSync(hash, ta_secret, ta_salt, ta_info, length);
+ hkdf(hash, ta_secret, ta_salt, ta_info, length,
+ common.mustSucceed((asyncResult) => {
+ assert.deepStrictEqual(syncResult, asyncResult);
+ }));
+ }
+
+ {
+ const ta_secret = new Uint8Array(Buffer.from(secret));
+ const ta_salt = new Uint16Array(Buffer.from(salt));
+ const ta_info = new Uint32Array(Buffer.from(info));
+
+ const syncResult = hkdfSync(
+ hash,
+ ta_secret.buffer,
+ ta_salt.buffer,
+ ta_info.buffer,
+ length);
+ hkdf(hash, ta_secret, ta_salt, ta_info, length,
+ common.mustSucceed((asyncResult) => {
+ assert.deepStrictEqual(syncResult, asyncResult);
+ }));
+ }
+
+ {
+ const ta_secret = new Uint8Array(Buffer.from(secret));
+ const sa_salt = new ArrayBuffer(0);
+ const sa_info = new ArrayBuffer(1);
+
+ const syncResult = hkdfSync(
+ hash,
+ ta_secret.buffer,
+ sa_salt,
+ sa_info,
+ length);
+ hkdf(hash, ta_secret, sa_salt, sa_info, length,
+ common.mustSucceed((asyncResult) => {
+ assert.deepStrictEqual(syncResult, asyncResult);
+ }));
+ }
+});
diff --git a/tests/node_compat/test/parallel/test-crypto-hmac.js b/tests/node_compat/test/parallel/test-crypto-hmac.js
new file mode 100644
index 000000000..174457a63
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-crypto-hmac.js
@@ -0,0 +1,483 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+'use strict';
+const common = require('../common');
+if (!common.hasCrypto)
+ common.skip('missing crypto');
+
+const assert = require('assert');
+const crypto = require('crypto');
+
+{
+ const Hmac = crypto.Hmac;
+ const instance = crypto.Hmac('sha256', 'Node');
+ assert(instance instanceof Hmac, 'Hmac is expected to return a new instance' +
+ ' when called without `new`');
+}
+
+assert.throws(
+ () => crypto.createHmac(null),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: 'The "hmac" argument must be of type string. Received null'
+ });
+
+// This used to segfault. See: https://github.com/nodejs/node/issues/9819
+assert.throws(
+ () => crypto.createHmac('sha256', 'key').digest({
+ toString: () => { throw new Error('boom'); },
+ }),
+ {
+ name: 'Error',
+ message: 'boom'
+ });
+
+assert.throws(
+ () => crypto.createHmac('sha1', null),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ });
+
+function testHmac(algo, key, data, expected) {
+ // TODO(kt3k): Skip non-string key for now.
+ // Enable this when we implement crypto.createSecretKey
+ if (typeof key !== "string") {
+ return;
+ }
+ // FIPS does not support MD5.
+ if (common.hasFipsCrypto && algo === 'md5')
+ return;
+
+ if (!Array.isArray(data))
+ data = [data];
+
+ // If the key is a Buffer, test Hmac with a key object as well.
+ const keyWrappers = [
+ (key) => key,
+ ...(typeof key === 'string' ? [] : [crypto.createSecretKey]),
+ ];
+
+ for (const keyWrapper of keyWrappers) {
+ const hmac = crypto.createHmac(algo, keyWrapper(key));
+ for (const chunk of data)
+ hmac.update(chunk);
+ const actual = hmac.digest('hex');
+ assert.strictEqual(actual, expected);
+ }
+}
+
+{
+ // Test HMAC with multiple updates.
+ testHmac('sha1', 'Node', ['some data', 'to hmac'],
+ '19fd6e1ba73d9ed2224dd5094a71babe85d9a892');
+}
+
+// Test HMAC (Wikipedia Test Cases)
+const wikipedia = [
+ {
+ key: 'key', data: 'The quick brown fox jumps over the lazy dog',
+ hmac: { // HMACs lifted from Wikipedia.
+ md5: '80070713463e7749b90c2dc24911e275',
+ sha1: 'de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9',
+ sha256:
+ 'f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc' +
+ '2d1a3cd8'
+ }
+ },
+ {
+ key: 'key', data: '',
+ hmac: { // Intermediate test to help debugging.
+ md5: '63530468a04e386459855da0063b6596',
+ sha1: 'f42bb0eeb018ebbd4597ae7213711ec60760843f',
+ sha256:
+ '5d5d139563c95b5967b9bd9a8c9b233a9dedb45072794cd232dc1b74' +
+ '832607d0'
+ }
+ },
+ {
+ key: '', data: 'The quick brown fox jumps over the lazy dog',
+ hmac: { // Intermediate test to help debugging.
+ md5: 'ad262969c53bc16032f160081c4a07a0',
+ sha1: '2ba7f707ad5f187c412de3106583c3111d668de8',
+ sha256:
+ 'fb011e6154a19b9a4c767373c305275a5a69e8b68b0b4c9200c383dc' +
+ 'ed19a416'
+ }
+ },
+ {
+ key: '', data: '',
+ hmac: { // HMACs lifted from Wikipedia.
+ md5: '74e6f7298a9c2d168935f58c001bad88',
+ sha1: 'fbdb1d1b18aa6c08324b7d64b71fb76370690e1d',
+ sha256:
+ 'b613679a0814d9ec772f95d778c35fc5ff1697c493715653c6c71214' +
+ '4292c5ad'
+ }
+ },
+];
+
+for (const { key, data, hmac } of wikipedia) {
+ for (const hash in hmac)
+ testHmac(hash, key, data, hmac[hash]);
+}
+
+// Test HMAC-SHA-* (rfc 4231 Test Cases)
+const rfc4231 = [
+ {
+ key: Buffer.from('0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b', 'hex'),
+ data: Buffer.from('4869205468657265', 'hex'), // 'Hi There'
+ hmac: {
+ sha224: '896fb1128abbdf196832107cd49df33f47b4b1169912ba4f53684b22',
+ sha256:
+ 'b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c' +
+ '2e32cff7',
+ sha384:
+ 'afd03944d84895626b0825f4ab46907f15f9dadbe4101ec682aa034c' +
+ '7cebc59cfaea9ea9076ede7f4af152e8b2fa9cb6',
+ sha512:
+ '87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b305' +
+ '45e17cdedaa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f170' +
+ '2e696c203a126854'
+ }
+ },
+ {
+ key: Buffer.from('4a656665', 'hex'), // 'Jefe'
+ data: Buffer.from('7768617420646f2079612077616e7420666f72206e6f74686' +
+ '96e673f', 'hex'), // 'what do ya want for nothing?'
+ hmac: {
+ sha224: 'a30e01098bc6dbbf45690f3a7e9e6d0f8bbea2a39e6148008fd05e44',
+ sha256:
+ '5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b9' +
+ '64ec3843',
+ sha384:
+ 'af45d2e376484031617f78d2b58a6b1b9c7ef464f5a01b47e42ec373' +
+ '6322445e8e2240ca5e69e2c78b3239ecfab21649',
+ sha512:
+ '164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7' +
+ 'ea2505549758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b' +
+ '636e070a38bce737'
+ }
+ },
+ {
+ key: Buffer.from('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'hex'),
+ data: Buffer.from('ddddddddddddddddddddddddddddddddddddddddddddddddd' +
+ 'ddddddddddddddddddddddddddddddddddddddddddddddddddd',
+ 'hex'),
+ hmac: {
+ sha224: '7fb3cb3588c6c1f6ffa9694d7d6ad2649365b0c1f65d69d1ec8333ea',
+ sha256:
+ '773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514' +
+ 'ced565fe',
+ sha384:
+ '88062608d3e6ad8a0aa2ace014c8a86f0aa635d947ac9febe83ef4e5' +
+ '5966144b2a5ab39dc13814b94e3ab6e101a34f27',
+ sha512:
+ 'fa73b0089d56a284efb0f0756c890be9b1b5dbdd8ee81a3655f83e33' +
+ 'b2279d39bf3e848279a722c806b485a47e67c807b946a337bee89426' +
+ '74278859e13292fb'
+ }
+ },
+ {
+ key: Buffer.from('0102030405060708090a0b0c0d0e0f10111213141516171819',
+ 'hex'),
+ data: Buffer.from('cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdc' +
+ 'dcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd',
+ 'hex'),
+ hmac: {
+ sha224: '6c11506874013cac6a2abc1bb382627cec6a90d86efc012de7afec5a',
+ sha256:
+ '82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff4' +
+ '6729665b',
+ sha384:
+ '3e8a69b7783c25851933ab6290af6ca77a9981480850009cc5577c6e' +
+ '1f573b4e6801dd23c4a7d679ccf8a386c674cffb',
+ sha512:
+ 'b0ba465637458c6990e5a8c5f61d4af7e576d97ff94b872de76f8050' +
+ '361ee3dba91ca5c11aa25eb4d679275cc5788063a5f19741120c4f2d' +
+ 'e2adebeb10a298dd'
+ }
+ },
+
+ {
+ key: Buffer.from('0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c', 'hex'),
+ // 'Test With Truncation'
+ data: Buffer.from('546573742057697468205472756e636174696f6e', 'hex'),
+ hmac: {
+ sha224: '0e2aea68a90c8d37c988bcdb9fca6fa8',
+ sha256: 'a3b6167473100ee06e0c796c2955552b',
+ sha384: '3abf34c3503b2a23a46efc619baef897',
+ sha512: '415fad6271580a531d4179bc891d87a6'
+ },
+ truncate: true
+ },
+ {
+ key: Buffer.from('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' +
+ 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' +
+ 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' +
+ 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' +
+ 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' +
+ 'aaaaaaaaaaaa', 'hex'),
+ // 'Test Using Larger Than Block-Size Key - Hash Key First'
+ data: Buffer.from('54657374205573696e67204c6172676572205468616e20426' +
+ 'c6f636b2d53697a65204b6579202d2048617368204b657920' +
+ '4669727374', 'hex'),
+ hmac: {
+ sha224: '95e9a0db962095adaebe9b2d6f0dbce2d499f112f2d2b7273fa6870e',
+ sha256:
+ '60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f' +
+ '0ee37f54',
+ sha384:
+ '4ece084485813e9088d2c63a041bc5b44f9ef1012a2b588f3cd11f05' +
+ '033ac4c60c2ef6ab4030fe8296248df163f44952',
+ sha512:
+ '80b24263c7c1a3ebb71493c1dd7be8b49b46d1f41b4aeec1121b0137' +
+ '83f8f3526b56d037e05f2598bd0fd2215d6a1e5295e64f73f63f0aec' +
+ '8b915a985d786598'
+ }
+ },
+ {
+ key: Buffer.from('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' +
+ 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' +
+ 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' +
+ 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' +
+ 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' +
+ 'aaaaaaaaaaaa', 'hex'),
+ // 'This is a test using a larger than block-size key and a larger ' +
+ // 'than block-size data. The key needs to be hashed before being ' +
+ // 'used by the HMAC algorithm.'
+ data: Buffer.from('5468697320697320612074657374207573696e672061206c6' +
+ '172676572207468616e20626c6f636b2d73697a65206b6579' +
+ '20616e642061206c6172676572207468616e20626c6f636b2' +
+ 'd73697a6520646174612e20546865206b6579206e65656473' +
+ '20746f20626520686173686564206265666f7265206265696' +
+ 'e6720757365642062792074686520484d414320616c676f72' +
+ '6974686d2e', 'hex'),
+ hmac: {
+ sha224: '3a854166ac5d9f023f54d517d0b39dbd946770db9c2b95c9f6f565d1',
+ sha256:
+ '9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f5153' +
+ '5c3a35e2',
+ sha384:
+ '6617178e941f020d351e2f254e8fd32c602420feb0b8fb9adccebb82' +
+ '461e99c5a678cc31e799176d3860e6110c46523e',
+ sha512:
+ 'e37b6a775dc87dbaa4dfa9f96e5e3ffddebd71f8867289865df5a32d' +
+ '20cdc944b6022cac3c4982b10d5eeb55c3e4de15134676fb6de04460' +
+ '65c97440fa8c6a58'
+ }
+ },
+];
+
+for (let i = 0, l = rfc4231.length; i < l; i++) {
+ for (const hash in rfc4231[i].hmac) {
+ const str = crypto.createHmac(hash, rfc4231[i].key);
+ str.end(rfc4231[i].data);
+ let strRes = str.read().toString('hex');
+ let actual = crypto.createHmac(hash, rfc4231[i].key)
+ .update(rfc4231[i].data)
+ .digest('hex');
+ if (rfc4231[i].truncate) {
+ actual = actual.slice(0, 32); // first 128 bits == 32 hex chars
+ strRes = strRes.slice(0, 32);
+ }
+ const expected = rfc4231[i].hmac[hash];
+ assert.strictEqual(
+ actual,
+ expected,
+ `Test HMAC-${hash} rfc 4231 case ${i + 1}: ${actual} must be ${expected}`
+ );
+ assert.strictEqual(
+ actual,
+ strRes,
+ `Should get same result from stream (hash: ${hash} and case: ${i + 1})` +
+ ` => ${actual} must be ${strRes}`
+ );
+ }
+}
+
+// Test HMAC-MD5/SHA1 (rfc 2202 Test Cases)
+const rfc2202_md5 = [
+ {
+ key: Buffer.from('0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b', 'hex'),
+ data: 'Hi There',
+ hmac: '9294727a3638bb1c13f48ef8158bfc9d'
+ },
+ {
+ key: 'Jefe',
+ data: 'what do ya want for nothing?',
+ hmac: '750c783e6ab0b503eaa86e310a5db738'
+ },
+ {
+ key: Buffer.from('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'hex'),
+ data: Buffer.from('ddddddddddddddddddddddddddddddddddddddddddddddddd' +
+ 'ddddddddddddddddddddddddddddddddddddddddddddddddddd',
+ 'hex'),
+ hmac: '56be34521d144c88dbb8c733f0e8b3f6'
+ },
+ {
+ key: Buffer.from('0102030405060708090a0b0c0d0e0f10111213141516171819',
+ 'hex'),
+ data: Buffer.from('cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdc' +
+ 'dcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd' +
+ 'cdcdcdcdcd',
+ 'hex'),
+ hmac: '697eaf0aca3a3aea3a75164746ffaa79'
+ },
+ {
+ key: Buffer.from('0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c', 'hex'),
+ data: 'Test With Truncation',
+ hmac: '56461ef2342edc00f9bab995690efd4c'
+ },
+ {
+ key: Buffer.from('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' +
+ 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' +
+ 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' +
+ 'aaaaaaaaaaaaaaaaaaaaaa',
+ 'hex'),
+ data: 'Test Using Larger Than Block-Size Key - Hash Key First',
+ hmac: '6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd'
+ },
+ {
+ key: Buffer.from('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' +
+ 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' +
+ 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' +
+ 'aaaaaaaaaaaaaaaaaaaaaa',
+ 'hex'),
+ data:
+ 'Test Using Larger Than Block-Size Key and Larger Than One ' +
+ 'Block-Size Data',
+ hmac: '6f630fad67cda0ee1fb1f562db3aa53e'
+ },
+];
+
+for (const { key, data, hmac } of rfc2202_md5)
+ testHmac('md5', key, data, hmac);
+
+const rfc2202_sha1 = [
+ {
+ key: Buffer.from('0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b', 'hex'),
+ data: 'Hi There',
+ hmac: 'b617318655057264e28bc0b6fb378c8ef146be00'
+ },
+ {
+ key: 'Jefe',
+ data: 'what do ya want for nothing?',
+ hmac: 'effcdf6ae5eb2fa2d27416d5f184df9c259a7c79'
+ },
+ {
+ key: Buffer.from('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'hex'),
+ data: Buffer.from('ddddddddddddddddddddddddddddddddddddddddddddd' +
+ 'ddddddddddddddddddddddddddddddddddddddddddddd' +
+ 'dddddddddd',
+ 'hex'),
+ hmac: '125d7342b9ac11cd91a39af48aa17b4f63f175d3'
+ },
+ {
+ key: Buffer.from('0102030405060708090a0b0c0d0e0f10111213141516171819',
+ 'hex'),
+ data: Buffer.from('cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdc' +
+ 'dcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd' +
+ 'cdcdcdcdcd',
+ 'hex'),
+ hmac: '4c9007f4026250c6bc8414f9bf50c86c2d7235da'
+ },
+ {
+ key: Buffer.from('0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c', 'hex'),
+ data: 'Test With Truncation',
+ hmac: '4c1a03424b55e07fe7f27be1d58bb9324a9a5a04'
+ },
+ {
+ key: Buffer.from('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' +
+ 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' +
+ 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' +
+ 'aaaaaaaaaaaaaaaaaaaaaa',
+ 'hex'),
+ data: 'Test Using Larger Than Block-Size Key - Hash Key First',
+ hmac: 'aa4ae5e15272d00e95705637ce8a3b55ed402112'
+ },
+ {
+ key: Buffer.from('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' +
+ 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' +
+ 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' +
+ 'aaaaaaaaaaaaaaaaaaaaaa',
+ 'hex'),
+ data:
+ 'Test Using Larger Than Block-Size Key and Larger Than One ' +
+ 'Block-Size Data',
+ hmac: 'e8e99d0f45237d786d6bbaa7965c7808bbff1a91'
+ },
+];
+
+for (const { key, data, hmac } of rfc2202_sha1)
+ testHmac('sha1', key, data, hmac);
+
+assert.strictEqual(
+ crypto.createHmac('sha256', 'w00t').digest('ucs2'),
+ crypto.createHmac('sha256', 'w00t').digest().toString('ucs2'));
+
+// Check initialized -> uninitialized state transition after calling digest().
+{
+ const expected =
+ '\u0010\u0041\u0052\u00c5\u00bf\u00dc\u00a0\u007b\u00c6\u0033' +
+ '\u00ee\u00bd\u0046\u0019\u009f\u0002\u0055\u00c9\u00f4\u009d';
+ {
+ const h = crypto.createHmac('sha1', 'key').update('data');
+ assert.deepStrictEqual(h.digest('buffer'), Buffer.from(expected, 'latin1'));
+ // TODO(kt3k): Enable this assertion
+ // assert.deepStrictEqual(h.digest('buffer'), Buffer.from(''));
+ }
+ {
+ const h = crypto.createHmac('sha1', 'key').update('data');
+ assert.strictEqual(h.digest('latin1'), expected);
+ // TODO(kt3k): Enable this assertion
+ // assert.strictEqual(h.digest('latin1'), '');
+ }
+}
+
+// Check initialized -> uninitialized state transition after calling digest().
+// Calls to update() omitted intentionally.
+{
+ const expected =
+ '\u00f4\u002b\u00b0\u00ee\u00b0\u0018\u00eb\u00bd\u0045\u0097' +
+ '\u00ae\u0072\u0013\u0071\u001e\u00c6\u0007\u0060\u0084\u003f';
+ {
+ const h = crypto.createHmac('sha1', 'key');
+ assert.deepStrictEqual(h.digest('buffer'), Buffer.from(expected, 'latin1'));
+ // TODO(kt3k): Enable this assertion
+ // assert.deepStrictEqual(h.digest('buffer'), Buffer.from(''));
+ }
+ {
+ const h = crypto.createHmac('sha1', 'key');
+ assert.strictEqual(h.digest('latin1'), expected);
+ // TODO(kt3k): Enable this assertion
+ // assert.strictEqual(h.digest('latin1'), '');
+ }
+}
+
+/*
+TODO(kt3k): Enable this test.
+{
+ assert.throws(
+ () => crypto.createHmac('sha7', 'key'),
+ /Invalid digest/);
+}
+*/
+
+/*
+ TODO(kt3k): enable this case when we implemented crypto.createSecretKey
+{
+ const buf = Buffer.alloc(0);
+ const keyObject = crypto.createSecretKey(Buffer.alloc(0));
+ assert.deepStrictEqual(
+ crypto.createHmac('sha256', buf).update('foo').digest(),
+ crypto.createHmac('sha256', keyObject).update('foo').digest(),
+ );
+}
+*/
diff --git a/tests/node_compat/test/parallel/test-crypto-prime.js b/tests/node_compat/test/parallel/test-crypto-prime.js
new file mode 100644
index 000000000..fc2218c2a
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-crypto-prime.js
@@ -0,0 +1,302 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+
+'use strict';
+
+const common = require('../common');
+if (!common.hasCrypto)
+ common.skip('missing crypto');
+
+const assert = require('assert');
+
+const {
+ generatePrime,
+ generatePrimeSync,
+ checkPrime,
+ checkPrimeSync,
+} = require('crypto');
+
+const { promisify } = require('util');
+const pgeneratePrime = promisify(generatePrime);
+const pCheckPrime = promisify(checkPrime);
+
+assert(!checkPrimeSync(Buffer.from([0x1])));
+assert(checkPrimeSync(Buffer.from([0x2])));
+assert(checkPrimeSync(Buffer.from([0x3])));
+assert(!checkPrimeSync(Buffer.from([0x4])));
+
+assert(
+ !checkPrimeSync(
+ Buffer.from([0x1]),
+ {
+ fast: true,
+ trialDivision: true,
+ checks: 10
+ }));
+
+(async function() {
+ const prime = await pgeneratePrime(36);
+ assert(await pCheckPrime(prime));
+})().then(common.mustCall());
+
+assert.throws(() => {
+ generatePrimeSync(32, { bigint: '' });
+}, { code: 'ERR_INVALID_ARG_TYPE' });
+
+assert.throws(() => {
+ generatePrime(32, { bigint: '' }, common.mustNotCall());
+}, { code: 'ERR_INVALID_ARG_TYPE' });
+
+{
+ const prime = generatePrimeSync(3, { bigint: true });
+ assert.strictEqual(typeof prime, 'bigint');
+ assert.strictEqual(prime, 7n);
+ assert(checkPrimeSync(prime));
+ checkPrime(prime, common.mustSucceed(assert));
+}
+
+{
+ generatePrime(3, { bigint: true }, common.mustSucceed((prime) => {
+ assert.strictEqual(typeof prime, 'bigint');
+ assert.strictEqual(prime, 7n);
+ assert(checkPrimeSync(prime));
+ checkPrime(prime, common.mustSucceed(assert));
+ }));
+}
+
+
+['hello', false, {}, []].forEach((i) => {
+ assert.throws(() => generatePrime(i), {
+ code: 'ERR_INVALID_ARG_TYPE'
+ });
+ assert.throws(() => generatePrimeSync(i), {
+ code: 'ERR_INVALID_ARG_TYPE'
+ });
+});
+
+['hello', false, 123].forEach((i) => {
+ assert.throws(() => generatePrime(80, i, common.mustNotCall()), {
+ code: 'ERR_INVALID_ARG_TYPE'
+ });
+ assert.throws(() => generatePrimeSync(80, i), {
+ code: 'ERR_INVALID_ARG_TYPE'
+ });
+});
+
+['hello', false, 123].forEach((i) => {
+ assert.throws(() => generatePrime(80, {}), {
+ code: 'ERR_INVALID_ARG_TYPE'
+ });
+});
+
+[-1, 0, 2 ** 31, 2 ** 31 + 1, 2 ** 32 - 1, 2 ** 32].forEach((size) => {
+ assert.throws(() => generatePrime(size, common.mustNotCall()), {
+ code: 'ERR_OUT_OF_RANGE',
+ message: />= 1 && <= 2147483647/
+ });
+ assert.throws(() => generatePrimeSync(size), {
+ code: 'ERR_OUT_OF_RANGE',
+ message: />= 1 && <= 2147483647/
+ });
+});
+
+['test', -1, {}, []].forEach((i) => {
+ assert.throws(() => generatePrime(8, { safe: i }, common.mustNotCall()), {
+ code: 'ERR_INVALID_ARG_TYPE'
+ });
+ assert.throws(() => generatePrime(8, { rem: i }, common.mustNotCall()), {
+ code: 'ERR_INVALID_ARG_TYPE'
+ });
+ assert.throws(() => generatePrime(8, { add: i }, common.mustNotCall()), {
+ code: 'ERR_INVALID_ARG_TYPE'
+ });
+ assert.throws(() => generatePrimeSync(8, { safe: i }), {
+ code: 'ERR_INVALID_ARG_TYPE'
+ });
+ assert.throws(() => generatePrimeSync(8, { rem: i }), {
+ code: 'ERR_INVALID_ARG_TYPE'
+ });
+ assert.throws(() => generatePrimeSync(8, { add: i }), {
+ code: 'ERR_INVALID_ARG_TYPE'
+ });
+});
+
+{
+ // Negative BigInts should not be converted to 0 silently.
+
+ assert.throws(() => generatePrime(20, { add: -1n }, common.mustNotCall()), {
+ code: 'ERR_OUT_OF_RANGE',
+ message: 'The value of "options.add" is out of range. It must be >= 0. ' +
+ 'Received -1n'
+ });
+
+ assert.throws(() => generatePrime(20, { rem: -1n }, common.mustNotCall()), {
+ code: 'ERR_OUT_OF_RANGE',
+ message: 'The value of "options.rem" is out of range. It must be >= 0. ' +
+ 'Received -1n'
+ });
+
+ // assert.throws(() => checkPrime(-1n, common.mustNotCall()), {
+ // code: 'ERR_OUT_OF_RANGE',
+ // message: 'The value of "candidate" is out of range. It must be >= 0. ' +
+ // 'Received -1n'
+ // });
+}
+
+generatePrime(80, common.mustSucceed((prime) => {
+ assert(checkPrimeSync(prime));
+ checkPrime(prime, common.mustSucceed((result) => {
+ assert(result);
+ }));
+}));
+
+assert(checkPrimeSync(generatePrimeSync(80)));
+
+generatePrime(80, {}, common.mustSucceed((prime) => {
+ assert(checkPrimeSync(prime));
+}));
+
+assert(checkPrimeSync(generatePrimeSync(80, {})));
+
+// generatePrime(32, { safe: true }, common.mustSucceed((prime) => {
+// assert(checkPrimeSync(prime));
+// const buf = Buffer.from(prime);
+// const val = buf.readUInt32BE();
+// const check = (val - 1) / 2;
+// buf.writeUInt32BE(check);
+// assert(checkPrimeSync(buf));
+// }));
+
+// {
+// const prime = generatePrimeSync(32, { safe: true });
+// assert(checkPrimeSync(prime));
+// const buf = Buffer.from(prime);
+// const val = buf.readUInt32BE();
+// const check = (val - 1) / 2;
+// buf.writeUInt32BE(check);
+// assert(checkPrimeSync(buf));
+// }
+
+// const add = 12;
+// const rem = 11;
+// const add_buf = Buffer.from([add]);
+// const rem_buf = Buffer.from([rem]);
+// generatePrime(
+// 32,
+// { add: add_buf, rem: rem_buf },
+// common.mustSucceed((prime) => {
+// assert(checkPrimeSync(prime));
+// const buf = Buffer.from(prime);
+// const val = buf.readUInt32BE();
+// assert.strictEqual(val % add, rem);
+// }));
+
+// {
+// const prime = generatePrimeSync(32, { add: add_buf, rem: rem_buf });
+// assert(checkPrimeSync(prime));
+// const buf = Buffer.from(prime);
+// const val = buf.readUInt32BE();
+// assert.strictEqual(val % add, rem);
+// }
+
+// {
+// const prime = generatePrimeSync(32, { add: BigInt(add), rem: BigInt(rem) });
+// assert(checkPrimeSync(prime));
+// const buf = Buffer.from(prime);
+// const val = buf.readUInt32BE();
+// assert.strictEqual(val % add, rem);
+// }
+
+// {
+// // The behavior when specifying only add without rem should depend on the
+// // safe option.
+
+// if (process.versions.openssl >= '1.1.1f') {
+// generatePrime(128, {
+// bigint: true,
+// add: 5n
+// }, common.mustSucceed((prime) => {
+// assert(checkPrimeSync(prime));
+// assert.strictEqual(prime % 5n, 1n);
+// }));
+
+// generatePrime(128, {
+// bigint: true,
+// safe: true,
+// add: 5n
+// }, common.mustSucceed((prime) => {
+// assert(checkPrimeSync(prime));
+// assert.strictEqual(prime % 5n, 3n);
+// }));
+// }
+// }
+
+// {
+// // This is impossible because it implies (prime % 2**64) == 1 and
+// // prime < 2**64, meaning prime = 1, but 1 is not prime.
+// for (const add of [2n ** 64n, 2n ** 65n]) {
+// assert.throws(() => {
+// generatePrimeSync(64, { add });
+// }, {
+// code: 'ERR_OUT_OF_RANGE',
+// message: 'invalid options.add'
+// });
+// }
+
+// // Any parameters with rem >= add lead to an impossible condition.
+// for (const rem of [7n, 8n, 3000n]) {
+// assert.throws(() => {
+// generatePrimeSync(64, { add: 7n, rem });
+// }, {
+// code: 'ERR_OUT_OF_RANGE',
+// message: 'invalid options.rem'
+// });
+// }
+
+// // This is possible, but not allowed. It implies prime == 7, which means that
+// // we did not actually generate a random prime.
+// assert.throws(() => {
+// generatePrimeSync(3, { add: 8n, rem: 7n });
+// }, {
+// code: 'ERR_OUT_OF_RANGE'
+// });
+
+// if (process.versions.openssl >= '1.1.1f') {
+// // This is possible and allowed (but makes little sense).
+// assert.strictEqual(generatePrimeSync(4, {
+// add: 15n,
+// rem: 13n,
+// bigint: true
+// }), 13n);
+// }
+// }
+
+[1, 'hello', {}, []].forEach((i) => {
+ assert.throws(() => checkPrime(i), {
+ code: 'ERR_INVALID_ARG_TYPE'
+ });
+});
+
+for (const checks of ['hello', {}, []]) {
+ assert.throws(() => checkPrime(2n, { checks }, common.mustNotCall()), {
+ code: 'ERR_INVALID_ARG_TYPE',
+ message: /checks/
+ });
+ assert.throws(() => checkPrimeSync(2n, { checks }), {
+ code: 'ERR_INVALID_ARG_TYPE',
+ message: /checks/
+ });
+}
+
+for (const checks of [-(2 ** 31), -1, 2 ** 31, 2 ** 32 - 1, 2 ** 32, 2 ** 50]) {
+ assert.throws(() => checkPrime(2n, { checks }, common.mustNotCall()), {
+ code: 'ERR_OUT_OF_RANGE',
+ message: /<= 2147483647/
+ });
+ assert.throws(() => checkPrimeSync(2n, { checks }), {
+ code: 'ERR_OUT_OF_RANGE',
+ message: /<= 2147483647/
+ });
+}
diff --git a/tests/node_compat/test/parallel/test-crypto-secret-keygen.js b/tests/node_compat/test/parallel/test-crypto-secret-keygen.js
new file mode 100644
index 000000000..b108269d3
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-crypto-secret-keygen.js
@@ -0,0 +1,144 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+if (!common.hasCrypto)
+ common.skip('missing crypto');
+
+const assert = require('assert');
+
+const {
+ generateKey,
+ generateKeySync
+} = require('crypto');
+
+[1, true, [], {}, Infinity, null, undefined].forEach((i) => {
+ assert.throws(() => generateKey(i, 1, common.mustNotCall()), {
+ code: 'ERR_INVALID_ARG_TYPE',
+ message: /The "type" argument must be /
+ });
+ assert.throws(() => generateKeySync(i, 1), {
+ code: 'ERR_INVALID_ARG_TYPE',
+ message: /The "type" argument must be /
+ });
+});
+
+['', true, [], null, undefined].forEach((i) => {
+ assert.throws(() => generateKey('aes', i, common.mustNotCall()), {
+ code: 'ERR_INVALID_ARG_TYPE',
+ message: /The "options" argument must be /
+ });
+ assert.throws(() => generateKeySync('aes', i), {
+ code: 'ERR_INVALID_ARG_TYPE',
+ message: /The "options" argument must be /
+ });
+});
+
+['', true, {}, [], null, undefined].forEach((length) => {
+ assert.throws(() => generateKey('hmac', { length }, common.mustNotCall()), {
+ code: 'ERR_INVALID_ARG_TYPE',
+ message: /The "options\.length" property must be /
+ });
+ assert.throws(() => generateKeySync('hmac', { length }), {
+ code: 'ERR_INVALID_ARG_TYPE',
+ message: /The "options\.length" property must be /
+ });
+});
+
+assert.throws(() => generateKey('aes', { length: 256 }), {
+ code: 'ERR_INVALID_ARG_TYPE'
+});
+
+assert.throws(() => generateKey('hmac', { length: -1 }, common.mustNotCall()), {
+ code: 'ERR_OUT_OF_RANGE'
+});
+
+assert.throws(() => generateKey('hmac', { length: 4 }, common.mustNotCall()), {
+ code: 'ERR_OUT_OF_RANGE'
+});
+
+assert.throws(() => generateKey('hmac', { length: 7 }, common.mustNotCall()), {
+ code: 'ERR_OUT_OF_RANGE'
+});
+
+assert.throws(
+ () => generateKey('hmac', { length: 2 ** 31 }, common.mustNotCall()), {
+ code: 'ERR_OUT_OF_RANGE'
+ });
+
+assert.throws(() => generateKeySync('hmac', { length: -1 }), {
+ code: 'ERR_OUT_OF_RANGE'
+});
+
+assert.throws(() => generateKeySync('hmac', { length: 4 }), {
+ code: 'ERR_OUT_OF_RANGE'
+});
+
+assert.throws(() => generateKeySync('hmac', { length: 7 }), {
+ code: 'ERR_OUT_OF_RANGE'
+});
+
+assert.throws(
+ () => generateKeySync('hmac', { length: 2 ** 31 }), {
+ code: 'ERR_OUT_OF_RANGE'
+ });
+
+assert.throws(() => generateKeySync('aes', { length: 123 }), {
+ code: 'ERR_INVALID_ARG_VALUE',
+ message: /The property 'options\.length' must be one of: 128, 192, 256/
+});
+
+{
+ const key = generateKeySync('aes', { length: 128 });
+ assert(key);
+ const keybuf = key.export();
+ assert.strictEqual(keybuf.byteLength, 128 / 8);
+
+ generateKey('aes', { length: 128 }, common.mustSucceed((key) => {
+ assert(key);
+ const keybuf = key.export();
+ assert.strictEqual(keybuf.byteLength, 128 / 8);
+ }));
+}
+
+{
+ const key = generateKeySync('aes', { length: 256 });
+ assert(key);
+ const keybuf = key.export();
+ assert.strictEqual(keybuf.byteLength, 256 / 8);
+
+ generateKey('aes', { length: 256 }, common.mustSucceed((key) => {
+ assert(key);
+ const keybuf = key.export();
+ assert.strictEqual(keybuf.byteLength, 256 / 8);
+ }));
+}
+
+{
+ const key = generateKeySync('hmac', { length: 123 });
+ assert(key);
+ const keybuf = key.export();
+ assert.strictEqual(keybuf.byteLength, Math.floor(123 / 8));
+
+ generateKey('hmac', { length: 123 }, common.mustSucceed((key) => {
+ assert(key);
+ const keybuf = key.export();
+ assert.strictEqual(keybuf.byteLength, Math.floor(123 / 8));
+ }));
+}
+
+assert.throws(
+ () => generateKey('unknown', { length: 123 }, common.mustNotCall()), {
+ code: 'ERR_INVALID_ARG_VALUE',
+ message: /The argument 'type' must be a supported key type/
+ });
+
+assert.throws(() => generateKeySync('unknown', { length: 123 }), {
+ code: 'ERR_INVALID_ARG_VALUE',
+ message: /The argument 'type' must be a supported key type/
+});
diff --git a/tests/node_compat/test/parallel/test-crypto-stream.js b/tests/node_compat/test/parallel/test-crypto-stream.js
new file mode 100644
index 000000000..07d3c5c6d
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-crypto-stream.js
@@ -0,0 +1,96 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+if (!common.hasCrypto)
+ common.skip('missing crypto');
+
+const assert = require('assert');
+const stream = require('stream');
+const crypto = require('crypto');
+
+if (!common.hasFipsCrypto) {
+ // Small stream to buffer converter
+ class Stream2buffer extends stream.Writable {
+ constructor(callback) {
+ super();
+
+ this._buffers = [];
+ this.once('finish', function() {
+ callback(null, Buffer.concat(this._buffers));
+ });
+ }
+
+ _write(data, encoding, done) {
+ this._buffers.push(data);
+ return done(null);
+ }
+ }
+
+ // Create an md5 hash of "Hallo world"
+ const hasher1 = crypto.createHash('md5');
+ hasher1.pipe(new Stream2buffer(common.mustCall(function end(err, hash) {
+ assert.strictEqual(err, null);
+ assert.strictEqual(
+ hash.toString('hex'), '06460dadb35d3d503047ce750ceb2d07'
+ );
+ })));
+ hasher1.end('Hallo world');
+
+ // Simpler check for unpipe, setEncoding, pause and resume
+ crypto.createHash('md5').unpipe({});
+ crypto.createHash('md5').setEncoding('utf8');
+ crypto.createHash('md5').pause();
+ crypto.createHash('md5').resume();
+}
+
+// Decipher._flush() should emit an error event, not an exception.
+const key = Buffer.from('48fb56eb10ffeb13fc0ef551bbca3b1b', 'hex');
+const badkey = Buffer.from('12341234123412341234123412341234', 'hex');
+const iv = Buffer.from('6d358219d1f488f5f4eb12820a66d146', 'hex');
+const cipher = crypto.createCipheriv('aes-128-cbc', key, iv);
+const decipher = crypto.createDecipheriv('aes-128-cbc', badkey, iv);
+
+// TODO(kt3k): Align error message of decipher with wrong padding and
+// enable the below test case.
+/*
+cipher.pipe(decipher)
+ .on('error', common.expectsError(common.hasOpenSSL3 ? {
+ message: /bad decrypt/,
+ library: 'Provider routines',
+ reason: 'bad decrypt',
+ } : {
+ message: /bad decrypt/,
+ function: 'EVP_DecryptFinal_ex',
+ library: 'digital envelope routines',
+ reason: 'bad decrypt',
+ }));
+*/
+
+cipher.end('Papaya!'); // Should not cause an unhandled exception.
diff --git a/tests/node_compat/test/parallel/test-crypto-update-encoding.js b/tests/node_compat/test/parallel/test-crypto-update-encoding.js
new file mode 100644
index 000000000..deb3c17c3
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-crypto-update-encoding.js
@@ -0,0 +1,29 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+
+if (!common.hasCrypto)
+ common.skip('missing crypto');
+
+const crypto = require('crypto');
+
+const zeros = Buffer.alloc;
+const key = zeros(16);
+const iv = zeros(16);
+
+const cipher = () => crypto.createCipheriv('aes-128-cbc', key, iv);
+const decipher = () => crypto.createDecipheriv('aes-128-cbc', key, iv);
+const hash = () => crypto.createSign('sha256');
+const hmac = () => crypto.createHmac('sha256', key);
+const sign = () => crypto.createSign('sha256');
+const verify = () => crypto.createVerify('sha256');
+
+for (const f of [cipher, decipher, hash, hmac, sign, verify])
+ for (const n of [15, 16])
+ f().update(zeros(n), 'hex'); // Should ignore inputEncoding.
diff --git a/tests/node_compat/test/parallel/test-crypto-x509.js b/tests/node_compat/test/parallel/test-crypto-x509.js
new file mode 100644
index 000000000..eeee2f7d7
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-crypto-x509.js
@@ -0,0 +1,109 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+
+'use strict';
+const common = require('../common');
+
+if (!common.hasCrypto)
+ common.skip('missing crypto');
+
+const {
+ X509Certificate,
+} = require('crypto');
+
+const assert = require('assert');
+const fixtures = require('../common/fixtures');
+const { readFileSync } = require('fs');
+
+const cert = readFileSync(fixtures.path('keys', 'agent1-cert.pem'));
+const ca = readFileSync(fixtures.path('keys', 'ca1-cert.pem'));
+
+[1, {}, false, null].forEach((i) => {
+ assert.throws(() => new X509Certificate(i), {
+ code: 'ERR_INVALID_ARG_TYPE'
+ });
+});
+
+const subjectCheck = `C=US
+ST=CA
+L=SF
+O=Joyent
+OU=Node.js
+CN=agent1
+Email=ry@tinyclouds.org`;
+
+const issuerCheck = `C=US
+ST=CA
+L=SF
+O=Joyent
+OU=Node.js
+CN=ca1
+Email=ry@tinyclouds.org`;
+
+let infoAccessCheck = `OCSP - URI:http://ocsp.nodejs.org/
+CA Issuers - URI:http://ca.nodejs.org/ca.cert`;
+if (!common.hasOpenSSL3)
+ infoAccessCheck += '\n';
+
+const der = Buffer.from(
+ '308203e8308202d0a0030201020214147d36c1c2f74206de9fab5f2226d78adb00a42630' +
+ '0d06092a864886f70d01010b0500307a310b3009060355040613025553310b3009060355' +
+ '04080c024341310b300906035504070c025346310f300d060355040a0c064a6f79656e74' +
+ '3110300e060355040b0c074e6f64652e6a73310c300a06035504030c036361313120301e' +
+ '06092a864886f70d010901161172794074696e79636c6f7564732e6f72673020170d3232' +
+ '303930333231343033375a180f32323936303631373231343033375a307d310b30090603' +
+ '55040613025553310b300906035504080c024341310b300906035504070c025346310f30' +
+ '0d060355040a0c064a6f79656e743110300e060355040b0c074e6f64652e6a73310f300d' +
+ '06035504030c066167656e74313120301e06092a864886f70d010901161172794074696e' +
+ '79636c6f7564732e6f726730820122300d06092a864886f70d01010105000382010f0030' +
+ '82010a0282010100d456320afb20d3827093dc2c4284ed04dfbabd56e1ddae529e28b790' +
+ 'cd4256db273349f3735ffd337c7a6363ecca5a27b7f73dc7089a96c6d886db0c62388f1c' +
+ 'dd6a963afcd599d5800e587a11f908960f84ed50ba25a28303ecda6e684fbe7baedc9ce8' +
+ '801327b1697af25097cee3f175e400984c0db6a8eb87be03b4cf94774ba56fffc8c63c68' +
+ 'd6adeb60abbe69a7b14ab6a6b9e7baa89b5adab8eb07897c07f6d4fa3d660dff574107d2' +
+ '8e8f63467a788624c574197693e959cea1362ffae1bba10c8c0d88840abfef103631b2e8' +
+ 'f5c39b5548a7ea57e8a39f89291813f45a76c448033a2b7ed8403f4baa147cf35e2d2554' +
+ 'aa65ce49695797095bf4dc6b0203010001a361305f305d06082b06010505070101045130' +
+ '4f302306082b060105050730018617687474703a2f2f6f6373702e6e6f64656a732e6f72' +
+ '672f302806082b06010505073002861c687474703a2f2f63612e6e6f64656a732e6f7267' +
+ '2f63612e63657274300d06092a864886f70d01010b05000382010100c3349810632ccb7d' +
+ 'a585de3ed51e34ed154f0f7215608cf2701c00eda444dc2427072c8aca4da6472c1d9e68' +
+ 'f177f99a90a8b5dbf3884586d61cb1c14ea7016c8d38b70d1b46b42947db30edc1e9961e' +
+ 'd46c0f0e35da427bfbe52900771817e733b371adf19e12137235141a34347db0dfc05579' +
+ '8b1f269f3bdf5e30ce35d1339d56bb3c570de9096215433047f87ca42447b44e7e6b5d0e' +
+ '48f7894ab186f85b6b1a74561b520952fea888617f32f582afce1111581cd63efcc68986' +
+ '00d248bb684dedb9c3d6710c38de9e9bc21f9c3394b729d5f707d64ea890603e5989f8fa' +
+ '59c19ad1a00732e7adc851b89487cc00799dde068aa64b3b8fd976e8bc113ef2',
+ 'hex');
+
+{
+ const x509 = new X509Certificate(cert);
+
+ assert(!x509.ca);
+ assert.strictEqual(x509.subject, subjectCheck);
+ assert.strictEqual(x509.subjectAltName, undefined);
+ assert.strictEqual(x509.issuer, issuerCheck);
+ assert.strictEqual(x509.validFrom, 'Sep 3 21:40:37 2022 +00:00');
+ assert.strictEqual(x509.validTo, 'Jun 17 21:40:37 2296 +00:00');
+ assert.strictEqual(
+ x509.fingerprint,
+ '8B:89:16:C4:99:87:D2:13:1A:64:94:36:38:A5:32:01:F0:95:3B:53');
+ assert.strictEqual(
+ x509.fingerprint256,
+ '2C:62:59:16:91:89:AB:90:6A:3E:98:88:A6:D3:C5:58:58:6C:AE:FF:9C:33:' +
+ '22:7C:B6:77:D3:34:E7:53:4B:05'
+ );
+ assert.strictEqual(
+ x509.fingerprint512,
+ '0B:6F:D0:4D:6B:22:53:99:66:62:51:2D:2C:96:F2:58:3F:95:1C:CC:4C:44:' +
+ '9D:B5:59:AA:AD:A8:F6:2A:24:8A:BB:06:A5:26:42:52:30:A3:37:61:30:A9:' +
+ '5A:42:63:E0:21:2F:D6:70:63:07:96:6F:27:A7:78:12:08:02:7A:8B'
+ );
+ assert.strictEqual(x509.keyUsage, undefined);
+ assert.strictEqual(x509.serialNumber, '147D36C1C2F74206DE9FAB5F2226D78ADB00A426');
+
+ assert.strictEqual(x509.checkEmail('ry@tinyclouds.org'), 'ry@tinyclouds.org');
+ assert.strictEqual(x509.checkEmail('sally@example.com'), undefined);
+} \ No newline at end of file
diff --git a/tests/node_compat/test/parallel/test-dgram-close-during-bind.js b/tests/node_compat/test/parallel/test-dgram-close-during-bind.js
new file mode 100644
index 000000000..fd1fe523e
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-dgram-close-during-bind.js
@@ -0,0 +1,26 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Flags: --expose-internals
+'use strict';
+const common = require('../common');
+const dgram = require('dgram');
+const { kStateSymbol } = require('internal/dgram');
+const socket = dgram.createSocket('udp4');
+const { handle } = socket[kStateSymbol];
+const lookup = handle.lookup;
+
+// Test the scenario where the socket is closed during a bind operation.
+handle.bind = common.mustNotCall('bind() should not be called.');
+
+handle.lookup = common.mustCall(function(address, callback) {
+ socket.close(common.mustCall(() => {
+ lookup.call(this, address, callback);
+ }));
+});
+
+socket.bind(common.mustNotCall('Socket should not bind.'));
diff --git a/tests/node_compat/test/parallel/test-dgram-close-signal.js b/tests/node_compat/test/parallel/test-dgram-close-signal.js
new file mode 100644
index 000000000..ef6ac3a32
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-dgram-close-signal.js
@@ -0,0 +1,38 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const assert = require('assert');
+const dgram = require('dgram');
+
+{
+ // Test bad signal.
+ assert.throws(
+ () => dgram.createSocket({ type: 'udp4', signal: {} }),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError'
+ });
+}
+
+{
+ // Test close.
+ const controller = new AbortController();
+ const { signal } = controller;
+ const server = dgram.createSocket({ type: 'udp4', signal });
+ server.on('close', common.mustCall());
+ controller.abort();
+}
+
+{
+ // Test close with pre-aborted signal.
+ const signal = AbortSignal.abort();
+ const server = dgram.createSocket({ type: 'udp4', signal });
+ server.on('close', common.mustCall());
+}
diff --git a/tests/node_compat/test/parallel/test-dgram-custom-lookup.js b/tests/node_compat/test/parallel/test-dgram-custom-lookup.js
new file mode 100644
index 000000000..ca3bd3df3
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-dgram-custom-lookup.js
@@ -0,0 +1,56 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 16.13.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const dgram = require('dgram');
+const dns = require('dns');
+
+{
+ // Verify that the provided lookup function is called.
+ const lookup = common.mustCall((host, family, callback) => {
+ dns.lookup(host, family, callback);
+ });
+
+ const socket = dgram.createSocket({ type: 'udp4', lookup });
+
+ socket.bind(common.mustCall(() => {
+ socket.close();
+ }));
+}
+
+// TODO: unable to overwrite imports with spies
+// {
+// // Verify that lookup defaults to dns.lookup().
+// const originalLookup = dns.lookup;
+
+// dns.lookup = common.mustCall((host, family, callback) => {
+// dns.lookup = originalLookup;
+// originalLookup(host, family, callback);
+// });
+
+// const socket = dgram.createSocket({ type: 'udp4' });
+
+// socket.bind(common.mustCall(() => {
+// socket.close();
+// }));
+// }
+
+{
+ // Verify that non-functions throw.
+ [null, true, false, 0, 1, NaN, '', 'foo', {}, Symbol()].forEach((value) => {
+ assert.throws(() => {
+ dgram.createSocket({ type: 'udp4', lookup: value });
+ }, {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: 'The "lookup" argument must be of type function.' +
+ common.invalidArgTypeHelper(value)
+ });
+ });
+}
diff --git a/tests/node_compat/test/parallel/test-dgram-ipv6only.js b/tests/node_compat/test/parallel/test-dgram-ipv6only.js
new file mode 100644
index 000000000..31f4e1fd9
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-dgram-ipv6only.js
@@ -0,0 +1,44 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 16.13.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// TODO(cmorten): Deno.listenDatagram is currently `0.0.0.0` when you listen to `::`.
+
+'use strict';
+
+const common = require('../common');
+if (!common.hasIPv6)
+ common.skip('no IPv6 support');
+
+const dgram = require('dgram');
+
+// This test ensures that dual-stack support is disabled when
+// we specify the `ipv6Only` option in `dgram.createSocket()`.
+const socket = dgram.createSocket({
+ type: 'udp6',
+ ipv6Only: true,
+});
+
+socket.bind({
+ port: 0,
+ address: '::',
+}, common.mustCall(() => {
+ const { port } = socket.address();
+ const client = dgram.createSocket('udp4');
+
+ // We can still bind to '0.0.0.0'.
+ // TODO: uncomment out when Deno allows IPv4 and IPv6 to be bound
+ // independently
+ // client.bind({
+ // port,
+ // address: '0.0.0.0',
+ // }, common.mustCall(() => {
+ client.close();
+ socket.close();
+ // }));
+
+ client.on('error', common.mustNotCall());
+}));
diff --git a/tests/node_compat/test/parallel/test-dgram-send-cb-quelches-error.js b/tests/node_compat/test/parallel/test-dgram-send-cb-quelches-error.js
new file mode 100644
index 000000000..d2fd5af50
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-dgram-send-cb-quelches-error.js
@@ -0,0 +1,47 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 16.13.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// TODO(cmorten): uncomment dns module code once dns.setServer() has been
+// implemented
+
+'use strict';
+const common = require('../common');
+const mustCall = common.mustCall;
+const assert = require('assert');
+const dgram = require('dgram');
+// const dns = require('dns');
+
+const socket = dgram.createSocket('udp4');
+const buffer = Buffer.from('gary busey');
+
+// dns.setServers([]);
+
+socket.once('error', onEvent);
+
+// assert that:
+// * callbacks act as "error" listeners if given.
+// * error is never emitter for missing dns entries
+// if a callback that handles error is present
+// * error is emitted if a callback with no argument is passed
+socket.send(buffer, 0, buffer.length, 100,
+ 'dne.example.com', mustCall(callbackOnly));
+
+function callbackOnly(err) {
+ assert.ok(err);
+ socket.removeListener('error', onEvent);
+ socket.on('error', mustCall(onError));
+ socket.send(buffer, 0, buffer.length, 100, 'dne.invalid');
+}
+
+function onEvent(err) {
+ assert.fail(`Error should not be emitted if there is callback: ${err}`);
+}
+
+function onError(err) {
+ assert.ok(err);
+ socket.close();
+}
diff --git a/tests/node_compat/test/parallel/test-dgram-socket-buffer-size.js b/tests/node_compat/test/parallel/test-dgram-socket-buffer-size.js
new file mode 100644
index 000000000..b2fc33262
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-dgram-socket-buffer-size.js
@@ -0,0 +1,178 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 16.13.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// Flags: --expose-internals
+'use strict';
+
+const common = require('../common');
+const assert = require('assert');
+const dgram = require('dgram');
+const { inspect } = require('util');
+const { internalBinding } = require('internal/test/binding');
+const {
+ UV_EBADF,
+ UV_EINVAL,
+ UV_ENOTSOCK
+} = internalBinding('uv');
+
+// Note error test amendments from Node due to Deno formatting errors slightly
+// differently.
+function getExpectedError(type) {
+ const code = common.isWindows ? 'ENOTSOCK' : 'EBADF';
+ const message = common.isWindows ?
+ 'socket operation on non-socket' : 'bad file descriptor';
+ const errno = common.isWindows ? UV_ENOTSOCK : UV_EBADF;
+ const syscall = `uv_${type}_buffer_size`;
+ const suffix = common.isWindows ?
+ 'ENOTSOCK (socket operation on non-socket)' : 'EBADF (bad file descriptor)';
+ const error = {
+ code: 'ERR_SOCKET_BUFFER_SIZE',
+ name: 'SystemError',
+ message: `Could not get or set buffer size: ${syscall} returned ${suffix}`,
+ info: {
+ code,
+ message,
+ errno,
+ syscall
+ }
+ };
+ return error;
+}
+
+{
+ // Should throw error if the socket is never bound.
+ const errorObj = getExpectedError('send');
+
+ const socket = dgram.createSocket('udp4');
+
+ assert.throws(() => {
+ socket.setSendBufferSize(8192);
+ }, (err) => {
+ assert.strictEqual(
+ inspect(err).replace(/^ +at .*\n/gm, ""),
+ `ERR_SOCKET_BUFFER_SIZE [SystemError]: ${errorObj.message}\n` +
+ " code: 'ERR_SOCKET_BUFFER_SIZE',\n" +
+ " info: {\n" +
+ ` errno: ${errorObj.info.errno},\n` +
+ ` code: '${errorObj.info.code}',\n` +
+ ` message: '${errorObj.info.message}',\n` +
+ ` syscall: '${errorObj.info.syscall}'\n` +
+ " },\n" +
+ ` errno: [Getter/Setter],\n` +
+ ` syscall: [Getter/Setter]\n` +
+ "}"
+ );
+ return true;
+ });
+
+ assert.throws(() => {
+ socket.getSendBufferSize();
+ }, errorObj);
+}
+
+{
+ const socket = dgram.createSocket('udp4');
+
+ // Should throw error if the socket is never bound.
+ const errorObj = getExpectedError('recv');
+
+ assert.throws(() => {
+ socket.setRecvBufferSize(8192);
+ }, errorObj);
+
+ assert.throws(() => {
+ socket.getRecvBufferSize();
+ }, errorObj);
+}
+
+{
+ // Should throw error if invalid buffer size is specified
+ const errorObj = {
+ code: 'ERR_SOCKET_BAD_BUFFER_SIZE',
+ name: 'TypeError',
+ message: /^Buffer size must be a positive integer$/
+ };
+
+ const badBufferSizes = [-1, Infinity, 'Doh!'];
+
+ const socket = dgram.createSocket('udp4');
+
+ socket.bind(common.mustCall(() => {
+ badBufferSizes.forEach((badBufferSize) => {
+ assert.throws(() => {
+ socket.setRecvBufferSize(badBufferSize);
+ }, errorObj);
+
+ assert.throws(() => {
+ socket.setSendBufferSize(badBufferSize);
+ }, errorObj);
+ });
+ socket.close();
+ }));
+}
+
+{
+ // Can set and get buffer sizes after binding the socket.
+ const socket = dgram.createSocket('udp4');
+
+ socket.bind(common.mustCall(() => {
+ socket.setRecvBufferSize(10000);
+ socket.setSendBufferSize(10000);
+
+ // note: linux will double the buffer size
+ const expectedBufferSize = common.isLinux ? 20000 : 10000;
+ assert.strictEqual(socket.getRecvBufferSize(), expectedBufferSize);
+ assert.strictEqual(socket.getSendBufferSize(), expectedBufferSize);
+ socket.close();
+ }));
+}
+
+{
+ const info = {
+ code: 'EINVAL',
+ message: 'invalid argument',
+ errno: UV_EINVAL,
+ syscall: 'uv_recv_buffer_size'
+ };
+ const errorObj = {
+ code: 'ERR_SOCKET_BUFFER_SIZE',
+ name: 'SystemError',
+ message: 'Could not get or set buffer size: uv_recv_buffer_size ' +
+ 'returned EINVAL (invalid argument)',
+ info
+ };
+ const socket = dgram.createSocket('udp4');
+ socket.bind(common.mustCall(() => {
+ assert.throws(() => {
+ socket.setRecvBufferSize(2147483648);
+ }, errorObj);
+ socket.close();
+ }));
+}
+
+{
+ const info = {
+ code: 'EINVAL',
+ message: 'invalid argument',
+ errno: UV_EINVAL,
+ syscall: 'uv_send_buffer_size'
+ };
+ const errorObj = {
+ code: 'ERR_SOCKET_BUFFER_SIZE',
+ name: 'SystemError',
+ message: 'Could not get or set buffer size: uv_send_buffer_size ' +
+ 'returned EINVAL (invalid argument)',
+ info
+ };
+ const socket = dgram.createSocket('udp4');
+ socket.bind(common.mustCall(() => {
+ assert.throws(() => {
+ socket.setSendBufferSize(2147483648);
+ }, errorObj);
+ socket.close();
+ }));
+}
diff --git a/tests/node_compat/test/parallel/test-dgram-udp6-link-local-address.js b/tests/node_compat/test/parallel/test-dgram-udp6-link-local-address.js
new file mode 100644
index 000000000..c828413a2
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-dgram-udp6-link-local-address.js
@@ -0,0 +1,61 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 16.13.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+'use strict';
+const common = require('../common');
+if (!common.hasIPv6)
+ common.skip('no IPv6 support');
+
+const assert = require('assert');
+const dgram = require('dgram');
+const os = require('os');
+
+const { isWindows } = common;
+
+function linklocal() {
+ for (const [ifname, entries] of Object.entries(os.networkInterfaces())) {
+ for (const { address, family, scopeid } of entries) {
+ if (family === 'IPv6' && address.startsWith('fe80:')) {
+ return { address, ifname, scopeid };
+ }
+ }
+ }
+}
+const iface = linklocal();
+
+if (!iface)
+ common.skip('cannot find any IPv6 interfaces with a link local address');
+
+const address = isWindows ? iface.address : `${iface.address}%${iface.ifname}`;
+const message = 'Hello, local world!';
+
+// Create a client socket for sending to the link-local address.
+const client = dgram.createSocket('udp6');
+
+// Create the server socket listening on the link-local address.
+const server = dgram.createSocket('udp6');
+
+server.on('listening', common.mustCall(() => {
+ const port = server.address().port;
+ client.send(message, 0, message.length, port, address);
+}));
+
+server.on('message', common.mustCall((buf, info) => {
+ const received = buf.toString();
+ assert.strictEqual(received, message);
+ // Check that the sender address is the one bound,
+ // including the link local scope identifier.
+ // TODO(cmorten): info.address is missing the link local scope identifier
+ // assert.strictEqual(
+ // info.address,
+ // isWindows ? `${iface.address}%${iface.scopeid}` : address
+ // );
+ server.close();
+ client.close();
+}, 1));
+
+server.bind({ address });
diff --git a/tests/node_compat/test/parallel/test-diagnostics-channel-has-subscribers.js b/tests/node_compat/test/parallel/test-diagnostics-channel-has-subscribers.js
new file mode 100644
index 000000000..66a548c37
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-diagnostics-channel-has-subscribers.js
@@ -0,0 +1,17 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+const { channel, hasSubscribers } = require('diagnostics_channel');
+
+const dc = channel('test');
+assert.ok(!hasSubscribers('test'));
+
+dc.subscribe(() => {});
+assert.ok(hasSubscribers('test'));
diff --git a/tests/node_compat/test/parallel/test-diagnostics-channel-object-channel-pub-sub.js b/tests/node_compat/test/parallel/test-diagnostics-channel-object-channel-pub-sub.js
new file mode 100644
index 000000000..00b786582
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-diagnostics-channel-object-channel-pub-sub.js
@@ -0,0 +1,53 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const dc = require('diagnostics_channel');
+const assert = require('assert');
+const { Channel } = dc;
+
+const input = {
+ foo: 'bar'
+};
+
+// Should not have named channel
+assert.ok(!dc.hasSubscribers('test'));
+
+// Individual channel objects can be created to avoid future lookups
+const channel = dc.channel('test');
+assert.ok(channel instanceof Channel);
+
+// No subscribers yet, should not publish
+assert.ok(!channel.hasSubscribers);
+
+const subscriber = common.mustCall((message, name) => {
+ assert.strictEqual(name, channel.name);
+ assert.deepStrictEqual(message, input);
+});
+
+// Now there's a subscriber, should publish
+channel.subscribe(subscriber);
+assert.ok(channel.hasSubscribers);
+
+// The ActiveChannel prototype swap should not fail instanceof
+assert.ok(channel instanceof Channel);
+
+// Should trigger the subscriber once
+channel.publish(input);
+
+// Should not publish after subscriber is unsubscribed
+assert.ok(channel.unsubscribe(subscriber));
+assert.ok(!channel.hasSubscribers);
+
+// unsubscribe() should return false when subscriber is not found
+assert.ok(!channel.unsubscribe(subscriber));
+
+assert.throws(() => {
+ channel.subscribe(null);
+}, { code: 'ERR_INVALID_ARG_TYPE' });
diff --git a/tests/node_compat/test/parallel/test-diagnostics-channel-pub-sub.js b/tests/node_compat/test/parallel/test-diagnostics-channel-pub-sub.js
new file mode 100644
index 000000000..378cf051e
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-diagnostics-channel-pub-sub.js
@@ -0,0 +1,51 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const dc = require('diagnostics_channel');
+const assert = require('assert');
+const { Channel } = dc;
+
+const name = 'test';
+const input = {
+ foo: 'bar'
+};
+
+// Individual channel objects can be created to avoid future lookups
+const channel = dc.channel(name);
+assert.ok(channel instanceof Channel);
+
+// No subscribers yet, should not publish
+assert.ok(!channel.hasSubscribers);
+
+const subscriber = common.mustCall((message, name) => {
+ assert.strictEqual(name, channel.name);
+ assert.deepStrictEqual(message, input);
+});
+
+// Now there's a subscriber, should publish
+dc.subscribe(name, subscriber);
+assert.ok(channel.hasSubscribers);
+
+// The ActiveChannel prototype swap should not fail instanceof
+assert.ok(channel instanceof Channel);
+
+// Should trigger the subscriber once
+channel.publish(input);
+
+// Should not publish after subscriber is unsubscribed
+assert.ok(dc.unsubscribe(name, subscriber));
+assert.ok(!channel.hasSubscribers);
+
+// unsubscribe() should return false when subscriber is not found
+assert.ok(!dc.unsubscribe(name, subscriber));
+
+assert.throws(() => {
+ dc.subscribe(name, null);
+}, { code: 'ERR_INVALID_ARG_TYPE' });
diff --git a/tests/node_compat/test/parallel/test-diagnostics-channel-symbol-named.js b/tests/node_compat/test/parallel/test-diagnostics-channel-symbol-named.js
new file mode 100644
index 000000000..3067c78e9
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-diagnostics-channel-symbol-named.js
@@ -0,0 +1,35 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const dc = require('diagnostics_channel');
+const assert = require('assert');
+
+const input = {
+ foo: 'bar'
+};
+
+const symbol = Symbol('test');
+
+// Individual channel objects can be created to avoid future lookups
+const channel = dc.channel(symbol);
+
+// Expect two successful publishes later
+channel.subscribe(common.mustCall((message, name) => {
+ assert.strictEqual(name, symbol);
+ assert.deepStrictEqual(message, input);
+}));
+
+channel.publish(input);
+
+{
+ assert.throws(() => {
+ dc.channel(null);
+ }, /ERR_INVALID_ARG_TYPE/);
+}
diff --git a/tests/node_compat/test/parallel/test-diagnostics-channel-udp.js b/tests/node_compat/test/parallel/test-diagnostics-channel-udp.js
new file mode 100644
index 000000000..ddf757a12
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-diagnostics-channel-udp.js
@@ -0,0 +1,22 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const dgram = require('dgram');
+const dc = require('diagnostics_channel');
+
+const udpSocketChannel = dc.channel('udp.socket');
+
+const isUDPSocket = (socket) => socket instanceof dgram.Socket;
+
+udpSocketChannel.subscribe(common.mustCall(({ socket }) => {
+ assert.strictEqual(isUDPSocket(socket), true);
+}));
+const socket = dgram.createSocket('udp4');
+socket.close();
diff --git a/tests/node_compat/test/parallel/test-dns-lookup.js b/tests/node_compat/test/parallel/test-dns-lookup.js
new file mode 100644
index 000000000..d137586d2
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-dns-lookup.js
@@ -0,0 +1,179 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 16.13.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// Flags: --expose-internals
+'use strict';
+
+// TODO: enable remaining tests once functionality is implemented.
+
+const common = require('../common');
+const assert = require('assert');
+// const { internalBinding } = require('internal/test/binding');
+// const cares = internalBinding('cares_wrap');
+
+// Stub `getaddrinfo` to *always* error. This has to be done before we load the
+// `dns` module to guarantee that the `dns` module uses the stub.
+// cares.getaddrinfo = () => internalBinding('uv').UV_ENOMEM;
+
+const dns = require('dns');
+const dnsPromises = dns.promises;
+
+{
+ const err = {
+ code: "ERR_INVALID_ARG_TYPE",
+ name: "TypeError",
+ message:
+ /^The "hostname" argument must be of type string\. Received type number/,
+ };
+
+ assert.throws(() => dns.lookup(1, {}), err);
+ assert.throws(() => dnsPromises.lookup(1, {}), err);
+}
+
+// This also verifies different expectWarning notations.
+// common.expectWarning({
+// // For 'internal/test/binding' module.
+// 'internal/test/binding': [
+// 'These APIs are for internal testing only. Do not use them.',
+// ],
+// // For calling `dns.lookup` with falsy `hostname`.
+// 'DeprecationWarning': {
+// DEP0118: 'The provided hostname "false" is not a valid ' +
+// 'hostname, and is supported in the dns module solely for compatibility.'
+// }
+// });
+
+assert.throws(
+ () => {
+ dns.lookup(false, "cb");
+ },
+ {
+ code: "ERR_INVALID_ARG_TYPE",
+ name: "TypeError",
+ }
+);
+
+assert.throws(
+ () => {
+ dns.lookup(false, "options", "cb");
+ },
+ {
+ code: "ERR_INVALID_ARG_TYPE",
+ name: "TypeError",
+ }
+);
+
+{
+ const err = {
+ code: 'ERR_INVALID_ARG_VALUE',
+ name: 'TypeError',
+ message: "The argument 'hints' is invalid. Received 100"
+ };
+ const options = {
+ hints: 100,
+ family: 0,
+ all: false
+ };
+
+ assert.throws(() => { dnsPromises.lookup(false, options); }, err);
+ assert.throws(() => {
+ dns.lookup(false, options, common.mustNotCall());
+ }, err);
+}
+
+{
+ const family = 20;
+ const err = {
+ code: "ERR_INVALID_ARG_VALUE",
+ name: "TypeError",
+ message: `The property 'options.family' must be one of: 0, 4, 6. Received ${family}`,
+ };
+ const options = {
+ hints: 0,
+ family,
+ all: false
+ };
+
+ assert.throws(() => { dnsPromises.lookup(false, options); }, err);
+ assert.throws(() => {
+ dns.lookup(false, options, common.mustNotCall());
+ }, err);
+}
+
+(async function() {
+ let res;
+
+ res = await dnsPromises.lookup(false, {
+ hints: 0,
+ family: 0,
+ all: true
+ });
+ assert.deepStrictEqual(res, []);
+
+ res = await dnsPromises.lookup('127.0.0.1', {
+ hints: 0,
+ family: 4,
+ all: true
+ });
+ assert.deepStrictEqual(res, [{ address: '127.0.0.1', family: 4 }]);
+
+ res = await dnsPromises.lookup('127.0.0.1', {
+ hints: 0,
+ family: 4,
+ all: false
+ });
+ assert.deepStrictEqual(res, { address: '127.0.0.1', family: 4 });
+})().then(common.mustCall());
+
+dns.lookup(false, {
+ hints: 0,
+ family: 0,
+ all: true
+}, common.mustSucceed((result, addressType) => {
+ assert.deepStrictEqual(result, []);
+ assert.strictEqual(addressType, undefined);
+}));
+
+dns.lookup('127.0.0.1', {
+ hints: 0,
+ family: 4,
+ all: true
+}, common.mustSucceed((result, addressType) => {
+ assert.deepStrictEqual(result, [{
+ address: '127.0.0.1',
+ family: 4
+ }]);
+ assert.strictEqual(addressType, undefined);
+}));
+
+dns.lookup('127.0.0.1', {
+ hints: 0,
+ family: 4,
+ all: false
+}, common.mustSucceed((result, addressType) => {
+ assert.deepStrictEqual(result, '127.0.0.1');
+ assert.strictEqual(addressType, 4);
+}));
+
+// let tickValue = 0;
+
+// Should fail due to stub.
+// dns.lookup('example.com', common.mustCall((error, result, addressType) => {
+// assert(error);
+// assert.strictEqual(tickValue, 1);
+// assert.strictEqual(error.code, 'ENOMEM');
+// const descriptor = Object.getOwnPropertyDescriptor(error, 'message');
+// // The error message should be non-enumerable.
+// assert.strictEqual(descriptor.enumerable, false);
+// }));
+
+// Make sure that the error callback is called on next tick.
+// tickValue = 1;
+
+// Should fail due to stub.
+// assert.rejects(dnsPromises.lookup('example.com'),
+// { code: 'ENOMEM', hostname: 'example.com' });
diff --git a/tests/node_compat/test/parallel/test-dns-memory-error.js b/tests/node_compat/test/parallel/test-dns-memory-error.js
new file mode 100644
index 000000000..6ef6968be
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-dns-memory-error.js
@@ -0,0 +1,23 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Flags: --expose-internals
+'use strict';
+
+// Check that if libuv reports a memory error on a DNS query, that the memory
+// error is passed through and not replaced with ENOTFOUND.
+
+require('../common');
+
+const assert = require('assert');
+const errors = require('internal/errors');
+const { internalBinding } = require('internal/test/binding');
+
+const { UV_EAI_MEMORY } = internalBinding('uv');
+const memoryError = errors.dnsException(UV_EAI_MEMORY, 'fhqwhgads');
+
+assert.strictEqual(memoryError.code, 'EAI_MEMORY');
diff --git a/tests/node_compat/test/parallel/test-dns-promises-exists.js b/tests/node_compat/test/parallel/test-dns-promises-exists.js
new file mode 100644
index 000000000..10f9f81df
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-dns-promises-exists.js
@@ -0,0 +1,40 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+require('../common');
+const assert = require('assert');
+const dnsPromises = require('dns/promises');
+const dns = require('dns');
+
+assert.strictEqual(dnsPromises, dns.promises);
+
+assert.strictEqual(dnsPromises.NODATA, dns.NODATA);
+assert.strictEqual(dnsPromises.FORMERR, dns.FORMERR);
+assert.strictEqual(dnsPromises.SERVFAIL, dns.SERVFAIL);
+assert.strictEqual(dnsPromises.NOTFOUND, dns.NOTFOUND);
+assert.strictEqual(dnsPromises.NOTIMP, dns.NOTIMP);
+assert.strictEqual(dnsPromises.REFUSED, dns.REFUSED);
+assert.strictEqual(dnsPromises.BADQUERY, dns.BADQUERY);
+assert.strictEqual(dnsPromises.BADNAME, dns.BADNAME);
+assert.strictEqual(dnsPromises.BADFAMILY, dns.BADFAMILY);
+assert.strictEqual(dnsPromises.BADRESP, dns.BADRESP);
+assert.strictEqual(dnsPromises.CONNREFUSED, dns.CONNREFUSED);
+assert.strictEqual(dnsPromises.TIMEOUT, dns.TIMEOUT);
+assert.strictEqual(dnsPromises.EOF, dns.EOF);
+assert.strictEqual(dnsPromises.FILE, dns.FILE);
+assert.strictEqual(dnsPromises.NOMEM, dns.NOMEM);
+assert.strictEqual(dnsPromises.DESTRUCTION, dns.DESTRUCTION);
+assert.strictEqual(dnsPromises.BADSTR, dns.BADSTR);
+assert.strictEqual(dnsPromises.BADFLAGS, dns.BADFLAGS);
+assert.strictEqual(dnsPromises.NONAME, dns.NONAME);
+assert.strictEqual(dnsPromises.BADHINTS, dns.BADHINTS);
+assert.strictEqual(dnsPromises.NOTINITIALIZED, dns.NOTINITIALIZED);
+assert.strictEqual(dnsPromises.LOADIPHLPAPI, dns.LOADIPHLPAPI);
+assert.strictEqual(dnsPromises.ADDRGETNETWORKPARAMS, dns.ADDRGETNETWORKPARAMS);
+assert.strictEqual(dnsPromises.CANCELLED, dns.CANCELLED);
diff --git a/tests/node_compat/test/parallel/test-dns-resolveany.js b/tests/node_compat/test/parallel/test-dns-resolveany.js
new file mode 100644
index 000000000..56d533ad9
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-dns-resolveany.js
@@ -0,0 +1,78 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 16.13.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// TODO: enable remaining tests once functionality is implemented.
+
+'use strict';
+const common = require('../common');
+const dnstools = require('../common/dns');
+const dns = require('dns');
+const assert = require('assert');
+const dgram = require('dgram');
+const dnsPromises = dns.promises;
+
+const answers = [
+ { type: 'A', address: '1.2.3.4', /*ttl: 123*/ },
+ { type: 'AAAA', address: '::42', /*ttl: 123*/ },
+ {
+ type: 'CAA',
+ critical: 128,
+ issue: 'platynum.ch'
+ },
+ { type: 'MX', priority: 42, exchange: 'foobar.com', ttl: 124 },
+ { type: 'NS', value: 'foobar.org', ttl: 457 },
+ { type: 'PTR', value: 'baz.org', ttl: 987 },
+ {
+ type: 'SOA',
+ nsname: 'ns1.example.com',
+ hostmaster: 'admin.example.com',
+ serial: 156696742,
+ refresh: 900,
+ retry: 900,
+ expire: 1800,
+ minttl: 60
+ },
+ { type: 'TXT', entries: [ 'v=spf1 ~all', 'xyz\x00foo' ] },
+];
+
+const server = dgram.createSocket('udp4');
+
+server.on('message', common.mustCall((msg, { address, port }) => {
+ const parsed = dnstools.parseDNSPacket(msg);
+ const domain = parsed.questions[0].domain;
+ assert.strictEqual(domain, 'example.org');
+
+ server.send(dnstools.writeDNSPacket({
+ id: parsed.id,
+ questions: parsed.questions,
+ answers: answers.map((answer) => Object.assign({ domain }, answer)),
+ }), port, address);
+}, /*2*/ 30));
+
+server.bind(0, common.mustCall(async () => {
+ const address = server.address();
+ dns.setServers([`127.0.0.1:${address.port}`]);
+
+ validateResults(await dnsPromises.resolveAny('example.org'));
+
+ dns.resolveAny('example.org', common.mustSucceed((res) => {
+ validateResults(res);
+ server.close();
+ }));
+}));
+
+function validateResults(res) {
+ // TTL values are only provided for A and AAAA entries.
+ assert.deepStrictEqual(res.map(maybeRedactTTL), answers.map(maybeRedactTTL));
+}
+
+function maybeRedactTTL(r) {
+ const ret = { ...r };
+ if (!['A', 'AAAA'].includes(r.type))
+ delete ret.ttl;
+ return ret;
+}
diff --git a/tests/node_compat/test/parallel/test-dns-resolvens-typeerror.js b/tests/node_compat/test/parallel/test-dns-resolvens-typeerror.js
new file mode 100644
index 000000000..f4b0770fd
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-dns-resolvens-typeerror.js
@@ -0,0 +1,62 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+require('../common');
+
+// This test ensures `dns.resolveNs()` does not raise a C++-land assertion error
+// and throw a JavaScript TypeError instead.
+// Issue https://github.com/nodejs/node-v0.x-archive/issues/7070
+
+const assert = require('assert');
+const dns = require('dns');
+const dnsPromises = dns.promises;
+
+assert.throws(
+ () => dnsPromises.resolveNs([]), // bad name
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: /^The "name" argument must be of type string/
+ }
+);
+assert.throws(
+ () => dns.resolveNs([]), // bad name
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: /^The "name" argument must be of type string/
+ }
+);
+assert.throws(
+ () => dns.resolveNs(''), // bad callback
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError'
+ }
+);
diff --git a/tests/node_compat/test/parallel/test-dns-setservers-type-check.js b/tests/node_compat/test/parallel/test-dns-setservers-type-check.js
new file mode 100644
index 000000000..e4e65b35a
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-dns-setservers-type-check.js
@@ -0,0 +1,127 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const { addresses } = require('../common/internet');
+const assert = require('assert');
+const dns = require('dns');
+const resolver = new dns.promises.Resolver();
+const dnsPromises = dns.promises;
+const promiseResolver = new dns.promises.Resolver();
+
+{
+ [
+ null,
+ undefined,
+ Number(addresses.DNS4_SERVER),
+ addresses.DNS4_SERVER,
+ {
+ address: addresses.DNS4_SERVER
+ },
+ ].forEach((val) => {
+ const errObj = {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: 'The "servers" argument must be an instance of Array.' +
+ common.invalidArgTypeHelper(val)
+ };
+ assert.throws(
+ () => {
+ dns.setServers(val);
+ }, errObj
+ );
+ assert.throws(
+ () => {
+ resolver.setServers(val);
+ }, errObj
+ );
+ assert.throws(
+ () => {
+ dnsPromises.setServers(val);
+ }, errObj
+ );
+ assert.throws(
+ () => {
+ promiseResolver.setServers(val);
+ }, errObj
+ );
+ });
+}
+
+{
+ [
+ [null],
+ [undefined],
+ [Number(addresses.DNS4_SERVER)],
+ [
+ {
+ address: addresses.DNS4_SERVER
+ },
+ ],
+ ].forEach((val) => {
+ const errObj = {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: 'The "servers[0]" argument must be of type string.' +
+ common.invalidArgTypeHelper(val[0])
+ };
+ assert.throws(
+ () => {
+ dns.setServers(val);
+ }, errObj
+ );
+ assert.throws(
+ () => {
+ resolver.setServers(val);
+ }, errObj
+ );
+ assert.throws(
+ () => {
+ dnsPromises.setServers(val);
+ }, errObj
+ );
+ assert.throws(
+ () => {
+ promiseResolver.setServers(val);
+ }, errObj
+ );
+ });
+}
+
+// This test for 'dns/promises'
+{
+ const {
+ setServers
+ } = require('dns/promises');
+
+ // This should not throw any error.
+ (async () => {
+ setServers([ '127.0.0.1' ]);
+ })().then(common.mustCall());
+
+ [
+ [null],
+ [undefined],
+ [Number(addresses.DNS4_SERVER)],
+ [
+ {
+ address: addresses.DNS4_SERVER
+ },
+ ],
+ ].forEach((val) => {
+ const errObj = {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: 'The "servers[0]" argument must be of type string.' +
+ common.invalidArgTypeHelper(val[0])
+ };
+ assert.throws(() => {
+ setServers(val);
+ }, errObj);
+ });
+}
diff --git a/tests/node_compat/test/parallel/test-dns.js b/tests/node_compat/test/parallel/test-dns.js
new file mode 100644
index 000000000..e56f7ca40
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-dns.js
@@ -0,0 +1,471 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 16.13.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+
+// TODO: enable remaining tests once functionality is implemented.
+
+const common = require('../common');
+const dnstools = require('../common/dns');
+const assert = require('assert');
+
+const dns = require('dns');
+const dnsPromises = dns.promises;
+const dgram = require('dgram');
+
+// TODO(cmorten): currently don't expose defaults
+// const existing = dns.getServers();
+// assert(existing.length > 0);
+
+// Verify that setServers() handles arrays with holes and other oddities
+{
+ const servers = [];
+
+ servers[0] = '127.0.0.1';
+ servers[2] = '0.0.0.0';
+ dns.setServers(servers);
+
+ assert.deepStrictEqual(dns.getServers(), ['127.0.0.1', '0.0.0.0']);
+}
+
+{
+ const servers = ['127.0.0.1', '192.168.1.1'];
+
+ servers[3] = '127.1.0.1';
+ servers[4] = '127.1.0.1';
+ servers[5] = '127.1.1.1';
+
+ Object.defineProperty(servers, 2, {
+ enumerable: true,
+ get: () => {
+ servers.length = 3;
+ return '0.0.0.0';
+ }
+ });
+
+ dns.setServers(servers);
+ assert.deepStrictEqual(dns.getServers(), [
+ '127.0.0.1',
+ '192.168.1.1',
+ '0.0.0.0',
+ ]);
+}
+
+{
+ // Various invalidities, all of which should throw a clean error.
+ const invalidServers = [
+ ' ',
+ '\n',
+ '\0',
+ '1'.repeat(3 * 4),
+ // Check for REDOS issues.
+ ':'.repeat(100000),
+ '['.repeat(100000),
+ '['.repeat(100000) + ']'.repeat(100000) + 'a',
+ ];
+ invalidServers.forEach((serv) => {
+ assert.throws(
+ () => {
+ dns.setServers([serv]);
+ },
+ {
+ name: 'TypeError',
+ code: 'ERR_INVALID_IP_ADDRESS'
+ }
+ );
+ });
+}
+
+const goog = [
+ '8.8.8.8',
+ '8.8.4.4',
+];
+dns.setServers(goog);
+assert.deepStrictEqual(dns.getServers(), goog);
+assert.throws(() => dns.setServers(['foobar']), {
+ code: 'ERR_INVALID_IP_ADDRESS',
+ name: 'TypeError',
+ message: 'Invalid IP address: foobar'
+});
+assert.throws(() => dns.setServers(['127.0.0.1:va']), {
+ code: 'ERR_INVALID_IP_ADDRESS',
+ name: 'TypeError',
+ message: 'Invalid IP address: 127.0.0.1:va'
+});
+assert.deepStrictEqual(dns.getServers(), goog);
+
+const goog6 = [
+ '2001:4860:4860::8888',
+ '2001:4860:4860::8844',
+];
+dns.setServers(goog6);
+assert.deepStrictEqual(dns.getServers(), goog6);
+
+goog6.push('4.4.4.4');
+dns.setServers(goog6);
+assert.deepStrictEqual(dns.getServers(), goog6);
+
+const ports = [
+ '4.4.4.4:53',
+ '[2001:4860:4860::8888]:53',
+ '103.238.225.181:666',
+ '[fe80::483a:5aff:fee6:1f04]:666',
+ '[fe80::483a:5aff:fee6:1f04]',
+];
+const portsExpected = [
+ '4.4.4.4',
+ '2001:4860:4860::8888',
+ '103.238.225.181:666',
+ '[fe80::483a:5aff:fee6:1f04]:666',
+ 'fe80::483a:5aff:fee6:1f04',
+];
+dns.setServers(ports);
+assert.deepStrictEqual(dns.getServers(), portsExpected);
+
+dns.setServers([]);
+assert.deepStrictEqual(dns.getServers(), []);
+
+{
+ const errObj = {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: 'The "rrtype" argument must be of type string. ' +
+ 'Received an instance of Array'
+ };
+ assert.throws(() => {
+ dns.resolve('example.com', [], common.mustNotCall());
+ }, errObj);
+ assert.throws(() => {
+ dnsPromises.resolve('example.com', []);
+ }, errObj);
+}
+{
+ const errObj = {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: 'The "name" argument must be of type string. ' +
+ 'Received undefined'
+ };
+ assert.throws(() => {
+ dnsPromises.resolve();
+ }, errObj);
+}
+
+// dns.lookup should accept only falsey and string values
+{
+ const errorReg = {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: /^The "hostname" argument must be of type string\. Received .*/
+ };
+
+ assert.throws(() => dns.lookup({}, common.mustNotCall()), errorReg);
+
+ assert.throws(() => dns.lookup([], common.mustNotCall()), errorReg);
+
+ assert.throws(() => dns.lookup(true, common.mustNotCall()), errorReg);
+
+ assert.throws(() => dns.lookup(1, common.mustNotCall()), errorReg);
+
+ assert.throws(() => dns.lookup(common.mustNotCall(), common.mustNotCall()),
+ errorReg);
+
+ assert.throws(() => dnsPromises.lookup({}), errorReg);
+ assert.throws(() => dnsPromises.lookup([]), errorReg);
+ assert.throws(() => dnsPromises.lookup(true), errorReg);
+ assert.throws(() => dnsPromises.lookup(1), errorReg);
+ assert.throws(() => dnsPromises.lookup(common.mustNotCall()), errorReg);
+}
+
+// dns.lookup should accept falsey values
+{
+ const checkCallback = (err, address, family) => {
+ assert.ifError(err);
+ assert.strictEqual(address, null);
+ assert.strictEqual(family, 4);
+ };
+
+ ['', null, undefined, 0, NaN].forEach(async (value) => {
+ const res = await dnsPromises.lookup(value);
+ assert.deepStrictEqual(res, { address: null, family: 4 });
+ dns.lookup(value, common.mustCall(checkCallback));
+ });
+}
+
+{
+ // Make sure that dns.lookup throws if hints does not represent a valid flag.
+ // (dns.V4MAPPED | dns.ADDRCONFIG | dns.ALL) + 1 is invalid because:
+ // - it's different from dns.V4MAPPED and dns.ADDRCONFIG and dns.ALL.
+ // - it's different from any subset of them bitwise ored.
+ // - it's different from 0.
+ // - it's an odd number different than 1, and thus is invalid, because
+ // flags are either === 1 or even.
+ const hints = (dns.V4MAPPED | dns.ADDRCONFIG | dns.ALL) + 1;
+ const err = {
+ code: 'ERR_INVALID_ARG_VALUE',
+ name: 'TypeError',
+ message: /The argument 'hints' is invalid\. Received \d+/
+ };
+
+ assert.throws(() => {
+ dnsPromises.lookup('nodejs.org', { hints });
+ }, err);
+ assert.throws(() => {
+ dns.lookup('nodejs.org', { hints }, common.mustNotCall());
+ }, err);
+}
+
+assert.throws(() => dns.lookup("nodejs.org"), {
+ code: "ERR_INVALID_ARG_TYPE",
+ name: "TypeError",
+});
+
+assert.throws(() => dns.lookup("nodejs.org", 4), {
+ code: "ERR_INVALID_ARG_TYPE",
+ name: "TypeError",
+});
+
+dns.lookup('', { family: 4, hints: 0 }, common.mustCall());
+
+dns.lookup('', {
+ family: 6,
+ hints: dns.ADDRCONFIG
+}, common.mustCall());
+
+dns.lookup('', { hints: dns.V4MAPPED }, common.mustCall());
+
+dns.lookup('', {
+ hints: dns.ADDRCONFIG | dns.V4MAPPED
+}, common.mustCall());
+
+dns.lookup('', {
+ hints: dns.ALL
+}, common.mustCall());
+
+dns.lookup('', {
+ hints: dns.V4MAPPED | dns.ALL
+}, common.mustCall());
+
+dns.lookup('', {
+ hints: dns.ADDRCONFIG | dns.V4MAPPED | dns.ALL
+}, common.mustCall());
+
+(async function() {
+ await dnsPromises.lookup('', { family: 4, hints: 0 });
+ await dnsPromises.lookup('', { family: 6, hints: dns.ADDRCONFIG });
+ await dnsPromises.lookup('', { hints: dns.V4MAPPED });
+ await dnsPromises.lookup('', { hints: dns.ADDRCONFIG | dns.V4MAPPED });
+ await dnsPromises.lookup('', { hints: dns.ALL });
+ await dnsPromises.lookup('', { hints: dns.V4MAPPED | dns.ALL });
+ await dnsPromises.lookup('', {
+ hints: dns.ADDRCONFIG | dns.V4MAPPED | dns.ALL
+ });
+})().then(common.mustCall());
+
+// {
+// const err = {
+// code: 'ERR_MISSING_ARGS',
+// name: 'TypeError',
+// message: 'The "address", "port", and "callback" arguments must be ' +
+// 'specified'
+// };
+
+// assert.throws(() => dns.lookupService('0.0.0.0'), err);
+// err.message = 'The "address" and "port" arguments must be specified';
+// assert.throws(() => dnsPromises.lookupService('0.0.0.0'), err);
+// }
+
+// {
+// const invalidAddress = 'fasdfdsaf';
+// const err = {
+// code: 'ERR_INVALID_ARG_VALUE',
+// name: 'TypeError',
+// message: `The argument 'address' is invalid. Received '${invalidAddress}'`
+// };
+
+// assert.throws(() => {
+// dnsPromises.lookupService(invalidAddress, 0);
+// }, err);
+
+// assert.throws(() => {
+// dns.lookupService(invalidAddress, 0, common.mustNotCall());
+// }, err);
+// }
+
+// const portErr = (port) => {
+// const err = {
+// code: 'ERR_SOCKET_BAD_PORT',
+// message:
+// `Port should be >= 0 and < 65536. Received ${port}.`,
+// name: 'RangeError'
+// };
+
+// assert.throws(() => {
+// dnsPromises.lookupService('0.0.0.0', port);
+// }, err);
+
+// assert.throws(() => {
+// dns.lookupService('0.0.0.0', port, common.mustNotCall());
+// }, err);
+// };
+// portErr(null);
+// portErr(undefined);
+// portErr(65538);
+// portErr('test');
+
+// assert.throws(() => {
+// dns.lookupService('0.0.0.0', 80, null);
+// }, {
+// code: 'ERR_INVALID_ARG_TYPE',
+// name: 'TypeError'
+// });
+
+{
+ dns.resolveMx('foo.onion', function(err) {
+ assert.deepStrictEqual(err.code, 'ENOTFOUND');
+ assert.deepStrictEqual(err.syscall, 'queryMx');
+ assert.deepStrictEqual(err.hostname, 'foo.onion');
+ assert.deepStrictEqual(err.message, 'queryMx ENOTFOUND foo.onion');
+ });
+}
+
+{
+ const cases = [
+ {
+ method: "resolveAny",
+ answers: [
+ { type: "A", address: "1.2.3.4" /*ttl: 3333333333*/ },
+ { type: "AAAA", address: "::42" /*ttl: 3333333333*/ },
+ { type: "MX", priority: 42, exchange: "foobar.com", ttl: 3333333333 },
+ { type: "NS", value: "foobar.org", ttl: 3333333333 },
+ { type: "PTR", value: "baz.org", ttl: 3333333333 },
+ {
+ type: "SOA",
+ nsname: "ns1.example.com",
+ hostmaster: "admin.example.com",
+ serial: 3210987654,
+ refresh: 900,
+ retry: 900,
+ expire: 1800,
+ minttl: 3333333333,
+ },
+ ],
+ },
+
+ // TODO(cmorten): support ttl option
+ // {
+ // method: "resolve4",
+ // options: { ttl: true },
+ // answers: [{ type: "A", address: "1.2.3.4", ttl: 3333333333 }],
+ // },
+
+ // {
+ // method: "resolve6",
+ // options: { ttl: true },
+ // answers: [{ type: "AAAA", address: "::42", ttl: 3333333333 }],
+ // },
+
+ {
+ method: "resolveSoa",
+ answers: [
+ {
+ type: "SOA",
+ nsname: "ns1.example.com",
+ hostmaster: "admin.example.com",
+ serial: 3210987654,
+ refresh: 900,
+ retry: 900,
+ expire: 1800,
+ minttl: 3333333333,
+ },
+ ],
+ },
+ ];
+
+ const server = dgram.createSocket('udp4');
+
+ server.on('message', common.mustCall((msg, { address, port }) => {
+ const parsed = dnstools.parseDNSPacket(msg);
+ const domain = parsed.questions[0].domain;
+ assert.strictEqual(domain, 'example.org');
+
+ server.send(dnstools.writeDNSPacket({
+ id: parsed.id,
+ questions: parsed.questions,
+ answers: cases[0].answers.map(
+ (answer) => Object.assign({ domain }, answer)
+ ),
+ }), port, address);
+ // Don't have "ANY" query type available so calls greatly increased with
+ // polyfill method.
+ }, /*cases.length * 2*/ 32));
+
+ server.bind(0, common.mustCall(() => {
+ const address = server.address();
+ dns.setServers([`127.0.0.1:${address.port}`]);
+
+ function validateResults(res) {
+ if (!Array.isArray(res))
+ res = [res];
+
+ assert.deepStrictEqual(res.map(tweakEntry),
+ cases[0].answers.map(tweakEntry));
+ }
+
+ function tweakEntry(r) {
+ const ret = { ...r };
+
+ const { method } = cases[0];
+
+ // TTL values are only provided for A and AAAA entries.
+ if (!['A', 'AAAA'].includes(ret.type) && !/^resolve(4|6)?$/.test(method))
+ delete ret.ttl;
+
+ if (method !== 'resolveAny')
+ delete ret.type;
+
+ return ret;
+ }
+
+ (async function nextCase() {
+ if (cases.length === 0)
+ return server.close();
+
+ const { method, options } = cases[0];
+
+ validateResults(await dnsPromises[method]('example.org', options));
+
+ dns[method]('example.org', options, common.mustSucceed((res) => {
+ validateResults(res);
+ cases.shift();
+ nextCase();
+ }));
+ })().then(common.mustCall());
+
+ }));
+}
diff --git a/tests/node_compat/test/parallel/test-eval-strict-referenceerror.js b/tests/node_compat/test/parallel/test-eval-strict-referenceerror.js
new file mode 100644
index 000000000..b521b17ba
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-eval-strict-referenceerror.js
@@ -0,0 +1,34 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+/* eslint-disable strict */
+require('../common');
+
+// In Node.js 0.10, a bug existed that caused strict functions to not capture
+// their environment when evaluated. When run in 0.10 `test()` fails with a
+// `ReferenceError`. See https://github.com/nodejs/node/issues/2245 for details.
+
+const assert = require('assert');
+
+function test() {
+
+ const code = [
+ 'var foo = {m: 1};',
+ '',
+ 'function bar() {',
+ '\'use strict\';',
+ 'return foo; // foo isn\'t captured in 0.10',
+ '};',
+ ].join('\n');
+
+ eval(code);
+
+ return bar(); // eslint-disable-line no-undef
+
+}
+
+assert.deepStrictEqual(test(), { m: 1 });
diff --git a/tests/node_compat/test/parallel/test-eval.js b/tests/node_compat/test/parallel/test-eval.js
new file mode 100644
index 000000000..78254a377
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-eval.js
@@ -0,0 +1,14 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+require('../common');
+const assert = require('assert');
+
+// Verify that eval is allowed by default.
+assert.strictEqual(eval('"eval"'), 'eval');
diff --git a/tests/node_compat/test/parallel/test-event-emitter-add-listeners.js b/tests/node_compat/test/parallel/test-event-emitter-add-listeners.js
new file mode 100644
index 000000000..8ad798021
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-event-emitter-add-listeners.js
@@ -0,0 +1,93 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const EventEmitter = require('events');
+
+{
+ const ee = new EventEmitter();
+ const events_new_listener_emitted = [];
+ const listeners_new_listener_emitted = [];
+
+ // Sanity check
+ assert.strictEqual(ee.addListener, ee.on);
+
+ ee.on('newListener', function(event, listener) {
+ // Don't track newListener listeners.
+ if (event === 'newListener')
+ return;
+
+ events_new_listener_emitted.push(event);
+ listeners_new_listener_emitted.push(listener);
+ });
+
+ const hello = common.mustCall(function(a, b) {
+ assert.strictEqual(a, 'a');
+ assert.strictEqual(b, 'b');
+ });
+
+ ee.once('newListener', function(name, listener) {
+ assert.strictEqual(name, 'hello');
+ assert.strictEqual(listener, hello);
+ assert.deepStrictEqual(this.listeners('hello'), []);
+ });
+
+ ee.on('hello', hello);
+ ee.once('foo', assert.fail);
+ assert.deepStrictEqual(['hello', 'foo'], events_new_listener_emitted);
+ assert.deepStrictEqual([hello, assert.fail], listeners_new_listener_emitted);
+
+ ee.emit('hello', 'a', 'b');
+}
+
+// Just make sure that this doesn't throw:
+{
+ const f = new EventEmitter();
+
+ f.setMaxListeners(0);
+}
+
+{
+ const listen1 = () => {};
+ const listen2 = () => {};
+ const ee = new EventEmitter();
+
+ ee.once('newListener', function() {
+ assert.deepStrictEqual(ee.listeners('hello'), []);
+ ee.once('newListener', function() {
+ assert.deepStrictEqual(ee.listeners('hello'), []);
+ });
+ ee.on('hello', listen2);
+ });
+ ee.on('hello', listen1);
+ // The order of listeners on an event is not always the order in which the
+ // listeners were added.
+ assert.deepStrictEqual(ee.listeners('hello'), [listen2, listen1]);
+}
diff --git a/tests/node_compat/test/parallel/test-event-emitter-emit-context.js b/tests/node_compat/test/parallel/test-event-emitter-emit-context.js
new file mode 100644
index 000000000..d3673827f
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-event-emitter-emit-context.js
@@ -0,0 +1,25 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const EventEmitter = require('events');
+
+// Test emit called by other context
+const EE = new EventEmitter();
+
+// Works as expected if the context has no `constructor.name`
+{
+ const ctx = Object.create(null);
+ assert.throws(
+ () => EE.emit.call(ctx, 'error', new Error('foo')),
+ common.expectsError({ name: 'Error', message: 'foo' })
+ );
+}
+
+assert.strictEqual(EE.emit.call({}, 'foo'), false);
diff --git a/tests/node_compat/test/parallel/test-event-emitter-error-monitor.js b/tests/node_compat/test/parallel/test-event-emitter-error-monitor.js
new file mode 100644
index 000000000..714a47e59
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-event-emitter-error-monitor.js
@@ -0,0 +1,39 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const EventEmitter = require('events');
+
+const EE = new EventEmitter();
+const theErr = new Error('MyError');
+
+EE.on(
+ EventEmitter.errorMonitor,
+ common.mustCall(function onErrorMonitor(e) {
+ assert.strictEqual(e, theErr);
+ }, 3)
+);
+
+// Verify with no error listener
+assert.throws(
+ () => EE.emit('error', theErr), theErr
+);
+
+// Verify with error listener
+EE.once('error', common.mustCall((e) => assert.strictEqual(e, theErr)));
+EE.emit('error', theErr);
+
+
+// Verify it works with once
+process.nextTick(() => EE.emit('error', theErr));
+assert.rejects(EventEmitter.once(EE, 'notTriggered'), theErr);
+
+// Only error events trigger error monitor
+EE.on('aEvent', common.mustCall());
+EE.emit('aEvent');
diff --git a/tests/node_compat/test/parallel/test-event-emitter-errors.js b/tests/node_compat/test/parallel/test-event-emitter-errors.js
new file mode 100644
index 000000000..39a896b05
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-event-emitter-errors.js
@@ -0,0 +1,44 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+const EventEmitter = require('events');
+const util = require('util');
+
+const EE = new EventEmitter();
+
+assert.throws(
+ () => EE.emit('error', 'Accepts a string'),
+ {
+ code: 'ERR_UNHANDLED_ERROR',
+ name: 'Error',
+ message: "Unhandled error. ('Accepts a string')",
+ }
+);
+
+assert.throws(
+ () => EE.emit('error', { message: 'Error!' }),
+ {
+ code: 'ERR_UNHANDLED_ERROR',
+ name: 'Error',
+ message: "Unhandled error. ({ message: 'Error!' })",
+ }
+);
+
+assert.throws(
+ () => EE.emit('error', {
+ message: 'Error!',
+ [util.inspect.custom]() { throw new Error(); },
+ }),
+ {
+ code: 'ERR_UNHANDLED_ERROR',
+ name: 'Error',
+ message: 'Unhandled error. ([object Object])',
+ }
+);
diff --git a/tests/node_compat/test/parallel/test-event-emitter-get-max-listeners.js b/tests/node_compat/test/parallel/test-event-emitter-get-max-listeners.js
new file mode 100644
index 000000000..9eeb5ecf9
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-event-emitter-get-max-listeners.js
@@ -0,0 +1,26 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+const EventEmitter = require('events');
+
+const emitter = new EventEmitter();
+
+assert.strictEqual(emitter.getMaxListeners(), EventEmitter.defaultMaxListeners);
+
+emitter.setMaxListeners(0);
+assert.strictEqual(emitter.getMaxListeners(), 0);
+
+emitter.setMaxListeners(3);
+assert.strictEqual(emitter.getMaxListeners(), 3);
+
+// https://github.com/nodejs/node/issues/523 - second call should not throw.
+const recv = {};
+EventEmitter.prototype.on.call(recv, 'event', () => {});
+EventEmitter.prototype.on.call(recv, 'event', () => {});
diff --git a/tests/node_compat/test/parallel/test-event-emitter-invalid-listener.js b/tests/node_compat/test/parallel/test-event-emitter-invalid-listener.js
new file mode 100644
index 000000000..604110a5e
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-event-emitter-invalid-listener.js
@@ -0,0 +1,27 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+require('../common');
+const assert = require('assert');
+const EventEmitter = require('events');
+
+const eventsMethods = ['on', 'once', 'removeListener', 'prependOnceListener'];
+
+// Verify that the listener must be a function for events methods
+for (const method of eventsMethods) {
+ assert.throws(() => {
+ const ee = new EventEmitter();
+ ee[method]('foo', null);
+ }, {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: 'The "listener" argument must be of type function. ' +
+ 'Received null',
+ }, `event.${method}('foo', null) should throw the proper error`);
+}
diff --git a/tests/node_compat/test/parallel/test-event-emitter-listener-count.js b/tests/node_compat/test/parallel/test-event-emitter-listener-count.js
new file mode 100644
index 000000000..e86a9512f
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-event-emitter-listener-count.js
@@ -0,0 +1,25 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+require('../common');
+const assert = require('assert');
+const EventEmitter = require('events');
+
+const emitter = new EventEmitter();
+emitter.on('foo', () => {});
+emitter.on('foo', () => {});
+emitter.on('baz', () => {});
+// Allow any type
+emitter.on(123, () => {});
+
+assert.strictEqual(EventEmitter.listenerCount(emitter, 'foo'), 2);
+assert.strictEqual(emitter.listenerCount('foo'), 2);
+assert.strictEqual(emitter.listenerCount('bar'), 0);
+assert.strictEqual(emitter.listenerCount('baz'), 1);
+assert.strictEqual(emitter.listenerCount(123), 1);
diff --git a/tests/node_compat/test/parallel/test-event-emitter-listeners-side-effects.js b/tests/node_compat/test/parallel/test-event-emitter-listeners-side-effects.js
new file mode 100644
index 000000000..3daa73b21
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-event-emitter-listeners-side-effects.js
@@ -0,0 +1,67 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+
+require('../common');
+const assert = require('assert');
+
+const EventEmitter = require('events').EventEmitter;
+
+const e = new EventEmitter();
+let fl; // foo listeners
+
+fl = e.listeners('foo');
+assert(Array.isArray(fl));
+assert.strictEqual(fl.length, 0);
+assert(!(e._events instanceof Object));
+assert.deepStrictEqual(Object.keys(e._events), []);
+
+e.on('foo', assert.fail);
+fl = e.listeners('foo');
+assert.strictEqual(e._events.foo, assert.fail);
+assert(Array.isArray(fl));
+assert.strictEqual(fl.length, 1);
+assert.strictEqual(fl[0], assert.fail);
+
+e.listeners('bar');
+
+e.on('foo', assert.ok);
+fl = e.listeners('foo');
+
+assert(Array.isArray(e._events.foo));
+assert.strictEqual(e._events.foo.length, 2);
+assert.strictEqual(e._events.foo[0], assert.fail);
+assert.strictEqual(e._events.foo[1], assert.ok);
+
+assert(Array.isArray(fl));
+assert.strictEqual(fl.length, 2);
+assert.strictEqual(fl[0], assert.fail);
+assert.strictEqual(fl[1], assert.ok);
+
+console.log('ok');
diff --git a/tests/node_compat/test/parallel/test-event-emitter-listeners.js b/tests/node_compat/test/parallel/test-event-emitter-listeners.js
new file mode 100644
index 000000000..ddb52da1a
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-event-emitter-listeners.js
@@ -0,0 +1,131 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+
+require('../common');
+const assert = require('assert');
+const events = require('events');
+
+function listener() {}
+
+function listener2() {}
+
+function listener3() {
+ return 0;
+}
+
+function listener4() {
+ return 1;
+}
+
+{
+ const ee = new events.EventEmitter();
+ ee.on('foo', listener);
+ const fooListeners = ee.listeners('foo');
+ assert.deepStrictEqual(ee.listeners('foo'), [listener]);
+ ee.removeAllListeners('foo');
+ assert.deepStrictEqual(ee.listeners('foo'), []);
+ assert.deepStrictEqual(fooListeners, [listener]);
+}
+
+{
+ const ee = new events.EventEmitter();
+ ee.on('foo', listener);
+ const eeListenersCopy = ee.listeners('foo');
+ assert.deepStrictEqual(eeListenersCopy, [listener]);
+ assert.deepStrictEqual(ee.listeners('foo'), [listener]);
+ eeListenersCopy.push(listener2);
+ assert.deepStrictEqual(ee.listeners('foo'), [listener]);
+ assert.deepStrictEqual(eeListenersCopy, [listener, listener2]);
+}
+
+{
+ const ee = new events.EventEmitter();
+ ee.on('foo', listener);
+ const eeListenersCopy = ee.listeners('foo');
+ ee.on('foo', listener2);
+ assert.deepStrictEqual(ee.listeners('foo'), [listener, listener2]);
+ assert.deepStrictEqual(eeListenersCopy, [listener]);
+}
+
+{
+ const ee = new events.EventEmitter();
+ ee.once('foo', listener);
+ assert.deepStrictEqual(ee.listeners('foo'), [listener]);
+}
+
+{
+ const ee = new events.EventEmitter();
+ ee.on('foo', listener);
+ ee.once('foo', listener2);
+ assert.deepStrictEqual(ee.listeners('foo'), [listener, listener2]);
+}
+
+{
+ const ee = new events.EventEmitter();
+ ee._events = undefined;
+ assert.deepStrictEqual(ee.listeners('foo'), []);
+}
+
+{
+ class TestStream extends events.EventEmitter {}
+ const s = new TestStream();
+ assert.deepStrictEqual(s.listeners('foo'), []);
+}
+
+{
+ const ee = new events.EventEmitter();
+ ee.on('foo', listener);
+ const wrappedListener = ee.rawListeners('foo');
+ assert.strictEqual(wrappedListener.length, 1);
+ assert.strictEqual(wrappedListener[0], listener);
+ assert.notStrictEqual(wrappedListener, ee.rawListeners('foo'));
+ ee.once('foo', listener);
+ const wrappedListeners = ee.rawListeners('foo');
+ assert.strictEqual(wrappedListeners.length, 2);
+ assert.strictEqual(wrappedListeners[0], listener);
+ assert.notStrictEqual(wrappedListeners[1], listener);
+ assert.strictEqual(wrappedListeners[1].listener, listener);
+ assert.notStrictEqual(wrappedListeners, ee.rawListeners('foo'));
+ ee.emit('foo');
+ assert.strictEqual(wrappedListeners.length, 2);
+ assert.strictEqual(wrappedListeners[1].listener, listener);
+}
+
+{
+ const ee = new events.EventEmitter();
+ ee.once('foo', listener3);
+ ee.on('foo', listener4);
+ const rawListeners = ee.rawListeners('foo');
+ assert.strictEqual(rawListeners.length, 2);
+ assert.strictEqual(rawListeners[0](), 0);
+ const rawListener = ee.rawListeners('foo');
+ assert.strictEqual(rawListener.length, 1);
+ assert.strictEqual(rawListener[0](), 1);
+}
diff --git a/tests/node_compat/test/parallel/test-event-emitter-max-listeners.js b/tests/node_compat/test/parallel/test-event-emitter-max-listeners.js
new file mode 100644
index 000000000..1245c6b92
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-event-emitter-max-listeners.js
@@ -0,0 +1,80 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 16.13.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const events = require('events');
+const { inspect } = require('util');
+const e = new events.EventEmitter();
+
+e.on('maxListeners', common.mustCall());
+
+// Should not corrupt the 'maxListeners' queue.
+e.setMaxListeners(42);
+
+const throwsObjs = [NaN, -1, 'and even this'];
+
+for (const obj of throwsObjs) {
+ assert.throws(
+ () => e.setMaxListeners(obj),
+ {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError',
+ message: 'The value of "n" is out of range. ' +
+ `It must be a non-negative number. Received ${inspect(obj)}`
+ }
+ );
+
+ assert.throws(
+ () => events.defaultMaxListeners = obj,
+ {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError',
+ message: 'The value of "defaultMaxListeners" is out of range. ' +
+ `It must be a non-negative number. Received ${inspect(obj)}`
+ }
+ );
+}
+
+e.emit('maxListeners');
+
+{
+ const { EventEmitter, defaultMaxListeners } = events;
+ for (const obj of throwsObjs) {
+ assert.throws(() => EventEmitter.setMaxListeners(obj), {
+ code: 'ERR_OUT_OF_RANGE',
+ });
+ }
+
+ // FIXME(bartlomieju):
+ // assert.throws(
+ // () => EventEmitter.setMaxListeners(defaultMaxListeners, 'INVALID_EMITTER'),
+ // { code: 'ERR_INVALID_ARG_TYPE' }
+ // );
+}
diff --git a/tests/node_compat/test/parallel/test-event-emitter-method-names.js b/tests/node_compat/test/parallel/test-event-emitter-method-names.js
new file mode 100644
index 000000000..7b7822fe1
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-event-emitter-method-names.js
@@ -0,0 +1,42 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+const events = require('events');
+
+const E = events.EventEmitter.prototype;
+assert.strictEqual(E.constructor.name, 'EventEmitter');
+assert.strictEqual(E.on, E.addListener); // Same method.
+assert.strictEqual(E.off, E.removeListener); // Same method.
+Object.getOwnPropertyNames(E).forEach(function(name) {
+ if (name === 'constructor' || name === 'on' || name === 'off') return;
+ if (typeof E[name] !== 'function') return;
+ assert.strictEqual(E[name].name, name);
+});
diff --git a/tests/node_compat/test/parallel/test-event-emitter-modify-in-emit.js b/tests/node_compat/test/parallel/test-event-emitter-modify-in-emit.js
new file mode 100644
index 000000000..4953241ba
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-event-emitter-modify-in-emit.js
@@ -0,0 +1,87 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+const events = require('events');
+
+let callbacks_called = [];
+
+const e = new events.EventEmitter();
+
+function callback1() {
+ callbacks_called.push('callback1');
+ e.on('foo', callback2);
+ e.on('foo', callback3);
+ e.removeListener('foo', callback1);
+}
+
+function callback2() {
+ callbacks_called.push('callback2');
+ e.removeListener('foo', callback2);
+}
+
+function callback3() {
+ callbacks_called.push('callback3');
+ e.removeListener('foo', callback3);
+}
+
+e.on('foo', callback1);
+assert.strictEqual(e.listeners('foo').length, 1);
+
+e.emit('foo');
+assert.strictEqual(e.listeners('foo').length, 2);
+assert.deepStrictEqual(['callback1'], callbacks_called);
+
+e.emit('foo');
+assert.strictEqual(e.listeners('foo').length, 0);
+assert.deepStrictEqual(['callback1', 'callback2', 'callback3'],
+ callbacks_called);
+
+e.emit('foo');
+assert.strictEqual(e.listeners('foo').length, 0);
+assert.deepStrictEqual(['callback1', 'callback2', 'callback3'],
+ callbacks_called);
+
+e.on('foo', callback1);
+e.on('foo', callback2);
+assert.strictEqual(e.listeners('foo').length, 2);
+e.removeAllListeners('foo');
+assert.strictEqual(e.listeners('foo').length, 0);
+
+// Verify that removing callbacks while in emit allows emits to propagate to
+// all listeners
+callbacks_called = [];
+
+e.on('foo', callback2);
+e.on('foo', callback3);
+assert.strictEqual(e.listeners('foo').length, 2);
+e.emit('foo');
+assert.deepStrictEqual(['callback2', 'callback3'], callbacks_called);
+assert.strictEqual(e.listeners('foo').length, 0);
diff --git a/tests/node_compat/test/parallel/test-event-emitter-no-error-provided-to-error-event.js b/tests/node_compat/test/parallel/test-event-emitter-no-error-provided-to-error-event.js
new file mode 100644
index 000000000..8ab7aec44
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-event-emitter-no-error-provided-to-error-event.js
@@ -0,0 +1,65 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 16.13.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const events = require('events');
+/* TODO(uki00a): Uncomment this block when the 'domain' module is implemented.
+const domain = require('domain');
+
+{
+ const e = new events.EventEmitter();
+ const d = domain.create();
+ d.add(e);
+ d.on('error', common.mustCall((er) => {
+ assert(er instanceof Error, 'error created');
+ }));
+ e.emit('error');
+}
+
+for (const arg of [false, null, undefined]) {
+ const e = new events.EventEmitter();
+ const d = domain.create();
+ d.add(e);
+ d.on('error', common.mustCall((er) => {
+ assert(er instanceof Error, 'error created');
+ }));
+ e.emit('error', arg);
+}
+
+for (const arg of [42, 'fortytwo', true]) {
+ const e = new events.EventEmitter();
+ const d = domain.create();
+ d.add(e);
+ d.on('error', common.mustCall((er) => {
+ assert.strictEqual(er, arg);
+ }));
+ e.emit('error', arg);
+}
+*/
diff --git a/tests/node_compat/test/parallel/test-event-emitter-num-args.js b/tests/node_compat/test/parallel/test-event-emitter-num-args.js
new file mode 100644
index 000000000..05ed54cb6
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-event-emitter-num-args.js
@@ -0,0 +1,61 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+const events = require('events');
+
+const e = new events.EventEmitter();
+const num_args_emitted = [];
+
+e.on('numArgs', function() {
+ const numArgs = arguments.length;
+ num_args_emitted.push(numArgs);
+});
+
+e.on('foo', function() {
+ num_args_emitted.push(arguments.length);
+});
+
+e.on('foo', function() {
+ num_args_emitted.push(arguments.length);
+});
+
+e.emit('numArgs');
+e.emit('numArgs', null);
+e.emit('numArgs', null, null);
+e.emit('numArgs', null, null, null);
+e.emit('numArgs', null, null, null, null);
+e.emit('numArgs', null, null, null, null, null);
+
+e.emit('foo', null, null, null, null);
+
+process.on('exit', function() {
+ assert.deepStrictEqual(num_args_emitted, [0, 1, 2, 3, 4, 5, 4, 4]);
+});
diff --git a/tests/node_compat/test/parallel/test-event-emitter-once.js b/tests/node_compat/test/parallel/test-event-emitter-once.js
new file mode 100644
index 000000000..1d02a639e
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-event-emitter-once.js
@@ -0,0 +1,77 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const EventEmitter = require('events');
+
+const e = new EventEmitter();
+
+e.once('hello', common.mustCall());
+
+e.emit('hello', 'a', 'b');
+e.emit('hello', 'a', 'b');
+e.emit('hello', 'a', 'b');
+e.emit('hello', 'a', 'b');
+
+function remove() {
+ assert.fail('once->foo should not be emitted');
+}
+
+e.once('foo', remove);
+e.removeListener('foo', remove);
+e.emit('foo');
+
+e.once('e', common.mustCall(function() {
+ e.emit('e');
+}));
+
+e.once('e', common.mustCall());
+
+e.emit('e');
+
+{
+ // once() has different code paths based on the number of arguments being
+ // emitted. Verify that all of the cases are covered.
+ const maxArgs = 4;
+
+ for (let i = 0; i <= maxArgs; ++i) {
+ const ee = new EventEmitter();
+ const args = ['foo'];
+
+ for (let j = 0; j < i; ++j)
+ args.push(j);
+
+ ee.once('foo', common.mustCall((...params) => {
+ assert.deepStrictEqual(params, args.slice(1));
+ }));
+
+ EventEmitter.prototype.emit.apply(ee, args);
+ }
+}
diff --git a/tests/node_compat/test/parallel/test-event-emitter-prepend.js b/tests/node_compat/test/parallel/test-event-emitter-prepend.js
new file mode 100644
index 000000000..b06722742
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-event-emitter-prepend.js
@@ -0,0 +1,50 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 16.13.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+'use strict';
+
+const common = require('../common');
+const EventEmitter = require('events');
+const assert = require('assert');
+
+const myEE = new EventEmitter();
+let m = 0;
+// This one comes last.
+myEE.on('foo', common.mustCall(() => assert.strictEqual(m, 2)));
+
+// This one comes second.
+myEE.prependListener('foo', common.mustCall(() => assert.strictEqual(m++, 1)));
+
+// This one comes first.
+myEE.prependOnceListener('foo',
+ common.mustCall(() => assert.strictEqual(m++, 0)));
+
+myEE.emit('foo');
+
+// Test fallback if prependListener is undefined.
+const stream = require('stream');
+
+delete EventEmitter.prototype.prependListener;
+
+function Writable() {
+ this.writable = true;
+ stream.Stream.call(this);
+}
+Object.setPrototypeOf(Writable.prototype, stream.Stream.prototype);
+Object.setPrototypeOf(Writable, stream.Stream);
+
+function Readable() {
+ this.readable = true;
+ stream.Stream.call(this);
+}
+Object.setPrototypeOf(Readable.prototype, stream.Stream.prototype);
+Object.setPrototypeOf(Readable, stream.Stream);
+
+// FIXME(bartlomieju):
+// const w = new Writable();
+// const r = new Readable();
+// r.pipe(w);
diff --git a/tests/node_compat/test/parallel/test-event-emitter-remove-all-listeners.js b/tests/node_compat/test/parallel/test-event-emitter-remove-all-listeners.js
new file mode 100644
index 000000000..576c02aa0
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-event-emitter-remove-all-listeners.js
@@ -0,0 +1,130 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const events = require('events');
+
+
+function expect(expected) {
+ const actual = [];
+ process.on('exit', function() {
+ assert.deepStrictEqual(actual.sort(), expected.sort());
+ });
+ function listener(name) {
+ actual.push(name);
+ }
+ return common.mustCall(listener, expected.length);
+}
+
+{
+ const ee = new events.EventEmitter();
+ const noop = common.mustNotCall();
+ ee.on('foo', noop);
+ ee.on('bar', noop);
+ ee.on('baz', noop);
+ ee.on('baz', noop);
+ const fooListeners = ee.listeners('foo');
+ const barListeners = ee.listeners('bar');
+ const bazListeners = ee.listeners('baz');
+ ee.on('removeListener', expect(['bar', 'baz', 'baz']));
+ ee.removeAllListeners('bar');
+ ee.removeAllListeners('baz');
+ assert.deepStrictEqual(ee.listeners('foo'), [noop]);
+ assert.deepStrictEqual(ee.listeners('bar'), []);
+ assert.deepStrictEqual(ee.listeners('baz'), []);
+ // After calling removeAllListeners(),
+ // the old listeners array should stay unchanged.
+ assert.deepStrictEqual(fooListeners, [noop]);
+ assert.deepStrictEqual(barListeners, [noop]);
+ assert.deepStrictEqual(bazListeners, [noop, noop]);
+ // After calling removeAllListeners(),
+ // new listeners arrays is different from the old.
+ assert.notStrictEqual(ee.listeners('bar'), barListeners);
+ assert.notStrictEqual(ee.listeners('baz'), bazListeners);
+}
+
+{
+ const ee = new events.EventEmitter();
+ ee.on('foo', common.mustNotCall());
+ ee.on('bar', common.mustNotCall());
+ // Expect LIFO order
+ ee.on('removeListener', expect(['foo', 'bar', 'removeListener']));
+ ee.on('removeListener', expect(['foo', 'bar']));
+ ee.removeAllListeners();
+ assert.deepStrictEqual([], ee.listeners('foo'));
+ assert.deepStrictEqual([], ee.listeners('bar'));
+}
+
+{
+ const ee = new events.EventEmitter();
+ ee.on('removeListener', common.mustNotCall());
+ // Check for regression where removeAllListeners() throws when
+ // there exists a 'removeListener' listener, but there exists
+ // no listeners for the provided event type.
+ ee.removeAllListeners.bind(ee, 'foo');
+}
+
+{
+ const ee = new events.EventEmitter();
+ let expectLength = 2;
+ ee.on('removeListener', function(name, noop) {
+ assert.strictEqual(expectLength--, this.listeners('baz').length);
+ });
+ ee.on('baz', common.mustNotCall());
+ ee.on('baz', common.mustNotCall());
+ ee.on('baz', common.mustNotCall());
+ assert.strictEqual(ee.listeners('baz').length, expectLength + 1);
+ ee.removeAllListeners('baz');
+ assert.strictEqual(ee.listeners('baz').length, 0);
+}
+
+{
+ const ee = new events.EventEmitter();
+ assert.deepStrictEqual(ee, ee.removeAllListeners());
+}
+
+{
+ const ee = new events.EventEmitter();
+ ee._events = undefined;
+ assert.strictEqual(ee, ee.removeAllListeners());
+}
+
+{
+ const ee = new events.EventEmitter();
+ const symbol = Symbol('symbol');
+ const noop = common.mustNotCall();
+ ee.on(symbol, noop);
+
+ ee.on('removeListener', common.mustCall((...args) => {
+ assert.deepStrictEqual(args, [symbol, noop]);
+ }));
+
+ ee.removeAllListeners();
+}
diff --git a/tests/node_compat/test/parallel/test-event-emitter-remove-listeners.js b/tests/node_compat/test/parallel/test-event-emitter-remove-listeners.js
new file mode 100644
index 000000000..8ee09c30a
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-event-emitter-remove-listeners.js
@@ -0,0 +1,177 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const EventEmitter = require('events');
+
+function listener1() {}
+
+function listener2() {}
+
+{
+ const ee = new EventEmitter();
+ ee.on('hello', listener1);
+ ee.on('removeListener', common.mustCall((name, cb) => {
+ assert.strictEqual(name, 'hello');
+ assert.strictEqual(cb, listener1);
+ }));
+ ee.removeListener('hello', listener1);
+ assert.deepStrictEqual([], ee.listeners('hello'));
+}
+
+{
+ const ee = new EventEmitter();
+ ee.on('hello', listener1);
+ ee.on('removeListener', common.mustNotCall());
+ ee.removeListener('hello', listener2);
+ assert.deepStrictEqual([listener1], ee.listeners('hello'));
+}
+
+{
+ const ee = new EventEmitter();
+ ee.on('hello', listener1);
+ ee.on('hello', listener2);
+ ee.once('removeListener', common.mustCall((name, cb) => {
+ assert.strictEqual(name, 'hello');
+ assert.strictEqual(cb, listener1);
+ assert.deepStrictEqual([listener2], ee.listeners('hello'));
+ }));
+ ee.removeListener('hello', listener1);
+ assert.deepStrictEqual([listener2], ee.listeners('hello'));
+ ee.once('removeListener', common.mustCall((name, cb) => {
+ assert.strictEqual(name, 'hello');
+ assert.strictEqual(cb, listener2);
+ assert.deepStrictEqual([], ee.listeners('hello'));
+ }));
+ ee.removeListener('hello', listener2);
+ assert.deepStrictEqual([], ee.listeners('hello'));
+}
+
+{
+ const ee = new EventEmitter();
+
+ function remove1() {
+ assert.fail('remove1 should not have been called');
+ }
+
+ function remove2() {
+ assert.fail('remove2 should not have been called');
+ }
+
+ ee.on('removeListener', common.mustCall(function(name, cb) {
+ if (cb !== remove1) return;
+ this.removeListener('quux', remove2);
+ this.emit('quux');
+ }, 2));
+ ee.on('quux', remove1);
+ ee.on('quux', remove2);
+ ee.removeListener('quux', remove1);
+}
+
+{
+ const ee = new EventEmitter();
+ ee.on('hello', listener1);
+ ee.on('hello', listener2);
+ ee.once('removeListener', common.mustCall((name, cb) => {
+ assert.strictEqual(name, 'hello');
+ assert.strictEqual(cb, listener1);
+ assert.deepStrictEqual([listener2], ee.listeners('hello'));
+ ee.once('removeListener', common.mustCall((name, cb) => {
+ assert.strictEqual(name, 'hello');
+ assert.strictEqual(cb, listener2);
+ assert.deepStrictEqual([], ee.listeners('hello'));
+ }));
+ ee.removeListener('hello', listener2);
+ assert.deepStrictEqual([], ee.listeners('hello'));
+ }));
+ ee.removeListener('hello', listener1);
+ assert.deepStrictEqual([], ee.listeners('hello'));
+}
+
+{
+ const ee = new EventEmitter();
+ const listener3 = common.mustCall(() => {
+ ee.removeListener('hello', listener4);
+ }, 2);
+ const listener4 = common.mustCall();
+
+ ee.on('hello', listener3);
+ ee.on('hello', listener4);
+
+ // listener4 will still be called although it is removed by listener 3.
+ ee.emit('hello');
+ // This is so because the internal listener array at time of emit
+ // was [listener3,listener4]
+
+ // Internal listener array [listener3]
+ ee.emit('hello');
+}
+
+{
+ const ee = new EventEmitter();
+
+ ee.once('hello', listener1);
+ ee.on('removeListener', common.mustCall((eventName, listener) => {
+ assert.strictEqual(eventName, 'hello');
+ assert.strictEqual(listener, listener1);
+ }));
+ ee.emit('hello');
+}
+
+{
+ const ee = new EventEmitter();
+
+ assert.deepStrictEqual(ee, ee.removeListener('foo', () => {}));
+}
+
+{
+ const ee = new EventEmitter();
+ const listener = () => {};
+ ee._events = undefined;
+ const e = ee.removeListener('foo', listener);
+ assert.strictEqual(e, ee);
+}
+
+{
+ const ee = new EventEmitter();
+
+ ee.on('foo', listener1);
+ ee.on('foo', listener2);
+ assert.deepStrictEqual(ee.listeners('foo'), [listener1, listener2]);
+
+ ee.removeListener('foo', listener1);
+ assert.strictEqual(ee._events.foo, listener2);
+
+ ee.on('foo', listener1);
+ assert.deepStrictEqual(ee.listeners('foo'), [listener2, listener1]);
+
+ ee.removeListener('foo', listener1);
+ assert.strictEqual(ee._events.foo, listener2);
+}
diff --git a/tests/node_compat/test/parallel/test-event-emitter-set-max-listeners-side-effects.js b/tests/node_compat/test/parallel/test-event-emitter-set-max-listeners-side-effects.js
new file mode 100644
index 000000000..431876fbd
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-event-emitter-set-max-listeners-side-effects.js
@@ -0,0 +1,39 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+const events = require('events');
+
+const e = new events.EventEmitter();
+
+assert(!(e._events instanceof Object));
+assert.deepStrictEqual(Object.keys(e._events), []);
+e.setMaxListeners(5);
+assert.deepStrictEqual(Object.keys(e._events), []);
diff --git a/tests/node_compat/test/parallel/test-event-emitter-special-event-names.js b/tests/node_compat/test/parallel/test-event-emitter-special-event-names.js
new file mode 100644
index 000000000..067b557f1
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-event-emitter-special-event-names.js
@@ -0,0 +1,44 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const EventEmitter = require('events');
+const assert = require('assert');
+
+const ee = new EventEmitter();
+const handler = () => {};
+
+assert.deepStrictEqual(ee.eventNames(), []);
+
+assert.strictEqual(ee._events.hasOwnProperty, undefined);
+assert.strictEqual(ee._events.toString, undefined);
+
+ee.on('__proto__', handler);
+ee.on('__defineGetter__', handler);
+ee.on('toString', handler);
+
+assert.deepStrictEqual(ee.eventNames(), [
+ '__proto__',
+ '__defineGetter__',
+ 'toString',
+]);
+
+assert.deepStrictEqual(ee.listeners('__proto__'), [handler]);
+assert.deepStrictEqual(ee.listeners('__defineGetter__'), [handler]);
+assert.deepStrictEqual(ee.listeners('toString'), [handler]);
+
+ee.on('__proto__', common.mustCall(function(val) {
+ assert.strictEqual(val, 1);
+}));
+ee.emit('__proto__', 1);
+
+process.on('__proto__', common.mustCall(function(val) {
+ assert.strictEqual(val, 1);
+}));
+process.emit('__proto__', 1);
diff --git a/tests/node_compat/test/parallel/test-event-emitter-subclass.js b/tests/node_compat/test/parallel/test-event-emitter-subclass.js
new file mode 100644
index 000000000..02442c489
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-event-emitter-subclass.js
@@ -0,0 +1,74 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const EventEmitter = require('events').EventEmitter;
+
+Object.setPrototypeOf(MyEE.prototype, EventEmitter.prototype);
+Object.setPrototypeOf(MyEE, EventEmitter);
+
+function MyEE(cb) {
+ this.once(1, cb);
+ this.emit(1);
+ this.removeAllListeners();
+ EventEmitter.call(this);
+}
+
+const myee = new MyEE(common.mustCall());
+
+Object.setPrototypeOf(ErrorEE.prototype, EventEmitter.prototype);
+Object.setPrototypeOf(ErrorEE, EventEmitter);
+function ErrorEE() {
+ this.emit('error', new Error('blerg'));
+}
+
+assert.throws(function() {
+ new ErrorEE();
+}, /blerg/);
+
+process.on('exit', function() {
+ assert(!(myee._events instanceof Object));
+ assert.deepStrictEqual(Object.keys(myee._events), []);
+ console.log('ok');
+});
+
+
+function MyEE2() {
+ EventEmitter.call(this);
+}
+
+MyEE2.prototype = new EventEmitter();
+
+const ee1 = new MyEE2();
+const ee2 = new MyEE2();
+
+ee1.on('x', () => {});
+
+assert.strictEqual(ee2.listenerCount('x'), 0);
diff --git a/tests/node_compat/test/parallel/test-event-emitter-symbols.js b/tests/node_compat/test/parallel/test-event-emitter-symbols.js
new file mode 100644
index 000000000..8f95d52bd
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-event-emitter-symbols.js
@@ -0,0 +1,30 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const EventEmitter = require('events');
+const assert = require('assert');
+
+const ee = new EventEmitter();
+const foo = Symbol('foo');
+const listener = common.mustCall();
+
+ee.on(foo, listener);
+assert.deepStrictEqual(ee.listeners(foo), [listener]);
+
+ee.emit(foo);
+
+ee.removeAllListeners();
+assert.deepStrictEqual(ee.listeners(foo), []);
+
+ee.on(foo, listener);
+assert.deepStrictEqual(ee.listeners(foo), [listener]);
+
+ee.removeListener(foo, listener);
+assert.deepStrictEqual(ee.listeners(foo), []);
diff --git a/tests/node_compat/test/parallel/test-events-list.js b/tests/node_compat/test/parallel/test-events-list.js
new file mode 100644
index 000000000..c66da1602
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-events-list.js
@@ -0,0 +1,26 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+require('../common');
+const EventEmitter = require('events');
+const assert = require('assert');
+
+const EE = new EventEmitter();
+const m = () => {};
+EE.on('foo', () => {});
+assert.deepStrictEqual(['foo'], EE.eventNames());
+EE.on('bar', m);
+assert.deepStrictEqual(['foo', 'bar'], EE.eventNames());
+EE.removeListener('bar', m);
+assert.deepStrictEqual(['foo'], EE.eventNames());
+const s = Symbol('s');
+EE.on(s, m);
+assert.deepStrictEqual(['foo', s], EE.eventNames());
+EE.removeListener(s, m);
+assert.deepStrictEqual(['foo'], EE.eventNames());
diff --git a/tests/node_compat/test/parallel/test-events-on-async-iterator.js b/tests/node_compat/test/parallel/test-events-on-async-iterator.js
new file mode 100644
index 000000000..87efeb842
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-events-on-async-iterator.js
@@ -0,0 +1,399 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Flags: --expose-internals --no-warnings
+'use strict';
+
+const common = require('../common');
+const assert = require('assert');
+const { on, EventEmitter } = require('events');
+const {
+ NodeEventTarget,
+} = require('internal/event_target');
+
+async function basic() {
+ const ee = new EventEmitter();
+ process.nextTick(() => {
+ ee.emit('foo', 'bar');
+ // 'bar' is a spurious event, we are testing
+ // that it does not show up in the iterable
+ ee.emit('bar', 24);
+ ee.emit('foo', 42);
+ });
+
+ const iterable = on(ee, 'foo');
+
+ const expected = [['bar'], [42]];
+
+ for await (const event of iterable) {
+ const current = expected.shift();
+
+ assert.deepStrictEqual(current, event);
+
+ if (expected.length === 0) {
+ break;
+ }
+ }
+ assert.strictEqual(ee.listenerCount('foo'), 0);
+ assert.strictEqual(ee.listenerCount('error'), 0);
+}
+
+async function invalidArgType() {
+ assert.throws(() => on({}, 'foo'), common.expectsError({
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ }));
+}
+
+async function error() {
+ const ee = new EventEmitter();
+ const _err = new Error('kaboom');
+ process.nextTick(() => {
+ ee.emit('error', _err);
+ });
+
+ const iterable = on(ee, 'foo');
+ let looped = false;
+ let thrown = false;
+
+ try {
+ // eslint-disable-next-line no-unused-vars
+ for await (const event of iterable) {
+ looped = true;
+ }
+ } catch (err) {
+ thrown = true;
+ assert.strictEqual(err, _err);
+ }
+ assert.strictEqual(thrown, true);
+ assert.strictEqual(looped, false);
+}
+
+async function errorDelayed() {
+ const ee = new EventEmitter();
+ const _err = new Error('kaboom');
+ process.nextTick(() => {
+ ee.emit('foo', 42);
+ ee.emit('error', _err);
+ });
+
+ const iterable = on(ee, 'foo');
+ const expected = [[42]];
+ let thrown = false;
+
+ try {
+ for await (const event of iterable) {
+ const current = expected.shift();
+ assert.deepStrictEqual(current, event);
+ }
+ } catch (err) {
+ thrown = true;
+ assert.strictEqual(err, _err);
+ }
+ assert.strictEqual(thrown, true);
+ assert.strictEqual(ee.listenerCount('foo'), 0);
+ assert.strictEqual(ee.listenerCount('error'), 0);
+}
+
+async function throwInLoop() {
+ const ee = new EventEmitter();
+ const _err = new Error('kaboom');
+
+ process.nextTick(() => {
+ ee.emit('foo', 42);
+ });
+
+ try {
+ for await (const event of on(ee, 'foo')) {
+ assert.deepStrictEqual(event, [42]);
+ throw _err;
+ }
+ } catch (err) {
+ assert.strictEqual(err, _err);
+ }
+
+ assert.strictEqual(ee.listenerCount('foo'), 0);
+ assert.strictEqual(ee.listenerCount('error'), 0);
+}
+
+async function next() {
+ const ee = new EventEmitter();
+ const iterable = on(ee, 'foo');
+
+ process.nextTick(function() {
+ ee.emit('foo', 'bar');
+ ee.emit('foo', 42);
+ iterable.return();
+ });
+
+ const results = await Promise.all([
+ iterable.next(),
+ iterable.next(),
+ iterable.next(),
+ ]);
+
+ assert.deepStrictEqual(results, [{
+ value: ['bar'],
+ done: false,
+ }, {
+ value: [42],
+ done: false,
+ }, {
+ value: undefined,
+ done: true,
+ }]);
+
+ assert.deepStrictEqual(await iterable.next(), {
+ value: undefined,
+ done: true,
+ });
+}
+
+async function nextError() {
+ const ee = new EventEmitter();
+ const iterable = on(ee, 'foo');
+ const _err = new Error('kaboom');
+ process.nextTick(function() {
+ ee.emit('error', _err);
+ });
+ const results = await Promise.allSettled([
+ iterable.next(),
+ iterable.next(),
+ iterable.next(),
+ ]);
+ assert.deepStrictEqual(results, [{
+ status: 'rejected',
+ reason: _err,
+ }, {
+ status: 'fulfilled',
+ value: {
+ value: undefined,
+ done: true,
+ },
+ }, {
+ status: 'fulfilled',
+ value: {
+ value: undefined,
+ done: true,
+ },
+ }]);
+ assert.strictEqual(ee.listeners('error').length, 0);
+}
+
+async function iterableThrow() {
+ const ee = new EventEmitter();
+ const iterable = on(ee, 'foo');
+
+ process.nextTick(() => {
+ ee.emit('foo', 'bar');
+ ee.emit('foo', 42); // lost in the queue
+ iterable.throw(_err);
+ });
+
+ const _err = new Error('kaboom');
+ let thrown = false;
+
+ assert.throws(() => {
+ // No argument
+ iterable.throw();
+ }, {
+ message: 'The "EventEmitter.AsyncIterator" property must be' +
+ ' an instance of Error. Received undefined',
+ name: 'TypeError',
+ });
+
+ const expected = [['bar'], [42]];
+
+ try {
+ for await (const event of iterable) {
+ assert.deepStrictEqual(event, expected.shift());
+ }
+ } catch (err) {
+ thrown = true;
+ assert.strictEqual(err, _err);
+ }
+ assert.strictEqual(thrown, true);
+ assert.strictEqual(expected.length, 0);
+ assert.strictEqual(ee.listenerCount('foo'), 0);
+ assert.strictEqual(ee.listenerCount('error'), 0);
+}
+
+async function eventTarget() {
+ const et = new EventTarget();
+ const tick = () => et.dispatchEvent(new Event('tick'));
+ const interval = setInterval(tick, 0);
+ let count = 0;
+ for await (const [ event ] of on(et, 'tick')) {
+ count++;
+ assert.strictEqual(event.type, 'tick');
+ if (count >= 5) {
+ break;
+ }
+ }
+ assert.strictEqual(count, 5);
+ clearInterval(interval);
+}
+
+async function errorListenerCount() {
+ const et = new EventEmitter();
+ on(et, 'foo');
+ assert.strictEqual(et.listenerCount('error'), 1);
+}
+
+async function nodeEventTarget() {
+ const et = new NodeEventTarget();
+ const tick = () => et.dispatchEvent(new Event('tick'));
+ const interval = setInterval(tick, 0);
+ let count = 0;
+ for await (const [ event] of on(et, 'tick')) {
+ count++;
+ assert.strictEqual(event.type, 'tick');
+ if (count >= 5) {
+ break;
+ }
+ }
+ assert.strictEqual(count, 5);
+ clearInterval(interval);
+}
+
+async function abortableOnBefore() {
+ const ee = new EventEmitter();
+ const abortedSignal = AbortSignal.abort();
+ [1, {}, null, false, 'hi'].forEach((signal) => {
+ assert.throws(() => on(ee, 'foo', { signal }), {
+ code: 'ERR_INVALID_ARG_TYPE',
+ });
+ });
+ assert.throws(() => on(ee, 'foo', { signal: abortedSignal }), {
+ name: 'AbortError',
+ });
+}
+
+async function eventTargetAbortableOnBefore() {
+ const et = new EventTarget();
+ const abortedSignal = AbortSignal.abort();
+ [1, {}, null, false, 'hi'].forEach((signal) => {
+ assert.throws(() => on(et, 'foo', { signal }), {
+ code: 'ERR_INVALID_ARG_TYPE',
+ });
+ });
+ assert.throws(() => on(et, 'foo', { signal: abortedSignal }), {
+ name: 'AbortError',
+ });
+}
+
+async function abortableOnAfter() {
+ const ee = new EventEmitter();
+ const ac = new AbortController();
+
+ const i = setInterval(() => ee.emit('foo', 'foo'), 10);
+
+ async function foo() {
+ for await (const f of on(ee, 'foo', { signal: ac.signal })) {
+ assert.strictEqual(f, 'foo');
+ }
+ }
+
+ foo().catch(common.mustCall((error) => {
+ assert.strictEqual(error.name, 'AbortError');
+ })).finally(() => {
+ clearInterval(i);
+ });
+
+ process.nextTick(() => ac.abort());
+}
+
+async function eventTargetAbortableOnAfter() {
+ const et = new EventTarget();
+ const ac = new AbortController();
+
+ const i = setInterval(() => et.dispatchEvent(new Event('foo')), 10);
+
+ async function foo() {
+ for await (const f of on(et, 'foo', { signal: ac.signal })) {
+ assert(f);
+ }
+ }
+
+ foo().catch(common.mustCall((error) => {
+ assert.strictEqual(error.name, 'AbortError');
+ })).finally(() => {
+ clearInterval(i);
+ });
+
+ process.nextTick(() => ac.abort());
+}
+
+async function eventTargetAbortableOnAfter2() {
+ const et = new EventTarget();
+ const ac = new AbortController();
+
+ const i = setInterval(() => et.dispatchEvent(new Event('foo')), 10);
+
+ async function foo() {
+ for await (const f of on(et, 'foo', { signal: ac.signal })) {
+ assert(f);
+ // Cancel after a single event has been triggered.
+ ac.abort();
+ }
+ }
+
+ foo().catch(common.mustCall((error) => {
+ assert.strictEqual(error.name, 'AbortError');
+ })).finally(() => {
+ clearInterval(i);
+ });
+}
+
+async function abortableOnAfterDone() {
+ const ee = new EventEmitter();
+ const ac = new AbortController();
+
+ const i = setInterval(() => ee.emit('foo', 'foo'), 1);
+ let count = 0;
+
+ async function foo() {
+ for await (const f of on(ee, 'foo', { signal: ac.signal })) {
+ assert.strictEqual(f[0], 'foo');
+ if (++count === 5)
+ break;
+ }
+ ac.abort(); // No error will occur
+ }
+
+ foo().finally(() => {
+ clearInterval(i);
+ });
+}
+
+async function run() {
+ const funcs = [
+ basic,
+ invalidArgType,
+ error,
+ errorDelayed,
+ throwInLoop,
+ next,
+ nextError,
+ iterableThrow,
+ eventTarget,
+ errorListenerCount,
+ nodeEventTarget,
+ abortableOnBefore,
+ abortableOnAfter,
+ eventTargetAbortableOnBefore,
+ eventTargetAbortableOnAfter,
+ eventTargetAbortableOnAfter2,
+ abortableOnAfterDone,
+ ];
+
+ for (const fn of funcs) {
+ await fn();
+ }
+}
+
+run().then(common.mustCall());
diff --git a/tests/node_compat/test/parallel/test-events-once.js b/tests/node_compat/test/parallel/test-events-once.js
new file mode 100644
index 000000000..7236f9830
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-events-once.js
@@ -0,0 +1,272 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.8.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// TODO(cjihrig): kEvents is an internally used symbol in Node.js. It is not
+// implemented in Deno, so parts of this test must be removed in order to pass.
+
+'use strict';
+// Flags: --no-warnings
+
+const common = require('../common');
+const { once, EventEmitter } = require('events');
+const {
+ strictEqual,
+ deepStrictEqual,
+ fail,
+ rejects,
+} = require('assert');
+
+async function onceAnEvent() {
+ const ee = new EventEmitter();
+
+ process.nextTick(() => {
+ ee.emit('myevent', 42);
+ });
+
+ const [value] = await once(ee, 'myevent');
+ strictEqual(value, 42);
+ strictEqual(ee.listenerCount('error'), 0);
+ strictEqual(ee.listenerCount('myevent'), 0);
+}
+
+async function onceAnEventWithNullOptions() {
+ const ee = new EventEmitter();
+
+ process.nextTick(() => {
+ ee.emit('myevent', 42);
+ });
+
+ const [value] = await once(ee, 'myevent', null);
+ strictEqual(value, 42);
+}
+
+
+async function onceAnEventWithTwoArgs() {
+ const ee = new EventEmitter();
+
+ process.nextTick(() => {
+ ee.emit('myevent', 42, 24);
+ });
+
+ const value = await once(ee, 'myevent');
+ deepStrictEqual(value, [42, 24]);
+}
+
+async function catchesErrors() {
+ const ee = new EventEmitter();
+
+ const expected = new Error('kaboom');
+ let err;
+ process.nextTick(() => {
+ ee.emit('error', expected);
+ });
+
+ try {
+ await once(ee, 'myevent');
+ } catch (_e) {
+ err = _e;
+ }
+ strictEqual(err, expected);
+ strictEqual(ee.listenerCount('error'), 0);
+ strictEqual(ee.listenerCount('myevent'), 0);
+}
+
+async function catchesErrorsWithAbortSignal() {
+ const ee = new EventEmitter();
+ const ac = new AbortController();
+ const signal = ac.signal;
+
+ const expected = new Error('boom');
+ let err;
+ process.nextTick(() => {
+ ee.emit('error', expected);
+ });
+
+ try {
+ const promise = once(ee, 'myevent', { signal });
+ strictEqual(ee.listenerCount('error'), 1);
+
+ await promise;
+ } catch (e) {
+ err = e;
+ }
+ strictEqual(err, expected);
+ strictEqual(ee.listenerCount('error'), 0);
+ strictEqual(ee.listenerCount('myevent'), 0);
+}
+
+async function stopListeningAfterCatchingError() {
+ const ee = new EventEmitter();
+
+ const expected = new Error('kaboom');
+ let err;
+ process.nextTick(() => {
+ ee.emit('error', expected);
+ ee.emit('myevent', 42, 24);
+ });
+
+ try {
+ await once(ee, 'myevent');
+ } catch (_e) {
+ err = _e;
+ }
+ process.removeAllListeners('multipleResolves');
+ strictEqual(err, expected);
+ strictEqual(ee.listenerCount('error'), 0);
+ strictEqual(ee.listenerCount('myevent'), 0);
+}
+
+async function onceError() {
+ const ee = new EventEmitter();
+
+ const expected = new Error('kaboom');
+ process.nextTick(() => {
+ ee.emit('error', expected);
+ });
+
+ const promise = once(ee, 'error');
+ strictEqual(ee.listenerCount('error'), 1);
+ const [ err ] = await promise;
+ strictEqual(err, expected);
+ strictEqual(ee.listenerCount('error'), 0);
+ strictEqual(ee.listenerCount('myevent'), 0);
+}
+
+async function onceWithEventTarget() {
+ const et = new EventTarget();
+ const event = new Event('myevent');
+ process.nextTick(() => {
+ et.dispatchEvent(event);
+ });
+ const [ value ] = await once(et, 'myevent');
+ strictEqual(value, event);
+}
+
+async function onceWithEventTargetError() {
+ const et = new EventTarget();
+ const error = new Event('error');
+ process.nextTick(() => {
+ et.dispatchEvent(error);
+ });
+
+ const [ err ] = await once(et, 'error');
+ strictEqual(err, error);
+}
+
+async function prioritizesEventEmitter() {
+ const ee = new EventEmitter();
+ ee.addEventListener = fail;
+ ee.removeAllListeners = fail;
+ process.nextTick(() => ee.emit('foo'));
+ await once(ee, 'foo');
+}
+
+async function abortSignalBefore() {
+ const ee = new EventEmitter();
+ ee.on('error', common.mustNotCall());
+ const abortedSignal = AbortSignal.abort();
+
+ await Promise.all([1, {}, 'hi', null, false].map((signal) => {
+ return rejects(once(ee, 'foo', { signal }), {
+ code: 'ERR_INVALID_ARG_TYPE'
+ });
+ }));
+
+ return rejects(once(ee, 'foo', { signal: abortedSignal }), {
+ name: 'AbortError'
+ });
+}
+
+async function abortSignalAfter() {
+ const ee = new EventEmitter();
+ const ac = new AbortController();
+ ee.on('error', common.mustNotCall());
+ const r = rejects(once(ee, 'foo', { signal: ac.signal }), {
+ name: 'AbortError'
+ });
+ process.nextTick(() => ac.abort());
+ return r;
+}
+
+async function abortSignalAfterEvent() {
+ const ee = new EventEmitter();
+ const ac = new AbortController();
+ process.nextTick(() => {
+ ee.emit('foo');
+ ac.abort();
+ });
+ const promise = once(ee, 'foo', { signal: ac.signal });
+ await promise;
+}
+
+async function abortSignalRemoveListener() {
+ const ee = new EventEmitter();
+ const ac = new AbortController();
+
+ try {
+ process.nextTick(() => ac.abort());
+ await once(ee, 'test', { signal: ac.signal });
+ } catch {
+ strictEqual(ee.listeners('test').length, 0);
+ strictEqual(ee.listeners('error').length, 0);
+ }
+}
+
+async function eventTargetAbortSignalBefore() {
+ const et = new EventTarget();
+ const abortedSignal = AbortSignal.abort();
+
+ await Promise.all([1, {}, 'hi', null, false].map((signal) => {
+ return rejects(once(et, 'foo', { signal }), {
+ code: 'ERR_INVALID_ARG_TYPE'
+ });
+ }));
+
+ return rejects(once(et, 'foo', { signal: abortedSignal }), {
+ name: 'AbortError'
+ });
+}
+
+async function eventTargetAbortSignalAfter() {
+ const et = new EventTarget();
+ const ac = new AbortController();
+ const r = rejects(once(et, 'foo', { signal: ac.signal }), {
+ name: 'AbortError'
+ });
+ process.nextTick(() => ac.abort());
+ return r;
+}
+
+async function eventTargetAbortSignalAfterEvent() {
+ const et = new EventTarget();
+ const ac = new AbortController();
+ process.nextTick(() => {
+ et.dispatchEvent(new Event('foo'));
+ ac.abort();
+ });
+ await once(et, 'foo', { signal: ac.signal });
+}
+
+Promise.all([
+ onceAnEvent(),
+ onceAnEventWithNullOptions(),
+ onceAnEventWithTwoArgs(),
+ catchesErrors(),
+ catchesErrorsWithAbortSignal(),
+ stopListeningAfterCatchingError(),
+ onceError(),
+ onceWithEventTarget(),
+ onceWithEventTargetError(),
+ prioritizesEventEmitter(),
+ abortSignalBefore(),
+ abortSignalAfter(),
+ abortSignalAfterEvent(),
+ abortSignalRemoveListener(),
+ eventTargetAbortSignalBefore(),
+ eventTargetAbortSignalAfter(),
+ eventTargetAbortSignalAfterEvent(),
+]).then(common.mustCall());
diff --git a/tests/node_compat/test/parallel/test-events-uncaught-exception-stack.js b/tests/node_compat/test/parallel/test-events-uncaught-exception-stack.js
new file mode 100644
index 000000000..d5b39c203
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-events-uncaught-exception-stack.js
@@ -0,0 +1,23 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const EventEmitter = require('events');
+
+// Tests that the error stack where the exception was thrown is *not* appended.
+
+process.on('uncaughtException', common.mustCall((err) => {
+ const lines = err.stack.split('\n');
+ assert.strictEqual(lines[0], 'Error');
+ lines.slice(1).forEach((line) => {
+ assert.match(line, /^ {4}at/);
+ });
+}));
+
+new EventEmitter().emit('error', new Error());
diff --git a/tests/node_compat/test/parallel/test-eventtarget-brandcheck.js b/tests/node_compat/test/parallel/test-eventtarget-brandcheck.js
new file mode 100644
index 000000000..db5cd53f6
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-eventtarget-brandcheck.js
@@ -0,0 +1,104 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Flags: --expose-internals
+'use strict';
+
+require('../common');
+const assert = require('assert');
+
+const {
+ Event,
+ CustomEvent,
+ EventTarget,
+ NodeEventTarget,
+} = require('internal/event_target');
+
+[
+ 'target',
+ 'currentTarget',
+ 'srcElement',
+ 'type',
+ 'cancelable',
+ 'defaultPrevented',
+ 'timeStamp',
+ 'returnValue',
+ 'bubbles',
+ 'composed',
+ 'eventPhase',
+].forEach((i) => {
+ assert.throws(() => Reflect.get(Event.prototype, i, {}), {
+ code: 'ERR_INVALID_THIS',
+ });
+});
+
+[
+ 'stopImmediatePropagation',
+ 'preventDefault',
+ 'composedPath',
+ 'cancelBubble',
+ 'stopPropagation',
+].forEach((i) => {
+ assert.throws(() => Reflect.apply(Event.prototype[i], [], {}), {
+ code: 'ERR_INVALID_THIS',
+ });
+});
+
+[
+ 'target',
+ 'currentTarget',
+ 'srcElement',
+ 'type',
+ 'cancelable',
+ 'defaultPrevented',
+ 'timeStamp',
+ 'returnValue',
+ 'bubbles',
+ 'composed',
+ 'eventPhase',
+ 'detail',
+].forEach((i) => {
+ assert.throws(() => Reflect.get(CustomEvent.prototype, i, {}), {
+ code: 'ERR_INVALID_THIS',
+ });
+});
+
+[
+ 'stopImmediatePropagation',
+ 'preventDefault',
+ 'composedPath',
+ 'cancelBubble',
+ 'stopPropagation',
+].forEach((i) => {
+ assert.throws(() => Reflect.apply(CustomEvent.prototype[i], [], {}), {
+ code: 'ERR_INVALID_THIS',
+ });
+});
+
+['addEventListener', 'removeEventListener', 'dispatchEvent'].forEach((i) => {
+ assert.throws(() => Reflect.apply(EventTarget.prototype[i], [], {}), {
+ code: 'ERR_INVALID_THIS',
+ });
+});
+
+[
+ 'setMaxListeners',
+ 'getMaxListeners',
+ 'eventNames',
+ 'listenerCount',
+ 'off',
+ 'removeListener',
+ 'on',
+ 'addListener',
+ 'once',
+ 'emit',
+ 'removeAllListeners',
+].forEach((i) => {
+ assert.throws(() => Reflect.apply(NodeEventTarget.prototype[i], [], {}), {
+ code: 'ERR_INVALID_THIS',
+ });
+});
diff --git a/tests/node_compat/test/parallel/test-exception-handler.js b/tests/node_compat/test/parallel/test-exception-handler.js
new file mode 100644
index 000000000..6c76d2463
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-exception-handler.js
@@ -0,0 +1,47 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+
+const MESSAGE = 'catch me if you can';
+
+process.on('uncaughtException', common.mustCall((e) => {
+ console.log('uncaught exception! 1');
+ assert.strictEqual(MESSAGE, e.message);
+}));
+
+process.on('uncaughtException', common.mustCall((e) => {
+ console.log('uncaught exception! 2');
+ assert.strictEqual(MESSAGE, e.message);
+}));
+
+setTimeout(() => {
+ throw new Error(MESSAGE);
+}, 10);
diff --git a/tests/node_compat/test/parallel/test-exception-handler2.js b/tests/node_compat/test/parallel/test-exception-handler2.js
new file mode 100644
index 000000000..6cb214593
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-exception-handler2.js
@@ -0,0 +1,43 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+
+process.on('uncaughtException', function(err) {
+ console.log(`Caught exception: ${err}`);
+});
+
+setTimeout(common.mustCall(function() {
+ console.log('This will still run.');
+}), 50);
+
+// Intentionally cause an exception, but don't catch it.
+nonexistentFunc(); // eslint-disable-line no-undef
+assert.fail('This will not run.');
diff --git a/tests/node_compat/test/parallel/test-file-read-noexist.js b/tests/node_compat/test/parallel/test-file-read-noexist.js
new file mode 100644
index 000000000..2e2d4320d
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-file-read-noexist.js
@@ -0,0 +1,39 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const fixtures = require('../common/fixtures');
+const assert = require('assert');
+const fs = require('fs');
+
+const filename = fixtures.path('does_not_exist.txt');
+fs.readFile(filename, 'latin1', common.mustCall(function(err, content) {
+ assert.ok(err);
+ assert.strictEqual(err.code, 'ENOENT');
+}));
diff --git a/tests/node_compat/test/parallel/test-file-write-stream.js b/tests/node_compat/test/parallel/test-file-write-stream.js
new file mode 100644
index 000000000..199cdd80e
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-file-write-stream.js
@@ -0,0 +1,91 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+
+const path = require('path');
+const fs = require('fs');
+const tmpdir = require('../common/tmpdir');
+const fn = path.join(tmpdir.path, 'write.txt');
+tmpdir.refresh();
+const file = fs.createWriteStream(fn, {
+ highWaterMark: 10
+});
+
+const EXPECTED = '012345678910';
+
+const callbacks = {
+ open: -1,
+ drain: -2,
+ close: -1
+};
+
+file
+ .on('open', function(fd) {
+ console.error('open!');
+ callbacks.open++;
+ assert.strictEqual(typeof fd, 'number');
+ })
+ .on('drain', function() {
+ console.error('drain!', callbacks.drain);
+ callbacks.drain++;
+ if (callbacks.drain === -1) {
+ assert.strictEqual(fs.readFileSync(fn, 'utf8'), EXPECTED);
+ file.write(EXPECTED);
+ } else if (callbacks.drain === 0) {
+ assert.strictEqual(fs.readFileSync(fn, 'utf8'), EXPECTED + EXPECTED);
+ file.end();
+ }
+ })
+ .on('close', function() {
+ console.error('close!');
+ assert.strictEqual(file.bytesWritten, EXPECTED.length * 2);
+
+ callbacks.close++;
+ file.write('should not work anymore', common.expectsError({
+ code: 'ERR_STREAM_WRITE_AFTER_END',
+ name: 'Error',
+ message: 'write after end'
+ }));
+ file.on('error', common.mustNotCall());
+
+ fs.unlinkSync(fn);
+ });
+
+for (let i = 0; i < 11; i++) {
+ file.write(`${i}`);
+}
+
+process.on('exit', function() {
+ for (const k in callbacks) {
+ assert.strictEqual(callbacks[k], 0, `${k} count off by ${callbacks[k]}`);
+ }
+ console.log('ok');
+});
diff --git a/tests/node_compat/test/parallel/test-file-write-stream2.js b/tests/node_compat/test/parallel/test-file-write-stream2.js
new file mode 100644
index 000000000..3aa712a2f
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-file-write-stream2.js
@@ -0,0 +1,116 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+
+const path = require('path');
+const fs = require('fs');
+
+const tmpdir = require('../common/tmpdir');
+
+
+const filepath = path.join(tmpdir.path, 'write.txt');
+
+const EXPECTED = '012345678910';
+
+const cb_expected = 'write open drain write drain close ';
+let cb_occurred = '';
+
+let countDrains = 0;
+
+
+process.on('exit', function() {
+ removeTestFile();
+ if (cb_occurred !== cb_expected) {
+ console.log(' Test callback events missing or out of order:');
+ console.log(` expected: ${cb_expected}`);
+ console.log(` occurred: ${cb_occurred}`);
+ assert.strictEqual(
+ cb_occurred, cb_expected,
+ `events missing or out of order: "${cb_occurred}" !== "${cb_expected}"`);
+ } else {
+ console.log('ok');
+ }
+});
+
+function removeTestFile() {
+ try {
+ fs.unlinkSync(filepath);
+ } catch {
+ // Continue regardless of error.
+ }
+}
+
+
+tmpdir.refresh();
+
+// Drain at 0, return false at 10.
+const file = fs.createWriteStream(filepath, {
+ highWaterMark: 11
+});
+
+file.on('open', function(fd) {
+ console.error('open');
+ cb_occurred += 'open ';
+ assert.strictEqual(typeof fd, 'number');
+});
+
+file.on('drain', function() {
+ console.error('drain');
+ cb_occurred += 'drain ';
+ ++countDrains;
+ if (countDrains === 1) {
+ console.error('drain=1, write again');
+ assert.strictEqual(fs.readFileSync(filepath, 'utf8'), EXPECTED);
+ console.error(`ondrain write ret= ${file.write(EXPECTED)}`);
+ cb_occurred += 'write ';
+ } else if (countDrains === 2) {
+ console.error('second drain, end');
+ assert.strictEqual(fs.readFileSync(filepath, 'utf8'), EXPECTED + EXPECTED);
+ file.end();
+ }
+});
+
+file.on('close', function() {
+ cb_occurred += 'close ';
+ assert.strictEqual(file.bytesWritten, EXPECTED.length * 2);
+ file.write('should not work anymore', (err) => {
+ assert.ok(err.message.includes('write after end'));
+ });
+});
+
+for (let i = 0; i < 11; i++) {
+ const ret = file.write(String(i));
+ console.error(`${i} ${ret}`);
+
+ // Return false when i hits 10
+ assert.strictEqual(ret, i !== 10);
+}
+cb_occurred += 'write ';
diff --git a/tests/node_compat/test/parallel/test-file-write-stream3.js b/tests/node_compat/test/parallel/test-file-write-stream3.js
new file mode 100644
index 000000000..d15a0b571
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-file-write-stream3.js
@@ -0,0 +1,221 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const path = require('path');
+const fs = require('fs');
+
+const tmpdir = require('../common/tmpdir');
+
+
+const filepath = path.join(tmpdir.path, 'write_pos.txt');
+
+
+const cb_expected = 'write open close write open close write open close ';
+let cb_occurred = '';
+
+const fileDataInitial = 'abcdefghijklmnopqrstuvwxyz';
+
+const fileDataExpected_1 = 'abcdefghijklmnopqrstuvwxyz';
+const fileDataExpected_2 = 'abcdefghij123456qrstuvwxyz';
+const fileDataExpected_3 = 'abcdefghij\u2026\u2026qrstuvwxyz';
+
+
+process.on('exit', function() {
+ if (cb_occurred !== cb_expected) {
+ console.log(' Test callback events missing or out of order:');
+ console.log(` expected: ${cb_expected}`);
+ console.log(` occurred: ${cb_occurred}`);
+ assert.strictEqual(
+ cb_occurred, cb_expected,
+ `events missing or out of order: "${cb_occurred}" !== "${cb_expected}"`);
+ }
+});
+
+
+tmpdir.refresh();
+
+
+function run_test_1() {
+ const options = {};
+ const file = fs.createWriteStream(filepath, options);
+ console.log(' (debug: start ', file.start);
+ console.log(' (debug: pos ', file.pos);
+
+ file.on('open', function(fd) {
+ cb_occurred += 'open ';
+ });
+
+ file.on('close', function() {
+ cb_occurred += 'close ';
+ console.log(' (debug: bytesWritten ', file.bytesWritten);
+ console.log(' (debug: start ', file.start);
+ console.log(' (debug: pos ', file.pos);
+ assert.strictEqual(file.bytesWritten, buffer.length);
+ const fileData = fs.readFileSync(filepath, 'utf8');
+ console.log(' (debug: file data ', fileData);
+ console.log(' (debug: expected ', fileDataExpected_1);
+ assert.strictEqual(fileData, fileDataExpected_1);
+
+ run_test_2();
+ });
+
+ file.on('error', function(err) {
+ cb_occurred += 'error ';
+ console.log(' (debug: err event ', err);
+ throw err;
+ });
+
+ const buffer = Buffer.from(fileDataInitial);
+ file.write(buffer);
+ cb_occurred += 'write ';
+
+ file.end();
+}
+
+
+function run_test_2() {
+
+ const buffer = Buffer.from('123456');
+
+ const options = { start: 10,
+ flags: 'r+' };
+ const file = fs.createWriteStream(filepath, options);
+ console.log(' (debug: start ', file.start);
+ console.log(' (debug: pos ', file.pos);
+
+ file.on('open', function(fd) {
+ cb_occurred += 'open ';
+ });
+
+ file.on('close', function() {
+ cb_occurred += 'close ';
+ console.log(' (debug: bytesWritten ', file.bytesWritten);
+ console.log(' (debug: start ', file.start);
+ console.log(' (debug: pos ', file.pos);
+ assert.strictEqual(file.bytesWritten, buffer.length);
+ const fileData = fs.readFileSync(filepath, 'utf8');
+ console.log(' (debug: file data ', fileData);
+ console.log(' (debug: expected ', fileDataExpected_2);
+ assert.strictEqual(fileData, fileDataExpected_2);
+
+ run_test_3();
+ });
+
+ file.on('error', function(err) {
+ cb_occurred += 'error ';
+ console.log(' (debug: err event ', err);
+ throw err;
+ });
+
+ file.write(buffer);
+ cb_occurred += 'write ';
+
+ file.end();
+}
+
+
+function run_test_3() {
+
+ const data = '\u2026\u2026'; // 3 bytes * 2 = 6 bytes in UTF-8
+
+ const options = { start: 10,
+ flags: 'r+' };
+ const file = fs.createWriteStream(filepath, options);
+ console.log(' (debug: start ', file.start);
+ console.log(' (debug: pos ', file.pos);
+
+ file.on('open', function(fd) {
+ cb_occurred += 'open ';
+ });
+
+ file.on('close', function() {
+ cb_occurred += 'close ';
+ console.log(' (debug: bytesWritten ', file.bytesWritten);
+ console.log(' (debug: start ', file.start);
+ console.log(' (debug: pos ', file.pos);
+ assert.strictEqual(file.bytesWritten, data.length * 3);
+ const fileData = fs.readFileSync(filepath, 'utf8');
+ console.log(' (debug: file data ', fileData);
+ console.log(' (debug: expected ', fileDataExpected_3);
+ assert.strictEqual(fileData, fileDataExpected_3);
+
+ run_test_4();
+ run_test_5();
+ });
+
+ file.on('error', function(err) {
+ cb_occurred += 'error ';
+ console.log(' (debug: err event ', err);
+ throw err;
+ });
+
+ file.write(data, 'utf8');
+ cb_occurred += 'write ';
+
+ file.end();
+}
+
+
+const run_test_4 = common.mustCall(function() {
+ // Error: start must be >= zero
+ const fn = () => {
+ fs.createWriteStream(filepath, { start: -5, flags: 'r+' });
+ };
+ // Verify the range of values using a common integer verifier.
+ // Limit Number.MAX_SAFE_INTEGER
+ const err = {
+ code: 'ERR_OUT_OF_RANGE',
+ message: 'The value of "start" is out of range. ' +
+ `It must be >= 0 && <= ${Number.MAX_SAFE_INTEGER}. Received -5`,
+ name: 'RangeError'
+ };
+ assert.throws(fn, err);
+});
+
+
+const run_test_5 = common.mustCall(function() {
+ // Error: start must be <= 2 ** 53 - 1
+ const fn = () => {
+ fs.createWriteStream(filepath, { start: 2 ** 53, flags: 'r+' });
+ };
+ // Verify the range of values using a common integer verifier.
+ // Limit Number.MAX_SAFE_INTEGER
+ const err = {
+ code: 'ERR_OUT_OF_RANGE',
+ message: 'The value of "start" is out of range. It must be ' +
+ `>= 0 && <= ${Number.MAX_SAFE_INTEGER}. ` +
+ 'Received 9_007_199_254_740_992',
+ name: 'RangeError'
+ };
+ assert.throws(fn, err);
+});
+
+run_test_1();
diff --git a/tests/node_compat/test/parallel/test-file-write-stream4.js b/tests/node_compat/test/parallel/test-file-write-stream4.js
new file mode 100644
index 000000000..392a8ef23
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-file-write-stream4.js
@@ -0,0 +1,28 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+// Test that 'close' emits once and not twice when `emitClose: true` is set.
+// Refs: https://github.com/nodejs/node/issues/31366
+
+const common = require('../common');
+const path = require('path');
+const fs = require('fs');
+
+const tmpdir = require('../common/tmpdir');
+tmpdir.refresh();
+
+const filepath = path.join(tmpdir.path, 'write_pos.txt');
+
+const fileReadStream = fs.createReadStream(process.execPath);
+const fileWriteStream = fs.createWriteStream(filepath, {
+ emitClose: true
+});
+
+fileReadStream.pipe(fileWriteStream);
+fileWriteStream.on('close', common.mustCall());
diff --git a/tests/node_compat/test/parallel/test-fs-access.js b/tests/node_compat/test/parallel/test-fs-access.js
new file mode 100644
index 000000000..2351d4171
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-access.js
@@ -0,0 +1,242 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Flags: --expose-internals
+'use strict';
+
+// This tests that fs.access and fs.accessSync works as expected
+// and the errors thrown from these APIs include the desired properties
+
+const common = require('../common');
+if (!common.isWindows && process.getuid() === 0)
+ common.skip('as this test should not be run as `root`');
+
+if (common.isIBMi)
+ common.skip('IBMi has a different access permission mechanism');
+
+const assert = require('assert');
+const fs = require('fs');
+const path = require('path');
+
+const { internalBinding } = require('internal/test/binding');
+const { UV_ENOENT } = internalBinding('uv');
+
+const tmpdir = require('../common/tmpdir');
+const doesNotExist = path.join(tmpdir.path, '__this_should_not_exist');
+const readOnlyFile = path.join(tmpdir.path, 'read_only_file');
+const readWriteFile = path.join(tmpdir.path, 'read_write_file');
+
+function createFileWithPerms(file, mode) {
+ fs.writeFileSync(file, '');
+ fs.chmodSync(file, mode);
+}
+
+tmpdir.refresh();
+createFileWithPerms(readOnlyFile, 0o444);
+createFileWithPerms(readWriteFile, 0o666);
+
+// On non-Windows supported platforms, fs.access(readOnlyFile, W_OK, ...)
+// always succeeds if node runs as the super user, which is sometimes the
+// case for tests running on our continuous testing platform agents.
+//
+// In this case, this test tries to change its process user id to a
+// non-superuser user so that the test that checks for write access to a
+// read-only file can be more meaningful.
+//
+// The change of user id is done after creating the fixtures files for the same
+// reason: the test may be run as the superuser within a directory in which
+// only the superuser can create files, and thus it may need superuser
+// privileges to create them.
+//
+// There's not really any point in resetting the process' user id to 0 after
+// changing it to 'nobody', since in the case that the test runs without
+// superuser privilege, it is not possible to change its process user id to
+// superuser.
+//
+// It can prevent the test from removing files created before the change of user
+// id, but that's fine. In this case, it is the responsibility of the
+// continuous integration platform to take care of that.
+let hasWriteAccessForReadonlyFile = false;
+if (!common.isWindows && process.getuid() === 0) {
+ hasWriteAccessForReadonlyFile = true;
+ try {
+ process.setuid('nobody');
+ hasWriteAccessForReadonlyFile = false;
+ } catch {
+ // Continue regardless of error.
+ }
+}
+
+assert.strictEqual(typeof fs.F_OK, 'number');
+assert.strictEqual(typeof fs.R_OK, 'number');
+assert.strictEqual(typeof fs.W_OK, 'number');
+assert.strictEqual(typeof fs.X_OK, 'number');
+
+const throwNextTick = (e) => { process.nextTick(() => { throw e; }); };
+
+fs.access(__filename, common.mustCall(function(...args) {
+ assert.deepStrictEqual(args, [null]);
+}));
+fs.promises.access(__filename)
+ .then(common.mustCall())
+ .catch(throwNextTick);
+fs.access(__filename, fs.R_OK, common.mustCall(function(...args) {
+ assert.deepStrictEqual(args, [null]);
+}));
+fs.promises.access(__filename, fs.R_OK)
+ .then(common.mustCall())
+ .catch(throwNextTick);
+fs.access(readOnlyFile, fs.R_OK, common.mustCall(function(...args) {
+ assert.deepStrictEqual(args, [null]);
+}));
+fs.promises.access(readOnlyFile, fs.R_OK)
+ .then(common.mustCall())
+ .catch(throwNextTick);
+
+{
+ const expectedError = (err) => {
+ assert.notStrictEqual(err, null);
+ assert.strictEqual(err.code, 'ENOENT');
+ assert.strictEqual(err.path, doesNotExist);
+ };
+ fs.access(doesNotExist, common.mustCall(expectedError));
+ fs.promises.access(doesNotExist)
+ .then(common.mustNotCall(), common.mustCall(expectedError))
+ .catch(throwNextTick);
+}
+
+{
+ function expectedError(err) {
+ assert.strictEqual(this, undefined);
+ if (hasWriteAccessForReadonlyFile) {
+ assert.ifError(err);
+ } else {
+ assert.notStrictEqual(err, null);
+ assert.strictEqual(err.path, readOnlyFile);
+ }
+ }
+ fs.access(readOnlyFile, fs.W_OK, common.mustCall(expectedError));
+ fs.promises.access(readOnlyFile, fs.W_OK)
+ .then(common.mustNotCall(), common.mustCall(expectedError))
+ .catch(throwNextTick);
+}
+
+{
+ const expectedError = (err) => {
+ assert.strictEqual(err.code, 'ERR_INVALID_ARG_TYPE');
+ assert.ok(err instanceof TypeError);
+ return true;
+ };
+ assert.throws(
+ () => { fs.access(100, fs.F_OK, common.mustNotCall()); },
+ expectedError
+ );
+
+ fs.promises.access(100, fs.F_OK)
+ .then(common.mustNotCall(), common.mustCall(expectedError))
+ .catch(throwNextTick);
+}
+
+assert.throws(
+ () => {
+ fs.access(__filename, fs.F_OK);
+ },
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError'
+ });
+
+assert.throws(
+ () => {
+ fs.access(__filename, fs.F_OK, common.mustNotMutateObjectDeep({}));
+ },
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError'
+ });
+
+// Regular access should not throw.
+fs.accessSync(__filename);
+const mode = fs.R_OK | fs.W_OK;
+fs.accessSync(readWriteFile, mode);
+
+// Invalid modes should throw.
+[
+ false,
+ 1n,
+ { [Symbol.toPrimitive]() { return fs.R_OK; } },
+ [1],
+ 'r',
+].forEach((mode, i) => {
+ console.log(mode, i);
+ assert.throws(
+ () => fs.access(readWriteFile, mode, common.mustNotCall()),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ }
+ );
+ assert.throws(
+ () => fs.accessSync(readWriteFile, mode),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ }
+ );
+});
+
+// Out of range modes should throw
+[
+ -1,
+ 8,
+ Infinity,
+ NaN,
+].forEach((mode, i) => {
+ console.log(mode, i);
+ assert.throws(
+ () => fs.access(readWriteFile, mode, common.mustNotCall()),
+ {
+ code: 'ERR_OUT_OF_RANGE',
+ }
+ );
+ assert.throws(
+ () => fs.accessSync(readWriteFile, mode),
+ {
+ code: 'ERR_OUT_OF_RANGE',
+ }
+ );
+});
+
+assert.throws(
+ () => { fs.accessSync(doesNotExist); },
+ (err) => {
+ assert.strictEqual(err.code, 'ENOENT');
+ assert.strictEqual(err.path, doesNotExist);
+ assert.strictEqual(
+ err.message,
+ `ENOENT: no such file or directory, access '${doesNotExist}'`
+ );
+ assert.strictEqual(err.constructor, Error);
+ assert.strictEqual(err.syscall, 'access');
+ assert.strictEqual(err.errno, UV_ENOENT);
+ return true;
+ }
+);
+
+assert.throws(
+ () => { fs.accessSync(Buffer.from(doesNotExist)); },
+ (err) => {
+ assert.strictEqual(err.code, 'ENOENT');
+ assert.strictEqual(err.path, doesNotExist);
+ assert.strictEqual(
+ err.message,
+ `ENOENT: no such file or directory, access '${doesNotExist}'`
+ );
+ assert.strictEqual(err.constructor, Error);
+ assert.strictEqual(err.syscall, 'access');
+ assert.strictEqual(err.errno, UV_ENOENT);
+ return true;
+ }
+);
diff --git a/tests/node_compat/test/parallel/test-fs-append-file-sync.js b/tests/node_compat/test/parallel/test-fs-append-file-sync.js
new file mode 100644
index 000000000..d5adc427d
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-append-file-sync.js
@@ -0,0 +1,115 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const join = require('path').join;
+const fs = require('fs');
+
+const currentFileData = 'ABCD';
+const m = 0o600;
+const num = 220;
+const data = '南越国是前203年至前111年存在于岭南地区的一个国家,国都位于番禺,疆域包括今天中国的广东、' +
+ '广西两省区的大部份地区,福建省、湖南、贵州、云南的一小部份地区和越南的北部。' +
+ '南越国是秦朝灭亡后,由南海郡尉赵佗于前203年起兵兼并桂林郡和象郡后建立。' +
+ '前196年和前179年,南越国曾先后两次名义上臣属于西汉,成为西汉的“外臣”。前112年,' +
+ '南越国末代君主赵建德与西汉发生战争,被汉武帝于前111年所灭。南越国共存在93年,' +
+ '历经五代君主。南越国是岭南地区的第一个有记载的政权国家,采用封建制和郡县制并存的制度,' +
+ '它的建立保证了秦末乱世岭南地区社会秩序的稳定,有效的改善了岭南地区落后的政治、##济现状。\n';
+
+const tmpdir = require('../common/tmpdir');
+tmpdir.refresh();
+
+// Test that empty file will be created and have content added.
+const filename = join(tmpdir.path, 'append-sync.txt');
+
+fs.appendFileSync(filename, data);
+
+const fileData = fs.readFileSync(filename);
+
+assert.strictEqual(Buffer.byteLength(data), fileData.length);
+
+// Test that appends data to a non empty file.
+const filename2 = join(tmpdir.path, 'append-sync2.txt');
+fs.writeFileSync(filename2, currentFileData);
+
+fs.appendFileSync(filename2, data);
+
+const fileData2 = fs.readFileSync(filename2);
+
+assert.strictEqual(Buffer.byteLength(data) + currentFileData.length,
+ fileData2.length);
+
+// Test that appendFileSync accepts buffers.
+const filename3 = join(tmpdir.path, 'append-sync3.txt');
+fs.writeFileSync(filename3, currentFileData);
+
+const buf = Buffer.from(data, 'utf8');
+fs.appendFileSync(filename3, buf);
+
+const fileData3 = fs.readFileSync(filename3);
+
+assert.strictEqual(buf.length + currentFileData.length, fileData3.length);
+
+const filename4 = join(tmpdir.path, 'append-sync4.txt');
+fs.writeFileSync(filename4, currentFileData, common.mustNotMutateObjectDeep({ mode: m }));
+
+[
+ true, false, 0, 1, Infinity, () => {}, {}, [], undefined, null,
+].forEach((value) => {
+ assert.throws(
+ () => fs.appendFileSync(filename4, value, common.mustNotMutateObjectDeep({ mode: m })),
+ { message: /data/, code: 'ERR_INVALID_ARG_TYPE' }
+ );
+});
+fs.appendFileSync(filename4, `${num}`, common.mustNotMutateObjectDeep({ mode: m }));
+
+// Windows permissions aren't Unix.
+if (!common.isWindows) {
+ const st = fs.statSync(filename4);
+ assert.strictEqual(st.mode & 0o700, m);
+}
+
+const fileData4 = fs.readFileSync(filename4);
+
+assert.strictEqual(Buffer.byteLength(String(num)) + currentFileData.length,
+ fileData4.length);
+
+// Test that appendFile accepts file descriptors.
+const filename5 = join(tmpdir.path, 'append-sync5.txt');
+fs.writeFileSync(filename5, currentFileData);
+
+const filename5fd = fs.openSync(filename5, 'a+', 0o600);
+fs.appendFileSync(filename5fd, data);
+fs.closeSync(filename5fd);
+
+const fileData5 = fs.readFileSync(filename5);
+
+assert.strictEqual(Buffer.byteLength(data) + currentFileData.length,
+ fileData5.length);
diff --git a/tests/node_compat/test/parallel/test-fs-append-file.js b/tests/node_compat/test/parallel/test-fs-append-file.js
new file mode 100644
index 000000000..41c6be684
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-append-file.js
@@ -0,0 +1,202 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 16.13.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const fs = require('fs');
+const join = require('path').join;
+
+const tmpdir = require('../common/tmpdir');
+
+const currentFileData = 'ABCD';
+
+const s = '南越国是前203年至前111年存在于岭南地区的一个国家,国都位于番禺,疆域包括今天中国的广东、' +
+ '广西两省区的大部份地区,福建省、湖南、贵州、云南的一小部份地区和越南的北部。' +
+ '南越国是秦朝灭亡后,由南海郡尉赵佗于前203年起兵兼并桂林郡和象郡后建立。' +
+ '前196年和前179年,南越国曾先后两次名义上臣属于西汉,成为西汉的“外臣”。前112年,' +
+ '南越国末代君主赵建德与西汉发生战争,被汉武帝于前111年所灭。南越国共存在93年,' +
+ '历经五代君主。南越国是岭南地区的第一个有记载的政权国家,采用封建制和郡县制并存的制度,' +
+ '它的建立保证了秦末乱世岭南地区社会秩序的稳定,有效的改善了岭南地区落后的政治、##济现状。\n';
+
+tmpdir.refresh();
+
+const throwNextTick = (e) => { process.nextTick(() => { throw e; }); };
+
+// Test that empty file will be created and have content added (callback API).
+{
+ const filename = join(tmpdir.path, 'append.txt');
+
+ fs.appendFile(filename, s, common.mustSucceed(() => {
+ fs.readFile(filename, common.mustSucceed((buffer) => {
+ assert.strictEqual(Buffer.byteLength(s), buffer.length);
+ }));
+ }));
+}
+
+// Test that empty file will be created and have content added (promise API).
+{
+ const filename = join(tmpdir.path, 'append-promise.txt');
+
+ fs.promises.appendFile(filename, s)
+ .then(common.mustCall(() => fs.promises.readFile(filename)))
+ .then((buffer) => {
+ assert.strictEqual(Buffer.byteLength(s), buffer.length);
+ })
+ .catch(throwNextTick);
+}
+
+// Test that appends data to a non-empty file (callback API).
+{
+ const filename = join(tmpdir.path, 'append-non-empty.txt');
+ fs.writeFileSync(filename, currentFileData);
+
+ fs.appendFile(filename, s, common.mustSucceed(() => {
+ fs.readFile(filename, common.mustSucceed((buffer) => {
+ assert.strictEqual(Buffer.byteLength(s) + currentFileData.length,
+ buffer.length);
+ }));
+ }));
+}
+
+// Test that appends data to a non-empty file (promise API).
+{
+ const filename = join(tmpdir.path, 'append-non-empty-promise.txt');
+ fs.writeFileSync(filename, currentFileData);
+
+ fs.promises.appendFile(filename, s)
+ .then(common.mustCall(() => fs.promises.readFile(filename)))
+ .then((buffer) => {
+ assert.strictEqual(Buffer.byteLength(s) + currentFileData.length,
+ buffer.length);
+ })
+ .catch(throwNextTick);
+}
+
+// Test that appendFile accepts buffers (callback API).
+{
+ const filename = join(tmpdir.path, 'append-buffer.txt');
+ fs.writeFileSync(filename, currentFileData);
+
+ const buf = Buffer.from(s, 'utf8');
+
+ fs.appendFile(filename, buf, common.mustSucceed(() => {
+ fs.readFile(filename, common.mustSucceed((buffer) => {
+ assert.strictEqual(buf.length + currentFileData.length, buffer.length);
+ }));
+ }));
+}
+
+// Test that appendFile accepts buffers (promises API).
+{
+ const filename = join(tmpdir.path, 'append-buffer-promises.txt');
+ fs.writeFileSync(filename, currentFileData);
+
+ const buf = Buffer.from(s, 'utf8');
+
+ fs.promises.appendFile(filename, buf)
+ .then(common.mustCall(() => fs.promises.readFile(filename)))
+ .then((buffer) => {
+ assert.strictEqual(buf.length + currentFileData.length, buffer.length);
+ })
+ .catch(throwNextTick);
+}
+
+// Test that appendFile does not accept invalid data type (callback API).
+[false, 5, {}, null, undefined].forEach(async (data) => {
+ const errObj = {
+ code: 'ERR_INVALID_ARG_TYPE',
+ message: /"data"|"buffer"/
+ };
+ const filename = join(tmpdir.path, 'append-invalid-data.txt');
+
+ assert.throws(
+ () => fs.appendFile(filename, data, common.mustNotCall()),
+ errObj
+ );
+
+ assert.throws(
+ () => fs.appendFileSync(filename, data),
+ errObj
+ );
+
+ await assert.rejects(
+ fs.promises.appendFile(filename, data),
+ errObj
+ );
+ // The filename shouldn't exist if throwing error.
+ assert.throws(
+ () => fs.statSync(filename),
+ {
+ code: 'ENOENT',
+ message: /no such file or directory/
+ }
+ );
+});
+
+// Test that appendFile accepts file descriptors (callback API).
+{
+ const filename = join(tmpdir.path, 'append-descriptors.txt');
+ fs.writeFileSync(filename, currentFileData);
+
+ fs.open(filename, 'a+', common.mustSucceed((fd) => {
+ fs.appendFile(fd, s, common.mustSucceed(() => {
+ fs.close(fd, common.mustSucceed(() => {
+ fs.readFile(filename, common.mustSucceed((buffer) => {
+ assert.strictEqual(Buffer.byteLength(s) + currentFileData.length,
+ buffer.length);
+ }));
+ }));
+ }));
+ }));
+}
+
+// FIXME(F3n67u): fs.promises.appendFile support FileHandle
+// Test that appendFile accepts file descriptors (promises API).
+// {
+// const filename = join(tmpdir.path, 'append-descriptors-promises.txt');
+// fs.writeFileSync(filename, currentFileData);
+
+// let fd;
+// fs.promises.open(filename, 'a+')
+// .then(common.mustCall((fileDescriptor) => {
+// fd = fileDescriptor;
+// return fs.promises.appendFile(fd, s);
+// }))
+// .then(common.mustCall(() => fd.close()))
+// .then(common.mustCall(() => fs.promises.readFile(filename)))
+// .then(common.mustCall((buffer) => {
+// assert.strictEqual(Buffer.byteLength(s) + currentFileData.length,
+// buffer.length);
+// }))
+// .catch(throwNextTick);
+// }
+
+assert.throws(
+ () => fs.appendFile(join(tmpdir.path, 'append6.txt'), console.log),
+ { code: 'ERR_INVALID_ARG_TYPE' });
diff --git a/tests/node_compat/test/parallel/test-fs-chmod-mask.js b/tests/node_compat/test/parallel/test-fs-chmod-mask.js
new file mode 100644
index 000000000..f11567c7e
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-chmod-mask.js
@@ -0,0 +1,106 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 16.13.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+'use strict';
+
+// This tests that the lower bits of mode > 0o777 still works in fs APIs.
+
+const common = require('../common');
+const assert = require('assert');
+const path = require('path');
+const fs = require('fs');
+
+// TODO(f3n67u): fs.chmod is not supported in Windows
+if (common.isWindows) {
+ return;
+}
+
+let mode;
+// On Windows chmod is only able to manipulate write permission
+if (common.isWindows) {
+ mode = 0o444; // read-only
+} else {
+ mode = 0o777;
+}
+
+const maskToIgnore = 0o10000;
+
+const tmpdir = require('../common/tmpdir');
+tmpdir.refresh();
+
+function test(mode, asString) {
+ const suffix = asString ? 'str' : 'num';
+ const input = asString ?
+ (mode | maskToIgnore).toString(8) : (mode | maskToIgnore);
+
+ {
+ const file = path.join(tmpdir.path, `chmod-async-${suffix}.txt`);
+ fs.writeFileSync(file, 'test', 'utf-8');
+
+ fs.chmod(file, input, common.mustSucceed(() => {
+ assert.strictEqual(fs.statSync(file).mode & 0o777, mode);
+ }));
+ }
+
+ {
+ const file = path.join(tmpdir.path, `chmodSync-${suffix}.txt`);
+ fs.writeFileSync(file, 'test', 'utf-8');
+
+ fs.chmodSync(file, input);
+ assert.strictEqual(fs.statSync(file).mode & 0o777, mode);
+ }
+
+ // TODO(f3n67u): implement fs.fchmod
+ // {
+ // const file = path.join(tmpdir.path, `fchmod-async-${suffix}.txt`);
+ // fs.writeFileSync(file, 'test', 'utf-8');
+ // fs.open(file, 'w', common.mustSucceed((fd) => {
+ // fs.fchmod(fd, input, common.mustSucceed(() => {
+ // assert.strictEqual(fs.fstatSync(fd).mode & 0o777, mode);
+ // fs.close(fd, assert.ifError);
+ // }));
+ // }));
+ // }
+
+ // TODO(f3n67u): implement fs.fchmodSync
+ // {
+ // const file = path.join(tmpdir.path, `fchmodSync-${suffix}.txt`);
+ // fs.writeFileSync(file, 'test', 'utf-8');
+ // const fd = fs.openSync(file, 'w');
+
+ // fs.fchmodSync(fd, input);
+ // assert.strictEqual(fs.fstatSync(fd).mode & 0o777, mode);
+
+ // fs.close(fd, assert.ifError);
+ // }
+
+ // TODO(f3n67u): implement fs.lchmod
+ // if (fs.lchmod) {
+ // const link = path.join(tmpdir.path, `lchmod-src-${suffix}`);
+ // const file = path.join(tmpdir.path, `lchmod-dest-${suffix}`);
+ // fs.writeFileSync(file, 'test', 'utf-8');
+ // fs.symlinkSync(file, link);
+
+ // fs.lchmod(link, input, common.mustSucceed(() => {
+ // assert.strictEqual(fs.lstatSync(link).mode & 0o777, mode);
+ // }));
+ // }
+
+ // TODO(f3n67u): implement fs.lchmodSync
+ // if (fs.lchmodSync) {
+ // const link = path.join(tmpdir.path, `lchmodSync-src-${suffix}`);
+ // const file = path.join(tmpdir.path, `lchmodSync-dest-${suffix}`);
+ // fs.writeFileSync(file, 'test', 'utf-8');
+ // fs.symlinkSync(file, link);
+
+ // fs.lchmodSync(link, input);
+ // assert.strictEqual(fs.lstatSync(link).mode & 0o777, mode);
+ // }
+}
+
+test(mode, true);
+test(mode, false);
diff --git a/tests/node_compat/test/parallel/test-fs-chmod.js b/tests/node_compat/test/parallel/test-fs-chmod.js
new file mode 100644
index 000000000..b5f524f64
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-chmod.js
@@ -0,0 +1,167 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 16.13.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const path = require('path');
+const fs = require('fs');
+
+let mode_async;
+let mode_sync;
+
+// Need to hijack fs.open/close to make sure that things
+// get closed once they're opened.
+fs._open = fs.open;
+fs._openSync = fs.openSync;
+fs.open = open;
+fs.openSync = openSync;
+fs._close = fs.close;
+fs._closeSync = fs.closeSync;
+fs.close = close;
+fs.closeSync = closeSync;
+
+let openCount = 0;
+
+function open() {
+ openCount++;
+ return fs._open.apply(fs, arguments);
+}
+
+function openSync() {
+ openCount++;
+ return fs._openSync.apply(fs, arguments);
+}
+
+function close() {
+ openCount--;
+ return fs._close.apply(fs, arguments);
+}
+
+function closeSync() {
+ openCount--;
+ return fs._closeSync.apply(fs, arguments);
+}
+
+// TODO(f3n67u): fs.chmod is not supported in Windows
+if (common.isWindows) {
+ return;
+}
+
+// On Windows chmod is only able to manipulate write permission
+if (common.isWindows) {
+ mode_async = 0o400; // read-only
+ mode_sync = 0o600; // read-write
+} else {
+ mode_async = 0o777;
+ mode_sync = 0o644;
+}
+
+const tmpdir = require('../common/tmpdir');
+tmpdir.refresh();
+
+const file1 = path.join(tmpdir.path, 'a.js');
+const file2 = path.join(tmpdir.path, 'a1.js');
+
+// Create file1.
+fs.closeSync(fs.openSync(file1, 'w'));
+
+fs.chmod(file1, mode_async.toString(8), common.mustSucceed(() => {
+ if (common.isWindows) {
+ assert.ok((fs.statSync(file1).mode & 0o777) & mode_async);
+ } else {
+ assert.strictEqual(fs.statSync(file1).mode & 0o777, mode_async);
+ }
+
+ fs.chmodSync(file1, mode_sync);
+ if (common.isWindows) {
+ assert.ok((fs.statSync(file1).mode & 0o777) & mode_sync);
+ } else {
+ assert.strictEqual(fs.statSync(file1).mode & 0o777, mode_sync);
+ }
+}));
+
+// TODO(f3n67u): implement fs.fchmod
+// fs.open(file2, 'w', common.mustSucceed((fd) => {
+// fs.fchmod(fd, mode_async.toString(8), common.mustSucceed(() => {
+// if (common.isWindows) {
+// assert.ok((fs.fstatSync(fd).mode & 0o777) & mode_async);
+// } else {
+// assert.strictEqual(fs.fstatSync(fd).mode & 0o777, mode_async);
+// }
+
+// assert.throws(
+// () => fs.fchmod(fd, {}),
+// {
+// code: 'ERR_INVALID_ARG_TYPE',
+// }
+// );
+
+// fs.fchmodSync(fd, mode_sync);
+// if (common.isWindows) {
+// assert.ok((fs.fstatSync(fd).mode & 0o777) & mode_sync);
+// } else {
+// assert.strictEqual(fs.fstatSync(fd).mode & 0o777, mode_sync);
+// }
+
+// fs.close(fd, assert.ifError);
+// }));
+// }));
+
+
+// TODO(f3n67u): implement fs.lchmod
+// // lchmod
+// if (fs.lchmod) {
+// const link = path.join(tmpdir.path, 'symbolic-link');
+
+// fs.symlinkSync(file2, link);
+
+// fs.lchmod(link, mode_async, common.mustSucceed(() => {
+// assert.strictEqual(fs.lstatSync(link).mode & 0o777, mode_async);
+
+// fs.lchmodSync(link, mode_sync);
+// assert.strictEqual(fs.lstatSync(link).mode & 0o777, mode_sync);
+
+// }));
+// }
+
+[false, 1, {}, [], null, undefined].forEach((input) => {
+ const errObj = {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: 'The "path" argument must be of type string or an instance ' +
+ 'of Buffer or URL.' +
+ common.invalidArgTypeHelper(input)
+ };
+ assert.throws(() => fs.chmod(input, 1, common.mustNotCall()), errObj);
+ assert.throws(() => fs.chmodSync(input, 1), errObj);
+});
+
+process.on('exit', function() {
+ assert.strictEqual(openCount, 0);
+});
diff --git a/tests/node_compat/test/parallel/test-fs-chown-type-check.js b/tests/node_compat/test/parallel/test-fs-chown-type-check.js
new file mode 100644
index 000000000..147edf837
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-chown-type-check.js
@@ -0,0 +1,60 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const assert = require('assert');
+const fs = require('fs');
+
+[false, 1, {}, [], null, undefined].forEach((i) => {
+ assert.throws(
+ () => fs.chown(i, 1, 1, common.mustNotCall()),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError'
+ }
+ );
+ assert.throws(
+ () => fs.chownSync(i, 1, 1),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError'
+ }
+ );
+});
+
+[false, 'test', {}, [], null, undefined].forEach((i) => {
+ assert.throws(
+ () => fs.chown('not_a_file_that_exists', i, 1, common.mustNotCall()),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError'
+ }
+ );
+ assert.throws(
+ () => fs.chown('not_a_file_that_exists', 1, i, common.mustNotCall()),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError'
+ }
+ );
+ assert.throws(
+ () => fs.chownSync('not_a_file_that_exists', i, 1),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError'
+ }
+ );
+ assert.throws(
+ () => fs.chownSync('not_a_file_that_exists', 1, i),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError'
+ }
+ );
+});
diff --git a/tests/node_compat/test/parallel/test-fs-copyfile.js b/tests/node_compat/test/parallel/test-fs-copyfile.js
new file mode 100644
index 000000000..085fc19bf
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-copyfile.js
@@ -0,0 +1,174 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Flags: --expose-internals
+'use strict';
+const common = require('../common');
+const fixtures = require('../common/fixtures');
+const tmpdir = require('../common/tmpdir');
+const assert = require('assert');
+const fs = require('fs');
+const { internalBinding } = require('internal/test/binding');
+const {
+ UV_ENOENT,
+ UV_EEXIST
+} = internalBinding('uv');
+const path = require('path');
+const src = fixtures.path('a.js');
+const dest = path.join(tmpdir.path, 'copyfile.out');
+const {
+ COPYFILE_EXCL,
+ COPYFILE_FICLONE,
+ COPYFILE_FICLONE_FORCE,
+ UV_FS_COPYFILE_EXCL,
+ UV_FS_COPYFILE_FICLONE,
+ UV_FS_COPYFILE_FICLONE_FORCE
+} = fs.constants;
+
+function verify(src, dest) {
+ const srcData = fs.readFileSync(src, 'utf8');
+ const srcStat = fs.statSync(src);
+ const destData = fs.readFileSync(dest, 'utf8');
+ const destStat = fs.statSync(dest);
+
+ assert.strictEqual(srcData, destData);
+ assert.strictEqual(srcStat.mode, destStat.mode);
+ assert.strictEqual(srcStat.size, destStat.size);
+}
+
+tmpdir.refresh();
+
+// Verify that flags are defined.
+assert.strictEqual(typeof COPYFILE_EXCL, 'number');
+assert.strictEqual(typeof COPYFILE_FICLONE, 'number');
+assert.strictEqual(typeof COPYFILE_FICLONE_FORCE, 'number');
+assert.strictEqual(typeof UV_FS_COPYFILE_EXCL, 'number');
+assert.strictEqual(typeof UV_FS_COPYFILE_FICLONE, 'number');
+assert.strictEqual(typeof UV_FS_COPYFILE_FICLONE_FORCE, 'number');
+assert.strictEqual(COPYFILE_EXCL, UV_FS_COPYFILE_EXCL);
+assert.strictEqual(COPYFILE_FICLONE, UV_FS_COPYFILE_FICLONE);
+assert.strictEqual(COPYFILE_FICLONE_FORCE, UV_FS_COPYFILE_FICLONE_FORCE);
+
+// Verify that files are overwritten when no flags are provided.
+fs.writeFileSync(dest, '', 'utf8');
+const result = fs.copyFileSync(src, dest);
+assert.strictEqual(result, undefined);
+verify(src, dest);
+
+// Verify that files are overwritten with default flags.
+fs.copyFileSync(src, dest, 0);
+verify(src, dest);
+
+// Verify that UV_FS_COPYFILE_FICLONE can be used.
+fs.unlinkSync(dest);
+fs.copyFileSync(src, dest, UV_FS_COPYFILE_FICLONE);
+verify(src, dest);
+
+// Verify that COPYFILE_FICLONE_FORCE can be used.
+try {
+ fs.unlinkSync(dest);
+ fs.copyFileSync(src, dest, COPYFILE_FICLONE_FORCE);
+ verify(src, dest);
+} catch (err) {
+ assert.strictEqual(err.syscall, 'copyfile');
+ assert(err.code === 'ENOTSUP' || err.code === 'ENOTTY' ||
+ err.code === 'ENOSYS' || err.code === 'EXDEV');
+ assert.strictEqual(err.path, src);
+ assert.strictEqual(err.dest, dest);
+}
+
+// Copies asynchronously.
+tmpdir.refresh(); // Don't use unlinkSync() since the last test may fail.
+fs.copyFile(src, dest, common.mustSucceed(() => {
+ verify(src, dest);
+
+ // Copy asynchronously with flags.
+ fs.copyFile(src, dest, COPYFILE_EXCL, common.mustCall((err) => {
+ if (err.code === 'ENOENT') { // Could be ENOENT or EEXIST
+ assert.strictEqual(err.message,
+ 'ENOENT: no such file or directory, copyfile ' +
+ `'${src}' -> '${dest}'`);
+ assert.strictEqual(err.errno, UV_ENOENT);
+ assert.strictEqual(err.code, 'ENOENT');
+ assert.strictEqual(err.syscall, 'copyfile');
+ } else {
+ assert.strictEqual(err.message,
+ 'EEXIST: file already exists, copyfile ' +
+ `'${src}' -> '${dest}'`);
+ assert.strictEqual(err.errno, UV_EEXIST);
+ assert.strictEqual(err.code, 'EEXIST');
+ assert.strictEqual(err.syscall, 'copyfile');
+ }
+ }));
+}));
+
+// Throws if callback is not a function.
+assert.throws(() => {
+ fs.copyFile(src, dest, 0, 0);
+}, {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError'
+});
+
+// Throws if the source path is not a string.
+[false, 1, {}, [], null, undefined].forEach((i) => {
+ assert.throws(
+ () => fs.copyFile(i, dest, common.mustNotCall()),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: /src/
+ }
+ );
+ assert.throws(
+ () => fs.copyFile(src, i, common.mustNotCall()),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: /dest/
+ }
+ );
+ assert.throws(
+ () => fs.copyFileSync(i, dest),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: /src/
+ }
+ );
+ assert.throws(
+ () => fs.copyFileSync(src, i),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: /dest/
+ }
+ );
+});
+
+assert.throws(() => {
+ fs.copyFileSync(src, dest, 'r');
+}, {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: /mode/
+});
+
+assert.throws(() => {
+ fs.copyFileSync(src, dest, 8);
+}, {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError',
+});
+
+assert.throws(() => {
+ fs.copyFile(src, dest, 'r', common.mustNotCall());
+}, {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: /mode/
+});
diff --git a/tests/node_compat/test/parallel/test-fs-empty-readStream.js b/tests/node_compat/test/parallel/test-fs-empty-readStream.js
new file mode 100644
index 000000000..4f70fda27
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-empty-readStream.js
@@ -0,0 +1,57 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const fs = require('fs');
+const fixtures = require('../common/fixtures');
+
+const emptyFile = fixtures.path('empty.txt');
+
+fs.open(emptyFile, 'r', common.mustSucceed((fd) => {
+ const read = fs.createReadStream(emptyFile, { fd });
+
+ read.once('data', common.mustNotCall('data event should not emit'));
+
+ read.once('end', common.mustCall());
+}));
+
+fs.open(emptyFile, 'r', common.mustSucceed((fd) => {
+ const read = fs.createReadStream(emptyFile, { fd });
+
+ read.pause();
+
+ read.once('data', common.mustNotCall('data event should not emit'));
+
+ read.once('end', common.mustNotCall('end event should not emit'));
+
+ setTimeout(common.mustCall(() => {
+ assert.strictEqual(read.isPaused(), true);
+ }), common.platformTimeout(50));
+}));
diff --git a/tests/node_compat/test/parallel/test-fs-mkdir.js b/tests/node_compat/test/parallel/test-fs-mkdir.js
new file mode 100644
index 000000000..5a3897e91
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-mkdir.js
@@ -0,0 +1,379 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.8.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const fs = require('fs');
+const path = require('path');
+
+const tmpdir = require('../common/tmpdir');
+tmpdir.refresh();
+
+let dirc = 0;
+function nextdir() {
+ return `test${++dirc}`;
+}
+
+// fs.mkdir creates directory using assigned path
+{
+ const pathname = path.join(tmpdir.path, nextdir());
+
+ fs.mkdir(pathname, common.mustCall(function(err) {
+ assert.strictEqual(err, null);
+ assert.strictEqual(fs.existsSync(pathname), true);
+ }));
+}
+
+// fs.mkdir creates directory with assigned mode value
+{
+ const pathname = path.join(tmpdir.path, nextdir());
+
+ fs.mkdir(pathname, 0o777, common.mustCall(function(err) {
+ assert.strictEqual(err, null);
+ assert.strictEqual(fs.existsSync(pathname), true);
+ }));
+}
+
+// fs.mkdir creates directory with mode passed as an options object
+{
+ const pathname = path.join(tmpdir.path, nextdir());
+
+ fs.mkdir(pathname, common.mustNotMutateObjectDeep({ mode: 0o777 }), common.mustCall(function(err) {
+ assert.strictEqual(err, null);
+ assert.strictEqual(fs.existsSync(pathname), true);
+ }));
+}
+
+// fs.mkdirSync creates directory with mode passed as an options object
+{
+ const pathname = path.join(tmpdir.path, nextdir());
+
+ fs.mkdirSync(pathname, common.mustNotMutateObjectDeep({ mode: 0o777 }));
+
+ assert.strictEqual(fs.existsSync(pathname), true);
+}
+
+// mkdirSync successfully creates directory from given path
+{
+ const pathname = path.join(tmpdir.path, nextdir());
+
+ fs.mkdirSync(pathname);
+
+ const exists = fs.existsSync(pathname);
+ assert.strictEqual(exists, true);
+}
+
+// mkdirSync and mkdir require path to be a string, buffer or url.
+// Anything else generates an error.
+[false, 1, {}, [], null, undefined].forEach((i) => {
+ assert.throws(
+ () => fs.mkdir(i, common.mustNotCall()),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError'
+ }
+ );
+ assert.throws(
+ () => fs.mkdirSync(i),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError'
+ }
+ );
+});
+
+// mkdirpSync when both top-level, and sub-folders do not exist.
+{
+ const pathname = path.join(tmpdir.path, nextdir(), nextdir());
+
+ fs.mkdirSync(pathname, common.mustNotMutateObjectDeep({ recursive: true }));
+
+ const exists = fs.existsSync(pathname);
+ assert.strictEqual(exists, true);
+ assert.strictEqual(fs.statSync(pathname).isDirectory(), true);
+}
+
+// mkdirpSync when folder already exists.
+{
+ const pathname = path.join(tmpdir.path, nextdir(), nextdir());
+
+ fs.mkdirSync(pathname, { recursive: true });
+ // Should not cause an error.
+ fs.mkdirSync(pathname, { recursive: true });
+
+ const exists = fs.existsSync(pathname);
+ assert.strictEqual(exists, true);
+ assert.strictEqual(fs.statSync(pathname).isDirectory(), true);
+}
+
+// mkdirpSync ../
+{
+ const pathname = `${tmpdir.path}/${nextdir()}/../${nextdir()}/${nextdir()}`;
+ fs.mkdirSync(pathname, { recursive: true });
+ const exists = fs.existsSync(pathname);
+ assert.strictEqual(exists, true);
+ assert.strictEqual(fs.statSync(pathname).isDirectory(), true);
+}
+
+// mkdirpSync when path is a file.
+{
+ const pathname = path.join(tmpdir.path, nextdir(), nextdir());
+
+ fs.mkdirSync(path.dirname(pathname));
+ fs.writeFileSync(pathname, '', 'utf8');
+
+ assert.throws(
+ () => { fs.mkdirSync(pathname, common.mustNotMutateObjectDeep({ recursive: true })); },
+ {
+ code: 'EEXIST',
+ message: /EEXIST: .*mkdir/,
+ name: 'Error',
+ syscall: 'mkdir',
+ }
+ );
+}
+
+// mkdirpSync when part of the path is a file.
+{
+ const filename = path.join(tmpdir.path, nextdir(), nextdir());
+ const pathname = path.join(filename, nextdir(), nextdir());
+
+ fs.mkdirSync(path.dirname(filename));
+ fs.writeFileSync(filename, '', 'utf8');
+
+ assert.throws(
+ () => { fs.mkdirSync(pathname, { recursive: true }); },
+ {
+ code: 'ENOTDIR',
+ message: /ENOTDIR: .*mkdir/,
+ name: 'Error',
+ syscall: 'mkdir',
+ path: pathname // See: https://github.com/nodejs/node/issues/28015
+ }
+ );
+}
+
+// `mkdirp` when folder does not yet exist.
+{
+ const pathname = path.join(tmpdir.path, nextdir(), nextdir());
+
+ fs.mkdir(pathname, common.mustNotMutateObjectDeep({ recursive: true }), common.mustCall(function(err) {
+ assert.strictEqual(err, null);
+ assert.strictEqual(fs.existsSync(pathname), true);
+ assert.strictEqual(fs.statSync(pathname).isDirectory(), true);
+ }));
+}
+
+// `mkdirp` when path is a file.
+{
+ const pathname = path.join(tmpdir.path, nextdir(), nextdir());
+
+ fs.mkdirSync(path.dirname(pathname));
+ fs.writeFileSync(pathname, '', 'utf8');
+ fs.mkdir(pathname, common.mustNotMutateObjectDeep({ recursive: true }), common.mustCall((err) => {
+ assert.strictEqual(err.code, 'EEXIST');
+ // TODO(wafuwafu13): Enable this
+ // assert.strictEqual(err.syscall, 'mkdir');
+ assert.strictEqual(fs.statSync(pathname).isDirectory(), false);
+ }));
+}
+
+// `mkdirp` when part of the path is a file.
+{
+ const filename = path.join(tmpdir.path, nextdir(), nextdir());
+ const pathname = path.join(filename, nextdir(), nextdir());
+
+ fs.mkdirSync(path.dirname(filename));
+ fs.writeFileSync(filename, '', 'utf8');
+ fs.mkdir(pathname, common.mustNotMutateObjectDeep({ recursive: true }), common.mustCall((err) => {
+ // TODO(wafuwafu13): Enable this
+ // assert.strictEqual(err.code, 'ENOTDIR');
+ // assert.strictEqual(err.syscall, 'mkdir');
+ assert.strictEqual(fs.existsSync(pathname), false);
+ // See: https://github.com/nodejs/node/issues/28015
+ // The path field varies slightly in Windows errors, vs., other platforms
+ // see: https://github.com/libuv/libuv/issues/2661, for this reason we
+ // use startsWith() rather than comparing to the full "pathname".
+ // TODO(wafuwafu13): Enable this
+ // assert(err.path.startsWith(filename));
+ }));
+}
+
+// mkdirpSync dirname loop
+// XXX: windows and smartos have issues removing a directory that you're in.
+if (common.isMainThread && (common.isLinux || common.isOSX)) {
+ const pathname = path.join(tmpdir.path, nextdir());
+ fs.mkdirSync(pathname);
+ process.chdir(pathname);
+ fs.rmdirSync(pathname);
+ assert.throws(
+ () => { fs.mkdirSync('X', common.mustNotMutateObjectDeep({ recursive: true })); },
+ {
+ code: 'ENOENT',
+ message: /ENOENT: .*mkdir/,
+ name: 'Error',
+ syscall: 'mkdir',
+ }
+ );
+ fs.mkdir('X', common.mustNotMutateObjectDeep({ recursive: true }), (err) => {
+ assert.strictEqual(err.code, 'ENOENT');
+ // TODO(wafuwafu13): Enable this
+ // assert.strictEqual(err.syscall, 'mkdir');
+ });
+}
+
+// mkdirSync and mkdir require options.recursive to be a boolean.
+// Anything else generates an error.
+{
+ const pathname = path.join(tmpdir.path, nextdir());
+ ['', 1, {}, [], null, Symbol('test'), () => {}].forEach((recursive) => {
+ const received = common.invalidArgTypeHelper(recursive);
+ assert.throws(
+ () => fs.mkdir(pathname, common.mustNotMutateObjectDeep({ recursive }), common.mustNotCall()),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: 'The "options.recursive" property must be of type boolean.' +
+ received
+ }
+ );
+ assert.throws(
+ () => fs.mkdirSync(pathname, common.mustNotMutateObjectDeep({ recursive })),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: 'The "options.recursive" property must be of type boolean.' +
+ received
+ }
+ );
+ });
+}
+
+// `mkdirp` returns first folder created, when all folders are new.
+{
+ const dir1 = nextdir();
+ const dir2 = nextdir();
+ const firstPathCreated = path.join(tmpdir.path, dir1);
+ const pathname = path.join(tmpdir.path, dir1, dir2);
+
+ fs.mkdir(pathname, common.mustNotMutateObjectDeep({ recursive: true }), common.mustCall(function(err, path) {
+ assert.strictEqual(err, null);
+ assert.strictEqual(fs.existsSync(pathname), true);
+ assert.strictEqual(fs.statSync(pathname).isDirectory(), true);
+ // TODO(wafuwafu13): Enable this
+ // assert.strictEqual(path, firstPathCreated);
+ }));
+}
+
+// `mkdirp` returns first folder created, when last folder is new.
+{
+ const dir1 = nextdir();
+ const dir2 = nextdir();
+ const pathname = path.join(tmpdir.path, dir1, dir2);
+ fs.mkdirSync(path.join(tmpdir.path, dir1));
+ fs.mkdir(pathname, common.mustNotMutateObjectDeep({ recursive: true }), common.mustCall(function(err, path) {
+ assert.strictEqual(err, null);
+ assert.strictEqual(fs.existsSync(pathname), true);
+ assert.strictEqual(fs.statSync(pathname).isDirectory(), true);
+ // TODO(wafuwafu13): Enable this
+ // assert.strictEqual(path, pathname);
+ }));
+}
+
+// `mkdirp` returns undefined, when no new folders are created.
+{
+ const dir1 = nextdir();
+ const dir2 = nextdir();
+ const pathname = path.join(tmpdir.path, dir1, dir2);
+ fs.mkdirSync(path.join(tmpdir.path, dir1, dir2), common.mustNotMutateObjectDeep({ recursive: true }));
+ fs.mkdir(pathname, common.mustNotMutateObjectDeep({ recursive: true }), common.mustCall(function(err, path) {
+ assert.strictEqual(err, null);
+ assert.strictEqual(fs.existsSync(pathname), true);
+ assert.strictEqual(fs.statSync(pathname).isDirectory(), true);
+ assert.strictEqual(path, undefined);
+ }));
+}
+
+// `mkdirp.sync` returns first folder created, when all folders are new.
+{
+ const dir1 = nextdir();
+ const dir2 = nextdir();
+ const firstPathCreated = path.join(tmpdir.path, dir1);
+ const pathname = path.join(tmpdir.path, dir1, dir2);
+ const p = fs.mkdirSync(pathname, common.mustNotMutateObjectDeep({ recursive: true }));
+ assert.strictEqual(fs.existsSync(pathname), true);
+ assert.strictEqual(fs.statSync(pathname).isDirectory(), true);
+ // TODO(wafuwafu13): Enable this
+ // assert.strictEqual(p, firstPathCreated);
+}
+
+// `mkdirp.sync` returns first folder created, when last folder is new.
+{
+ const dir1 = nextdir();
+ const dir2 = nextdir();
+ const pathname = path.join(tmpdir.path, dir1, dir2);
+ fs.mkdirSync(path.join(tmpdir.path, dir1), common.mustNotMutateObjectDeep({ recursive: true }));
+ const p = fs.mkdirSync(pathname, common.mustNotMutateObjectDeep({ recursive: true }));
+ assert.strictEqual(fs.existsSync(pathname), true);
+ assert.strictEqual(fs.statSync(pathname).isDirectory(), true);
+ // TODO(wafuwafu13): Enable this
+ // assert.strictEqual(p, pathname);
+}
+
+// `mkdirp.sync` returns undefined, when no new folders are created.
+{
+ const dir1 = nextdir();
+ const dir2 = nextdir();
+ const pathname = path.join(tmpdir.path, dir1, dir2);
+ fs.mkdirSync(path.join(tmpdir.path, dir1, dir2), common.mustNotMutateObjectDeep({ recursive: true }));
+ const p = fs.mkdirSync(pathname, common.mustNotMutateObjectDeep({ recursive: true }));
+ assert.strictEqual(fs.existsSync(pathname), true);
+ assert.strictEqual(fs.statSync(pathname).isDirectory(), true);
+ assert.strictEqual(p, undefined);
+}
+
+// `mkdirp.promises` returns first folder created, when all folders are new.
+{
+ const dir1 = nextdir();
+ const dir2 = nextdir();
+ const firstPathCreated = path.join(tmpdir.path, dir1);
+ const pathname = path.join(tmpdir.path, dir1, dir2);
+ async function testCase() {
+ const p = await fs.promises.mkdir(pathname, common.mustNotMutateObjectDeep({ recursive: true }));
+ assert.strictEqual(fs.existsSync(pathname), true);
+ assert.strictEqual(fs.statSync(pathname).isDirectory(), true);
+ // TODO(wafuwafu13): Enable this
+ // assert.strictEqual(p, firstPathCreated);
+ }
+ testCase();
+}
+
+// Keep the event loop alive so the async mkdir() requests
+// have a chance to run (since they don't ref the event loop).
+process.nextTick(() => {});
diff --git a/tests/node_compat/test/parallel/test-fs-open-flags.js b/tests/node_compat/test/parallel/test-fs-open-flags.js
new file mode 100644
index 000000000..532194e06
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-open-flags.js
@@ -0,0 +1,101 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// Flags: --expose-internals
+'use strict';
+const common = require('../common');
+
+const fixtures = require('../common/fixtures');
+
+const assert = require('assert');
+const fs = require('fs');
+const path = require('path');
+
+// 0 if not found in fs.constants
+const { O_APPEND = 0,
+ O_CREAT = 0,
+ O_EXCL = 0,
+ O_RDONLY = 0,
+ O_RDWR = 0,
+ O_SYNC = 0,
+ O_DSYNC = 0,
+ O_TRUNC = 0,
+ O_WRONLY = 0 } = fs.constants;
+
+const { stringToFlags } = require('internal/fs/utils');
+
+assert.strictEqual(stringToFlags('r'), O_RDONLY);
+assert.strictEqual(stringToFlags('r+'), O_RDWR);
+assert.strictEqual(stringToFlags('rs+'), O_RDWR | O_SYNC);
+assert.strictEqual(stringToFlags('sr+'), O_RDWR | O_SYNC);
+assert.strictEqual(stringToFlags('w'), O_TRUNC | O_CREAT | O_WRONLY);
+assert.strictEqual(stringToFlags('w+'), O_TRUNC | O_CREAT | O_RDWR);
+assert.strictEqual(stringToFlags('a'), O_APPEND | O_CREAT | O_WRONLY);
+assert.strictEqual(stringToFlags('a+'), O_APPEND | O_CREAT | O_RDWR);
+
+assert.strictEqual(stringToFlags('wx'), O_TRUNC | O_CREAT | O_WRONLY | O_EXCL);
+assert.strictEqual(stringToFlags('xw'), O_TRUNC | O_CREAT | O_WRONLY | O_EXCL);
+assert.strictEqual(stringToFlags('wx+'), O_TRUNC | O_CREAT | O_RDWR | O_EXCL);
+assert.strictEqual(stringToFlags('xw+'), O_TRUNC | O_CREAT | O_RDWR | O_EXCL);
+assert.strictEqual(stringToFlags('ax'), O_APPEND | O_CREAT | O_WRONLY | O_EXCL);
+assert.strictEqual(stringToFlags('xa'), O_APPEND | O_CREAT | O_WRONLY | O_EXCL);
+assert.strictEqual(stringToFlags('as'), O_APPEND | O_CREAT | O_WRONLY | O_SYNC);
+assert.strictEqual(stringToFlags('sa'), O_APPEND | O_CREAT | O_WRONLY | O_SYNC);
+assert.strictEqual(stringToFlags('ax+'), O_APPEND | O_CREAT | O_RDWR | O_EXCL);
+assert.strictEqual(stringToFlags('xa+'), O_APPEND | O_CREAT | O_RDWR | O_EXCL);
+assert.strictEqual(stringToFlags('as+'), O_APPEND | O_CREAT | O_RDWR | O_SYNC);
+assert.strictEqual(stringToFlags('sa+'), O_APPEND | O_CREAT | O_RDWR | O_SYNC);
+
+('+ +a +r +w rw wa war raw r++ a++ w++ x +x x+ rx rx+ wxx wax xwx xxx')
+ .split(' ')
+ .forEach(function(flags) {
+ assert.throws(
+ () => stringToFlags(flags),
+ { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError' }
+ );
+ });
+
+assert.throws(
+ () => stringToFlags({}),
+ { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError' }
+);
+
+assert.throws(
+ () => stringToFlags(true),
+ { code: 'ERR_INVALID_ARG_VALUE', name: 'TypeError' }
+);
+
+if (common.isLinux || common.isOSX) {
+ const tmpdir = require('../common/tmpdir');
+ tmpdir.refresh();
+ const file = path.join(tmpdir.path, 'a.js');
+ fs.copyFileSync(fixtures.path('a.js'), file);
+ fs.open(file, O_DSYNC, common.mustSucceed((fd) => {
+ fs.closeSync(fd);
+ }));
+}
diff --git a/tests/node_compat/test/parallel/test-fs-open-mode-mask.js b/tests/node_compat/test/parallel/test-fs-open-mode-mask.js
new file mode 100644
index 000000000..4b56b3b38
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-open-mode-mask.js
@@ -0,0 +1,48 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+// This tests that the lower bits of mode > 0o777 still works in fs.open().
+
+const common = require('../common');
+const assert = require('assert');
+const path = require('path');
+const fs = require('fs');
+
+const mode = common.isWindows ? 0o444 : 0o644;
+
+const maskToIgnore = 0o10000;
+
+const tmpdir = require('../common/tmpdir');
+tmpdir.refresh();
+
+function test(mode, asString) {
+ const suffix = asString ? 'str' : 'num';
+ const input = asString ?
+ (mode | maskToIgnore).toString(8) : (mode | maskToIgnore);
+
+ {
+ const file = path.join(tmpdir.path, `openSync-${suffix}.txt`);
+ const fd = fs.openSync(file, 'w+', input);
+ assert.strictEqual(fs.fstatSync(fd).mode & 0o777, mode);
+ fs.closeSync(fd);
+ assert.strictEqual(fs.statSync(file).mode & 0o777, mode);
+ }
+
+ {
+ const file = path.join(tmpdir.path, `open-${suffix}.txt`);
+ fs.open(file, 'w+', input, common.mustSucceed((fd) => {
+ assert.strictEqual(fs.fstatSync(fd).mode & 0o777, mode);
+ fs.closeSync(fd);
+ assert.strictEqual(fs.statSync(file).mode & 0o777, mode);
+ }));
+ }
+}
+
+test(mode, true);
+test(mode, false);
diff --git a/tests/node_compat/test/parallel/test-fs-open-no-close.js b/tests/node_compat/test/parallel/test-fs-open-no-close.js
new file mode 100644
index 000000000..abde2ad07
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-open-no-close.js
@@ -0,0 +1,38 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+// Refs: https://github.com/nodejs/node/issues/34266
+// Failing to close a file should not keep the event loop open.
+
+const common = require('../common');
+const assert = require('assert');
+
+const fs = require('fs');
+
+const debuglog = (arg) => {
+ console.log(new Date().toLocaleString(), arg);
+};
+
+const tmpdir = require('../common/tmpdir');
+tmpdir.refresh();
+
+let openFd;
+
+fs.open(`${tmpdir.path}/dummy`, 'wx+', common.mustCall((err, fd) => {
+ debuglog('fs open() callback');
+ assert.ifError(err);
+ openFd = fd;
+}));
+debuglog('waiting for callback');
+
+process.on('beforeExit', common.mustCall(() => {
+ if (openFd) {
+ fs.closeSync(openFd);
+ }
+}));
diff --git a/tests/node_compat/test/parallel/test-fs-open-numeric-flags.js b/tests/node_compat/test/parallel/test-fs-open-numeric-flags.js
new file mode 100644
index 000000000..3e8efde82
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-open-numeric-flags.js
@@ -0,0 +1,23 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+require('../common');
+
+const assert = require('assert');
+const fs = require('fs');
+const path = require('path');
+
+const tmpdir = require('../common/tmpdir');
+tmpdir.refresh();
+
+// O_WRONLY without O_CREAT shall fail with ENOENT
+const pathNE = path.join(tmpdir.path, 'file-should-not-exist');
+assert.throws(
+ () => fs.openSync(pathNE, fs.constants.O_WRONLY),
+ (e) => e.code === 'ENOENT'
+);
diff --git a/tests/node_compat/test/parallel/test-fs-open.js b/tests/node_compat/test/parallel/test-fs-open.js
new file mode 100644
index 000000000..631e96a2e
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-open.js
@@ -0,0 +1,128 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.8.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const fs = require('fs');
+
+let caughtException = false;
+
+try {
+ // Should throw ENOENT, not EBADF
+ // see https://github.com/joyent/node/pull/1228
+ fs.openSync('/8hvftyuncxrt/path/to/file/that/does/not/exist', 'r');
+} catch (e) {
+ assert.strictEqual(e.code, 'ENOENT');
+ caughtException = true;
+}
+assert.strictEqual(caughtException, true);
+
+fs.openSync(__filename);
+
+fs.open(__filename, common.mustSucceed());
+
+fs.open(__filename, 'r', common.mustSucceed());
+
+// TODO(wafuwafu13): Support 'rs' flag
+// fs.open(__filename, 'rs', common.mustSucceed());
+
+fs.open(__filename, 'r', 0, common.mustSucceed());
+
+fs.open(__filename, 'r', null, common.mustSucceed());
+
+async function promise() {
+ await fs.promises.open(__filename);
+ await fs.promises.open(__filename, 'r');
+}
+
+promise().then(common.mustCall()).catch(common.mustNotCall());
+
+assert.throws(
+ () => fs.open(__filename, 'r', 'boom', common.mustNotCall()),
+ {
+ code: 'ERR_INVALID_ARG_VALUE',
+ name: 'TypeError'
+ }
+);
+
+for (const extra of [[], ['r'], ['r', 0], ['r', 0, 'bad callback']]) {
+ assert.throws(
+ () => fs.open(__filename, ...extra),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError'
+ }
+ );
+}
+
+[false, 1, [], {}, null, undefined].forEach((i) => {
+ assert.throws(
+ () => fs.open(i, 'r', common.mustNotCall()),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError'
+ }
+ );
+ assert.throws(
+ () => fs.openSync(i, 'r', common.mustNotCall()),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError'
+ }
+ );
+ assert.rejects(
+ fs.promises.open(i, 'r'),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError'
+ }
+ );
+});
+
+// Check invalid modes.
+[false, [], {}].forEach((mode) => {
+ assert.throws(
+ () => fs.open(__filename, 'r', mode, common.mustNotCall()),
+ {
+ code: 'ERR_INVALID_ARG_TYPE'
+ }
+ );
+ assert.throws(
+ () => fs.openSync(__filename, 'r', mode, common.mustNotCall()),
+ {
+ code: 'ERR_INVALID_ARG_TYPE'
+ }
+ );
+ assert.rejects(
+ fs.promises.open(__filename, 'r', mode),
+ {
+ code: 'ERR_INVALID_ARG_TYPE'
+ }
+ );
+});
diff --git a/tests/node_compat/test/parallel/test-fs-opendir.js b/tests/node_compat/test/parallel/test-fs-opendir.js
new file mode 100644
index 000000000..75c4aa074
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-opendir.js
@@ -0,0 +1,300 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.8.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+'use strict';
+
+const common = require('../common');
+const assert = require('assert');
+const fs = require('fs');
+const path = require('path');
+
+const tmpdir = require('../common/tmpdir');
+
+const testDir = tmpdir.path;
+const files = ['empty', 'files', 'for', 'just', 'testing'];
+
+// Make sure tmp directory is clean
+tmpdir.refresh();
+
+// Create the necessary files
+files.forEach(function(filename) {
+ fs.closeSync(fs.openSync(path.join(testDir, filename), 'w'));
+});
+
+function assertDirent(dirent) {
+ assert(dirent instanceof fs.Dirent);
+ assert.strictEqual(dirent.isFile(), true);
+ assert.strictEqual(dirent.isDirectory(), false);
+ // TODO(wafuwafu13): Support these method
+ // assert.strictEqual(dirent.isSocket(), false);
+ // assert.strictEqual(dirent.isBlockDevice(), false);
+ // assert.strictEqual(dirent.isCharacterDevice(), false);
+ // assert.strictEqual(dirent.isFIFO(), false);
+ assert.strictEqual(dirent.isSymbolicLink(), false);
+}
+
+// NOTE: this error doesn't occur in Deno
+const dirclosedError = {
+ code: 'ERR_DIR_CLOSED'
+};
+
+// NOTE: this error doesn't occur in Deno
+const dirconcurrentError = {
+ code: 'ERR_DIR_CONCURRENT_OPERATION'
+};
+
+const invalidCallbackObj = {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError'
+};
+
+// Check the opendir Sync version
+{
+ const dir = fs.opendirSync(testDir);
+ const entries = files.map(() => {
+ const dirent = dir.readSync();
+ assertDirent(dirent);
+ return dirent.name;
+ });
+ assert.deepStrictEqual(files, entries.sort());
+
+ // dir.read should return null when no more entries exist
+ assert.strictEqual(dir.readSync(), null);
+
+ // check .path
+ assert.strictEqual(dir.path, testDir);
+
+ dir.closeSync();
+
+ // assert.throws(() => dir.readSync(), dirclosedError);
+ // assert.throws(() => dir.closeSync(), dirclosedError);
+}
+
+// Check the opendir async version
+fs.opendir(testDir, common.mustSucceed((dir) => {
+ let sync = true;
+ dir.read(common.mustSucceed((dirent) => {
+ assert(!sync);
+
+ // Order is operating / file system dependent
+ assert(files.includes(dirent.name), `'files' should include ${dirent}`);
+ assertDirent(dirent);
+
+ let syncInner = true;
+ dir.read(common.mustSucceed((dirent) => {
+ assert(!syncInner);
+
+ dir.close(common.mustSucceed());
+ }));
+ syncInner = false;
+ }));
+ sync = false;
+}));
+
+// opendir() on file should throw ENOTDIR
+assert.throws(function() {
+ fs.opendirSync(__filename);
+}, /Error: ENOTDIR: not a directory/);
+
+assert.throws(function() {
+ fs.opendir(__filename);
+}, /TypeError \[ERR_INVALID_ARG_TYPE\]: The "callback" argument must be of type function/);
+
+fs.opendir(__filename, common.mustCall(function(e) {
+ assert.strictEqual(e.code, 'ENOTDIR');
+}));
+
+[false, 1, [], {}, null, undefined].forEach((i) => {
+ assert.throws(
+ () => fs.opendir(i, common.mustNotCall()),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError'
+ }
+ );
+ assert.throws(
+ () => fs.opendirSync(i),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError'
+ }
+ );
+});
+
+// Promise-based tests
+async function doPromiseTest() {
+ // Check the opendir Promise version
+ const dir = await fs.promises.opendir(testDir);
+ const entries = [];
+
+ let i = files.length;
+ while (i--) {
+ const dirent = await dir.read();
+ entries.push(dirent.name);
+ assertDirent(dirent);
+ }
+
+ assert.deepStrictEqual(files, entries.sort());
+
+ // dir.read should return null when no more entries exist
+ assert.strictEqual(await dir.read(), null);
+
+ await dir.close();
+}
+doPromiseTest().then(common.mustCall());
+
+// Async iterator
+async function doAsyncIterTest() {
+ const entries = [];
+ for await (const dirent of await fs.promises.opendir(testDir)) {
+ entries.push(dirent.name);
+ assertDirent(dirent);
+ }
+
+ assert.deepStrictEqual(files, entries.sort());
+
+ // Automatically closed during iterator
+}
+doAsyncIterTest().then(common.mustCall());
+
+// Async iterators should do automatic cleanup
+
+async function doAsyncIterBreakTest() {
+ const dir = await fs.promises.opendir(testDir);
+ for await (const dirent of dir) { // eslint-disable-line no-unused-vars
+ break;
+ }
+
+ // await assert.rejects(async () => dir.read(), dirclosedError);
+}
+doAsyncIterBreakTest().then(common.mustCall());
+
+async function doAsyncIterReturnTest() {
+ const dir = await fs.promises.opendir(testDir);
+ await (async function() {
+ for await (const dirent of dir) {
+ return;
+ }
+ })();
+
+ // await assert.rejects(async () => dir.read(), dirclosedError);
+}
+doAsyncIterReturnTest().then(common.mustCall());
+
+async function doAsyncIterThrowTest() {
+ const dir = await fs.promises.opendir(testDir);
+ try {
+ for await (const dirent of dir) { // eslint-disable-line no-unused-vars
+ throw new Error('oh no');
+ }
+ } catch (err) {
+ if (err.message !== 'oh no') {
+ throw err;
+ }
+ }
+
+ // await assert.rejects(async () => dir.read(), dirclosedError);
+}
+doAsyncIterThrowTest().then(common.mustCall());
+
+// Check error thrown on invalid values of bufferSize
+for (const bufferSize of [-1, 0, 0.5, 1.5, Infinity, NaN]) {
+ assert.throws(
+ () => fs.opendirSync(testDir, common.mustNotMutateObjectDeep({ bufferSize })),
+ {
+ code: 'ERR_OUT_OF_RANGE'
+ });
+}
+for (const bufferSize of ['', '1', null]) {
+ assert.throws(
+ () => fs.opendirSync(testDir, common.mustNotMutateObjectDeep({ bufferSize })),
+ {
+ code: 'ERR_INVALID_ARG_TYPE'
+ });
+}
+
+// Check that passing a positive integer as bufferSize works
+{
+ const dir = fs.opendirSync(testDir, common.mustNotMutateObjectDeep({ bufferSize: 1024 }));
+ assertDirent(dir.readSync());
+ dir.close();
+}
+
+// TODO(wafuwafu13): enable this
+// // Check that when passing a string instead of function - throw an exception
+// async function doAsyncIterInvalidCallbackTest() {
+// const dir = await fs.promises.opendir(testDir);
+// assert.throws(() => dir.close('not function'), invalidCallbackObj);
+// }
+// doAsyncIterInvalidCallbackTest().then(common.mustCall());
+
+// Check first call to close() - should not report an error.
+async function doAsyncIterDirClosedTest() {
+ const dir = await fs.promises.opendir(testDir);
+ await dir.close();
+ // await assert.rejects(() => dir.close(), dirclosedError);
+}
+doAsyncIterDirClosedTest().then(common.mustCall());
+
+// Check that readSync() and closeSync() during read() throw exceptions
+async function doConcurrentAsyncAndSyncOps() {
+ const dir = await fs.promises.opendir(testDir);
+ const promise = dir.read();
+
+ // assert.throws(() => dir.closeSync(), dirconcurrentError);
+ // assert.throws(() => dir.readSync(), dirconcurrentError);
+
+ await promise;
+ dir.closeSync();
+}
+doConcurrentAsyncAndSyncOps().then(common.mustCall());
+
+// TODO(wafuwafu13): enable this
+// // Check read throw exceptions on invalid callback
+// {
+// const dir = fs.opendirSync(testDir);
+// assert.throws(() => dir.read('INVALID_CALLBACK'), /ERR_INVALID_ARG_TYPE/);
+// }
+
+// Check that concurrent read() operations don't do weird things.
+async function doConcurrentAsyncOps() {
+ const dir = await fs.promises.opendir(testDir);
+ const promise1 = dir.read();
+ const promise2 = dir.read();
+
+ assertDirent(await promise1);
+ assertDirent(await promise2);
+ dir.closeSync();
+}
+doConcurrentAsyncOps().then(common.mustCall());
+
+// Check that concurrent read() + close() operations don't do weird things.
+async function doConcurrentAsyncMixedOps() {
+ const dir = await fs.promises.opendir(testDir);
+ const promise1 = dir.read();
+ const promise2 = dir.close();
+
+ assertDirent(await promise1);
+ await promise2;
+}
+doConcurrentAsyncMixedOps().then(common.mustCall());
+
+// Check if directory already closed - the callback should pass an error.
+{
+ const dir = fs.opendirSync(testDir);
+ dir.closeSync();
+ dir.close(common.mustCall((error) => {
+ // assert.strictEqual(error.code, dirclosedError.code);
+ }));
+}
+
+// Check if directory already closed - throw an promise exception.
+{
+ const dir = fs.opendirSync(testDir);
+ dir.closeSync();
+ // assert.rejects(dir.close(), dirclosedError).then(common.mustCall());
+}
diff --git a/tests/node_compat/test/parallel/test-fs-read-stream-autoClose.js b/tests/node_compat/test/parallel/test-fs-read-stream-autoClose.js
new file mode 100644
index 000000000..aaa8b42e8
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-read-stream-autoClose.js
@@ -0,0 +1,23 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const fs = require('fs');
+const path = require('path');
+const assert = require('assert');
+const tmpdir = require('../common/tmpdir');
+const writeFile = path.join(tmpdir.path, 'write-autoClose.txt');
+tmpdir.refresh();
+
+const file = fs.createWriteStream(writeFile, { autoClose: true });
+
+file.on('finish', common.mustCall(() => {
+ assert.strictEqual(file.destroyed, false);
+}));
+file.end('asd');
diff --git a/tests/node_compat/test/parallel/test-fs-read-stream-concurrent-reads.js b/tests/node_compat/test/parallel/test-fs-read-stream-concurrent-reads.js
new file mode 100644
index 000000000..ac52d66a8
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-read-stream-concurrent-reads.js
@@ -0,0 +1,54 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const fixtures = require('../common/fixtures');
+const assert = require('assert');
+const fs = require('fs');
+
+// Test that concurrent file read streams don’t interfere with each other’s
+// contents, and that the chunks generated by the reads only retain a
+// 'reasonable' amount of memory.
+
+// Refs: https://github.com/nodejs/node/issues/21967
+
+const filename = fixtures.path('loop.js'); // Some small non-homogeneous file.
+const content = fs.readFileSync(filename);
+
+const N = 2000;
+let started = 0;
+let done = 0;
+
+const arrayBuffers = new Set();
+
+function startRead() {
+ ++started;
+ const chunks = [];
+ fs.createReadStream(filename)
+ .on('data', (chunk) => {
+ chunks.push(chunk);
+ arrayBuffers.add(chunk.buffer);
+ })
+ .on('end', common.mustCall(() => {
+ if (started < N)
+ startRead();
+ assert.deepStrictEqual(Buffer.concat(chunks), content);
+ if (++done === N) {
+ const retainedMemory =
+ [...arrayBuffers].map((ab) => ab.byteLength).reduce((a, b) => a + b);
+ assert(retainedMemory / (N * content.length) <= 3,
+ `Retaining ${retainedMemory} bytes in ABs for ${N} ` +
+ `chunks of size ${content.length}`);
+ }
+ }));
+}
+
+// Don’t start the reads all at once – that way we would have to allocate
+// a large amount of memory upfront.
+for (let i = 0; i < 6; ++i)
+ startRead();
diff --git a/tests/node_compat/test/parallel/test-fs-read-stream-double-close.js b/tests/node_compat/test/parallel/test-fs-read-stream-double-close.js
new file mode 100644
index 000000000..1706dd515
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-read-stream-double-close.js
@@ -0,0 +1,26 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const fs = require('fs');
+
+{
+ const s = fs.createReadStream(__filename);
+
+ s.close(common.mustCall());
+ s.close(common.mustCall());
+}
+
+{
+ const s = fs.createReadStream(__filename);
+
+ // This is a private API, but it is worth testing. close calls this
+ s.destroy(null, common.mustCall());
+ s.destroy(null, common.mustCall());
+}
diff --git a/tests/node_compat/test/parallel/test-fs-read-stream-encoding.js b/tests/node_compat/test/parallel/test-fs-read-stream-encoding.js
new file mode 100644
index 000000000..c3adee739
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-read-stream-encoding.js
@@ -0,0 +1,24 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+const fs = require('fs');
+const stream = require('stream');
+const fixtures = require('../common/fixtures');
+const encoding = 'base64';
+
+const example = fixtures.path('x.txt');
+const assertStream = new stream.Writable({
+ write: function(chunk, enc, next) {
+ const expected = Buffer.from('xyz');
+ assert(chunk.equals(expected));
+ }
+});
+assertStream.setDefaultEncoding(encoding);
+fs.createReadStream(example, encoding).pipe(assertStream);
diff --git a/tests/node_compat/test/parallel/test-fs-read-stream-fd.js b/tests/node_compat/test/parallel/test-fs-read-stream-fd.js
new file mode 100644
index 000000000..467c48b8d
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-read-stream-fd.js
@@ -0,0 +1,53 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const fs = require('fs');
+const assert = require('assert');
+const path = require('path');
+const tmpdir = require('../common/tmpdir');
+const file = path.join(tmpdir.path, '/read_stream_fd_test.txt');
+const input = 'hello world';
+
+let output = '';
+tmpdir.refresh();
+fs.writeFileSync(file, input);
+
+const fd = fs.openSync(file, 'r');
+const stream = fs.createReadStream(null, { fd: fd, encoding: 'utf8' });
+
+assert.strictEqual(stream.path, undefined);
+
+stream.on('data', common.mustCallAtLeast((data) => {
+ output += data;
+}));
+
+process.on('exit', () => {
+ assert.strictEqual(output, input);
+});
diff --git a/tests/node_compat/test/parallel/test-fs-read-stream-inherit.js b/tests/node_compat/test/parallel/test-fs-read-stream-inherit.js
new file mode 100644
index 000000000..2de42ffb5
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-read-stream-inherit.js
@@ -0,0 +1,212 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+
+const assert = require('assert');
+const fs = require('fs');
+const fixtures = require('../common/fixtures');
+
+const fn = fixtures.path('elipses.txt');
+const rangeFile = fixtures.path('x.txt');
+
+{
+ let paused = false;
+
+ const file = fs.ReadStream(fn);
+
+ file.on('open', common.mustCall(function(fd) {
+ file.length = 0;
+ assert.strictEqual(typeof fd, 'number');
+ assert.ok(file.readable);
+
+ // GH-535
+ file.pause();
+ file.resume();
+ file.pause();
+ file.resume();
+ }));
+
+ file.on('data', common.mustCallAtLeast(function(data) {
+ assert.ok(data instanceof Buffer);
+ assert.ok(!paused);
+ file.length += data.length;
+
+ paused = true;
+ file.pause();
+
+ setTimeout(function() {
+ paused = false;
+ file.resume();
+ }, 10);
+ }));
+
+
+ file.on('end', common.mustCall());
+
+
+ file.on('close', common.mustCall(function() {
+ assert.strictEqual(file.length, 30000);
+ }));
+}
+
+{
+ const file = fs.createReadStream(fn, Object.create({ encoding: 'utf8' }));
+ file.length = 0;
+ file.on('data', function(data) {
+ assert.strictEqual(typeof data, 'string');
+ file.length += data.length;
+
+ for (let i = 0; i < data.length; i++) {
+ // http://www.fileformat.info/info/unicode/char/2026/index.htm
+ assert.strictEqual(data[i], '\u2026');
+ }
+ });
+
+ file.on('close', common.mustCall(function() {
+ assert.strictEqual(file.length, 10000);
+ }));
+}
+
+{
+ const options = Object.create({ bufferSize: 1, start: 1, end: 2 });
+ const file = fs.createReadStream(rangeFile, options);
+ assert.strictEqual(file.start, 1);
+ assert.strictEqual(file.end, 2);
+ let contentRead = '';
+ file.on('data', function(data) {
+ contentRead += data.toString('utf-8');
+ });
+ file.on('end', common.mustCall(function() {
+ assert.strictEqual(contentRead, 'yz');
+ }));
+}
+
+{
+ const options = Object.create({ bufferSize: 1, start: 1 });
+ const file = fs.createReadStream(rangeFile, options);
+ assert.strictEqual(file.start, 1);
+ file.data = '';
+ file.on('data', function(data) {
+ file.data += data.toString('utf-8');
+ });
+ file.on('end', common.mustCall(function() {
+ assert.strictEqual(file.data, 'yz\n');
+ }));
+}
+
+// https://github.com/joyent/node/issues/2320
+{
+ const options = Object.create({ bufferSize: 1.23, start: 1 });
+ const file = fs.createReadStream(rangeFile, options);
+ assert.strictEqual(file.start, 1);
+ file.data = '';
+ file.on('data', function(data) {
+ file.data += data.toString('utf-8');
+ });
+ file.on('end', common.mustCall(function() {
+ assert.strictEqual(file.data, 'yz\n');
+ }));
+}
+
+{
+ const message =
+ 'The value of "start" is out of range. It must be <= "end" (here: 2).' +
+ ' Received 10';
+
+ assert.throws(
+ () => {
+ fs.createReadStream(rangeFile, Object.create({ start: 10, end: 2 }));
+ },
+ {
+ code: 'ERR_OUT_OF_RANGE',
+ message,
+ name: 'RangeError'
+ });
+}
+
+{
+ const options = Object.create({ start: 0, end: 0 });
+ const stream = fs.createReadStream(rangeFile, options);
+ assert.strictEqual(stream.start, 0);
+ assert.strictEqual(stream.end, 0);
+ stream.data = '';
+
+ stream.on('data', function(chunk) {
+ stream.data += chunk;
+ });
+
+ stream.on('end', common.mustCall(function() {
+ assert.strictEqual(stream.data, 'x');
+ }));
+}
+
+// Pause and then resume immediately.
+{
+ const pauseRes = fs.createReadStream(rangeFile);
+ pauseRes.pause();
+ pauseRes.resume();
+}
+
+{
+ let data = '';
+ let file =
+ fs.createReadStream(rangeFile, Object.create({ autoClose: false }));
+ assert.strictEqual(file.autoClose, false);
+ file.on('data', (chunk) => { data += chunk; });
+ file.on('end', common.mustCall(function() {
+ process.nextTick(common.mustCall(function() {
+ assert(!file.closed);
+ assert(!file.destroyed);
+ assert.strictEqual(data, 'xyz\n');
+ fileNext();
+ }));
+ }));
+
+ function fileNext() {
+ // This will tell us if the fd is usable again or not.
+ file = fs.createReadStream(null, Object.create({ fd: file.fd, start: 0 }));
+ file.data = '';
+ file.on('data', function(data) {
+ file.data += data;
+ });
+ file.on('end', common.mustCall(function() {
+ assert.strictEqual(file.data, 'xyz\n');
+ }));
+ }
+ process.on('exit', function() {
+ assert(file.closed);
+ assert(file.destroyed);
+ });
+}
+
+// Just to make sure autoClose won't close the stream because of error.
+{
+ const options = Object.create({ fd: 13337, autoClose: false });
+ const file = fs.createReadStream(null, options);
+ file.on('data', common.mustNotCall());
+ file.on('error', common.mustCall());
+ process.on('exit', function() {
+ assert(!file.closed);
+ assert(!file.destroyed);
+ assert(file.fd);
+ });
+}
+
+// Make sure stream is destroyed when file does not exist.
+{
+ const file = fs.createReadStream('/path/to/file/that/does/not/exist');
+ file.on('data', common.mustNotCall());
+ file.on('error', common.mustCall());
+
+ process.on('exit', function() {
+ assert(file.closed);
+ assert(file.destroyed);
+ });
+}
diff --git a/tests/node_compat/test/parallel/test-fs-read-stream-patch-open.js b/tests/node_compat/test/parallel/test-fs-read-stream-patch-open.js
new file mode 100644
index 000000000..2f9788894
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-read-stream-patch-open.js
@@ -0,0 +1,24 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const fs = require('fs');
+
+common.expectWarning(
+ 'DeprecationWarning',
+ 'ReadStream.prototype.open() is deprecated', 'DEP0135');
+const s = fs.createReadStream('asd')
+ // We don't care about errors in this test.
+ .on('error', () => {});
+s.open();
+
+process.nextTick(() => {
+ // Allow overriding open().
+ fs.ReadStream.prototype.open = common.mustCall();
+ fs.createReadStream('asd');
+});
diff --git a/tests/node_compat/test/parallel/test-fs-read-stream-resume.js b/tests/node_compat/test/parallel/test-fs-read-stream-resume.js
new file mode 100644
index 000000000..50ec85603
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-read-stream-resume.js
@@ -0,0 +1,59 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const fixtures = require('../common/fixtures');
+const assert = require('assert');
+
+const fs = require('fs');
+
+const file = fixtures.path('x.txt');
+let data = '';
+let first = true;
+
+const stream = fs.createReadStream(file);
+stream.setEncoding('utf8');
+stream.on('data', common.mustCallAtLeast(function(chunk) {
+ data += chunk;
+ if (first) {
+ first = false;
+ stream.resume();
+ }
+}));
+
+process.nextTick(function() {
+ stream.pause();
+ setTimeout(function() {
+ stream.resume();
+ }, 100);
+});
+
+process.on('exit', function() {
+ assert.strictEqual(data, 'xyz\n');
+});
diff --git a/tests/node_compat/test/parallel/test-fs-read-stream-throw-type-error.js b/tests/node_compat/test/parallel/test-fs-read-stream-throw-type-error.js
new file mode 100644
index 000000000..4dda1150f
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-read-stream-throw-type-error.js
@@ -0,0 +1,84 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+require('../common');
+const fixtures = require('../common/fixtures');
+const assert = require('assert');
+const fs = require('fs');
+
+// This test ensures that appropriate TypeError is thrown by createReadStream
+// when an argument with invalid type is passed
+
+const example = fixtures.path('x.txt');
+// Should not throw.
+fs.createReadStream(example, undefined);
+fs.createReadStream(example, null);
+fs.createReadStream(example, 'utf8');
+fs.createReadStream(example, { encoding: 'utf8' });
+
+const createReadStreamErr = (path, opt, error) => {
+ assert.throws(() => {
+ fs.createReadStream(path, opt);
+ }, error);
+};
+
+const typeError = {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError'
+};
+
+const rangeError = {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError'
+};
+
+[123, 0, true, false].forEach((opts) =>
+ createReadStreamErr(example, opts, typeError)
+);
+
+// Case 0: Should not throw if either start or end is undefined
+[{}, { start: 0 }, { end: Infinity }].forEach((opts) =>
+ fs.createReadStream(example, opts)
+);
+
+// Case 1: Should throw TypeError if either start or end is not of type 'number'
+[
+ { start: 'invalid' },
+ { end: 'invalid' },
+ { start: 'invalid', end: 'invalid' },
+].forEach((opts) => createReadStreamErr(example, opts, typeError));
+
+// Case 2: Should throw RangeError if either start or end is NaN
+[{ start: NaN }, { end: NaN }, { start: NaN, end: NaN }].forEach((opts) =>
+ createReadStreamErr(example, opts, rangeError)
+);
+
+// Case 3: Should throw RangeError if either start or end is negative
+[{ start: -1 }, { end: -1 }, { start: -1, end: -1 }].forEach((opts) =>
+ createReadStreamErr(example, opts, rangeError)
+);
+
+// Case 4: Should throw RangeError if either start or end is fractional
+[{ start: 0.1 }, { end: 0.1 }, { start: 0.1, end: 0.1 }].forEach((opts) =>
+ createReadStreamErr(example, opts, rangeError)
+);
+
+// Case 5: Should not throw if both start and end are whole numbers
+fs.createReadStream(example, { start: 1, end: 5 });
+
+// Case 6: Should throw RangeError if start is greater than end
+createReadStreamErr(example, { start: 5, end: 1 }, rangeError);
+
+// Case 7: Should throw RangeError if start or end is not safe integer
+const NOT_SAFE_INTEGER = 2 ** 53;
+[
+ { start: NOT_SAFE_INTEGER, end: Infinity },
+ { start: 0, end: NOT_SAFE_INTEGER },
+].forEach((opts) =>
+ createReadStreamErr(example, opts, rangeError)
+);
diff --git a/tests/node_compat/test/parallel/test-fs-read-stream.js b/tests/node_compat/test/parallel/test-fs-read-stream.js
new file mode 100644
index 000000000..e42347264
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-read-stream.js
@@ -0,0 +1,284 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const tmpdir = require('../common/tmpdir');
+
+const child_process = require('child_process');
+const assert = require('assert');
+const fs = require('fs');
+const fixtures = require('../common/fixtures');
+
+const fn = fixtures.path('elipses.txt');
+const rangeFile = fixtures.path('x.txt');
+
+function test1(options) {
+ let paused = false;
+ let bytesRead = 0;
+
+ const file = fs.createReadStream(fn, options);
+ const fileSize = fs.statSync(fn).size;
+
+ assert.strictEqual(file.bytesRead, 0);
+
+ file.on('open', common.mustCall(function(fd) {
+ file.length = 0;
+ assert.strictEqual(typeof fd, 'number');
+ assert.strictEqual(file.bytesRead, 0);
+ assert.ok(file.readable);
+
+ // GH-535
+ file.pause();
+ file.resume();
+ file.pause();
+ file.resume();
+ }));
+
+ file.on('data', function(data) {
+ assert.ok(data instanceof Buffer);
+ assert.ok(data.byteOffset % 8 === 0);
+ assert.ok(!paused);
+ file.length += data.length;
+
+ bytesRead += data.length;
+ assert.strictEqual(file.bytesRead, bytesRead);
+
+ paused = true;
+ file.pause();
+
+ setTimeout(function() {
+ paused = false;
+ file.resume();
+ }, 10);
+ });
+
+
+ file.on('end', common.mustCall(function(chunk) {
+ assert.strictEqual(bytesRead, fileSize);
+ assert.strictEqual(file.bytesRead, fileSize);
+ }));
+
+
+ file.on('close', common.mustCall(function() {
+ assert.strictEqual(bytesRead, fileSize);
+ assert.strictEqual(file.bytesRead, fileSize);
+ }));
+
+ process.on('exit', function() {
+ assert.strictEqual(file.length, 30000);
+ });
+}
+
+test1({});
+test1({
+ fs: {
+ open: common.mustCall(fs.open),
+ read: common.mustCallAtLeast(fs.read, 1),
+ close: common.mustCall(fs.close),
+ }
+});
+
+{
+ const file = fs.createReadStream(fn, common.mustNotMutateObjectDeep({ encoding: 'utf8' }));
+ file.length = 0;
+ file.on('data', function(data) {
+ assert.strictEqual(typeof data, 'string');
+ file.length += data.length;
+
+ for (let i = 0; i < data.length; i++) {
+ // http://www.fileformat.info/info/unicode/char/2026/index.htm
+ assert.strictEqual(data[i], '\u2026');
+ }
+ });
+
+ file.on('close', common.mustCall());
+
+ process.on('exit', function() {
+ assert.strictEqual(file.length, 10000);
+ });
+}
+
+{
+ const file =
+ fs.createReadStream(rangeFile, common.mustNotMutateObjectDeep({ bufferSize: 1, start: 1, end: 2 }));
+ let contentRead = '';
+ file.on('data', function(data) {
+ contentRead += data.toString('utf-8');
+ });
+ file.on('end', common.mustCall(function(data) {
+ assert.strictEqual(contentRead, 'yz');
+ }));
+}
+
+{
+ const file = fs.createReadStream(rangeFile, common.mustNotMutateObjectDeep({ bufferSize: 1, start: 1 }));
+ file.data = '';
+ file.on('data', function(data) {
+ file.data += data.toString('utf-8');
+ });
+ file.on('end', common.mustCall(function() {
+ assert.strictEqual(file.data, 'yz\n');
+ }));
+}
+
+{
+ // Ref: https://github.com/nodejs/node-v0.x-archive/issues/2320
+ const file = fs.createReadStream(rangeFile, common.mustNotMutateObjectDeep({ bufferSize: 1.23, start: 1 }));
+ file.data = '';
+ file.on('data', function(data) {
+ file.data += data.toString('utf-8');
+ });
+ file.on('end', common.mustCall(function() {
+ assert.strictEqual(file.data, 'yz\n');
+ }));
+}
+
+assert.throws(
+ () => {
+ fs.createReadStream(rangeFile, common.mustNotMutateObjectDeep({ start: 10, end: 2 }));
+ },
+ {
+ code: 'ERR_OUT_OF_RANGE',
+ message: 'The value of "start" is out of range. It must be <= "end"' +
+ ' (here: 2). Received 10',
+ name: 'RangeError'
+ });
+
+{
+ const stream = fs.createReadStream(rangeFile, common.mustNotMutateObjectDeep({ start: 0, end: 0 }));
+ stream.data = '';
+
+ stream.on('data', function(chunk) {
+ stream.data += chunk;
+ });
+
+ stream.on('end', common.mustCall(function() {
+ assert.strictEqual(stream.data, 'x');
+ }));
+}
+
+{
+ // Verify that end works when start is not specified.
+ const stream = new fs.createReadStream(rangeFile, common.mustNotMutateObjectDeep({ end: 1 }));
+ stream.data = '';
+
+ stream.on('data', function(chunk) {
+ stream.data += chunk;
+ });
+
+ stream.on('end', common.mustCall(function() {
+ assert.strictEqual(stream.data, 'xy');
+ }));
+}
+
+if (!common.isWindows) {
+ // Verify that end works when start is not specified, and we do not try to
+ // use positioned reads. This makes sure that this keeps working for
+ // non-seekable file descriptors.
+ tmpdir.refresh();
+ const filename = `${tmpdir.path}/foo.pipe`;
+ const mkfifoResult = child_process.spawnSync('mkfifo', [filename]);
+ if (!mkfifoResult.error) {
+ child_process.exec(`echo "xyz foobar" > '${filename}'`);
+ const stream = new fs.createReadStream(filename, common.mustNotMutateObjectDeep({ end: 1 }));
+ stream.data = '';
+
+ stream.on('data', function(chunk) {
+ stream.data += chunk;
+ });
+
+ stream.on('end', common.mustCall(function() {
+ assert.strictEqual(stream.data, 'xy');
+ fs.unlinkSync(filename);
+ }));
+ } else {
+ common.printSkipMessage('mkfifo not available');
+ }
+}
+
+{
+ // Pause and then resume immediately.
+ const pauseRes = fs.createReadStream(rangeFile);
+ pauseRes.pause();
+ pauseRes.resume();
+}
+
+{
+ let file = fs.createReadStream(rangeFile, common.mustNotMutateObjectDeep({ autoClose: false }));
+ let data = '';
+ file.on('data', function(chunk) { data += chunk; });
+ file.on('end', common.mustCall(function() {
+ assert.strictEqual(data, 'xyz\n');
+ process.nextTick(function() {
+ assert(!file.closed);
+ assert(!file.destroyed);
+ fileNext();
+ });
+ }));
+
+ function fileNext() {
+ // This will tell us if the fd is usable again or not.
+ file = fs.createReadStream(null, common.mustNotMutateObjectDeep({ fd: file.fd, start: 0 }));
+ file.data = '';
+ file.on('data', function(data) {
+ file.data += data;
+ });
+ file.on('end', common.mustCall(function(err) {
+ assert.strictEqual(file.data, 'xyz\n');
+ }));
+ process.on('exit', function() {
+ assert(file.closed);
+ assert(file.destroyed);
+ });
+ }
+}
+
+{
+ // Just to make sure autoClose won't close the stream because of error.
+ const file = fs.createReadStream(null, common.mustNotMutateObjectDeep({ fd: 13337, autoClose: false }));
+ file.on('data', common.mustNotCall());
+ file.on('error', common.mustCall());
+ process.on('exit', function() {
+ assert(!file.closed);
+ assert(!file.destroyed);
+ assert(file.fd);
+ });
+}
+
+{
+ // Make sure stream is destroyed when file does not exist.
+ const file = fs.createReadStream('/path/to/file/that/does/not/exist');
+ file.on('data', common.mustNotCall());
+ file.on('error', common.mustCall());
+
+ process.on('exit', function() {
+ assert(file.closed);
+ assert(file.destroyed);
+ });
+}
diff --git a/tests/node_compat/test/parallel/test-fs-read-type.js b/tests/node_compat/test/parallel/test-fs-read-type.js
new file mode 100644
index 000000000..99321ce3e
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-read-type.js
@@ -0,0 +1,250 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const fs = require('fs');
+const assert = require('assert');
+const fixtures = require('../common/fixtures');
+
+const filepath = fixtures.path('x.txt');
+const fd = fs.openSync(filepath, 'r');
+const expected = 'xyz\n';
+
+
+// Error must be thrown with string
+assert.throws(
+ () => fs.read(fd, expected.length, 0, 'utf-8', common.mustNotCall()),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: 'The "buffer" argument must be an instance of Buffer, ' +
+ 'TypedArray, or DataView. Received type number (4)'
+ }
+);
+
+[true, null, undefined, () => {}, {}].forEach((value) => {
+ assert.throws(() => {
+ fs.read(value,
+ Buffer.allocUnsafe(expected.length),
+ 0,
+ expected.length,
+ 0,
+ common.mustNotCall());
+ }, {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError'
+ });
+});
+
+assert.throws(() => {
+ fs.read(fd,
+ Buffer.allocUnsafe(expected.length),
+ -1,
+ expected.length,
+ 0,
+ common.mustNotCall());
+}, {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError',
+});
+
+assert.throws(() => {
+ fs.read(fd,
+ Buffer.allocUnsafe(expected.length),
+ NaN,
+ expected.length,
+ 0,
+ common.mustNotCall());
+}, {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError',
+ message: 'The value of "offset" is out of range. It must be an integer. ' +
+ 'Received NaN'
+});
+
+assert.throws(() => {
+ fs.read(fd,
+ Buffer.allocUnsafe(expected.length),
+ 0,
+ -1,
+ 0,
+ common.mustNotCall());
+}, {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError',
+ message: 'The value of "length" is out of range. ' +
+ 'It must be >= 0. Received -1'
+});
+
+[true, () => {}, {}, ''].forEach((value) => {
+ assert.throws(() => {
+ fs.read(fd,
+ Buffer.allocUnsafe(expected.length),
+ 0,
+ expected.length,
+ value,
+ common.mustNotCall());
+ }, {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError'
+ });
+});
+
+[0.5, 2 ** 53, 2n ** 63n].forEach((value) => {
+ assert.throws(() => {
+ fs.read(fd,
+ Buffer.allocUnsafe(expected.length),
+ 0,
+ expected.length,
+ value,
+ common.mustNotCall());
+ }, {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError'
+ });
+});
+
+fs.read(fd,
+ Buffer.allocUnsafe(expected.length),
+ 0,
+ expected.length,
+ 0n,
+ common.mustSucceed());
+
+fs.read(fd,
+ Buffer.allocUnsafe(expected.length),
+ 0,
+ expected.length,
+ 2n ** 53n - 1n,
+ common.mustCall((err) => {
+ if (err) {
+ if (common.isIBMi)
+ assert.strictEqual(err.code, 'EOVERFLOW');
+ else
+ assert.strictEqual(err.code, 'EFBIG');
+ }
+ }));
+
+assert.throws(
+ () => fs.readSync(fd, expected.length, 0, 'utf-8'),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: 'The "buffer" argument must be an instance of Buffer, ' +
+ 'TypedArray, or DataView. Received type number (4)'
+ }
+);
+
+[true, null, undefined, () => {}, {}].forEach((value) => {
+ assert.throws(() => {
+ fs.readSync(value,
+ Buffer.allocUnsafe(expected.length),
+ 0,
+ expected.length,
+ 0);
+ }, {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError'
+ });
+});
+
+assert.throws(() => {
+ fs.readSync(fd,
+ Buffer.allocUnsafe(expected.length),
+ -1,
+ expected.length,
+ 0);
+}, {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError',
+});
+
+assert.throws(() => {
+ fs.readSync(fd,
+ Buffer.allocUnsafe(expected.length),
+ NaN,
+ expected.length,
+ 0);
+}, {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError',
+ message: 'The value of "offset" is out of range. It must be an integer. ' +
+ 'Received NaN'
+});
+
+assert.throws(() => {
+ fs.readSync(fd,
+ Buffer.allocUnsafe(expected.length),
+ 0,
+ -1,
+ 0);
+}, {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError',
+ message: 'The value of "length" is out of range. ' +
+ 'It must be >= 0. Received -1'
+});
+
+assert.throws(() => {
+ fs.readSync(fd,
+ Buffer.allocUnsafe(expected.length),
+ 0,
+ expected.length + 1,
+ 0);
+}, {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError',
+ message: 'The value of "length" is out of range. ' +
+ 'It must be <= 4. Received 5'
+});
+
+[true, () => {}, {}, ''].forEach((value) => {
+ assert.throws(() => {
+ fs.readSync(fd,
+ Buffer.allocUnsafe(expected.length),
+ 0,
+ expected.length,
+ value);
+ }, {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError'
+ });
+});
+
+[0.5, 2 ** 53, 2n ** 63n].forEach((value) => {
+ assert.throws(() => {
+ fs.readSync(fd,
+ Buffer.allocUnsafe(expected.length),
+ 0,
+ expected.length,
+ value);
+ }, {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError'
+ });
+});
+
+fs.readSync(fd,
+ Buffer.allocUnsafe(expected.length),
+ 0,
+ expected.length,
+ 0n);
+
+try {
+ fs.readSync(fd,
+ Buffer.allocUnsafe(expected.length),
+ 0,
+ expected.length,
+ 2n ** 53n - 1n);
+} catch (err) {
+ // On systems where max file size is below 2^53-1, we'd expect a EFBIG error.
+ // This is not using `assert.throws` because the above call should not raise
+ // any error on systems that allows file of that size.
+ if (err.code !== 'EFBIG' && !(common.isIBMi && err.code === 'EOVERFLOW'))
+ throw err;
+}
diff --git a/tests/node_compat/test/parallel/test-fs-read-zero-length.js b/tests/node_compat/test/parallel/test-fs-read-zero-length.js
new file mode 100644
index 000000000..3a7501073
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-read-zero-length.js
@@ -0,0 +1,25 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const fixtures = require('../common/fixtures');
+const assert = require('assert');
+const fs = require('fs');
+const filepath = fixtures.path('x.txt');
+const fd = fs.openSync(filepath, 'r');
+const bufferAsync = Buffer.alloc(0);
+const bufferSync = Buffer.alloc(0);
+
+fs.read(fd, bufferAsync, 0, 0, 0, common.mustCall((err, bytesRead) => {
+ assert.strictEqual(bytesRead, 0);
+ assert.deepStrictEqual(bufferAsync, Buffer.alloc(0));
+}));
+
+const r = fs.readSync(fd, bufferSync, 0, 0, 0);
+assert.deepStrictEqual(bufferSync, Buffer.alloc(0));
+assert.strictEqual(r, 0);
diff --git a/tests/node_compat/test/parallel/test-fs-read.js b/tests/node_compat/test/parallel/test-fs-read.js
new file mode 100644
index 000000000..2a7a286d9
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-read.js
@@ -0,0 +1,109 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const fixtures = require('../common/fixtures');
+const assert = require('assert');
+const fs = require('fs');
+const filepath = fixtures.path('x.txt');
+const fd = fs.openSync(filepath, 'r');
+
+const expected = Buffer.from('xyz\n');
+
+function test(bufferAsync, bufferSync, expected) {
+ fs.read(fd,
+ bufferAsync,
+ 0,
+ expected.length,
+ 0,
+ common.mustSucceed((bytesRead) => {
+ assert.strictEqual(bytesRead, expected.length);
+ assert.deepStrictEqual(bufferAsync, expected);
+ }));
+
+ const r = fs.readSync(fd, bufferSync, 0, expected.length, 0);
+ assert.deepStrictEqual(bufferSync, expected);
+ assert.strictEqual(r, expected.length);
+}
+
+test(Buffer.allocUnsafe(expected.length),
+ Buffer.allocUnsafe(expected.length),
+ expected);
+
+test(new Uint8Array(expected.length),
+ new Uint8Array(expected.length),
+ Uint8Array.from(expected));
+
+{
+ // Reading beyond file length (3 in this case) should return no data.
+ // This is a test for a bug where reads > uint32 would return data
+ // from the current position in the file.
+ const pos = 0xffffffff + 1; // max-uint32 + 1
+ const nRead = fs.readSync(fd, Buffer.alloc(1), 0, 1, pos);
+ assert.strictEqual(nRead, 0);
+
+ fs.read(fd, Buffer.alloc(1), 0, 1, pos, common.mustSucceed((nRead) => {
+ assert.strictEqual(nRead, 0);
+ }));
+}
+
+assert.throws(() => new fs.Dir(), {
+ code: 'ERR_MISSING_ARGS',
+});
+
+assert.throws(
+ () => fs.read(fd, Buffer.alloc(1), 0, 1, 0),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ }
+);
+
+assert.throws(
+ () => fs.read(fd, { buffer: null }, common.mustNotCall()),
+ /TypeError: Cannot read properties of null \(reading 'byteLength'\)/,
+ 'throws when options.buffer is null'
+);
+
+assert.throws(
+ () => fs.readSync(fd, { buffer: null }),
+ {
+ name: 'TypeError',
+ message: 'The "buffer" argument must be an instance of Buffer, ' +
+ 'TypedArray, or DataView. Received an instance of Object',
+ },
+ 'throws when options.buffer is null'
+);
+
+assert.throws(
+ () => fs.read(null, Buffer.alloc(1), 0, 1, 0),
+ {
+ message: 'The "fd" argument must be of type number. Received null',
+ code: 'ERR_INVALID_ARG_TYPE',
+ }
+);
diff --git a/tests/node_compat/test/parallel/test-fs-readdir-stack-overflow.js b/tests/node_compat/test/parallel/test-fs-readdir-stack-overflow.js
new file mode 100644
index 000000000..1a60f9a71
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-readdir-stack-overflow.js
@@ -0,0 +1,26 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+require('../common');
+
+const assert = require('assert');
+const fs = require('fs');
+
+function recurse() {
+ fs.readdirSync('.');
+ recurse();
+}
+
+assert.throws(
+ () => recurse(),
+ {
+ name: 'RangeError',
+ message: 'Maximum call stack size exceeded'
+ }
+);
diff --git a/tests/node_compat/test/parallel/test-fs-readdir.js b/tests/node_compat/test/parallel/test-fs-readdir.js
new file mode 100644
index 000000000..768162fe2
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-readdir.js
@@ -0,0 +1,60 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const assert = require('assert');
+const fs = require('fs');
+
+const tmpdir = require('../common/tmpdir');
+
+const readdirDir = tmpdir.path;
+const files = ['empty', 'files', 'for', 'just', 'testing'];
+
+// Make sure tmp directory is clean
+tmpdir.refresh();
+
+// Create the necessary files
+files.forEach(function(currentFile) {
+ fs.closeSync(fs.openSync(`${readdirDir}/${currentFile}`, 'w'));
+});
+
+// Check the readdir Sync version
+assert.deepStrictEqual(files, fs.readdirSync(readdirDir).sort());
+
+// Check the readdir async version
+fs.readdir(readdirDir, common.mustSucceed((f) => {
+ assert.deepStrictEqual(files, f.sort());
+}));
+
+// readdir() on file should throw ENOTDIR
+// https://github.com/joyent/node/issues/1869
+assert.throws(function() {
+ fs.readdirSync(__filename);
+}, /Error: ENOTDIR: not a directory/);
+
+fs.readdir(__filename, common.mustCall(function(e) {
+ assert.strictEqual(e.code, 'ENOTDIR');
+}));
+
+[false, 1, [], {}, null, undefined].forEach((i) => {
+ assert.throws(
+ () => fs.readdir(i, common.mustNotCall()),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError'
+ }
+ );
+ assert.throws(
+ () => fs.readdirSync(i),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError'
+ }
+ );
+});
diff --git a/tests/node_compat/test/parallel/test-fs-readfile-empty.js b/tests/node_compat/test/parallel/test-fs-readfile-empty.js
new file mode 100644
index 000000000..15f08ef8c
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-readfile-empty.js
@@ -0,0 +1,52 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+
+// Trivial test of fs.readFile on an empty file.
+const common = require('../common');
+const fs = require('fs');
+const assert = require('assert');
+const fixtures = require('../common/fixtures');
+
+const fn = fixtures.path('empty.txt');
+
+fs.readFile(fn, common.mustCall((err, data) => {
+ assert.ok(data);
+}));
+
+fs.readFile(fn, 'utf8', common.mustCall((err, data) => {
+ assert.strictEqual(data, '');
+}));
+
+fs.readFile(fn, { encoding: 'utf8' }, common.mustCall((err, data) => {
+ assert.strictEqual(data, '');
+}));
+
+assert.ok(fs.readFileSync(fn));
+assert.strictEqual(fs.readFileSync(fn, 'utf8'), '');
diff --git a/tests/node_compat/test/parallel/test-fs-realpath-native.js b/tests/node_compat/test/parallel/test-fs-realpath-native.js
new file mode 100644
index 000000000..13e5b48cb
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-realpath-native.js
@@ -0,0 +1,25 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const fs = require('fs');
+
+const filename = __filename.toLowerCase();
+
+assert.strictEqual(
+ fs.realpathSync.native('./test/parallel/test-fs-realpath-native.js')
+ .toLowerCase(),
+ filename);
+
+fs.realpath.native(
+ './test/parallel/test-fs-realpath-native.js',
+ common.mustSucceed(function(res) {
+ assert.strictEqual(res.toLowerCase(), filename);
+ assert.strictEqual(this, undefined);
+ }));
diff --git a/tests/node_compat/test/parallel/test-fs-rmdir-recursive-sync-warns-not-found.js b/tests/node_compat/test/parallel/test-fs-rmdir-recursive-sync-warns-not-found.js
new file mode 100644
index 000000000..92ca59255
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-rmdir-recursive-sync-warns-not-found.js
@@ -0,0 +1,30 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const tmpdir = require('../common/tmpdir');
+const assert = require('assert');
+const fs = require('fs');
+const path = require('path');
+
+tmpdir.refresh();
+
+{
+ // Should warn when trying to delete a nonexistent path
+ common.expectWarning(
+ 'DeprecationWarning',
+ 'In future versions of Node.js, fs.rmdir(path, { recursive: true }) ' +
+ 'will be removed. Use fs.rm(path, { recursive: true }) instead',
+ 'DEP0147'
+ );
+ assert.throws(
+ () => fs.rmdirSync(path.join(tmpdir.path, 'noexist.txt'),
+ { recursive: true }),
+ { code: 'ENOENT' }
+ );
+}
diff --git a/tests/node_compat/test/parallel/test-fs-rmdir-recursive-sync-warns-on-file.js b/tests/node_compat/test/parallel/test-fs-rmdir-recursive-sync-warns-on-file.js
new file mode 100644
index 000000000..95703b99f
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-rmdir-recursive-sync-warns-on-file.js
@@ -0,0 +1,30 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const tmpdir = require('../common/tmpdir');
+const assert = require('assert');
+const fs = require('fs');
+const path = require('path');
+
+tmpdir.refresh();
+
+{
+ common.expectWarning(
+ 'DeprecationWarning',
+ 'In future versions of Node.js, fs.rmdir(path, { recursive: true }) ' +
+ 'will be removed. Use fs.rm(path, { recursive: true }) instead',
+ 'DEP0147'
+ );
+ const filePath = path.join(tmpdir.path, 'rmdir-recursive.txt');
+ fs.writeFileSync(filePath, '');
+ assert.throws(
+ () => fs.rmdirSync(filePath, { recursive: true }),
+ { code: common.isWindows ? 'ENOENT' : 'ENOTDIR' }
+ );
+}
diff --git a/tests/node_compat/test/parallel/test-fs-rmdir-recursive-throws-not-found.js b/tests/node_compat/test/parallel/test-fs-rmdir-recursive-throws-not-found.js
new file mode 100644
index 000000000..9a6d584d9
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-rmdir-recursive-throws-not-found.js
@@ -0,0 +1,43 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const tmpdir = require('../common/tmpdir');
+const assert = require('assert');
+const fs = require('fs');
+const path = require('path');
+
+tmpdir.refresh();
+
+{
+ assert.throws(
+ () =>
+ fs.rmdirSync(path.join(tmpdir.path, 'noexist.txt'), { recursive: true }),
+ {
+ code: 'ENOENT',
+ }
+ );
+}
+{
+ fs.rmdir(
+ path.join(tmpdir.path, 'noexist.txt'),
+ { recursive: true },
+ common.mustCall((err) => {
+ assert.strictEqual(err.code, 'ENOENT');
+ })
+ );
+}
+{
+ assert.rejects(
+ () => fs.promises.rmdir(path.join(tmpdir.path, 'noexist.txt'),
+ { recursive: true }),
+ {
+ code: 'ENOENT',
+ }
+ ).then(common.mustCall());
+}
diff --git a/tests/node_compat/test/parallel/test-fs-rmdir-recursive-throws-on-file.js b/tests/node_compat/test/parallel/test-fs-rmdir-recursive-throws-on-file.js
new file mode 100644
index 000000000..4dc27ab8f
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-rmdir-recursive-throws-on-file.js
@@ -0,0 +1,36 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const tmpdir = require('../common/tmpdir');
+const assert = require('assert');
+const fs = require('fs');
+const path = require('path');
+
+tmpdir.refresh();
+
+const code = common.isWindows ? 'ENOENT' : 'ENOTDIR';
+
+{
+ const filePath = path.join(tmpdir.path, 'rmdir-recursive.txt');
+ fs.writeFileSync(filePath, '');
+ assert.throws(() => fs.rmdirSync(filePath, { recursive: true }), { code });
+}
+{
+ const filePath = path.join(tmpdir.path, 'rmdir-recursive.txt');
+ fs.writeFileSync(filePath, '');
+ fs.rmdir(filePath, { recursive: true }, common.mustCall((err) => {
+ assert.strictEqual(err.code, code);
+ }));
+}
+{
+ const filePath = path.join(tmpdir.path, 'rmdir-recursive.txt');
+ fs.writeFileSync(filePath, '');
+ assert.rejects(() => fs.promises.rmdir(filePath, { recursive: true }),
+ { code }).then(common.mustCall());
+}
diff --git a/tests/node_compat/test/parallel/test-fs-rmdir-recursive-warns-not-found.js b/tests/node_compat/test/parallel/test-fs-rmdir-recursive-warns-not-found.js
new file mode 100644
index 000000000..3e9564ec1
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-rmdir-recursive-warns-not-found.js
@@ -0,0 +1,29 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const tmpdir = require('../common/tmpdir');
+const fs = require('fs');
+const path = require('path');
+
+tmpdir.refresh();
+
+{
+ // Should warn when trying to delete a nonexistent path
+ common.expectWarning(
+ 'DeprecationWarning',
+ 'In future versions of Node.js, fs.rmdir(path, { recursive: true }) ' +
+ 'will be removed. Use fs.rm(path, { recursive: true }) instead',
+ 'DEP0147'
+ );
+ fs.rmdir(
+ path.join(tmpdir.path, 'noexist.txt'),
+ { recursive: true },
+ common.mustCall()
+ );
+}
diff --git a/tests/node_compat/test/parallel/test-fs-rmdir-recursive-warns-on-file.js b/tests/node_compat/test/parallel/test-fs-rmdir-recursive-warns-on-file.js
new file mode 100644
index 000000000..99644e639
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-rmdir-recursive-warns-on-file.js
@@ -0,0 +1,29 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const tmpdir = require('../common/tmpdir');
+const assert = require('assert');
+const fs = require('fs');
+const path = require('path');
+
+tmpdir.refresh();
+
+{
+ common.expectWarning(
+ 'DeprecationWarning',
+ 'In future versions of Node.js, fs.rmdir(path, { recursive: true }) ' +
+ 'will be removed. Use fs.rm(path, { recursive: true }) instead',
+ 'DEP0147'
+ );
+ const filePath = path.join(tmpdir.path, 'rmdir-recursive.txt');
+ fs.writeFileSync(filePath, '');
+ fs.rmdir(filePath, { recursive: true }, common.mustCall((err) => {
+ assert.strictEqual(err.code, common.isWindows ? 'ENOENT' : 'ENOTDIR');
+ }));
+}
diff --git a/tests/node_compat/test/parallel/test-fs-rmdir-recursive.js b/tests/node_compat/test/parallel/test-fs-rmdir-recursive.js
new file mode 100644
index 000000000..31bde4487
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-rmdir-recursive.js
@@ -0,0 +1,252 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 16.13.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// Flags: --expose-internals
+'use strict';
+const common = require('../common');
+const tmpdir = require('../common/tmpdir');
+const assert = require('assert');
+const fs = require('fs');
+const path = require('path');
+const { validateRmdirOptions } = require('internal/fs/utils');
+
+common.expectWarning(
+ 'DeprecationWarning',
+ 'In future versions of Node.js, fs.rmdir(path, { recursive: true }) ' +
+ 'will be removed. Use fs.rm(path, { recursive: true }) instead',
+ 'DEP0147'
+);
+
+tmpdir.refresh();
+
+let count = 0;
+const nextDirPath = (name = 'rmdir-recursive') =>
+ path.join(tmpdir.path, `${name}-${count++}`);
+
+function makeNonEmptyDirectory(depth, files, folders, dirname, createSymLinks) {
+ fs.mkdirSync(dirname, { recursive: true });
+ fs.writeFileSync(path.join(dirname, 'text.txt'), 'hello', 'utf8');
+
+ const options = { flag: 'wx' };
+
+ for (let f = files; f > 0; f--) {
+ fs.writeFileSync(path.join(dirname, `f-${depth}-${f}`), '', options);
+ }
+
+ if (createSymLinks) {
+ // Valid symlink
+ fs.symlinkSync(
+ `f-${depth}-1`,
+ path.join(dirname, `link-${depth}-good`),
+ 'file'
+ );
+
+ // Invalid symlink
+ fs.symlinkSync(
+ 'does-not-exist',
+ path.join(dirname, `link-${depth}-bad`),
+ 'file'
+ );
+ }
+
+ // File with a name that looks like a glob
+ fs.writeFileSync(path.join(dirname, '[a-z0-9].txt'), '', options);
+
+ depth--;
+ if (depth <= 0) {
+ return;
+ }
+
+ for (let f = folders; f > 0; f--) {
+ fs.mkdirSync(
+ path.join(dirname, `folder-${depth}-${f}`),
+ { recursive: true }
+ );
+ makeNonEmptyDirectory(
+ depth,
+ files,
+ folders,
+ path.join(dirname, `d-${depth}-${f}`),
+ createSymLinks
+ );
+ }
+}
+
+function removeAsync(dir) {
+ // Removal should fail without the recursive option.
+ fs.rmdir(dir, common.mustCall((err) => {
+ assert.strictEqual(err.syscall, 'rmdir');
+
+ // Removal should fail without the recursive option set to true.
+ fs.rmdir(dir, { recursive: false }, common.mustCall((err) => {
+ assert.strictEqual(err.syscall, 'rmdir');
+
+ // Recursive removal should succeed.
+ fs.rmdir(dir, { recursive: true }, common.mustSucceed(() => {
+ // An error should occur if recursive and the directory does not exist.
+ fs.rmdir(dir, { recursive: true }, common.mustCall((err) => {
+ assert.strictEqual(err.code, 'ENOENT');
+ // Attempted removal should fail now because the directory is gone.
+ fs.rmdir(dir, common.mustCall((err) => {
+ assert.strictEqual(err.syscall, 'rmdir');
+ }));
+ }));
+ }));
+ }));
+ }));
+}
+
+// Test the asynchronous version
+{
+ // Create a 4-level folder hierarchy including symlinks
+ let dir = nextDirPath();
+ makeNonEmptyDirectory(4, 10, 2, dir, true);
+ removeAsync(dir);
+
+ // Create a 2-level folder hierarchy without symlinks
+ dir = nextDirPath();
+ makeNonEmptyDirectory(2, 10, 2, dir, false);
+ removeAsync(dir);
+
+ // Create a flat folder including symlinks
+ dir = nextDirPath();
+ makeNonEmptyDirectory(1, 10, 2, dir, true);
+ removeAsync(dir);
+}
+
+// Test the synchronous version.
+{
+ const dir = nextDirPath();
+ makeNonEmptyDirectory(4, 10, 2, dir, true);
+
+ // Removal should fail without the recursive option set to true.
+ assert.throws(() => {
+ fs.rmdirSync(dir);
+ }, { syscall: 'rmdir' });
+ assert.throws(() => {
+ fs.rmdirSync(dir, { recursive: false });
+ }, { syscall: 'rmdir' });
+
+ // Recursive removal should succeed.
+ fs.rmdirSync(dir, { recursive: true });
+
+ // An error should occur if recursive and the directory does not exist.
+ assert.throws(() => fs.rmdirSync(dir, { recursive: true }),
+ { code: 'ENOENT' });
+
+ // Attempted removal should fail now because the directory is gone.
+ assert.throws(() => fs.rmdirSync(dir), { syscall: 'rmdir' });
+}
+
+// Test the Promises based version.
+(async () => {
+ const dir = nextDirPath();
+ makeNonEmptyDirectory(4, 10, 2, dir, true);
+
+ // Removal should fail without the recursive option set to true.
+ assert.rejects(fs.promises.rmdir(dir), { syscall: 'rmdir' });
+ assert.rejects(fs.promises.rmdir(dir, { recursive: false }), {
+ syscall: 'rmdir'
+ });
+
+ // Recursive removal should succeed.
+ await fs.promises.rmdir(dir, { recursive: true });
+
+ // An error should occur if recursive and the directory does not exist.
+ await assert.rejects(fs.promises.rmdir(dir, { recursive: true }),
+ { code: 'ENOENT' });
+
+ // Attempted removal should fail now because the directory is gone.
+ assert.rejects(fs.promises.rmdir(dir), { syscall: 'rmdir' });
+})().then(common.mustCall());
+
+// Test input validation.
+{
+ const defaults = {
+ retryDelay: 100,
+ maxRetries: 0,
+ recursive: false
+ };
+ const modified = {
+ retryDelay: 953,
+ maxRetries: 5,
+ recursive: true
+ };
+
+ assert.deepStrictEqual(validateRmdirOptions(), defaults);
+ assert.deepStrictEqual(validateRmdirOptions({}), defaults);
+ assert.deepStrictEqual(validateRmdirOptions(modified), modified);
+ assert.deepStrictEqual(validateRmdirOptions({
+ maxRetries: 99
+ }), {
+ retryDelay: 100,
+ maxRetries: 99,
+ recursive: false
+ });
+
+ [null, 'foo', 5, NaN].forEach((bad) => {
+ assert.throws(() => {
+ validateRmdirOptions(bad);
+ }, {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: /^The "options" argument must be of type object\./
+ });
+ });
+
+ [undefined, null, 'foo', Infinity, function() {}].forEach((bad) => {
+ assert.throws(() => {
+ validateRmdirOptions({ recursive: bad });
+ }, {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: /^The "options\.recursive" property must be of type boolean\./
+ });
+ });
+
+ assert.throws(() => {
+ validateRmdirOptions({ retryDelay: -1 });
+ }, {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError',
+ message: /^The value of "options\.retryDelay" is out of range\./
+ });
+
+ assert.throws(() => {
+ validateRmdirOptions({ maxRetries: -1 });
+ }, {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError',
+ message: /^The value of "options\.maxRetries" is out of range\./
+ });
+}
+
+// FIXME(f3n67u): make this test pass
+// It should not pass recursive option to rmdirSync, when called from
+// rimraf (see: #35566)
+// {
+// // Make a non-empty directory:
+// const original = fs.rmdirSync;
+// const dir = `${nextDirPath()}/foo/bar`;
+// fs.mkdirSync(dir, { recursive: true });
+// fs.writeFileSync(`${dir}/foo.txt`, 'hello world', 'utf8');
+
+// // When called the second time from rimraf, the recursive option should
+// // not be set for rmdirSync:
+// let callCount = 0;
+// let rmdirSyncOptionsFromRimraf;
+// fs.rmdirSync = (path, options) => {
+// if (callCount > 0) {
+// rmdirSyncOptionsFromRimraf = { ...options };
+// }
+// callCount++;
+// return original(path, options);
+// };
+// fs.rmdirSync(dir, { recursive: true });
+// fs.rmdirSync = original;
+// assert.strictEqual(rmdirSyncOptionsFromRimraf.recursive, undefined);
+// }
diff --git a/tests/node_compat/test/parallel/test-fs-rmdir-type-check.js b/tests/node_compat/test/parallel/test-fs-rmdir-type-check.js
new file mode 100644
index 000000000..0ebfdacaf
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-rmdir-type-check.js
@@ -0,0 +1,29 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const assert = require('assert');
+const fs = require('fs');
+
+[false, 1, [], {}, null, undefined].forEach((i) => {
+ assert.throws(
+ () => fs.rmdir(i, common.mustNotCall()),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError'
+ }
+ );
+ assert.throws(
+ () => fs.rmdirSync(i),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError'
+ }
+ );
+});
diff --git a/tests/node_compat/test/parallel/test-fs-watchfile.js b/tests/node_compat/test/parallel/test-fs-watchfile.js
new file mode 100644
index 000000000..3a77fb56d
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-watchfile.js
@@ -0,0 +1,112 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+
+const assert = require('assert');
+const fs = require('fs');
+const path = require('path');
+
+const tmpdir = require('../common/tmpdir');
+
+// Basic usage tests.
+assert.throws(
+ () => {
+ fs.watchFile('./some-file');
+ },
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError'
+ });
+
+assert.throws(
+ () => {
+ fs.watchFile('./another-file', {}, 'bad listener');
+ },
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError'
+ });
+
+assert.throws(() => {
+ fs.watchFile(new Object(), common.mustNotCall());
+}, { code: 'ERR_INVALID_ARG_TYPE', name: 'TypeError' });
+
+const enoentFile = path.join(tmpdir.path, 'non-existent-file');
+const expectedStatObject = new fs.Stats(
+ 0, // dev
+ 0, // mode
+ 0, // nlink
+ 0, // uid
+ 0, // gid
+ 0, // rdev
+ 0, // blksize
+ 0, // ino
+ 0, // size
+ 0, // blocks
+ Date.UTC(1970, 0, 1, 0, 0, 0), // atime
+ Date.UTC(1970, 0, 1, 0, 0, 0), // mtime
+ Date.UTC(1970, 0, 1, 0, 0, 0), // ctime
+ Date.UTC(1970, 0, 1, 0, 0, 0) // birthtime
+);
+
+tmpdir.refresh();
+
+// If the file initially didn't exist, and gets created at a later point of
+// time, the callback should be invoked again with proper values in stat object
+let fileExists = false;
+
+const watcher =
+ fs.watchFile(enoentFile, { interval: 0 }, common.mustCall((curr, prev) => {
+ if (!fileExists) {
+ // If the file does not exist, all the fields should be zero and the date
+ // fields should be UNIX EPOCH time
+ assert.deepStrictEqual(curr, expectedStatObject);
+ assert.deepStrictEqual(prev, expectedStatObject);
+ // Create the file now, so that the callback will be called back once the
+ // event loop notices it.
+ fs.closeSync(fs.openSync(enoentFile, 'w'));
+ fileExists = true;
+ } else {
+ // If the ino (inode) value is greater than zero, it means that the file
+ // is present in the filesystem and it has a valid inode number.
+ assert(curr.ino > 0);
+ // As the file just got created, previous ino value should be lesser than
+ // or equal to zero (non-existent file).
+ assert(prev.ino <= 0);
+ // Stop watching the file
+ fs.unwatchFile(enoentFile);
+ watcher.stop(); // Stopping a stopped watcher should be a noop
+ }
+ }, 2));
+
+// 'stop' should only be emitted once - stopping a stopped watcher should
+// not trigger a 'stop' event.
+watcher.on('stop', common.mustCall());
+
+// Watch events should callback with a filename on supported systems.
+// Omitting AIX. It works but not reliably.
+if (common.isLinux || common.isOSX || common.isWindows) {
+ const dir = path.join(tmpdir.path, 'watch');
+
+ fs.mkdir(dir, common.mustCall(function(err) {
+ if (err) assert.fail(err);
+
+ fs.watch(dir, common.mustCall(function(eventType, filename) {
+ clearInterval(interval);
+ this._handle.close();
+ assert.strictEqual(filename, 'foo.txt');
+ }));
+
+ const interval = setInterval(() => {
+ fs.writeFile(path.join(dir, 'foo.txt'), 'foo', common.mustCall((err) => {
+ if (err) assert.fail(err);
+ }));
+ }, 1);
+ }));
+}
diff --git a/tests/node_compat/test/parallel/test-fs-write-buffer.js b/tests/node_compat/test/parallel/test-fs-write-buffer.js
new file mode 100644
index 000000000..16577a8f2
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-write-buffer.js
@@ -0,0 +1,172 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const path = require('path');
+const fs = require('fs');
+const expected = Buffer.from('hello');
+
+const tmpdir = require('../common/tmpdir');
+tmpdir.refresh();
+
+// fs.write with all parameters provided:
+{
+ const filename = path.join(tmpdir.path, 'write1.txt');
+ fs.open(filename, 'w', 0o644, common.mustSucceed((fd) => {
+ const cb = common.mustSucceed((written) => {
+ assert.strictEqual(written, expected.length);
+ fs.closeSync(fd);
+
+ const found = fs.readFileSync(filename, 'utf8');
+ assert.strictEqual(found, expected.toString());
+ });
+
+ fs.write(fd, expected, 0, expected.length, null, cb);
+ }));
+}
+
+// fs.write with a buffer, without the length parameter:
+{
+ const filename = path.join(tmpdir.path, 'write2.txt');
+ fs.open(filename, 'w', 0o644, common.mustSucceed((fd) => {
+ const cb = common.mustSucceed((written) => {
+ assert.strictEqual(written, 2);
+ fs.closeSync(fd);
+
+ const found = fs.readFileSync(filename, 'utf8');
+ assert.strictEqual(found, 'lo');
+ });
+
+ fs.write(fd, Buffer.from('hello'), 3, cb);
+ }));
+}
+
+// fs.write with a buffer, without the offset and length parameters:
+{
+ const filename = path.join(tmpdir.path, 'write3.txt');
+ fs.open(filename, 'w', 0o644, common.mustSucceed((fd) => {
+ const cb = common.mustSucceed((written) => {
+ assert.strictEqual(written, expected.length);
+ fs.closeSync(fd);
+
+ const found = fs.readFileSync(filename, 'utf8');
+ assert.deepStrictEqual(expected.toString(), found);
+ });
+
+ fs.write(fd, expected, cb);
+ }));
+}
+
+// fs.write with the offset passed as undefined followed by the callback:
+{
+ const filename = path.join(tmpdir.path, 'write4.txt');
+ fs.open(filename, 'w', 0o644, common.mustSucceed((fd) => {
+ const cb = common.mustSucceed((written) => {
+ assert.strictEqual(written, expected.length);
+ fs.closeSync(fd);
+
+ const found = fs.readFileSync(filename, 'utf8');
+ assert.deepStrictEqual(expected.toString(), found);
+ });
+
+ fs.write(fd, expected, undefined, cb);
+ }));
+}
+
+// fs.write with offset and length passed as undefined followed by the callback:
+{
+ const filename = path.join(tmpdir.path, 'write5.txt');
+ fs.open(filename, 'w', 0o644, common.mustSucceed((fd) => {
+ const cb = common.mustSucceed((written) => {
+ assert.strictEqual(written, expected.length);
+ fs.closeSync(fd);
+
+ const found = fs.readFileSync(filename, 'utf8');
+ assert.strictEqual(found, expected.toString());
+ });
+
+ fs.write(fd, expected, undefined, undefined, cb);
+ }));
+}
+
+// fs.write with a Uint8Array, without the offset and length parameters:
+{
+ const filename = path.join(tmpdir.path, 'write6.txt');
+ fs.open(filename, 'w', 0o644, common.mustSucceed((fd) => {
+ const cb = common.mustSucceed((written) => {
+ assert.strictEqual(written, expected.length);
+ fs.closeSync(fd);
+
+ const found = fs.readFileSync(filename, 'utf8');
+ assert.strictEqual(found, expected.toString());
+ });
+
+ fs.write(fd, Uint8Array.from(expected), cb);
+ }));
+}
+
+// fs.write with invalid offset type
+{
+ const filename = path.join(tmpdir.path, 'write7.txt');
+ fs.open(filename, 'w', 0o644, common.mustSucceed((fd) => {
+ assert.throws(() => {
+ fs.write(fd,
+ Buffer.from('abcd'),
+ NaN,
+ expected.length,
+ 0,
+ common.mustNotCall());
+ }, {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError',
+ message: 'The value of "offset" is out of range. ' +
+ 'It must be an integer. Received NaN'
+ });
+
+ fs.closeSync(fd);
+ }));
+}
+
+// fs.write with a DataView, without the offset and length parameters:
+{
+ const filename = path.join(tmpdir.path, 'write8.txt');
+ fs.open(filename, 'w', 0o644, common.mustSucceed((fd) => {
+ const cb = common.mustSucceed((written) => {
+ assert.strictEqual(written, expected.length);
+ fs.closeSync(fd);
+
+ const found = fs.readFileSync(filename, 'utf8');
+ assert.strictEqual(found, expected.toString());
+ });
+
+ const uint8 = Uint8Array.from(expected);
+ fs.write(fd, new DataView(uint8.buffer), cb);
+ }));
+}
diff --git a/tests/node_compat/test/parallel/test-fs-write-file-buffer.js b/tests/node_compat/test/parallel/test-fs-write-file-buffer.js
new file mode 100644
index 000000000..9283cc8b4
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-write-file-buffer.js
@@ -0,0 +1,62 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+require('../common');
+const join = require('path').join;
+const util = require('util');
+const fs = require('fs');
+
+let data = [
+ '/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAUDBAQEAwUEBAQFBQUGBwwIBwcH',
+ 'Bw8LCwkMEQ8SEhEPERETFhwXExQaFRERGCEYGh0dHx8fExciJCIeJBweHx7/',
+ '2wBDAQUFBQcGBw4ICA4eFBEUHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4e',
+ 'Hh4eHh4eHh4eHh4eHh4eHh4eHh4eHh7/wAARCAAQABADASIAAhEBAxEB/8QA',
+ 'HwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUF',
+ 'BAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkK',
+ 'FhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1',
+ 'dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXG',
+ 'x8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEB',
+ 'AQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAEC',
+ 'AxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRom',
+ 'JygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOE',
+ 'hYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU',
+ '1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDhfBUFl/wk',
+ 'OmPqKJJZw3aiZFBw4z93jnkkc9u9dj8XLfSI/EBt7DTo7ea2Ox5YXVo5FC7g',
+ 'Tjq24nJPXNVtO0KATRvNHCIg3zoWJWQHqp+o4pun+EtJ0zxBq8mnLJa2d1L5',
+ '0NvnKRjJBUE5PAx3NYxxUY0pRtvYHSc5Ka2X9d7H/9k='];
+
+data = data.join('\n');
+
+const tmpdir = require('../common/tmpdir');
+tmpdir.refresh();
+
+const buf = Buffer.from(data, 'base64');
+fs.writeFileSync(join(tmpdir.path, 'test.jpg'), buf);
+
+util.log('Done!');
diff --git a/tests/node_compat/test/parallel/test-fs-write-file-invalid-path.js b/tests/node_compat/test/parallel/test-fs-write-file-invalid-path.js
new file mode 100644
index 000000000..d56aa9a13
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-write-file-invalid-path.js
@@ -0,0 +1,53 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const assert = require('assert');
+const fs = require('fs');
+const path = require('path');
+
+if (!common.isWindows)
+ common.skip('This test is for Windows only.');
+
+const tmpdir = require('../common/tmpdir');
+tmpdir.refresh();
+
+const DATA_VALUE = 'hello';
+
+// Refs: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
+// Ignore '/', '\\' and ':'
+const RESERVED_CHARACTERS = '<>"|?*';
+
+[...RESERVED_CHARACTERS].forEach((ch) => {
+ const pathname = path.join(tmpdir.path, `somefile_${ch}`);
+ assert.throws(
+ () => {
+ fs.writeFileSync(pathname, DATA_VALUE);
+ },
+ /^Error: ENOENT: no such file or directory, open '.*'$/,
+ `failed with '${ch}'`);
+});
+
+// Test for ':' (NTFS data streams).
+// Refs: https://msdn.microsoft.com/en-us/library/windows/desktop/bb540537.aspx
+const pathname = path.join(tmpdir.path, 'foo:bar');
+fs.writeFileSync(pathname, DATA_VALUE);
+
+let content = '';
+const fileDataStream = fs.createReadStream(pathname, {
+ encoding: 'utf8'
+});
+
+fileDataStream.on('data', (data) => {
+ content += data;
+});
+
+fileDataStream.on('end', common.mustCall(() => {
+ assert.strictEqual(content, DATA_VALUE);
+}));
diff --git a/tests/node_compat/test/parallel/test-fs-write-file-sync.js b/tests/node_compat/test/parallel/test-fs-write-file-sync.js
new file mode 100644
index 000000000..027ba6377
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-write-file-sync.js
@@ -0,0 +1,128 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+
+if (!common.isMainThread)
+ common.skip('Setting process.umask is not supported in Workers');
+
+const assert = require('assert');
+const path = require('path');
+const fs = require('fs');
+
+// On Windows chmod is only able to manipulate read-only bit. Test if creating
+// the file in read-only mode works.
+const mode = common.isWindows ? 0o444 : 0o755;
+
+// Reset the umask for testing
+process.umask(0o000);
+
+const tmpdir = require('../common/tmpdir');
+tmpdir.refresh();
+
+// Test writeFileSync
+{
+ const file = path.join(tmpdir.path, 'testWriteFileSync.txt');
+
+ fs.writeFileSync(file, '123', { mode });
+ const content = fs.readFileSync(file, { encoding: 'utf8' });
+ assert.strictEqual(content, '123');
+ assert.strictEqual(fs.statSync(file).mode & 0o777, mode);
+}
+
+// Test appendFileSync
+{
+ const file = path.join(tmpdir.path, 'testAppendFileSync.txt');
+
+ fs.appendFileSync(file, 'abc', { mode });
+ const content = fs.readFileSync(file, { encoding: 'utf8' });
+ assert.strictEqual(content, 'abc');
+ assert.strictEqual(fs.statSync(file).mode & mode, mode);
+}
+
+// Test writeFileSync with file descriptor
+{
+ // Need to hijack fs.open/close to make sure that things
+ // get closed once they're opened.
+ const _openSync = fs.openSync;
+ const _closeSync = fs.closeSync;
+ let openCount = 0;
+
+ fs.openSync = (...args) => {
+ openCount++;
+ return _openSync(...args);
+ };
+
+ fs.closeSync = (...args) => {
+ openCount--;
+ return _closeSync(...args);
+ };
+
+ const file = path.join(tmpdir.path, 'testWriteFileSyncFd.txt');
+ const fd = fs.openSync(file, 'w+', mode);
+
+ fs.writeFileSync(fd, '123');
+ fs.closeSync(fd);
+ const content = fs.readFileSync(file, { encoding: 'utf8' });
+ assert.strictEqual(content, '123');
+ assert.strictEqual(fs.statSync(file).mode & 0o777, mode);
+
+ // Verify that all opened files were closed.
+ assert.strictEqual(openCount, 0);
+ fs.openSync = _openSync;
+ fs.closeSync = _closeSync;
+}
+
+// Test writeFileSync with flags
+{
+ const file = path.join(tmpdir.path, 'testWriteFileSyncFlags.txt');
+
+ fs.writeFileSync(file, 'hello ', { encoding: 'utf8', flag: 'a' });
+ fs.writeFileSync(file, 'world!', { encoding: 'utf8', flag: 'a' });
+ const content = fs.readFileSync(file, { encoding: 'utf8' });
+ assert.strictEqual(content, 'hello world!');
+}
+
+// Test writeFileSync with an object with an own toString function
+{
+ // Runtime deprecated by DEP0162
+ common.expectWarning('DeprecationWarning',
+ 'Implicit coercion of objects with own toString property is deprecated.',
+ 'DEP0162');
+ const file = path.join(tmpdir.path, 'testWriteFileSyncStringify.txt');
+ const data = {
+ toString() {
+ return 'hello world!';
+ }
+ };
+
+ fs.writeFileSync(file, data, { encoding: 'utf8', flag: 'a' });
+ const content = fs.readFileSync(file, { encoding: 'utf8' });
+ assert.strictEqual(content, String(data));
+}
diff --git a/tests/node_compat/test/parallel/test-fs-write-file.js b/tests/node_compat/test/parallel/test-fs-write-file.js
new file mode 100644
index 000000000..a5c93cd23
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-write-file.js
@@ -0,0 +1,115 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 16.13.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const fs = require('fs');
+const join = require('path').join;
+
+const tmpdir = require('../common/tmpdir');
+tmpdir.refresh();
+
+const filename = join(tmpdir.path, 'test.txt');
+
+const s = '南越国是前203年至前111年存在于岭南地区的一个国家,国都位于番禺,疆域包括今天中国的广东、' +
+ '广西两省区的大部份地区,福建省、湖南、贵州、云南的一小部份地区和越南的北部。' +
+ '南越国是秦朝灭亡后,由南海郡尉赵佗于前203年起兵兼并桂林郡和象郡后建立。' +
+ '前196年和前179年,南越国曾先后两次名义上臣属于西汉,成为西汉的“外臣”。前112年,' +
+ '南越国末代君主赵建德与西汉发生战争,被汉武帝于前111年所灭。南越国共存在93年,' +
+ '历经五代君主。南越国是岭南地区的第一个有记载的政权国家,采用封建制和郡县制并存的制度,' +
+ '它的建立保证了秦末乱世岭南地区社会秩序的稳定,有效的改善了岭南地区落后的政治、##济现状。\n';
+
+fs.writeFile(filename, s, common.mustSucceed(() => {
+ fs.readFile(filename, common.mustSucceed((buffer) => {
+ assert.strictEqual(Buffer.byteLength(s), buffer.length);
+ }));
+}));
+
+// Test that writeFile accepts buffers.
+const filename2 = join(tmpdir.path, 'test2.txt');
+const buf = Buffer.from(s, 'utf8');
+
+fs.writeFile(filename2, buf, common.mustSucceed(() => {
+ fs.readFile(filename2, common.mustSucceed((buffer) => {
+ assert.strictEqual(buf.length, buffer.length);
+ }));
+}));
+
+// Test that writeFile accepts file descriptors.
+const filename4 = join(tmpdir.path, 'test4.txt');
+
+fs.open(filename4, 'w+', common.mustSucceed((fd) => {
+ fs.writeFile(fd, s, common.mustSucceed(() => {
+ fs.close(fd, common.mustSucceed(() => {
+ fs.readFile(filename4, common.mustSucceed((buffer) => {
+ assert.strictEqual(Buffer.byteLength(s), buffer.length);
+ }));
+ }));
+ }));
+}));
+
+
+{
+ // Test that writeFile is cancellable with an AbortSignal.
+ // Before the operation has started
+ const controller = new AbortController();
+ const signal = controller.signal;
+ const filename3 = join(tmpdir.path, 'test3.txt');
+
+ fs.writeFile(filename3, s, { signal }, common.mustCall((err) => {
+ assert.strictEqual(err.name, 'AbortError');
+ }));
+
+ controller.abort();
+}
+
+// FIXME(bartlomieju):
+// {
+// // Test that writeFile is cancellable with an AbortSignal.
+// // After the operation has started
+// const controller = new AbortController();
+// const signal = controller.signal;
+// const filename4 = join(tmpdir.path, 'test5.txt');
+
+// fs.writeFile(filename4, s, { signal }, common.mustCall((err) => {
+// assert.strictEqual(err.name, 'AbortError');
+// }));
+
+// process.nextTick(() => controller.abort());
+// }
+
+{
+ // Test read-only mode
+ const filename = join(tmpdir.path, 'test6.txt');
+ fs.writeFileSync(filename, '');
+
+ // TODO: Correct the error type
+ const expectedError = common.isWindows ? /EPERM/ : /EBADF/;
+ fs.writeFile(filename, s, { flag: 'r' }, common.expectsError(expectedError));
+}
diff --git a/tests/node_compat/test/parallel/test-fs-write-no-fd.js b/tests/node_compat/test/parallel/test-fs-write-no-fd.js
new file mode 100644
index 000000000..58ab0fa44
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-write-no-fd.js
@@ -0,0 +1,19 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const fs = require('fs');
+const assert = require('assert');
+
+assert.throws(function() {
+ fs.write(null, Buffer.allocUnsafe(1), 0, 1, common.mustNotCall());
+}, /TypeError/);
+
+assert.throws(function() {
+ fs.write(null, '1', 0, 1, common.mustNotCall());
+}, /TypeError/);
diff --git a/tests/node_compat/test/parallel/test-fs-write-stream-autoclose-option.js b/tests/node_compat/test/parallel/test-fs-write-stream-autoclose-option.js
new file mode 100644
index 000000000..00958457f
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-write-stream-autoclose-option.js
@@ -0,0 +1,66 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const path = require('path');
+const fs = require('fs');
+
+const tmpdir = require('../common/tmpdir');
+
+const file = path.join(tmpdir.path, 'write-autoclose-opt1.txt');
+tmpdir.refresh();
+let stream = fs.createWriteStream(file, { flags: 'w+', autoClose: false });
+stream.write('Test1');
+stream.end();
+stream.on('finish', common.mustCall(function() {
+ stream.on('close', common.mustNotCall());
+ process.nextTick(common.mustCall(function() {
+ assert.strictEqual(stream.closed, false);
+ assert.notStrictEqual(stream.fd, null);
+ next();
+ }));
+}));
+
+function next() {
+ // This will tell us if the fd is usable again or not
+ stream = fs.createWriteStream(null, { fd: stream.fd, start: 0 });
+ stream.write('Test2');
+ stream.end();
+ stream.on('finish', common.mustCall(function() {
+ assert.strictEqual(stream.closed, false);
+ stream.on('close', common.mustCall(function() {
+ assert.strictEqual(stream.fd, null);
+ assert.strictEqual(stream.closed, true);
+ process.nextTick(next2);
+ }));
+ }));
+}
+
+function next2() {
+ // This will test if after reusing the fd data is written properly
+ fs.readFile(file, function(err, data) {
+ assert.ifError(err);
+ assert.strictEqual(data.toString(), 'Test2');
+ process.nextTick(common.mustCall(next3));
+ });
+}
+
+function next3() {
+ // This is to test success scenario where autoClose is true
+ const stream = fs.createWriteStream(file, { autoClose: true });
+ stream.write('Test3');
+ stream.end();
+ stream.on('finish', common.mustCall(function() {
+ assert.strictEqual(stream.closed, false);
+ stream.on('close', common.mustCall(function() {
+ assert.strictEqual(stream.fd, null);
+ assert.strictEqual(stream.closed, true);
+ }));
+ }));
+}
diff --git a/tests/node_compat/test/parallel/test-fs-write-stream-close-without-callback.js b/tests/node_compat/test/parallel/test-fs-write-stream-close-without-callback.js
new file mode 100644
index 000000000..61c3120d7
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-write-stream-close-without-callback.js
@@ -0,0 +1,20 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+require('../common');
+const fs = require('fs');
+const path = require('path');
+
+const tmpdir = require('../common/tmpdir');
+tmpdir.refresh();
+
+const s = fs.createWriteStream(path.join(tmpdir.path, 'nocallback'));
+
+s.end('hello world');
+s.close();
diff --git a/tests/node_compat/test/parallel/test-fs-write-stream-double-close.js b/tests/node_compat/test/parallel/test-fs-write-stream-double-close.js
new file mode 100644
index 000000000..1f38a3b7d
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-write-stream-double-close.js
@@ -0,0 +1,53 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const assert = require('assert');
+const fs = require('fs');
+const path = require('path');
+
+const tmpdir = require('../common/tmpdir');
+tmpdir.refresh();
+
+{
+ const s = fs.createWriteStream(path.join(tmpdir.path, 'rw'));
+
+ s.close(common.mustCall());
+ s.close(common.mustCall());
+}
+
+{
+ const s = fs.createWriteStream(path.join(tmpdir.path, 'rw2'));
+
+ let emits = 0;
+ s.on('close', () => {
+ emits++;
+ });
+
+ s.close(common.mustCall(() => {
+ assert.strictEqual(emits, 1);
+ s.close(common.mustCall(() => {
+ assert.strictEqual(emits, 1);
+ }));
+ process.nextTick(() => {
+ s.close(common.mustCall(() => {
+ assert.strictEqual(emits, 1);
+ }));
+ });
+ }));
+}
+
+{
+ const s = fs.createWriteStream(path.join(tmpdir.path, 'rw'), {
+ autoClose: false
+ });
+
+ s.close(common.mustCall());
+ s.close(common.mustCall());
+}
diff --git a/tests/node_compat/test/parallel/test-fs-write-stream-end.js b/tests/node_compat/test/parallel/test-fs-write-stream-end.js
new file mode 100644
index 000000000..f11cf86af
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-write-stream-end.js
@@ -0,0 +1,67 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const path = require('path');
+const fs = require('fs');
+
+const tmpdir = require('../common/tmpdir');
+tmpdir.refresh();
+
+{
+ const file = path.join(tmpdir.path, 'write-end-test0.txt');
+ const stream = fs.createWriteStream(file);
+ stream.end();
+ stream.on('close', common.mustCall());
+}
+
+{
+ const file = path.join(tmpdir.path, 'write-end-test1.txt');
+ const stream = fs.createWriteStream(file);
+ stream.end('a\n', 'utf8');
+ stream.on('close', common.mustCall(function() {
+ const content = fs.readFileSync(file, 'utf8');
+ assert.strictEqual(content, 'a\n');
+ }));
+}
+
+{
+ const file = path.join(tmpdir.path, 'write-end-test2.txt');
+ const stream = fs.createWriteStream(file);
+ stream.end();
+
+ let calledOpen = false;
+ stream.on('open', () => {
+ calledOpen = true;
+ });
+ stream.on('finish', common.mustCall(() => {
+ assert.strictEqual(calledOpen, true);
+ }));
+}
diff --git a/tests/node_compat/test/parallel/test-fs-write-stream-fs.js b/tests/node_compat/test/parallel/test-fs-write-stream-fs.js
new file mode 100644
index 000000000..533a60d4d
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-write-stream-fs.js
@@ -0,0 +1,45 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const path = require('path');
+const fs = require('fs');
+
+const tmpdir = require('../common/tmpdir');
+tmpdir.refresh();
+
+{
+ const file = path.join(tmpdir.path, 'write-end-test0.txt');
+ const stream = fs.createWriteStream(file, {
+ fs: {
+ open: common.mustCall(fs.open),
+ write: common.mustCallAtLeast(fs.write, 1),
+ close: common.mustCall(fs.close),
+ }
+ });
+ stream.end('asd');
+ stream.on('close', common.mustCall());
+}
+
+
+{
+ const file = path.join(tmpdir.path, 'write-end-test1.txt');
+ const stream = fs.createWriteStream(file, {
+ fs: {
+ open: common.mustCall(fs.open),
+ write: fs.write,
+ writev: common.mustCallAtLeast(fs.writev, 1),
+ close: common.mustCall(fs.close),
+ }
+ });
+ stream.write('asd');
+ stream.write('asd');
+ stream.write('asd');
+ stream.end();
+ stream.on('close', common.mustCall());
+}
diff --git a/tests/node_compat/test/parallel/test-fs-write-stream-throw-type-error.js b/tests/node_compat/test/parallel/test-fs-write-stream-throw-type-error.js
new file mode 100644
index 000000000..5540725f7
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-write-stream-throw-type-error.js
@@ -0,0 +1,39 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+const fs = require('fs');
+const path = require('path');
+
+const tmpdir = require('../common/tmpdir');
+
+const example = path.join(tmpdir.path, 'dummy');
+
+tmpdir.refresh();
+// Should not throw.
+fs.createWriteStream(example, undefined).end();
+fs.createWriteStream(example, null).end();
+fs.createWriteStream(example, 'utf8').end();
+fs.createWriteStream(example, { encoding: 'utf8' }).end();
+
+const createWriteStreamErr = (path, opt) => {
+ assert.throws(
+ () => {
+ fs.createWriteStream(path, opt);
+ },
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError'
+ });
+};
+
+createWriteStreamErr(example, 123);
+createWriteStreamErr(example, 0);
+createWriteStreamErr(example, true);
+createWriteStreamErr(example, false);
diff --git a/tests/node_compat/test/parallel/test-fs-write-stream.js b/tests/node_compat/test/parallel/test-fs-write-stream.js
new file mode 100644
index 000000000..4d03d44a8
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-write-stream.js
@@ -0,0 +1,74 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const path = require('path');
+const fs = require('fs');
+
+const tmpdir = require('../common/tmpdir');
+
+const file = path.join(tmpdir.path, 'write.txt');
+
+tmpdir.refresh();
+
+{
+ const stream = fs.WriteStream(file);
+ const _fs_close = fs.close;
+
+ fs.close = function(fd) {
+ assert.ok(fd, 'fs.close must not be called without an undefined fd.');
+ fs.close = _fs_close;
+ fs.closeSync(fd);
+ };
+ stream.destroy();
+}
+
+{
+ const stream = fs.createWriteStream(file);
+
+ stream.on('drain', function() {
+ assert.fail('\'drain\' event must not be emitted before ' +
+ 'stream.write() has been called at least once.');
+ });
+ stream.destroy();
+}
+
+// Throws if data is not of type Buffer.
+{
+ const stream = fs.createWriteStream(file);
+ stream.on('error', common.mustNotCall());
+ assert.throws(() => {
+ stream.write(42);
+ }, {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError'
+ });
+ stream.destroy();
+}
diff --git a/tests/node_compat/test/parallel/test-fs-write-sync.js b/tests/node_compat/test/parallel/test-fs-write-sync.js
new file mode 100644
index 000000000..8d9ee9efe
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-write-sync.js
@@ -0,0 +1,63 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+const path = require('path');
+const fs = require('fs');
+const tmpdir = require('../common/tmpdir');
+const filename = path.join(tmpdir.path, 'write.txt');
+
+tmpdir.refresh();
+
+{
+ const parameters = [Buffer.from('bár'), 0, Buffer.byteLength('bár')];
+
+ // The first time fs.writeSync is called with all parameters provided.
+ // After that, each pop in the cycle removes the final parameter. So:
+ // - The 2nd time fs.writeSync with a buffer, without the length parameter.
+ // - The 3rd time fs.writeSync with a buffer, without the offset and length
+ // parameters.
+ while (parameters.length > 0) {
+ const fd = fs.openSync(filename, 'w');
+
+ let written = fs.writeSync(fd, '');
+ assert.strictEqual(written, 0);
+
+ fs.writeSync(fd, 'foo');
+
+ written = fs.writeSync(fd, ...parameters);
+ assert.ok(written > 3);
+ fs.closeSync(fd);
+
+ assert.strictEqual(fs.readFileSync(filename, 'utf-8'), 'foobár');
+
+ parameters.pop();
+ }
+}
diff --git a/tests/node_compat/test/parallel/test-fs-write.js b/tests/node_compat/test/parallel/test-fs-write.js
new file mode 100644
index 000000000..33fcb84cf
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-write.js
@@ -0,0 +1,212 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 16.13.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// Flags: --expose_externalize_string
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const path = require('path');
+const fs = require('fs');
+const tmpdir = require('../common/tmpdir');
+
+tmpdir.refresh();
+
+const fn = path.join(tmpdir.path, 'write.txt');
+const fn2 = path.join(tmpdir.path, 'write2.txt');
+const fn3 = path.join(tmpdir.path, 'write3.txt');
+const fn4 = path.join(tmpdir.path, 'write4.txt');
+const fn5 = path.join(tmpdir.path, 'write5.txt');
+const expected = 'ümlaut.';
+const constants = fs.constants;
+
+const { externalizeString, isOneByteString } = global;
+
+// Account for extra globals exposed by --expose_externalize_string.
+common.allowGlobals(externalizeString, isOneByteString, global.x);
+
+{
+ const expected = 'ümlaut sechzig'; // Must be a unique string.
+ externalizeString(expected);
+ assert.strictEqual(isOneByteString(expected), true);
+ const fd = fs.openSync(fn, 'w');
+ fs.writeSync(fd, expected, 0, 'latin1');
+ fs.closeSync(fd);
+ assert.strictEqual(fs.readFileSync(fn, 'latin1'), expected);
+}
+
+{
+ const expected = 'ümlaut neunzig'; // Must be a unique string.
+ externalizeString(expected);
+ assert.strictEqual(isOneByteString(expected), true);
+ const fd = fs.openSync(fn, 'w');
+ fs.writeSync(fd, expected, 0, 'utf8');
+ fs.closeSync(fd);
+ assert.strictEqual(fs.readFileSync(fn, 'utf8'), expected);
+}
+
+{
+ const expected = 'Zhōngwén 1'; // Must be a unique string.
+ externalizeString(expected);
+ assert.strictEqual(isOneByteString(expected), false);
+ const fd = fs.openSync(fn, 'w');
+ fs.writeSync(fd, expected, 0, 'ucs2');
+ fs.closeSync(fd);
+ assert.strictEqual(fs.readFileSync(fn, 'ucs2'), expected);
+}
+
+{
+ const expected = 'Zhōngwén 2'; // Must be a unique string.
+ externalizeString(expected);
+ assert.strictEqual(isOneByteString(expected), false);
+ const fd = fs.openSync(fn, 'w');
+ fs.writeSync(fd, expected, 0, 'utf8');
+ fs.closeSync(fd);
+ assert.strictEqual(fs.readFileSync(fn, 'utf8'), expected);
+}
+
+fs.open(fn, 'w', 0o644, common.mustSucceed((fd) => {
+ const done = common.mustSucceed((written) => {
+ assert.strictEqual(written, Buffer.byteLength(expected));
+ fs.closeSync(fd);
+ const found = fs.readFileSync(fn, 'utf8');
+ fs.unlinkSync(fn);
+ assert.strictEqual(found, expected);
+ });
+
+ const written = common.mustSucceed((written) => {
+ assert.strictEqual(written, 0);
+ fs.write(fd, expected, 0, 'utf8', done);
+ });
+
+ fs.write(fd, '', 0, 'utf8', written);
+}));
+
+// TODO(kt3k): Enable this test when fs.open supports number for `flags`
+// paramter.
+/*
+const args = constants.O_CREAT | constants.O_WRONLY | constants.O_TRUNC;
+fs.open(fn2, args, 0o644, common.mustSucceed((fd) => {
+ const done = common.mustSucceed((written) => {
+ assert.strictEqual(written, Buffer.byteLength(expected));
+ fs.closeSync(fd);
+ const found = fs.readFileSync(fn2, 'utf8');
+ fs.unlinkSync(fn2);
+ assert.strictEqual(found, expected);
+ });
+
+ const written = common.mustSucceed((written) => {
+ assert.strictEqual(written, 0);
+ fs.write(fd, expected, 0, 'utf8', done);
+ });
+
+ fs.write(fd, '', 0, 'utf8', written);
+}));
+*/
+
+fs.open(fn3, 'w', 0o644, common.mustSucceed((fd) => {
+ const done = common.mustSucceed((written) => {
+ assert.strictEqual(written, Buffer.byteLength(expected));
+ fs.closeSync(fd);
+ });
+
+ fs.write(fd, expected, done);
+}));
+
+fs.open(fn4, 'w', 0o644, common.mustSucceed((fd) => {
+ const done = common.mustSucceed((written) => {
+ assert.strictEqual(written, Buffer.byteLength(expected));
+ fs.closeSync(fd);
+ });
+
+ const data = {
+ toString() { return expected; }
+ };
+ fs.write(fd, data, done);
+}));
+
+[false, 'test', {}, [], null, undefined].forEach((i) => {
+ assert.throws(
+ () => fs.write(i, common.mustNotCall()),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError'
+ }
+ );
+ assert.throws(
+ () => fs.writeSync(i),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError'
+ }
+ );
+});
+
+[false, 5, {}, [], null, undefined].forEach((data) => {
+ assert.throws(
+ () => fs.write(1, data, common.mustNotCall()),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ message: /"buffer"/
+ }
+ );
+ assert.throws(
+ () => fs.writeSync(1, data),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ message: /"buffer"/
+ }
+ );
+});
+
+{
+ // Regression test for https://github.com/nodejs/node/issues/38168
+ const fd = fs.openSync(fn5, 'w');
+
+ assert.throws(
+ () => fs.writeSync(fd, 'abc', 0, 'hex'),
+ {
+ code: 'ERR_INVALID_ARG_VALUE',
+ message: /'encoding' is invalid for data of length 3/
+ }
+ );
+
+ assert.throws(
+ () => fs.writeSync(fd, 'abc', 0, 'hex', common.mustNotCall()),
+ {
+ code: 'ERR_INVALID_ARG_VALUE',
+ message: /'encoding' is invalid for data of length 3/
+ }
+ );
+
+ assert.strictEqual(fs.writeSync(fd, 'abcd', 0, 'hex'), 2);
+
+ fs.write(fd, 'abcd', 0, 'hex', common.mustSucceed((written) => {
+ assert.strictEqual(written, 2);
+ fs.closeSync(fd);
+ }));
+}
diff --git a/tests/node_compat/test/parallel/test-fs-writev-sync.js b/tests/node_compat/test/parallel/test-fs-writev-sync.js
new file mode 100644
index 000000000..53fa48af1
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-fs-writev-sync.js
@@ -0,0 +1,104 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+require('../common');
+const assert = require('assert');
+const path = require('path');
+const fs = require('fs');
+const tmpdir = require('../common/tmpdir');
+
+tmpdir.refresh();
+
+const expected = 'ümlaut. Лорем 運務ホソモ指及 आपको करने विकास 紙読決多密所 أضف';
+
+const getFileName = (i) => path.join(tmpdir.path, `writev_sync_${i}.txt`);
+
+/**
+ * Testing with a array of buffers input
+ */
+
+// fs.writevSync with array of buffers with all parameters
+{
+ const filename = getFileName(1);
+ const fd = fs.openSync(filename, 'w');
+
+ const buffer = Buffer.from(expected);
+ const bufferArr = [buffer, buffer];
+ const expectedLength = bufferArr.length * buffer.byteLength;
+
+ let written = fs.writevSync(fd, [Buffer.from('')], null);
+ assert.strictEqual(written, 0);
+
+ written = fs.writevSync(fd, bufferArr, null);
+ assert.strictEqual(written, expectedLength);
+
+ fs.closeSync(fd);
+
+ assert(Buffer.concat(bufferArr).equals(fs.readFileSync(filename)));
+}
+
+// fs.writevSync with array of buffers without position
+{
+ const filename = getFileName(2);
+ const fd = fs.openSync(filename, 'w');
+
+ const buffer = Buffer.from(expected);
+ const bufferArr = [buffer, buffer, buffer];
+ const expectedLength = bufferArr.length * buffer.byteLength;
+
+ let written = fs.writevSync(fd, [Buffer.from('')]);
+ assert.strictEqual(written, 0);
+
+ written = fs.writevSync(fd, bufferArr);
+ assert.strictEqual(written, expectedLength);
+
+ fs.closeSync(fd);
+
+ assert(Buffer.concat(bufferArr).equals(fs.readFileSync(filename)));
+}
+
+// fs.writevSync with empty array of buffers
+{
+ const filename = getFileName(3);
+ const fd = fs.openSync(filename, 'w');
+ const written = fs.writevSync(fd, []);
+ assert.strictEqual(written, 0);
+ fs.closeSync(fd);
+
+}
+
+/**
+ * Testing with wrong input types
+ */
+{
+ const filename = getFileName(4);
+ const fd = fs.openSync(filename, 'w');
+
+ [false, 'test', {}, [{}], ['sdf'], null, undefined].forEach((i) => {
+ assert.throws(
+ () => fs.writevSync(fd, i, null), {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError'
+ }
+ );
+ });
+
+ fs.closeSync(fd);
+}
+
+// fs.writevSync with wrong fd types
+[false, 'test', {}, [{}], null, undefined].forEach((i) => {
+ assert.throws(
+ () => fs.writevSync(i),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError'
+ }
+ );
+});
diff --git a/tests/node_compat/test/parallel/test-handle-wrap-close-abort.js b/tests/node_compat/test/parallel/test-handle-wrap-close-abort.js
new file mode 100644
index 000000000..d143dd439
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-handle-wrap-close-abort.js
@@ -0,0 +1,44 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+
+process.on('uncaughtException', common.mustCall(2));
+
+setTimeout(function() {
+ process.nextTick(function() {
+ const c = setInterval(function() {
+ clearInterval(c);
+ throw new Error('setInterval');
+ }, 1);
+ });
+ setTimeout(function() {
+ throw new Error('setTimeout');
+ }, 1);
+}, 1);
diff --git a/tests/node_compat/test/parallel/test-http-agent-getname.js b/tests/node_compat/test/parallel/test-http-agent-getname.js
new file mode 100644
index 000000000..3404252a8
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-http-agent-getname.js
@@ -0,0 +1,63 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+require('../common');
+const assert = require('assert');
+const http = require('http');
+const path = require('path');
+
+const tmpdir = require('../common/tmpdir');
+
+const agent = new http.Agent();
+
+// Default to localhost
+assert.strictEqual(
+ agent.getName({
+ port: 80,
+ localAddress: '192.168.1.1'
+ }),
+ 'localhost:80:192.168.1.1'
+);
+
+// empty argument
+assert.strictEqual(
+ agent.getName(),
+ 'localhost::'
+);
+
+// empty options
+assert.strictEqual(
+ agent.getName({}),
+ 'localhost::'
+);
+
+// pass all arguments
+assert.strictEqual(
+ agent.getName({
+ host: '0.0.0.0',
+ port: 80,
+ localAddress: '192.168.1.1'
+ }),
+ '0.0.0.0:80:192.168.1.1'
+);
+
+// unix socket
+const socketPath = path.join(tmpdir.path, 'foo', 'bar');
+assert.strictEqual(
+ agent.getName({
+ socketPath
+ }),
+ `localhost:::${socketPath}`
+);
+
+for (const family of [0, null, undefined, 'bogus'])
+ assert.strictEqual(agent.getName({ family }), 'localhost::');
+
+for (const family of [4, 6])
+ assert.strictEqual(agent.getName({ family }), `localhost:::${family}`);
diff --git a/tests/node_compat/test/parallel/test-http-client-get-url.js b/tests/node_compat/test/parallel/test-http-client-get-url.js
new file mode 100644
index 000000000..a38d3ff7b
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-http-client-get-url.js
@@ -0,0 +1,53 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const http = require('http');
+const url = require('url');
+const testPath = '/foo?bar';
+
+const server = http.createServer(common.mustCall((req, res) => {
+ assert.strictEqual(req.method, 'GET');
+ assert.strictEqual(req.url, testPath);
+ res.writeHead(200, { 'Content-Type': 'text/plain' });
+ res.write('hello\n');
+ res.end();
+}, 3));
+
+server.listen(0, common.localhostIPv4, common.mustCall(() => {
+ const u = `http://${common.localhostIPv4}:${server.address().port}${testPath}`;
+ http.get(u, common.mustCall(() => {
+ http.get(url.parse(u), common.mustCall(() => {
+ http.get(new URL(u), common.mustCall(() => {
+ server.close();
+ }));
+ }));
+ }));
+}));
diff --git a/tests/node_compat/test/parallel/test-http-client-read-in-error.js b/tests/node_compat/test/parallel/test-http-client-read-in-error.js
new file mode 100644
index 000000000..3c86ad8f5
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-http-client-read-in-error.js
@@ -0,0 +1,48 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const net = require('net');
+const http = require('http');
+
+class Agent extends http.Agent {
+ createConnection() {
+ const socket = new net.Socket();
+
+ socket.on('error', function() {
+ socket.push('HTTP/1.1 200\r\n\r\n');
+ });
+
+ let onNewListener;
+ socket.on('newListener', onNewListener = (name) => {
+ if (name !== 'error')
+ return;
+ socket.removeListener('newListener', onNewListener);
+
+ // Let other listeners to be set up too
+ process.nextTick(() => {
+ this.breakSocket(socket);
+ });
+ });
+
+ return socket;
+ }
+
+ breakSocket(socket) {
+ socket.emit('error', new Error('Intentional error'));
+ }
+}
+
+const agent = new Agent();
+
+http.request({
+ agent
+}).once('error', function() {
+ console.log('ignore');
+ this.on('data', common.mustNotCall());
+});
diff --git a/tests/node_compat/test/parallel/test-http-localaddress.js b/tests/node_compat/test/parallel/test-http-localaddress.js
new file mode 100644
index 000000000..ab3eff808
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-http-localaddress.js
@@ -0,0 +1,64 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// Flags: --expose-internals
+'use strict';
+const common = require('../common');
+if (!common.hasMultiLocalhost())
+ common.skip('platform-specific test.');
+
+const http = require('http');
+const assert = require('assert');
+
+const server = http.createServer((req, res) => {
+ console.log(`Connect from: ${req.connection.remoteAddress}`);
+ assert.strictEqual(req.connection.remoteAddress, '127.0.0.2');
+
+ req.on('end', () => {
+ res.writeHead(200, { 'Content-Type': 'text/plain' });
+ res.end(`You are from: ${req.connection.remoteAddress}`);
+ });
+ req.resume();
+});
+
+server.listen(0, '127.0.0.1', () => {
+ const options = { host: 'localhost',
+ port: server.address().port,
+ family: 4,
+ path: '/',
+ method: 'GET',
+ localAddress: '127.0.0.2' };
+
+ const req = http.request(options, function(res) {
+ res.on('end', () => {
+ server.close();
+ });
+ res.resume();
+ });
+ req.end();
+});
diff --git a/tests/node_compat/test/parallel/test-http-outgoing-internal-headernames-getter.js b/tests/node_compat/test/parallel/test-http-outgoing-internal-headernames-getter.js
new file mode 100644
index 000000000..e9b324892
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-http-outgoing-internal-headernames-getter.js
@@ -0,0 +1,30 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+
+const { OutgoingMessage } = require('http');
+const assert = require('assert');
+
+const warn = 'OutgoingMessage.prototype._headerNames is deprecated';
+common.expectWarning('DeprecationWarning', warn, 'DEP0066');
+
+{
+ // Tests for _headerNames get method
+ const outgoingMessage = new OutgoingMessage();
+ outgoingMessage._headerNames; // eslint-disable-line no-unused-expressions
+}
+
+{
+ // Tests _headerNames getter result after setting a header.
+ const outgoingMessage = new OutgoingMessage();
+ outgoingMessage.setHeader('key', 'value');
+ const expect = Object.create(null);
+ expect.key = 'key';
+ assert.deepStrictEqual(outgoingMessage._headerNames, expect);
+}
diff --git a/tests/node_compat/test/parallel/test-http-outgoing-internal-headernames-setter.js b/tests/node_compat/test/parallel/test-http-outgoing-internal-headernames-setter.js
new file mode 100644
index 000000000..9531e5611
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-http-outgoing-internal-headernames-setter.js
@@ -0,0 +1,22 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+
+const { OutgoingMessage } = require('http');
+
+const warn = 'OutgoingMessage.prototype._headerNames is deprecated';
+common.expectWarning('DeprecationWarning', warn, 'DEP0066');
+
+{
+ // Tests for _headerNames set method
+ const outgoingMessage = new OutgoingMessage();
+ outgoingMessage._headerNames = {
+ 'x-flow-id': '61bba6c5-28a3-4eab-9241-2ecaa6b6a1fd'
+ };
+}
diff --git a/tests/node_compat/test/parallel/test-http-outgoing-internal-headers.js b/tests/node_compat/test/parallel/test-http-outgoing-internal-headers.js
new file mode 100644
index 000000000..0e4783a6d
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-http-outgoing-internal-headers.js
@@ -0,0 +1,51 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Flags: --expose-internals
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+
+const { kOutHeaders } = require('internal/http');
+const { OutgoingMessage } = require('http');
+
+const warn = 'OutgoingMessage.prototype._headers is deprecated';
+common.expectWarning('DeprecationWarning', warn, 'DEP0066');
+
+{
+ // Tests for _headers get method
+ const outgoingMessage = new OutgoingMessage();
+ outgoingMessage.getHeaders = common.mustCall();
+ outgoingMessage._headers; // eslint-disable-line no-unused-expressions
+}
+
+{
+ // Tests for _headers set method
+ const outgoingMessage = new OutgoingMessage();
+ outgoingMessage._headers = {
+ host: 'risingstack.com',
+ Origin: 'localhost'
+ };
+
+ assert.deepStrictEqual(
+ Object.entries(outgoingMessage[kOutHeaders]),
+ Object.entries({
+ host: ['host', 'risingstack.com'],
+ origin: ['Origin', 'localhost']
+ }));
+}
+
+{
+ // Tests for _headers set method `null`
+ const outgoingMessage = new OutgoingMessage();
+ outgoingMessage._headers = null;
+
+ assert.strictEqual(
+ outgoingMessage[kOutHeaders],
+ null
+ );
+}
diff --git a/tests/node_compat/test/parallel/test-http-outgoing-renderHeaders.js b/tests/node_compat/test/parallel/test-http-outgoing-renderHeaders.js
new file mode 100644
index 000000000..194a9345a
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-http-outgoing-renderHeaders.js
@@ -0,0 +1,57 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+// Flags: --expose-internals
+
+require('../common');
+const assert = require('assert');
+
+const kOutHeaders = require('internal/http').kOutHeaders;
+const http = require('http');
+const OutgoingMessage = http.OutgoingMessage;
+
+{
+ const outgoingMessage = new OutgoingMessage();
+ outgoingMessage._header = {};
+ assert.throws(
+ () => outgoingMessage._renderHeaders(),
+ {
+ code: 'ERR_HTTP_HEADERS_SENT',
+ name: 'Error',
+ message: 'Cannot render headers after they are sent to the client'
+ }
+ );
+}
+
+{
+ const outgoingMessage = new OutgoingMessage();
+ outgoingMessage[kOutHeaders] = null;
+ const result = outgoingMessage._renderHeaders();
+ assert.deepStrictEqual(result, {});
+}
+
+
+{
+ const outgoingMessage = new OutgoingMessage();
+ outgoingMessage[kOutHeaders] = {};
+ const result = outgoingMessage._renderHeaders();
+ assert.deepStrictEqual(result, {});
+}
+
+{
+ const outgoingMessage = new OutgoingMessage();
+ outgoingMessage[kOutHeaders] = {
+ host: ['host', 'nodejs.org'],
+ origin: ['Origin', 'localhost']
+ };
+ const result = outgoingMessage._renderHeaders();
+ assert.deepStrictEqual(result, {
+ host: 'nodejs.org',
+ Origin: 'localhost'
+ });
+}
diff --git a/tests/node_compat/test/parallel/test-http-outgoing-settimeout.js b/tests/node_compat/test/parallel/test-http-outgoing-settimeout.js
new file mode 100644
index 000000000..592e576b4
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-http-outgoing-settimeout.js
@@ -0,0 +1,37 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+
+const { OutgoingMessage } = require('http');
+
+{
+ // Tests for settimeout method with socket
+ const expectedMsecs = 42;
+ const outgoingMessage = new OutgoingMessage();
+ outgoingMessage.socket = {
+ setTimeout: common.mustCall((msecs) => {
+ assert.strictEqual(msecs, expectedMsecs);
+ })
+ };
+ outgoingMessage.setTimeout(expectedMsecs);
+}
+
+{
+ // Tests for settimeout method without socket
+ const expectedMsecs = 23;
+ const outgoingMessage = new OutgoingMessage();
+ outgoingMessage.setTimeout(expectedMsecs);
+
+ outgoingMessage.emit('socket', {
+ setTimeout: common.mustCall((msecs) => {
+ assert.strictEqual(msecs, expectedMsecs);
+ })
+ });
+}
diff --git a/tests/node_compat/test/parallel/test-http-url.parse-auth-with-header-in-request.js b/tests/node_compat/test/parallel/test-http-url.parse-auth-with-header-in-request.js
new file mode 100644
index 000000000..24cc2f33d
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-http-url.parse-auth-with-header-in-request.js
@@ -0,0 +1,59 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+const http = require('http');
+const url = require('url');
+
+function check(request) {
+ // The correct authorization header is be passed
+ assert.strictEqual(request.headers.authorization, 'NoAuthForYOU');
+}
+
+const server = http.createServer(function(request, response) {
+ // Run the check function
+ check(request);
+ response.writeHead(200, {});
+ response.end('ok');
+ server.close();
+});
+
+server.listen(0, function() {
+ const testURL =
+ url.parse(`http://asdf:qwer@localhost:${this.address().port}`);
+ // The test here is if you set a specific authorization header in the
+ // request we should not override that with basic auth
+ testURL.headers = {
+ Authorization: 'NoAuthForYOU'
+ };
+
+ // make the request
+ http.request(testURL).end();
+});
diff --git a/tests/node_compat/test/parallel/test-http-url.parse-auth.js b/tests/node_compat/test/parallel/test-http-url.parse-auth.js
new file mode 100644
index 000000000..c9b691aa2
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-http-url.parse-auth.js
@@ -0,0 +1,55 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+const http = require('http');
+const url = require('url');
+
+function check(request) {
+ // The correct authorization header is be passed
+ assert.strictEqual(request.headers.authorization, 'Basic dXNlcjpwYXNzOg==');
+}
+
+const server = http.createServer(function(request, response) {
+ // Run the check function
+ check(request);
+ response.writeHead(200, {});
+ response.end('ok');
+ server.close();
+});
+
+server.listen(0, function() {
+ const port = this.address().port;
+ // username = "user", password = "pass:"
+ const testURL = url.parse(`http://user:pass%3A@localhost:${port}`);
+
+ // make the request
+ http.request(testURL).end();
+});
diff --git a/tests/node_compat/test/parallel/test-http-url.parse-basic.js b/tests/node_compat/test/parallel/test-http-url.parse-basic.js
new file mode 100644
index 000000000..e41bf41a1
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-http-url.parse-basic.js
@@ -0,0 +1,65 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+const http = require('http');
+const url = require('url');
+
+let testURL;
+
+// Make sure the basics work
+function check(request) {
+ // Default method should still be 'GET'
+ assert.strictEqual(request.method, 'GET');
+ // There are no URL params, so you should not see any
+ assert.strictEqual(request.url, '/');
+ // The host header should use the url.parse.hostname
+ assert.strictEqual(request.headers.host,
+ `${testURL.hostname}:${testURL.port}`);
+}
+
+const server = http.createServer(function(request, response) {
+ // Run the check function
+ check(request);
+ response.writeHead(200, {});
+ response.end('ok');
+ server.close();
+});
+
+server.listen(0, function() {
+ testURL = url.parse(`http://localhost:${this.address().port}`);
+
+ // make the request
+ const clientRequest = http.request(testURL);
+ // Since there is a little magic with the agent
+ // make sure that an http request uses the http.Agent
+ assert.ok(clientRequest.agent instanceof http.Agent);
+ clientRequest.end();
+});
diff --git a/tests/node_compat/test/parallel/test-http-url.parse-https.request.js b/tests/node_compat/test/parallel/test-http-url.parse-https.request.js
new file mode 100644
index 000000000..89c7ca2b4
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-http-url.parse-https.request.js
@@ -0,0 +1,69 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+if (!common.hasCrypto)
+ common.skip('missing crypto');
+const { readKey } = require('../common/fixtures');
+
+const assert = require('assert');
+const https = require('https');
+const url = require('url');
+
+// https options
+const httpsOptions = {
+ key: readKey('agent1-key.pem'),
+ cert: readKey('agent1-cert.pem')
+};
+
+function check(request) {
+ // Assert that I'm https
+ assert.ok(request.socket._secureEstablished);
+}
+
+const server = https.createServer(httpsOptions, function(request, response) {
+ // Run the check function
+ check(request);
+ response.writeHead(200, {});
+ response.end('ok');
+ server.close();
+});
+
+// TODO(wafuwafu13): rejectUnauthorized is always true in Deno
+// server.listen(0, function() {
+// const testURL = url.parse(`https://localhost:${this.address().port}`);
+// testURL.rejectUnauthorized = false;
+
+// // make the request
+// const clientRequest = https.request(testURL);
+// // Since there is a little magic with the agent
+// // make sure that the request uses the https.Agent
+// assert.ok(clientRequest.agent instanceof https.Agent);
+// clientRequest.end();
+// });
diff --git a/tests/node_compat/test/parallel/test-http-url.parse-only-support-http-https-protocol.js b/tests/node_compat/test/parallel/test-http-url.parse-only-support-http-https-protocol.js
new file mode 100644
index 000000000..4f50f8a54
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-http-url.parse-only-support-http-https-protocol.js
@@ -0,0 +1,52 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+const http = require('http');
+const url = require('url');
+
+const invalidUrls = [
+ 'file:///whatever',
+ 'mailto:asdf@asdf.com',
+ 'ftp://www.example.com',
+ 'javascript:alert(\'hello\');',
+ 'xmpp:foo@bar.com',
+ 'f://some.host/path',
+];
+
+invalidUrls.forEach((invalid) => {
+ assert.throws(
+ () => { http.request(url.parse(invalid)); },
+ {
+ code: 'ERR_INVALID_PROTOCOL',
+ name: 'TypeError'
+ }
+ );
+});
diff --git a/tests/node_compat/test/parallel/test-http-url.parse-path.js b/tests/node_compat/test/parallel/test-http-url.parse-path.js
new file mode 100644
index 000000000..7077fcae1
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-http-url.parse-path.js
@@ -0,0 +1,53 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+const http = require('http');
+const url = require('url');
+
+function check(request) {
+ // A path should come over
+ assert.strictEqual(request.url, '/asdf');
+}
+
+const server = http.createServer(function(request, response) {
+ // Run the check function
+ check(request);
+ response.writeHead(200, {});
+ response.end('ok');
+ server.close();
+});
+
+server.listen(0, function() {
+ const testURL = url.parse(`http://localhost:${this.address().port}/asdf`);
+
+ // make the request
+ http.request(testURL).end();
+});
diff --git a/tests/node_compat/test/parallel/test-http-url.parse-post.js b/tests/node_compat/test/parallel/test-http-url.parse-post.js
new file mode 100644
index 000000000..da316d2db
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-http-url.parse-post.js
@@ -0,0 +1,61 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+const http = require('http');
+const url = require('url');
+
+let testURL;
+
+function check(request) {
+ // url.parse should not mess with the method
+ assert.strictEqual(request.method, 'POST');
+ // Everything else should be right
+ assert.strictEqual(request.url, '/asdf?qwer=zxcv');
+ // The host header should use the url.parse.hostname
+ assert.strictEqual(request.headers.host,
+ `${testURL.hostname}:${testURL.port}`);
+}
+
+const server = http.createServer(function(request, response) {
+ // Run the check function
+ check(request);
+ response.writeHead(200, {});
+ response.end('ok');
+ server.close();
+});
+
+server.listen(0, function() {
+ testURL = url.parse(`http://localhost:${this.address().port}/asdf?qwer=zxcv`);
+ testURL.method = 'POST';
+
+ // make the request
+ http.request(testURL).end();
+});
diff --git a/tests/node_compat/test/parallel/test-http-url.parse-search.js b/tests/node_compat/test/parallel/test-http-url.parse-search.js
new file mode 100644
index 000000000..52651869d
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-http-url.parse-search.js
@@ -0,0 +1,54 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+const http = require('http');
+const url = require('url');
+
+function check(request) {
+ // A path should come over with params
+ assert.strictEqual(request.url, '/asdf?qwer=zxcv');
+}
+
+const server = http.createServer(function(request, response) {
+ // Run the check function
+ check(request);
+ response.writeHead(200, {});
+ response.end('ok');
+ server.close();
+});
+
+server.listen(0, function() {
+ const port = this.address().port;
+ const testURL = url.parse(`http://localhost:${port}/asdf?qwer=zxcv`);
+
+ // make the request
+ http.request(testURL).end();
+});
diff --git a/tests/node_compat/test/parallel/test-net-access-byteswritten.js b/tests/node_compat/test/parallel/test-net-access-byteswritten.js
new file mode 100644
index 000000000..a20a1a7a7
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-net-access-byteswritten.js
@@ -0,0 +1,28 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+if (!common.hasCrypto)
+ common.skip('missing crypto');
+
+const assert = require('assert');
+const net = require('net');
+const tls = require('tls');
+const tty = require('tty');
+
+// Check that the bytesWritten getter doesn't crash if object isn't
+// constructed.
+assert.strictEqual(net.Socket.prototype.bytesWritten, undefined);
+assert.strictEqual(Object.getPrototypeOf(tls.TLSSocket).prototype.bytesWritten,
+ undefined);
+assert.strictEqual(tls.TLSSocket.prototype.bytesWritten, undefined);
+assert.strictEqual(Object.getPrototypeOf(tty.ReadStream).prototype.bytesWritten,
+ undefined);
+assert.strictEqual(tty.ReadStream.prototype.bytesWritten, undefined);
+assert.strictEqual(tty.WriteStream.prototype.bytesWritten, undefined);
diff --git a/tests/node_compat/test/parallel/test-net-better-error-messages-listen-path.js b/tests/node_compat/test/parallel/test-net-better-error-messages-listen-path.js
new file mode 100644
index 000000000..edafbcdc4
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-net-better-error-messages-listen-path.js
@@ -0,0 +1,17 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const net = require('net');
+const fp = '/blah/fadfa';
+const server = net.createServer(common.mustNotCall());
+server.listen(fp, common.mustNotCall());
+server.on('error', common.mustCall(function(e) {
+ assert.strictEqual(e.address, fp);
+}));
diff --git a/tests/node_compat/test/parallel/test-net-better-error-messages-path.js b/tests/node_compat/test/parallel/test-net-better-error-messages-path.js
new file mode 100644
index 000000000..d1bada362
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-net-better-error-messages-path.js
@@ -0,0 +1,29 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 16.13.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const net = require('net');
+
+{
+ const fp = '/tmp/fadagagsdfgsdf';
+ const c = net.connect(fp);
+
+ c.on('connect', common.mustNotCall());
+ c.on('error', common.expectsError({
+ code: 'ENOENT',
+ message: `connect ENOENT ${fp}`
+ }));
+}
+
+{
+ assert.throws(
+ () => net.createConnection({ path: {} }),
+ { code: 'ERR_INVALID_ARG_TYPE' }
+ );
+}
diff --git a/tests/node_compat/test/parallel/test-net-better-error-messages-port-hostname.js b/tests/node_compat/test/parallel/test-net-better-error-messages-port-hostname.js
new file mode 100644
index 000000000..6db63fef3
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-net-better-error-messages-port-hostname.js
@@ -0,0 +1,44 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+// This tests that the error thrown from net.createConnection
+// comes with host and port properties.
+// See https://github.com/nodejs/node-v0.x-archive/issues/7005
+
+const common = require('../common');
+const assert = require('assert');
+const net = require('net');
+
+const { addresses } = require('../common/internet');
+const {
+ errorLookupMock,
+ mockedErrorCode
+} = require('../common/dns');
+
+// Using port 0 as hostname used is already invalid.
+const c = net.createConnection({
+ port: 0,
+ host: addresses.INVALID_HOST,
+ lookup: common.mustCall(errorLookupMock())
+});
+
+c.on('connect', common.mustNotCall());
+
+c.on('error', common.mustCall((error) => {
+ assert.ok(!('port' in error));
+ assert.ok(!('host' in error));
+ assert.throws(() => { throw error; }, {
+ errno: mockedErrorCode,
+ code: mockedErrorCode,
+ name: 'Error',
+ message: 'getaddrinfo ENOTFOUND something.invalid',
+ hostname: addresses.INVALID_HOST,
+ syscall: 'getaddrinfo'
+ });
+}));
diff --git a/tests/node_compat/test/parallel/test-net-connect-after-destroy.js b/tests/node_compat/test/parallel/test-net-connect-after-destroy.js
new file mode 100644
index 000000000..e08d7c036
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-net-connect-after-destroy.js
@@ -0,0 +1,16 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+// Regression test for https://github.com/nodejs/node-v0.x-archive/issues/819.
+
+require('../common');
+const net = require('net');
+
+// Connect to something that we need to DNS resolve
+const c = net.createConnection(80, 'google.com');
+c.destroy();
diff --git a/tests/node_compat/test/parallel/test-net-connect-buffer.js b/tests/node_compat/test/parallel/test-net-connect-buffer.js
new file mode 100644
index 000000000..04e71247e
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-net-connect-buffer.js
@@ -0,0 +1,86 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 16.13.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const net = require('net');
+
+// TODO: support not using "new"
+const tcp = new net.Server(common.mustCall((s) => {
+ tcp.close();
+
+ let buf = '';
+ s.setEncoding('utf8');
+ s.on('data', function(d) {
+ buf += d;
+ });
+
+ s.on('end', common.mustCall(function() {
+ console.error('SERVER: end', buf);
+ assert.strictEqual(buf, "L'État, c'est moi");
+ s.end();
+ }));
+}));
+
+tcp.listen(0, common.mustCall(function() {
+ // TODO: support not using "new"
+ const socket = new net.Stream({ highWaterMark: 0 });
+
+ let connected = false;
+ assert.strictEqual(socket.pending, true);
+ socket.connect(this.address().port, common.mustCall(() => connected = true));
+
+ assert.strictEqual(socket.pending, true);
+ assert.strictEqual(socket.connecting, true);
+ assert.strictEqual(socket.readyState, 'opening');
+
+ // Write a string that contains a multi-byte character sequence to test that
+ // `bytesWritten` is incremented with the # of bytes, not # of characters.
+ const a = "L'État, c'est ";
+ const b = 'moi';
+
+ // We're still connecting at this point so the datagram is first pushed onto
+ // the connect queue. Make sure that it's not added to `bytesWritten` again
+ // when the actual write happens.
+ const r = socket.write(a, common.mustCall((er) => {
+ console.error('write cb');
+ assert.ok(connected);
+ assert.strictEqual(socket.bytesWritten, Buffer.from(a + b).length);
+ assert.strictEqual(socket.pending, false);
+ }));
+ socket.on('close', common.mustCall(() => {
+ assert.strictEqual(socket.pending, true);
+ }));
+
+ assert.strictEqual(socket.bytesWritten, Buffer.from(a).length);
+ assert.strictEqual(r, false);
+ socket.end(b);
+
+ assert.strictEqual(socket.readyState, 'opening');
+}));
diff --git a/tests/node_compat/test/parallel/test-net-connect-buffer2.js b/tests/node_compat/test/parallel/test-net-connect-buffer2.js
new file mode 100644
index 000000000..499f3849f
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-net-connect-buffer2.js
@@ -0,0 +1,63 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 16.13.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const net = require('net');
+
+const tcp = new net.Server(common.mustCall((s) => {
+ tcp.close();
+
+ let buf = '';
+ s.setEncoding('utf8');
+ s.on('data', function(d) {
+ buf += d;
+ });
+
+ s.on('end', common.mustCall(function() {
+ console.error('SERVER: end', buf);
+ assert.strictEqual(buf, "L'État, c'est moi");
+ s.end();
+ }));
+}));
+
+tcp.listen(0, common.mustCall(function() {
+ const socket = new net.Stream({ highWaterMark: 0 });
+
+ let connected = false;
+ assert.strictEqual(socket.pending, true);
+ socket.connect(this.address().port, common.mustCall(() => connected = true));
+
+ assert.strictEqual(socket.pending, true);
+ assert.strictEqual(socket.connecting, true);
+ assert.strictEqual(socket.readyState, 'opening');
+
+ // Write a string that contains a multi-byte character sequence to test that
+ // `bytesWritten` is incremented with the # of bytes, not # of characters.
+ const a = "L'État, c'est ";
+ const b = 'moi';
+
+ // We're still connecting at this point so the datagram is first pushed onto
+ // the connect queue. Make sure that it's not added to `bytesWritten` again
+ // when the actual write happens.
+ const r = socket.write(a, common.mustCall((er) => {
+ console.error('write cb');
+ assert.ok(connected);
+ assert.strictEqual(socket.bytesWritten, Buffer.from(a + b).length);
+ assert.strictEqual(socket.pending, false);
+ }));
+ socket.on('close', common.mustCall(() => {
+ assert.strictEqual(socket.pending, true);
+ }));
+
+ assert.strictEqual(socket.bytesWritten, Buffer.from(a).length);
+ assert.strictEqual(r, false);
+ socket.end(b);
+
+ assert.strictEqual(socket.readyState, 'opening');
+}));
diff --git a/tests/node_compat/test/parallel/test-net-connect-destroy.js b/tests/node_compat/test/parallel/test-net-connect-destroy.js
new file mode 100644
index 000000000..2dcea39b2
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-net-connect-destroy.js
@@ -0,0 +1,14 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const net = require('net');
+
+const socket = new net.Socket();
+socket.on('close', common.mustCall());
+socket.destroy();
diff --git a/tests/node_compat/test/parallel/test-net-connect-immediate-destroy.js b/tests/node_compat/test/parallel/test-net-connect-immediate-destroy.js
new file mode 100644
index 000000000..08d65f75e
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-net-connect-immediate-destroy.js
@@ -0,0 +1,18 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const net = require('net');
+
+const server = net.createServer();
+server.listen(0);
+const port = server.address().port;
+const socket = net.connect(port, common.localhostIPv4, common.mustNotCall());
+socket.on('error', common.mustNotCall());
+server.close();
+socket.destroy();
diff --git a/tests/node_compat/test/parallel/test-net-connect-immediate-finish.js b/tests/node_compat/test/parallel/test-net-connect-immediate-finish.js
new file mode 100644
index 000000000..4df92e9c1
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-net-connect-immediate-finish.js
@@ -0,0 +1,66 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+
+// This tests that if the socket is still in the 'connecting' state
+// when the user calls socket.end() ('finish'), the socket would emit
+// 'connect' and defer the handling until the 'connect' event is handled.
+
+const common = require('../common');
+const assert = require('assert');
+const net = require('net');
+
+const { addresses } = require('../common/internet');
+const {
+ errorLookupMock,
+ mockedErrorCode,
+ mockedSysCall
+} = require('../common/dns');
+
+const client = net.connect({
+ host: addresses.INVALID_HOST,
+ port: 80, // Port number doesn't matter because host name is invalid
+ lookup: common.mustCall(errorLookupMock())
+}, common.mustNotCall());
+
+client.once('error', common.mustCall((error) => {
+ // TODO(BridgeAR): Add a better way to handle not defined properties using
+ // `assert.throws(fn, object)`.
+ assert.ok(!('port' in error));
+ assert.ok(!('host' in error));
+ assert.throws(() => { throw error; }, {
+ code: mockedErrorCode,
+ errno: mockedErrorCode,
+ syscall: mockedSysCall,
+ hostname: addresses.INVALID_HOST,
+ message: 'getaddrinfo ENOTFOUND something.invalid'
+ });
+}));
+
+client.end();
diff --git a/tests/node_compat/test/parallel/test-net-connect-no-arg.js b/tests/node_compat/test/parallel/test-net-connect-no-arg.js
new file mode 100644
index 000000000..3e3e3eec4
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-net-connect-no-arg.js
@@ -0,0 +1,42 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+require('../common');
+const assert = require('assert');
+const net = require('net');
+
+// Tests that net.connect() called without arguments throws ERR_MISSING_ARGS.
+
+assert.throws(() => {
+ net.connect();
+}, {
+ code: 'ERR_MISSING_ARGS',
+ message: 'The "options" or "port" or "path" argument must be specified',
+});
+
+assert.throws(() => {
+ new net.Socket().connect();
+}, {
+ code: 'ERR_MISSING_ARGS',
+ message: 'The "options" or "port" or "path" argument must be specified',
+});
+
+assert.throws(() => {
+ net.connect({});
+}, {
+ code: 'ERR_MISSING_ARGS',
+ message: 'The "options" or "port" or "path" argument must be specified',
+});
+
+assert.throws(() => {
+ new net.Socket().connect({});
+}, {
+ code: 'ERR_MISSING_ARGS',
+ message: 'The "options" or "port" or "path" argument must be specified',
+});
diff --git a/tests/node_compat/test/parallel/test-net-dns-error.js b/tests/node_compat/test/parallel/test-net-dns-error.js
new file mode 100644
index 000000000..ce326dd6f
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-net-dns-error.js
@@ -0,0 +1,48 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+
+const assert = require('assert');
+const net = require('net');
+
+const host = '*'.repeat(64);
+// Resolving hostname > 63 characters may return EAI_FAIL (permanent failure).
+const errCodes = ['ENOTFOUND', 'EAI_FAIL'];
+
+const socket = net.connect(42, host, common.mustNotCall());
+socket.on('error', common.mustCall(function(err) {
+ assert(errCodes.includes(err.code), err);
+}));
+socket.on('lookup', common.mustCall(function(err, ip, type) {
+ assert(err instanceof Error);
+ assert(errCodes.includes(err.code), err);
+ assert.strictEqual(ip, undefined);
+ assert.strictEqual(type, undefined);
+}));
diff --git a/tests/node_compat/test/parallel/test-net-during-close.js b/tests/node_compat/test/parallel/test-net-during-close.js
new file mode 100644
index 000000000..f13c9fb18
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-net-during-close.js
@@ -0,0 +1,49 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const net = require('net');
+
+const server = net.createServer(function(socket) {
+ socket.end();
+});
+
+server.listen(0, common.mustCall(function() {
+ /* eslint-disable no-unused-expressions */
+ const client = net.createConnection(this.address().port);
+ server.close();
+ // Server connection event has not yet fired client is still attempting to
+ // connect. Accessing properties should not throw in this case.
+ client.remoteAddress;
+ client.remoteFamily;
+ client.remotePort;
+ // Exit now, do not wait for the client error event.
+ process.exit(0);
+ /* eslint-enable no-unused-expressions */
+}));
diff --git a/tests/node_compat/test/parallel/test-net-end-close.js b/tests/node_compat/test/parallel/test-net-end-close.js
new file mode 100644
index 000000000..a818dd097
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-net-end-close.js
@@ -0,0 +1,44 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 16.13.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// Flags: --expose-internals
+'use strict';
+require('../common');
+const assert = require('assert');
+const net = require('net');
+
+// const { internalBinding } = require('internal/test/binding');
+// const { UV_EOF } = internalBinding('uv');
+// const { streamBaseState, kReadBytesOrError } = internalBinding('stream_wrap');
+
+const s = new net.Socket({
+ handle: {
+ readStart: function() {
+ setImmediate(() => {
+ // streamBaseState[kReadBytesOrError] = UV_EOF;
+ // internal onread has different shape to Node.
+ this.onread(new Uint8Array(), -4095);
+ });
+ },
+ close: (cb) => setImmediate(cb)
+ },
+ writable: false
+});
+assert.strictEqual(s, s.resume());
+
+const events = [];
+
+s.on('end', () => {
+ events.push('end');
+});
+s.on('close', () => {
+ events.push('close');
+});
+
+process.on('exit', () => {
+ assert.deepStrictEqual(events, [ 'end', 'close' ]);
+});
diff --git a/tests/node_compat/test/parallel/test-net-end-without-connect.js b/tests/node_compat/test/parallel/test-net-end-without-connect.js
new file mode 100644
index 000000000..f14d81770
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-net-end-without-connect.js
@@ -0,0 +1,34 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+require('../common');
+const net = require('net');
+
+const sock = new net.Socket();
+sock.end(); // Should not throw.
diff --git a/tests/node_compat/test/parallel/test-net-isip.js b/tests/node_compat/test/parallel/test-net-isip.js
new file mode 100644
index 000000000..016277483
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-net-isip.js
@@ -0,0 +1,103 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+const net = require('net');
+
+assert.strictEqual(net.isIP('127.0.0.1'), 4);
+assert.strictEqual(net.isIP('x127.0.0.1'), 0);
+assert.strictEqual(net.isIP('example.com'), 0);
+assert.strictEqual(net.isIP('0000:0000:0000:0000:0000:0000:0000:0000'), 6);
+assert.strictEqual(net.isIP('0000:0000:0000:0000:0000:0000:0000:0000::0000'),
+ 0);
+assert.strictEqual(net.isIP('1050:0:0:0:5:600:300c:326b'), 6);
+assert.strictEqual(net.isIP('2001:252:0:1::2008:6'), 6);
+assert.strictEqual(net.isIP('2001:dead:beef:1::2008:6'), 6);
+assert.strictEqual(net.isIP('2001::'), 6);
+assert.strictEqual(net.isIP('2001:dead::'), 6);
+assert.strictEqual(net.isIP('2001:dead:beef::'), 6);
+assert.strictEqual(net.isIP('2001:dead:beef:1::'), 6);
+assert.strictEqual(net.isIP('ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff'), 6);
+assert.strictEqual(net.isIP(':2001:252:0:1::2008:6:'), 0);
+assert.strictEqual(net.isIP(':2001:252:0:1::2008:6'), 0);
+assert.strictEqual(net.isIP('2001:252:0:1::2008:6:'), 0);
+assert.strictEqual(net.isIP('2001:252::1::2008:6'), 0);
+assert.strictEqual(net.isIP('::2001:252:1:2008:6'), 6);
+assert.strictEqual(net.isIP('::2001:252:1:1.1.1.1'), 6);
+assert.strictEqual(net.isIP('::2001:252:1:255.255.255.255'), 6);
+assert.strictEqual(net.isIP('::2001:252:1:255.255.255.255.76'), 0);
+assert.strictEqual(net.isIP('fe80::2008%eth0'), 6);
+assert.strictEqual(net.isIP('fe80::2008%eth0.0'), 6);
+assert.strictEqual(net.isIP('fe80::2008%eth0@1'), 0);
+assert.strictEqual(net.isIP('::anything'), 0);
+assert.strictEqual(net.isIP('::1'), 6);
+assert.strictEqual(net.isIP('::'), 6);
+assert.strictEqual(net.isIP('0000:0000:0000:0000:0000:0000:12345:0000'), 0);
+assert.strictEqual(net.isIP('0'), 0);
+assert.strictEqual(net.isIP(), 0);
+assert.strictEqual(net.isIP(''), 0);
+assert.strictEqual(net.isIP(null), 0);
+assert.strictEqual(net.isIP(123), 0);
+assert.strictEqual(net.isIP(true), 0);
+assert.strictEqual(net.isIP({}), 0);
+assert.strictEqual(net.isIP({ toString: () => '::2001:252:1:255.255.255.255' }),
+ 6);
+assert.strictEqual(net.isIP({ toString: () => '127.0.0.1' }), 4);
+assert.strictEqual(net.isIP({ toString: () => 'bla' }), 0);
+
+assert.strictEqual(net.isIPv4('127.0.0.1'), true);
+assert.strictEqual(net.isIPv4('example.com'), false);
+assert.strictEqual(net.isIPv4('2001:252:0:1::2008:6'), false);
+assert.strictEqual(net.isIPv4(), false);
+assert.strictEqual(net.isIPv4(''), false);
+assert.strictEqual(net.isIPv4(null), false);
+assert.strictEqual(net.isIPv4(123), false);
+assert.strictEqual(net.isIPv4(true), false);
+assert.strictEqual(net.isIPv4({}), false);
+assert.strictEqual(net.isIPv4({
+ toString: () => '::2001:252:1:255.255.255.255'
+}), false);
+assert.strictEqual(net.isIPv4({ toString: () => '127.0.0.1' }), true);
+assert.strictEqual(net.isIPv4({ toString: () => 'bla' }), false);
+
+assert.strictEqual(net.isIPv6('127.0.0.1'), false);
+assert.strictEqual(net.isIPv6('example.com'), false);
+assert.strictEqual(net.isIPv6('2001:252:0:1::2008:6'), true);
+assert.strictEqual(net.isIPv6(), false);
+assert.strictEqual(net.isIPv6(''), false);
+assert.strictEqual(net.isIPv6(null), false);
+assert.strictEqual(net.isIPv6(123), false);
+assert.strictEqual(net.isIPv6(true), false);
+assert.strictEqual(net.isIPv6({}), false);
+assert.strictEqual(net.isIPv6({
+ toString: () => '::2001:252:1:255.255.255.255'
+}), true);
+assert.strictEqual(net.isIPv6({ toString: () => '127.0.0.1' }), false);
+assert.strictEqual(net.isIPv6({ toString: () => 'bla' }), false);
diff --git a/tests/node_compat/test/parallel/test-net-isipv4.js b/tests/node_compat/test/parallel/test-net-isipv4.js
new file mode 100644
index 000000000..a9733c342
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-net-isipv4.js
@@ -0,0 +1,53 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+const net = require('net');
+
+const v4 = [
+ '0.0.0.0',
+ '8.8.8.8',
+ '127.0.0.1',
+ '100.100.100.100',
+ '192.168.0.1',
+ '18.101.25.153',
+ '123.23.34.2',
+ '172.26.168.134',
+ '212.58.241.131',
+ '128.0.0.0',
+ '23.71.254.72',
+ '223.255.255.255',
+ '192.0.2.235',
+ '99.198.122.146',
+ '46.51.197.88',
+ '173.194.34.134',
+];
+
+const v4not = [
+ '.100.100.100.100',
+ '100..100.100.100.',
+ '100.100.100.100.',
+ '999.999.999.999',
+ '256.256.256.256',
+ '256.100.100.100.100',
+ '123.123.123',
+ 'http://123.123.123',
+ '1000.2.3.4',
+ '999.2.3.4',
+ '0000000192.168.0.200',
+ '192.168.0.2000000000',
+];
+
+v4.forEach((ip) => {
+ assert.strictEqual(net.isIPv4(ip), true);
+});
+
+v4not.forEach((ip) => {
+ assert.strictEqual(net.isIPv4(ip), false);
+});
diff --git a/tests/node_compat/test/parallel/test-net-isipv6.js b/tests/node_compat/test/parallel/test-net-isipv6.js
new file mode 100644
index 000000000..cc74fe657
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-net-isipv6.js
@@ -0,0 +1,251 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+const net = require('net');
+
+const v6 = [
+ '::',
+ '1::',
+ '::1',
+ '1::8',
+ '1::7:8',
+ '1:2:3:4:5:6:7:8',
+ '1:2:3:4:5:6::8',
+ '1:2:3:4:5:6:7::',
+ '1:2:3:4:5::7:8',
+ '1:2:3:4:5::8',
+ '1:2:3::8',
+ '1::4:5:6:7:8',
+ '1::6:7:8',
+ '1::3:4:5:6:7:8',
+ '1:2:3:4::6:7:8',
+ '1:2::4:5:6:7:8',
+ '::2:3:4:5:6:7:8',
+ '1:2::8',
+ '2001:0000:1234:0000:0000:C1C0:ABCD:0876',
+ '3ffe:0b00:0000:0000:0001:0000:0000:000a',
+ 'FF02:0000:0000:0000:0000:0000:0000:0001',
+ '0000:0000:0000:0000:0000:0000:0000:0001',
+ '0000:0000:0000:0000:0000:0000:0000:0000',
+ '::ffff:192.168.1.26',
+ '2::10',
+ 'ff02::1',
+ 'fe80::',
+ '2002::',
+ '2001:db8::',
+ '2001:0db8:1234::',
+ '::ffff:0:0',
+ '::ffff:192.168.1.1',
+ '1:2:3:4::8',
+ '1::2:3:4:5:6:7',
+ '1::2:3:4:5:6',
+ '1::2:3:4:5',
+ '1::2:3:4',
+ '1::2:3',
+ '::2:3:4:5:6:7',
+ '::2:3:4:5:6',
+ '::2:3:4:5',
+ '::2:3:4',
+ '::2:3',
+ '::8',
+ '1:2:3:4:5:6::',
+ '1:2:3:4:5::',
+ '1:2:3:4::',
+ '1:2:3::',
+ '1:2::',
+ '1:2:3:4::7:8',
+ '1:2:3::7:8',
+ '1:2::7:8',
+ '1:2:3:4:5:6:1.2.3.4',
+ '1:2:3:4:5::1.2.3.4',
+ '1:2:3:4::1.2.3.4',
+ '1:2:3::1.2.3.4',
+ '1:2::1.2.3.4',
+ '1::1.2.3.4',
+ '1:2:3:4::5:1.2.3.4',
+ '1:2:3::5:1.2.3.4',
+ '1:2::5:1.2.3.4',
+ '1::5:1.2.3.4',
+ '1::5:11.22.33.44',
+ 'fe80::217:f2ff:254.7.237.98',
+ 'fe80::217:f2ff:fe07:ed62',
+ '2001:DB8:0:0:8:800:200C:417A',
+ 'FF01:0:0:0:0:0:0:101',
+ '0:0:0:0:0:0:0:1',
+ '0:0:0:0:0:0:0:0',
+ '2001:DB8::8:800:200C:417A',
+ 'FF01::101',
+ '0:0:0:0:0:0:13.1.68.3',
+ '0:0:0:0:0:FFFF:129.144.52.38',
+ '::13.1.68.3',
+ '::FFFF:129.144.52.38',
+ 'fe80:0000:0000:0000:0204:61ff:fe9d:f156',
+ 'fe80:0:0:0:204:61ff:fe9d:f156',
+ 'fe80::204:61ff:fe9d:f156',
+ 'fe80:0:0:0:204:61ff:254.157.241.86',
+ 'fe80::204:61ff:254.157.241.86',
+ 'fe80::1',
+ '2001:0db8:85a3:0000:0000:8a2e:0370:7334',
+ '2001:db8:85a3:0:0:8a2e:370:7334',
+ '2001:db8:85a3::8a2e:370:7334',
+ '2001:0db8:0000:0000:0000:0000:1428:57ab',
+ '2001:0db8:0000:0000:0000::1428:57ab',
+ '2001:0db8:0:0:0:0:1428:57ab',
+ '2001:0db8:0:0::1428:57ab',
+ '2001:0db8::1428:57ab',
+ '2001:db8::1428:57ab',
+ '::ffff:12.34.56.78',
+ '::ffff:0c22:384e',
+ '2001:0db8:1234:0000:0000:0000:0000:0000',
+ '2001:0db8:1234:ffff:ffff:ffff:ffff:ffff',
+ '2001:db8:a::123',
+ '::ffff:192.0.2.128',
+ '::ffff:c000:280',
+ 'a:b:c:d:e:f:f1:f2',
+ 'a:b:c::d:e:f:f1',
+ 'a:b:c::d:e:f',
+ 'a:b:c::d:e',
+ 'a:b:c::d',
+ '::a',
+ '::a:b:c',
+ '::a:b:c:d:e:f:f1',
+ 'a::',
+ 'a:b:c::',
+ 'a:b:c:d:e:f:f1::',
+ 'a:bb:ccc:dddd:000e:00f:0f::',
+ '0:a:0:a:0:0:0:a',
+ '0:a:0:0:a:0:0:a',
+ '2001:db8:1:1:1:1:0:0',
+ '2001:db8:1:1:1:0:0:0',
+ '2001:db8:1:1:0:0:0:0',
+ '2001:db8:1:0:0:0:0:0',
+ '2001:db8:0:0:0:0:0:0',
+ '2001:0:0:0:0:0:0:0',
+ 'A:BB:CCC:DDDD:000E:00F:0F::',
+ '0:0:0:0:0:0:0:a',
+ '0:0:0:0:a:0:0:0',
+ '0:0:0:a:0:0:0:0',
+ 'a:0:0:a:0:0:a:a',
+ 'a:0:0:a:0:0:0:a',
+ 'a:0:0:0:a:0:0:a',
+ 'a:0:0:0:a:0:0:0',
+ 'a:0:0:0:0:0:0:0',
+ 'fe80::7:8%eth0',
+ 'fe80::7:8%1',
+];
+
+const v6not = [
+ '',
+ '1:',
+ ':1',
+ '11:36:12',
+ '02001:0000:1234:0000:0000:C1C0:ABCD:0876',
+ '2001:0000:1234:0000:00001:C1C0:ABCD:0876',
+ '2001:0000:1234: 0000:0000:C1C0:ABCD:0876',
+ '2001:1:1:1:1:1:255Z255X255Y255',
+ '3ffe:0b00:0000:0001:0000:0000:000a',
+ 'FF02:0000:0000:0000:0000:0000:0000:0000:0001',
+ '3ffe:b00::1::a',
+ '::1111:2222:3333:4444:5555:6666::',
+ '1:2:3::4:5::7:8',
+ '12345::6:7:8',
+ '1::5:400.2.3.4',
+ '1::5:260.2.3.4',
+ '1::5:256.2.3.4',
+ '1::5:1.256.3.4',
+ '1::5:1.2.256.4',
+ '1::5:1.2.3.256',
+ '1::5:300.2.3.4',
+ '1::5:1.300.3.4',
+ '1::5:1.2.300.4',
+ '1::5:1.2.3.300',
+ '1::5:900.2.3.4',
+ '1::5:1.900.3.4',
+ '1::5:1.2.900.4',
+ '1::5:1.2.3.900',
+ '1::5:300.300.300.300',
+ '1::5:3000.30.30.30',
+ '1::400.2.3.4',
+ '1::260.2.3.4',
+ '1::256.2.3.4',
+ '1::1.256.3.4',
+ '1::1.2.256.4',
+ '1::1.2.3.256',
+ '1::300.2.3.4',
+ '1::1.300.3.4',
+ '1::1.2.300.4',
+ '1::1.2.3.300',
+ '1::900.2.3.4',
+ '1::1.900.3.4',
+ '1::1.2.900.4',
+ '1::1.2.3.900',
+ '1::300.300.300.300',
+ '1::3000.30.30.30',
+ '::400.2.3.4',
+ '::260.2.3.4',
+ '::256.2.3.4',
+ '::1.256.3.4',
+ '::1.2.256.4',
+ '::1.2.3.256',
+ '::300.2.3.4',
+ '::1.300.3.4',
+ '::1.2.300.4',
+ '::1.2.3.300',
+ '::900.2.3.4',
+ '::1.900.3.4',
+ '::1.2.900.4',
+ '::1.2.3.900',
+ '::300.300.300.300',
+ '::3000.30.30.30',
+ '2001:DB8:0:0:8:800:200C:417A:221',
+ 'FF01::101::2',
+ '1111:2222:3333:4444::5555:',
+ '1111:2222:3333::5555:',
+ '1111:2222::5555:',
+ '1111::5555:',
+ '::5555:',
+ ':::',
+ '1111:',
+ ':',
+ ':1111:2222:3333:4444::5555',
+ ':1111:2222:3333::5555',
+ ':1111:2222::5555',
+ ':1111::5555',
+ ':::5555',
+ '1.2.3.4:1111:2222:3333:4444::5555',
+ '1.2.3.4:1111:2222:3333::5555',
+ '1.2.3.4:1111:2222::5555',
+ '1.2.3.4:1111::5555',
+ '1.2.3.4::5555',
+ '1.2.3.4::',
+ 'fe80:0000:0000:0000:0204:61ff:254.157.241.086',
+ '123',
+ 'ldkfj',
+ '2001::FFD3::57ab',
+ '2001:db8:85a3::8a2e:37023:7334',
+ '2001:db8:85a3::8a2e:370k:7334',
+ '1:2:3:4:5:6:7:8:9',
+ '1::2::3',
+ '1:::3:4:5',
+ '1:2:3::4:5:6:7:8:9',
+ '::ffff:2.3.4',
+ '::ffff:257.1.2.3',
+ '::ffff:12345678901234567890.1.26',
+ '2001:0000:1234:0000:0000:C1C0:ABCD:0876 0',
+ '02001:0000:1234:0000:0000:C1C0:ABCD:0876',
+];
+
+v6.forEach((ip) => {
+ assert.strictEqual(net.isIPv6(ip), true);
+});
+
+v6not.forEach((ip) => {
+ assert.strictEqual(net.isIPv6(ip), false);
+});
diff --git a/tests/node_compat/test/parallel/test-net-listen-close-server-callback-is-not-function.js b/tests/node_compat/test/parallel/test-net-listen-close-server-callback-is-not-function.js
new file mode 100644
index 000000000..69b72b9c2
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-net-listen-close-server-callback-is-not-function.js
@@ -0,0 +1,18 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const net = require('net');
+
+const server = net.createServer(common.mustNotCall());
+
+server.on('close', common.mustCall());
+
+server.listen(0, common.mustNotCall());
+
+server.close('bad argument');
diff --git a/tests/node_compat/test/parallel/test-net-listen-close-server.js b/tests/node_compat/test/parallel/test-net-listen-close-server.js
new file mode 100644
index 000000000..441cf4511
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-net-listen-close-server.js
@@ -0,0 +1,37 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const net = require('net');
+
+const server = net.createServer(function(socket) {
+});
+server.listen(0, common.mustNotCall());
+server.on('error', common.mustNotCall());
+server.close();
diff --git a/tests/node_compat/test/parallel/test-net-listen-invalid-port.js b/tests/node_compat/test/parallel/test-net-listen-invalid-port.js
new file mode 100644
index 000000000..10685f1d0
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-net-listen-invalid-port.js
@@ -0,0 +1,52 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 16.13.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+'use strict';
+const common = require('../common');
+
+// This test ensures that port numbers are validated in *all* kinds of `listen`
+// calls. If an invalid port is supplied, ensures a `RangeError` is thrown.
+// https://github.com/nodejs/node/issues/5727
+
+const assert = require('assert');
+const net = require('net');
+
+const invalidPort = -1 >>> 0;
+
+// TODO: support net.Server() without new
+
+new net.Server().listen(0, function() {
+ const address = this.address();
+ const key = `${address.family}:${address.address}:0`;
+
+ assert.strictEqual(this._connectionKey, key);
+ this.close();
+});
+
+// The first argument is a configuration object
+assert.throws(() => {
+ new net.Server().listen({ port: invalidPort }, common.mustNotCall());
+}, {
+ code: 'ERR_SOCKET_BAD_PORT',
+ name: 'RangeError'
+});
+
+// The first argument is the port, no IP given.
+assert.throws(() => {
+ new net.Server().listen(invalidPort, common.mustNotCall());
+}, {
+ code: 'ERR_SOCKET_BAD_PORT',
+ name: 'RangeError'
+});
+
+// The first argument is the port, the second an IP.
+assert.throws(() => {
+ new net.Server().listen(invalidPort, '0.0.0.0', common.mustNotCall());
+}, {
+ code: 'ERR_SOCKET_BAD_PORT',
+ name: 'RangeError'
+});
diff --git a/tests/node_compat/test/parallel/test-net-listening.js b/tests/node_compat/test/parallel/test-net-listening.js
new file mode 100644
index 000000000..275dd06eb
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-net-listening.js
@@ -0,0 +1,23 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const net = require('net');
+
+const server = net.createServer();
+
+assert.strictEqual(server.listening, false);
+
+server.listen(0, common.mustCall(() => {
+ assert.strictEqual(server.listening, true);
+
+ server.close(common.mustCall(() => {
+ assert.strictEqual(server.listening, false);
+ }));
+}));
diff --git a/tests/node_compat/test/parallel/test-net-localerror.js b/tests/node_compat/test/parallel/test-net-localerror.js
new file mode 100644
index 000000000..9e2080ed4
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-net-localerror.js
@@ -0,0 +1,51 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+const net = require('net');
+
+const connect = (opts, code, type) => {
+ assert.throws(
+ () => net.connect(opts),
+ { code, name: type.name }
+ );
+};
+
+connect({
+ host: 'localhost',
+ port: 0,
+ localAddress: 'foobar',
+}, 'ERR_INVALID_IP_ADDRESS', TypeError);
+
+connect({
+ host: 'localhost',
+ port: 0,
+ localPort: 'foobar',
+}, 'ERR_INVALID_ARG_TYPE', TypeError);
diff --git a/tests/node_compat/test/parallel/test-net-options-lookup.js b/tests/node_compat/test/parallel/test-net-options-lookup.js
new file mode 100644
index 000000000..d3ca0451c
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-net-options-lookup.js
@@ -0,0 +1,59 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const net = require('net');
+
+['foobar', 1, {}, []].forEach((input) => connectThrows(input));
+
+// Using port 0 as lookup is emitted before connecting.
+function connectThrows(input) {
+ const opts = {
+ host: 'localhost',
+ port: 0,
+ lookup: input
+ };
+
+ assert.throws(() => {
+ net.connect(opts);
+ }, {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError'
+ });
+}
+
+connectDoesNotThrow(() => {});
+
+function connectDoesNotThrow(input) {
+ const opts = {
+ host: 'localhost',
+ port: 0,
+ lookup: input
+ };
+
+ return net.connect(opts);
+}
+
+{
+ // Verify that an error is emitted when an invalid address family is returned.
+ const s = connectDoesNotThrow((host, options, cb) => {
+ if (options.all) {
+ cb(null, [{ address: '127.0.0.1', family: 100 }]);
+ } else {
+ cb(null, '127.0.0.1', 100);
+ }
+ });
+
+ s.on('error', common.expectsError({
+ code: 'ERR_INVALID_ADDRESS_FAMILY',
+ host: 'localhost',
+ port: 0,
+ message: 'Invalid address family: 100 localhost:0'
+ }));
+}
diff --git a/tests/node_compat/test/parallel/test-net-pipe-connect-errors.js b/tests/node_compat/test/parallel/test-net-pipe-connect-errors.js
new file mode 100644
index 000000000..451c9eb92
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-net-pipe-connect-errors.js
@@ -0,0 +1,104 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const fixtures = require('../common/fixtures');
+const fs = require('fs');
+const net = require('net');
+const assert = require('assert');
+
+// Test if ENOTSOCK is fired when trying to connect to a file which is not
+// a socket.
+
+let emptyTxt;
+
+if (common.isWindows) {
+ // On Win, common.PIPE will be a named pipe, so we use an existing empty
+ // file instead
+ emptyTxt = fixtures.path('empty.txt');
+} else {
+ const tmpdir = require('../common/tmpdir');
+ tmpdir.refresh();
+ // Keep the file name very short so that we don't exceed the 108 char limit
+ // on CI for a POSIX socket. Even though this isn't actually a socket file,
+ // the error will be different from the one we are expecting if we exceed the
+ // limit.
+ emptyTxt = `${tmpdir.path}0.txt`;
+
+ function cleanup() {
+ try {
+ fs.unlinkSync(emptyTxt);
+ } catch (e) {
+ assert.strictEqual(e.code, 'ENOENT');
+ }
+ }
+ process.on('exit', cleanup);
+ cleanup();
+ fs.writeFileSync(emptyTxt, '');
+}
+
+const notSocketClient = net.createConnection(emptyTxt, function() {
+ assert.fail('connection callback should not run');
+});
+
+notSocketClient.on('error', common.mustCall(function(err) {
+ assert(err.code === 'ENOTSOCK' || err.code === 'ECONNREFUSED',
+ `received ${err.code} instead of ENOTSOCK or ECONNREFUSED`);
+}));
+
+
+// Trying to connect to not-existing socket should result in ENOENT error
+const noEntSocketClient = net.createConnection('no-ent-file', function() {
+ assert.fail('connection to non-existent socket, callback should not run');
+});
+
+noEntSocketClient.on('error', common.mustCall(function(err) {
+ assert.strictEqual(err.code, 'ENOENT');
+}));
+
+
+// On Windows or IBMi or when running as root,
+// a chmod has no effect on named pipes
+if (!common.isWindows && !common.isIBMi && process.getuid() !== 0) {
+ // Trying to connect to a socket one has no access to should result in EACCES
+ const accessServer = net.createServer(
+ common.mustNotCall('server callback should not run'));
+ accessServer.listen(common.PIPE, common.mustCall(function() {
+ fs.chmodSync(common.PIPE, 0);
+
+ const accessClient = net.createConnection(common.PIPE, function() {
+ assert.fail('connection should get EACCES, callback should not run');
+ });
+
+ accessClient.on('error', common.mustCall(function(err) {
+ assert.strictEqual(err.code, 'EACCES');
+ accessServer.close();
+ }));
+ }));
+}
diff --git a/tests/node_compat/test/parallel/test-net-server-call-listen-multiple-times.js b/tests/node_compat/test/parallel/test-net-server-call-listen-multiple-times.js
new file mode 100644
index 000000000..30b443b18
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-net-server-call-listen-multiple-times.js
@@ -0,0 +1,56 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 16.13.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+'use strict';
+
+const common = require('../common');
+const assert = require('assert');
+const net = require('net');
+
+// TODO: support net.Server() without new
+
+// First test. Check that after error event you can listen right away.
+{
+ const dummyServer = new net.Server();
+ const server = new net.Server();
+
+ // Run some server in order to simulate EADDRINUSE error.
+ dummyServer.listen(common.mustCall(() => {
+ // Try to listen used port.
+ server.listen(dummyServer.address().port);
+ }));
+
+ server.on('error', common.mustCall((e) => {
+ server.listen(common.mustCall(() => {
+ dummyServer.close();
+ server.close();
+ }));
+ }));
+}
+
+// Second test. Check that second listen call throws an error.
+{
+ const server = new net.Server();
+
+ server.listen(common.mustCall(() => server.close()));
+
+ assert.throws(() => server.listen(), {
+ code: 'ERR_SERVER_ALREADY_LISTEN',
+ name: 'Error'
+ });
+}
+
+// Third test.
+// Check that after the close call you can run listen method just fine.
+{
+ const server = new net.Server();
+
+ server.listen(common.mustCall(() => {
+ server.close();
+ server.listen(common.mustCall(() => server.close()));
+ }));
+}
diff --git a/tests/node_compat/test/parallel/test-net-server-listen-options-signal.js b/tests/node_compat/test/parallel/test-net-server-listen-options-signal.js
new file mode 100644
index 000000000..b8547f516
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-net-server-listen-options-signal.js
@@ -0,0 +1,39 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const net = require('net');
+
+{
+ // Test bad signal.
+ const server = net.createServer();
+ assert.throws(
+ () => server.listen({ port: 0, signal: 'INVALID_SIGNAL' }),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError'
+ });
+}
+
+{
+ // Test close.
+ const server = net.createServer();
+ const controller = new AbortController();
+ server.on('close', common.mustCall());
+ server.listen({ port: 0, signal: controller.signal });
+ controller.abort();
+}
+
+{
+ // Test close with pre-aborted signal.
+ const server = net.createServer();
+ const signal = AbortSignal.abort();
+ server.on('close', common.mustCall());
+ server.listen({ port: 0, signal });
+}
diff --git a/tests/node_compat/test/parallel/test-net-server-listen-options.js b/tests/node_compat/test/parallel/test-net-server-listen-options.js
new file mode 100644
index 000000000..4d76a7ca7
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-net-server-listen-options.js
@@ -0,0 +1,101 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const net = require('net');
+
+function close() { this.close(); }
+
+{
+ // Test listen()
+ net.createServer().listen().on('listening', common.mustCall(close));
+ // Test listen(cb)
+ net.createServer().listen(common.mustCall(close));
+ // Test listen(port)
+ net.createServer().listen(0).on('listening', common.mustCall(close));
+ // Test listen({port})
+ net.createServer().listen({ port: 0 })
+ .on('listening', common.mustCall(close));
+}
+
+// Test listen(port, cb) and listen({ port }, cb) combinations
+const listenOnPort = [
+ (port, cb) => net.createServer().listen({ port }, cb),
+ (port, cb) => net.createServer().listen(port, cb),
+];
+
+{
+ const assertPort = () => {
+ return common.expectsError({
+ code: 'ERR_SOCKET_BAD_PORT',
+ name: 'RangeError'
+ });
+ };
+
+ for (const listen of listenOnPort) {
+ // Arbitrary unused ports
+ listen('0', common.mustCall(close));
+ listen(0, common.mustCall(close));
+ listen(undefined, common.mustCall(close));
+ listen(null, common.mustCall(close));
+ // Test invalid ports
+ assert.throws(() => listen(-1, common.mustNotCall()), assertPort());
+ assert.throws(() => listen(NaN, common.mustNotCall()), assertPort());
+ assert.throws(() => listen(123.456, common.mustNotCall()), assertPort());
+ assert.throws(() => listen(65536, common.mustNotCall()), assertPort());
+ assert.throws(() => listen(1 / 0, common.mustNotCall()), assertPort());
+ assert.throws(() => listen(-1 / 0, common.mustNotCall()), assertPort());
+ }
+ // In listen(options, cb), port takes precedence over path
+ assert.throws(() => {
+ net.createServer().listen({ port: -1, path: common.PIPE },
+ common.mustNotCall());
+ }, assertPort());
+}
+
+{
+ function shouldFailToListen(options) {
+ const fn = () => {
+ net.createServer().listen(options, common.mustNotCall());
+ };
+
+ if (typeof options === 'object' &&
+ !(('port' in options) || ('path' in options))) {
+ assert.throws(fn,
+ {
+ code: 'ERR_INVALID_ARG_VALUE',
+ name: 'TypeError',
+ message: /^The argument 'options' must have the property "port" or "path"\. Received .+$/,
+ });
+ } else {
+ assert.throws(fn,
+ {
+ code: 'ERR_INVALID_ARG_VALUE',
+ name: 'TypeError',
+ message: /^The argument 'options' is invalid\. Received .+$/,
+ });
+ }
+ }
+
+ shouldFailToListen(false, { port: false });
+ shouldFailToListen({ port: false });
+ shouldFailToListen(true);
+ shouldFailToListen({ port: true });
+ // Invalid fd as listen(handle)
+ shouldFailToListen({ fd: -1 });
+ // Invalid path in listen(options)
+ shouldFailToListen({ path: -1 });
+
+ // Neither port or path are specified in options
+ shouldFailToListen({});
+ shouldFailToListen({ host: 'localhost' });
+ shouldFailToListen({ host: 'localhost:3000' });
+ shouldFailToListen({ host: { port: 3000 } });
+ shouldFailToListen({ exclusive: true });
+}
diff --git a/tests/node_compat/test/parallel/test-net-server-listen-path.js b/tests/node_compat/test/parallel/test-net-server-listen-path.js
new file mode 100644
index 000000000..559e9c7eb
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-net-server-listen-path.js
@@ -0,0 +1,100 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 16.13.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+'use strict';
+
+const common = require('../common');
+const net = require('net');
+const assert = require('assert');
+const fs = require('fs');
+
+const tmpdir = require('../common/tmpdir');
+tmpdir.refresh();
+
+function closeServer() {
+ return common.mustCall(function() {
+ this.close();
+ });
+}
+
+let counter = 0;
+
+// Avoid conflict with listen-handle
+function randomPipePath() {
+ return `${common.PIPE}-listen-path-${counter++}`;
+}
+
+// Test listen(path)
+{
+ const handlePath = randomPipePath();
+ net.createServer()
+ .listen(handlePath)
+ .on('listening', closeServer());
+}
+
+// Test listen({path})
+{
+ const handlePath = randomPipePath();
+ net.createServer()
+ .listen({ path: handlePath })
+ .on('listening', closeServer());
+}
+
+// Test listen(path, cb)
+{
+ const handlePath = randomPipePath();
+ net.createServer()
+ .listen(handlePath, closeServer());
+}
+
+// Test listen(path, cb)
+{
+ const handlePath = randomPipePath();
+ net.createServer()
+ .listen({ path: handlePath }, closeServer());
+}
+
+// Test pipe chmod
+{
+ const handlePath = randomPipePath();
+
+ const server = net.createServer()
+ .listen({
+ path: handlePath,
+ readableAll: true,
+ writableAll: true
+ }, common.mustCall(() => {
+ if (process.platform !== 'win32') {
+ const mode = fs.statSync(handlePath).mode;
+ assert.notStrictEqual(mode & fs.constants.S_IROTH, 0);
+ assert.notStrictEqual(mode & fs.constants.S_IWOTH, 0);
+ }
+ server.close();
+ }));
+}
+
+// TODO(cmorten): seems Deno.listen() for Unix domains isn't throwing
+// Deno.errors.AddrInUse errors as would expect...?
+// Test should emit "error" events when listening fails.
+// {
+// const handlePath = randomPipePath();
+// const server1 = net.createServer().listen({ path: handlePath }, () => {
+// // As the handlePath is in use, binding to the same address again should
+// // make the server emit an 'EADDRINUSE' error.
+// const server2 = net.createServer()
+// .listen({
+// path: handlePath,
+// writableAll: true,
+// }, common.mustNotCall());
+
+// server2.on('error', common.mustCall((err) => {
+// server1.close();
+// assert.strictEqual(err.code, 'EADDRINUSE');
+// assert.match(err.message, /^listen EADDRINUSE: address already in use/);
+// }));
+// });
+// }
diff --git a/tests/node_compat/test/parallel/test-net-server-listen-remove-callback.js b/tests/node_compat/test/parallel/test-net-server-listen-remove-callback.js
new file mode 100644
index 000000000..15808a7a1
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-net-server-listen-remove-callback.js
@@ -0,0 +1,51 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+const net = require('net');
+
+// Server should only fire listen callback once
+const server = net.createServer();
+
+server.on('close', function() {
+ const listeners = server.listeners('listening');
+ console.log('Closed, listeners:', listeners.length);
+ assert.strictEqual(listeners.length, 0);
+});
+
+server.listen(0, function() {
+ server.close();
+});
+
+server.once('close', function() {
+ server.listen(0, function() {
+ server.close();
+ });
+});
diff --git a/tests/node_compat/test/parallel/test-net-server-options.js b/tests/node_compat/test/parallel/test-net-server-options.js
new file mode 100644
index 000000000..92086d149
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-net-server-options.js
@@ -0,0 +1,23 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+const net = require('net');
+
+assert.throws(() => net.createServer('path'),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError'
+ });
+
+assert.throws(() => net.createServer(0),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError'
+ });
diff --git a/tests/node_compat/test/parallel/test-net-server-try-ports.js b/tests/node_compat/test/parallel/test-net-server-try-ports.js
new file mode 100644
index 000000000..69dbc78b8
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-net-server-try-ports.js
@@ -0,0 +1,54 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 16.13.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+// This test binds to one port, then attempts to start a server on that
+// port. It should be EADDRINUSE but be able to then bind to another port.
+const common = require('../common');
+const assert = require('assert');
+const net = require('net');
+
+// TODO: support net.Server() without new
+
+const server1 = new net.Server();
+
+const server2 = new net.Server();
+
+server2.on('error', common.mustCall(function(e) {
+ assert.strictEqual(e.code, 'EADDRINUSE');
+
+ server2.listen(0, common.mustCall(function() {
+ server1.close();
+ server2.close();
+ }));
+}));
+
+server1.listen(0, common.mustCall(function() {
+ // This should make server2 emit EADDRINUSE
+ server2.listen(this.address().port);
+}));
diff --git a/tests/node_compat/test/parallel/test-net-server-unref-persistent.js b/tests/node_compat/test/parallel/test-net-server-unref-persistent.js
new file mode 100644
index 000000000..04b79686e
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-net-server-unref-persistent.js
@@ -0,0 +1,19 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const net = require('net');
+const server = net.createServer();
+
+// Unref before listening
+server.unref();
+server.listen();
+
+// If the timeout fires, that means the server held the event loop open
+// and the unref() was not persistent. Close the server and fail the test.
+setTimeout(common.mustNotCall(), 1000).unref();
diff --git a/tests/node_compat/test/parallel/test-net-server-unref.js b/tests/node_compat/test/parallel/test-net-server-unref.js
new file mode 100644
index 000000000..68fd6edb1
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-net-server-unref.js
@@ -0,0 +1,37 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const net = require('net');
+
+const s = net.createServer();
+s.listen(0);
+s.unref();
+
+setTimeout(common.mustNotCall(), 1000).unref();
diff --git a/tests/node_compat/test/parallel/test-net-socket-destroy-twice.js b/tests/node_compat/test/parallel/test-net-socket-destroy-twice.js
new file mode 100644
index 000000000..8cff55d70
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-net-socket-destroy-twice.js
@@ -0,0 +1,43 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const net = require('net');
+
+const server = net.createServer();
+server.listen(0);
+const port = server.address().port;
+const conn = net.createConnection(port);
+
+conn.on('error', common.mustCall(() => {
+ conn.destroy();
+}));
+
+conn.on('close', common.mustCall());
+server.close();
diff --git a/tests/node_compat/test/parallel/test-net-socket-no-halfopen-enforcer.js b/tests/node_compat/test/parallel/test-net-socket-no-halfopen-enforcer.js
new file mode 100644
index 000000000..c50b0061a
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-net-socket-no-halfopen-enforcer.js
@@ -0,0 +1,18 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+require('../common');
+
+// This test ensures that `net.Socket` does not inherit the no-half-open
+// enforcer from `stream.Duplex`.
+
+const { Socket } = require('net');
+const { strictEqual } = require('assert');
+
+const socket = new Socket({ allowHalfOpen: false });
+strictEqual(socket.listenerCount('end'), 1);
diff --git a/tests/node_compat/test/parallel/test-net-socket-timeout.js b/tests/node_compat/test/parallel/test-net-socket-timeout.js
new file mode 100644
index 000000000..b69e40530
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-net-socket-timeout.js
@@ -0,0 +1,88 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 16.13.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const net = require('net');
+const assert = require('assert');
+const { inspect } = require('util');
+
+// Verify that invalid delays throw
+const s = new net.Socket();
+const nonNumericDelays = [
+ '100', true, false, undefined, null, '', {}, () => {}, [],
+];
+const badRangeDelays = [-0.001, -1, -Infinity, Infinity, NaN];
+const validDelays = [0, 0.001, 1, 1e6];
+const invalidCallbacks = [
+ 1, '100', true, false, null, {}, [], Symbol('test'),
+];
+
+
+for (let i = 0; i < nonNumericDelays.length; i++) {
+ assert.throws(() => {
+ s.setTimeout(nonNumericDelays[i], () => {});
+ }, { code: 'ERR_INVALID_ARG_TYPE' }, nonNumericDelays[i]);
+}
+
+for (let i = 0; i < badRangeDelays.length; i++) {
+ assert.throws(() => {
+ s.setTimeout(badRangeDelays[i], () => {});
+ }, { code: 'ERR_OUT_OF_RANGE' }, badRangeDelays[i]);
+}
+
+for (let i = 0; i < validDelays.length; i++) {
+ s.setTimeout(validDelays[i], () => {});
+}
+
+for (let i = 0; i < invalidCallbacks.length; i++) {
+ [0, 1].forEach((mesc) =>
+ assert.throws(
+ () => s.setTimeout(mesc, invalidCallbacks[i]),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ }
+ )
+ );
+}
+
+// TODO: support net.Server() without new
+
+const server = new net.Server();
+server.listen(0, common.mustCall(() => {
+ const socket = net.createConnection(server.address().port);
+ assert.strictEqual(
+ socket.setTimeout(1, common.mustCall(() => {
+ socket.destroy();
+ assert.strictEqual(socket.setTimeout(1, common.mustNotCall()), socket);
+ server.close();
+ })),
+ socket
+ );
+}));
diff --git a/tests/node_compat/test/parallel/test-net-timeout-no-handle.js b/tests/node_compat/test/parallel/test-net-timeout-no-handle.js
new file mode 100644
index 000000000..1948dc9ad
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-net-timeout-no-handle.js
@@ -0,0 +1,24 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const net = require('net');
+const assert = require('assert');
+
+const socket = new net.Socket();
+socket.setTimeout(common.platformTimeout(50));
+
+socket.on('timeout', common.mustCall(() => {
+ assert.strictEqual(socket._handle, null);
+}));
+
+socket.on('connect', common.mustNotCall());
+
+// Since the timeout is unrefed, the code will exit without this
+setTimeout(() => {}, common.platformTimeout(200));
diff --git a/tests/node_compat/test/parallel/test-net-write-arguments.js b/tests/node_compat/test/parallel/test-net-write-arguments.js
new file mode 100644
index 000000000..d6beb72ee
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-net-write-arguments.js
@@ -0,0 +1,46 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 16.13.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+'use strict';
+const common = require('../common');
+const net = require('net');
+const assert = require('assert');
+const socket = new net.Stream({ highWaterMark: 0 });
+
+// Make sure that anything besides a buffer or a string throws.
+socket.on('error', common.mustNotCall());
+assert.throws(() => {
+ socket.write(null);
+}, {
+ code: 'ERR_STREAM_NULL_VALUES',
+ name: 'TypeError',
+ message: 'May not write null values to stream'
+});
+
+[
+ true,
+ false,
+ undefined,
+ 1,
+ 1.0,
+ +Infinity,
+ -Infinity,
+ [],
+ {},
+].forEach((value) => {
+ const socket = new net.Stream({ highWaterMark: 0 });
+ // We need to check the callback since 'error' will only
+ // be emitted once per instance.
+ assert.throws(() => {
+ socket.write(value);
+ }, {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: 'The "chunk" argument must be of type string or an instance of ' +
+ `Buffer or Uint8Array.${common.invalidArgTypeHelper(value)}`
+ });
+});
diff --git a/tests/node_compat/test/parallel/test-next-tick-doesnt-hang.js b/tests/node_compat/test/parallel/test-next-tick-doesnt-hang.js
new file mode 100644
index 000000000..6d0d6a7e0
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-next-tick-doesnt-hang.js
@@ -0,0 +1,37 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+
+// This test verifies that having a single nextTick statement and nothing else
+// does not hang the event loop. If this test times out it has failed.
+
+require('../common');
+process.nextTick(function() {
+ // Nothing
+});
diff --git a/tests/node_compat/test/parallel/test-next-tick-fixed-queue-regression.js b/tests/node_compat/test/parallel/test-next-tick-fixed-queue-regression.js
new file mode 100644
index 000000000..fff40f754
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-next-tick-fixed-queue-regression.js
@@ -0,0 +1,25 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+
+// This tests a highly specific regression tied to the FixedQueue size, which
+// was introduced in Node.js 9.7.0: https://github.com/nodejs/node/pull/18617
+// More specifically, a nextTick list could potentially end up not fully
+// clearing in one run through if exactly 2048 ticks were added after
+// microtasks were executed within the nextTick loop.
+
+process.nextTick(() => {
+ Promise.resolve(1).then(() => {
+ for (let i = 0; i < 2047; i++)
+ process.nextTick(common.mustCall());
+ const immediate = setImmediate(common.mustNotCall());
+ process.nextTick(common.mustCall(() => clearImmediate(immediate)));
+ });
+});
diff --git a/tests/node_compat/test/parallel/test-next-tick-intentional-starvation.js b/tests/node_compat/test/parallel/test-next-tick-intentional-starvation.js
new file mode 100644
index 000000000..b2c00b43a
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-next-tick-intentional-starvation.js
@@ -0,0 +1,68 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+
+// This is the inverse of test-next-tick-starvation. it verifies
+// that process.nextTick will *always* come before other events
+
+let ran = false;
+let starved = false;
+const start = +new Date();
+let timerRan = false;
+
+function spin() {
+ ran = true;
+ const now = +new Date();
+ if (now - start > 100) {
+ console.log('The timer is starving, just as we planned.');
+ starved = true;
+
+ // now let it out.
+ return;
+ }
+
+ process.nextTick(spin);
+}
+
+function onTimeout() {
+ if (!starved) throw new Error('The timer escaped!');
+ console.log('The timer ran once the ban was lifted');
+ timerRan = true;
+}
+
+spin();
+setTimeout(onTimeout, 50);
+
+process.on('exit', function() {
+ assert.ok(ran);
+ assert.ok(starved);
+ assert.ok(timerRan);
+});
diff --git a/tests/node_compat/test/parallel/test-next-tick-ordering.js b/tests/node_compat/test/parallel/test-next-tick-ordering.js
new file mode 100644
index 000000000..a2839a49e
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-next-tick-ordering.js
@@ -0,0 +1,62 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+let i;
+
+const N = 30;
+const done = [];
+
+function get_printer(timeout) {
+ return function() {
+ console.log(`Running from setTimeout ${timeout}`);
+ done.push(timeout);
+ };
+}
+
+process.nextTick(function() {
+ console.log('Running from nextTick');
+ done.push('nextTick');
+});
+
+for (i = 0; i < N; i += 1) {
+ setTimeout(get_printer(i), i);
+}
+
+console.log('Running from main.');
+
+
+process.on('exit', function() {
+ assert.strictEqual(done[0], 'nextTick');
+ // Disabling this test. I don't think we can ensure the order
+ // for (i = 0; i < N; i += 1) {
+ // assert.strictEqual(i, done[i + 1]);
+ // }
+});
diff --git a/tests/node_compat/test/parallel/test-next-tick-ordering2.js b/tests/node_compat/test/parallel/test-next-tick-ordering2.js
new file mode 100644
index 000000000..29c76d32e
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-next-tick-ordering2.js
@@ -0,0 +1,46 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+
+const order = [];
+process.nextTick(function() {
+ setTimeout(function() {
+ order.push('setTimeout');
+ }, 0);
+
+ process.nextTick(function() {
+ order.push('nextTick');
+ });
+});
+
+process.on('exit', function() {
+ assert.deepStrictEqual(order, ['nextTick', 'setTimeout']);
+});
diff --git a/tests/node_compat/test/parallel/test-next-tick-when-exiting.js b/tests/node_compat/test/parallel/test-next-tick-when-exiting.js
new file mode 100644
index 000000000..5f20b5247
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-next-tick-when-exiting.js
@@ -0,0 +1,21 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const assert = require('assert');
+
+process.on('exit', () => {
+ assert.strictEqual(process._exiting, true);
+
+ process.nextTick(
+ common.mustNotCall('process is exiting, should not be called')
+ );
+});
+
+process.exit();
diff --git a/tests/node_compat/test/parallel/test-next-tick.js b/tests/node_compat/test/parallel/test-next-tick.js
new file mode 100644
index 000000000..aee5c06a1
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-next-tick.js
@@ -0,0 +1,70 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+
+const assert = require('assert');
+
+process.nextTick(common.mustCall(function() {
+ process.nextTick(common.mustCall(function() {
+ process.nextTick(common.mustCall());
+ }));
+}));
+
+setTimeout(common.mustCall(function() {
+ process.nextTick(common.mustCall());
+}), 50);
+
+process.nextTick(common.mustCall());
+
+const obj = {};
+
+process.nextTick(function(a, b) {
+ assert.strictEqual(a, 42);
+ assert.strictEqual(b, obj);
+ assert.strictEqual(this, undefined);
+}, 42, obj);
+
+process.nextTick((a, b) => {
+ assert.strictEqual(a, 42);
+ assert.strictEqual(b, obj);
+ assert.deepStrictEqual(this, {});
+}, 42, obj);
+
+process.nextTick(function() {
+ assert.strictEqual(this, undefined);
+}, 1, 2, 3, 4);
+
+process.nextTick(() => {
+ assert.deepStrictEqual(this, {});
+}, 1, 2, 3, 4);
+
+process.on('exit', function() {
+ process.nextTick(common.mustNotCall());
+});
diff --git a/tests/node_compat/test/parallel/test-nodeeventtarget.js b/tests/node_compat/test/parallel/test-nodeeventtarget.js
new file mode 100644
index 000000000..b5c6e788f
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-nodeeventtarget.js
@@ -0,0 +1,190 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Flags: --expose-internals --no-warnings
+'use strict';
+
+const common = require('../common');
+const { NodeEventTarget } = require('internal/event_target');
+
+const {
+ deepStrictEqual,
+ ok,
+ strictEqual,
+ throws,
+} = require('assert');
+
+const { on } = require('events');
+
+{
+ const eventTarget = new NodeEventTarget();
+ strictEqual(eventTarget.listenerCount('foo'), 0);
+ deepStrictEqual(eventTarget.eventNames(), []);
+
+ const ev1 = common.mustCall(function(event) {
+ strictEqual(event.type, 'foo');
+ strictEqual(this, eventTarget);
+ }, 2);
+
+ const ev2 = {
+ handleEvent: common.mustCall(function(event) {
+ strictEqual(event.type, 'foo');
+ strictEqual(this, ev2);
+ })
+ };
+
+ eventTarget.addEventListener('foo', ev1);
+ eventTarget.addEventListener('foo', ev2, { once: true });
+ strictEqual(eventTarget.listenerCount('foo'), 2);
+ ok(eventTarget.dispatchEvent(new Event('foo')));
+ strictEqual(eventTarget.listenerCount('foo'), 1);
+ eventTarget.dispatchEvent(new Event('foo'));
+
+ eventTarget.removeEventListener('foo', ev1);
+ strictEqual(eventTarget.listenerCount('foo'), 0);
+ eventTarget.dispatchEvent(new Event('foo'));
+}
+
+{
+ const eventTarget = new NodeEventTarget();
+ strictEqual(eventTarget.listenerCount('foo'), 0);
+ deepStrictEqual(eventTarget.eventNames(), []);
+
+ const ev1 = common.mustCall((event) => {
+ strictEqual(event.type, 'foo');
+ }, 2);
+
+ const ev2 = {
+ handleEvent: common.mustCall((event) => {
+ strictEqual(event.type, 'foo');
+ })
+ };
+
+ strictEqual(eventTarget.on('foo', ev1), eventTarget);
+ strictEqual(eventTarget.once('foo', ev2, { once: true }), eventTarget);
+ strictEqual(eventTarget.listenerCount('foo'), 2);
+ eventTarget.dispatchEvent(new Event('foo'));
+ strictEqual(eventTarget.listenerCount('foo'), 1);
+ eventTarget.dispatchEvent(new Event('foo'));
+
+ strictEqual(eventTarget.off('foo', ev1), eventTarget);
+ strictEqual(eventTarget.listenerCount('foo'), 0);
+ eventTarget.dispatchEvent(new Event('foo'));
+}
+
+{
+ const eventTarget = new NodeEventTarget();
+ strictEqual(eventTarget.listenerCount('foo'), 0);
+ deepStrictEqual(eventTarget.eventNames(), []);
+
+ const ev1 = common.mustCall((event) => {
+ strictEqual(event.type, 'foo');
+ }, 2);
+
+ const ev2 = {
+ handleEvent: common.mustCall((event) => {
+ strictEqual(event.type, 'foo');
+ })
+ };
+
+ eventTarget.addListener('foo', ev1);
+ eventTarget.once('foo', ev2, { once: true });
+ strictEqual(eventTarget.listenerCount('foo'), 2);
+ eventTarget.dispatchEvent(new Event('foo'));
+ strictEqual(eventTarget.listenerCount('foo'), 1);
+ eventTarget.dispatchEvent(new Event('foo'));
+
+ eventTarget.removeListener('foo', ev1);
+ strictEqual(eventTarget.listenerCount('foo'), 0);
+ eventTarget.dispatchEvent(new Event('foo'));
+}
+
+{
+ const eventTarget = new NodeEventTarget();
+ strictEqual(eventTarget.listenerCount('foo'), 0);
+ deepStrictEqual(eventTarget.eventNames(), []);
+
+ // Won't actually be called.
+ const ev1 = () => {};
+
+ // Won't actually be called.
+ const ev2 = { handleEvent() {} };
+
+ eventTarget.addListener('foo', ev1);
+ eventTarget.addEventListener('foo', ev1);
+ eventTarget.once('foo', ev2, { once: true });
+ eventTarget.once('foo', ev2, { once: false });
+ eventTarget.on('bar', ev1);
+ strictEqual(eventTarget.listenerCount('foo'), 2);
+ strictEqual(eventTarget.listenerCount('bar'), 1);
+ deepStrictEqual(eventTarget.eventNames(), ['foo', 'bar']);
+ strictEqual(eventTarget.removeAllListeners('foo'), eventTarget);
+ strictEqual(eventTarget.listenerCount('foo'), 0);
+ strictEqual(eventTarget.listenerCount('bar'), 1);
+ deepStrictEqual(eventTarget.eventNames(), ['bar']);
+ strictEqual(eventTarget.removeAllListeners(), eventTarget);
+ strictEqual(eventTarget.listenerCount('foo'), 0);
+ strictEqual(eventTarget.listenerCount('bar'), 0);
+ deepStrictEqual(eventTarget.eventNames(), []);
+}
+
+{
+ const target = new NodeEventTarget();
+
+ process.on('warning', common.mustCall((warning) => {
+ ok(warning instanceof Error);
+ strictEqual(warning.name, 'MaxListenersExceededWarning');
+ strictEqual(warning.target, target);
+ strictEqual(warning.count, 2);
+ strictEqual(warning.type, 'foo');
+ ok(warning.message.includes(
+ '2 foo listeners added to NodeEventTarget'));
+ }));
+
+ strictEqual(target.getMaxListeners(), NodeEventTarget.defaultMaxListeners);
+ target.setMaxListeners(1);
+ target.on('foo', () => {});
+ target.on('foo', () => {});
+}
+{
+ // Test NodeEventTarget emit
+ const emitter = new NodeEventTarget();
+ emitter.addEventListener('foo', common.mustCall((e) => {
+ strictEqual(e.type, 'foo');
+ strictEqual(e.detail, 'bar');
+ ok(e instanceof Event);
+ }), { once: true });
+ emitter.once('foo', common.mustCall((e, droppedAdditionalArgument) => {
+ strictEqual(e, 'bar');
+ strictEqual(droppedAdditionalArgument, undefined);
+ }));
+ emitter.emit('foo', 'bar', 'baz');
+}
+{
+ // Test NodeEventTarget emit unsupported usage
+ const emitter = new NodeEventTarget();
+ throws(() => {
+ emitter.emit();
+ }, /ERR_INVALID_ARG_TYPE/);
+}
+
+(async () => {
+ // test NodeEventTarget async-iterability
+ const emitter = new NodeEventTarget();
+ const interval = setInterval(() => {
+ emitter.dispatchEvent(new Event('foo'));
+ }, 0);
+ let count = 0;
+ for await (const [ item ] of on(emitter, 'foo')) {
+ count++;
+ strictEqual(item.type, 'foo');
+ if (count > 5) {
+ break;
+ }
+ }
+ clearInterval(interval);
+})().then(common.mustCall());
diff --git a/tests/node_compat/test/parallel/test-os.js b/tests/node_compat/test/parallel/test-os.js
new file mode 100644
index 000000000..9de4f516f
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-os.js
@@ -0,0 +1,280 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 16.13.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const os = require('os');
+const path = require('path');
+const { inspect } = require('util');
+
+const is = {
+ number: (value, key) => {
+ assert(!Number.isNaN(value), `${key} should not be NaN`);
+ assert.strictEqual(typeof value, 'number');
+ },
+ string: (value) => { assert.strictEqual(typeof value, 'string'); },
+ array: (value) => { assert.ok(Array.isArray(value)); },
+ object: (value) => {
+ assert.strictEqual(typeof value, 'object');
+ assert.notStrictEqual(value, null);
+ }
+};
+
+/* TODO(kt3k): Enable this test
+process.env.TMPDIR = '/tmpdir';
+process.env.TMP = '/tmp';
+process.env.TEMP = '/temp';
+if (common.isWindows) {
+ assert.strictEqual(os.tmpdir(), '/temp');
+ process.env.TEMP = '';
+ assert.strictEqual(os.tmpdir(), '/tmp');
+ process.env.TMP = '';
+ const expected = `${process.env.SystemRoot || process.env.windir}\\temp`;
+ assert.strictEqual(os.tmpdir(), expected);
+ process.env.TEMP = '\\temp\\';
+ assert.strictEqual(os.tmpdir(), '\\temp');
+ process.env.TEMP = '\\tmpdir/';
+ assert.strictEqual(os.tmpdir(), '\\tmpdir/');
+ process.env.TEMP = '\\';
+ assert.strictEqual(os.tmpdir(), '\\');
+ process.env.TEMP = 'C:\\';
+ assert.strictEqual(os.tmpdir(), 'C:\\');
+} else {
+ assert.strictEqual(os.tmpdir(), '/tmpdir');
+ process.env.TMPDIR = '';
+ assert.strictEqual(os.tmpdir(), '/tmp');
+ process.env.TMP = '';
+ assert.strictEqual(os.tmpdir(), '/temp');
+ process.env.TEMP = '';
+ assert.strictEqual(os.tmpdir(), '/tmp');
+ process.env.TMPDIR = '/tmpdir/';
+ assert.strictEqual(os.tmpdir(), '/tmpdir');
+ process.env.TMPDIR = '/tmpdir\\';
+ assert.strictEqual(os.tmpdir(), '/tmpdir\\');
+ process.env.TMPDIR = '/';
+ assert.strictEqual(os.tmpdir(), '/');
+}
+*/
+
+const endianness = os.endianness();
+is.string(endianness);
+assert.match(endianness, /[BL]E/);
+
+const hostname = os.hostname();
+is.string(hostname);
+assert.ok(hostname.length > 0);
+
+// On IBMi, os.uptime() returns 'undefined'
+if (!common.isIBMi) {
+ const uptime = os.uptime();
+ is.number(uptime);
+ assert.ok(uptime > 0);
+}
+
+const cpus = os.cpus();
+is.array(cpus);
+assert.ok(cpus.length > 0);
+for (const cpu of cpus) {
+ assert.strictEqual(typeof cpu.model, 'string');
+ assert.strictEqual(typeof cpu.speed, 'number');
+ assert.strictEqual(typeof cpu.times.user, 'number');
+ assert.strictEqual(typeof cpu.times.nice, 'number');
+ assert.strictEqual(typeof cpu.times.sys, 'number');
+ assert.strictEqual(typeof cpu.times.idle, 'number');
+ assert.strictEqual(typeof cpu.times.irq, 'number');
+}
+
+const type = os.type();
+is.string(type);
+assert.ok(type.length > 0);
+
+const release = os.release();
+is.string(release);
+assert.ok(release.length > 0);
+// TODO: Check format on more than just AIX
+if (common.isAIX)
+ assert.match(release, /^\d+\.\d+$/);
+
+const platform = os.platform();
+is.string(platform);
+assert.ok(platform.length > 0);
+
+const availableParallelism = os.availableParallelism();
+assert.ok(availableParallelism === navigator.hardwareConcurrency);
+
+const arch = os.arch();
+is.string(arch);
+assert.ok(arch.length > 0);
+
+if (!common.isSunOS) {
+ // not implemented yet
+ assert.ok(os.loadavg().length > 0);
+ assert.ok(os.freemem() > 0);
+ assert.ok(os.totalmem() > 0);
+}
+
+const interfaces = os.networkInterfaces();
+switch (platform) {
+ case 'linux': {
+ const filter = (e) =>
+ e.address === '127.0.0.1' &&
+ e.netmask === '255.0.0.0';
+
+ const actual = interfaces.lo.filter(filter);
+ const expected = [{
+ address: '127.0.0.1',
+ netmask: '255.0.0.0',
+ family: 'IPv4',
+ mac: '00:00:00:00:00:00',
+ internal: true,
+ cidr: '127.0.0.1/8'
+ }];
+ assert.deepStrictEqual(actual, expected);
+ break;
+ }
+ case 'win32': {
+ const filter = (e) =>
+ e.address === '127.0.0.1';
+
+ const actual = interfaces['Loopback Pseudo-Interface 1'].filter(filter);
+ const expected = [{
+ address: '127.0.0.1',
+ netmask: '255.0.0.0',
+ family: 'IPv4',
+ mac: '00:00:00:00:00:00',
+ internal: true,
+ cidr: '127.0.0.1/8'
+ }];
+ assert.deepStrictEqual(actual, expected);
+ break;
+ }
+}
+const netmaskToCIDRSuffixMap = new Map(Object.entries({
+ '255.0.0.0': 8,
+ '255.255.255.0': 24,
+ 'ffff:ffff:ffff:ffff::': 64,
+ 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff': 128
+}));
+
+Object.values(interfaces)
+ .flat(Infinity)
+ .map((v) => ({ v, mask: netmaskToCIDRSuffixMap.get(v.netmask) }))
+ .forEach(({ v, mask }) => {
+ assert.ok('cidr' in v, `"cidr" prop not found in ${inspect(v)}`);
+ if (mask) {
+ assert.strictEqual(v.cidr, `${v.address}/${mask}`);
+ }
+ });
+
+const EOL = os.EOL;
+if (common.isWindows) {
+ assert.strictEqual(EOL, '\r\n');
+} else {
+ assert.strictEqual(EOL, '\n');
+}
+
+const home = os.homedir();
+is.string(home);
+assert.ok(home.includes(path.sep));
+
+const version = os.version();
+assert.strictEqual(typeof version, 'string');
+assert(version);
+
+if (common.isWindows && process.env.USERPROFILE) {
+ assert.strictEqual(home, process.env.USERPROFILE);
+ delete process.env.USERPROFILE;
+ assert.ok(os.homedir().includes(path.sep));
+ process.env.USERPROFILE = home;
+} else if (!common.isWindows && process.env.HOME) {
+ assert.strictEqual(home, process.env.HOME);
+ delete process.env.HOME;
+ assert.ok(os.homedir().includes(path.sep));
+ process.env.HOME = home;
+}
+
+const pwd = os.userInfo();
+is.object(pwd);
+const pwdBuf = os.userInfo({ encoding: 'buffer' });
+
+if (common.isWindows) {
+ assert.strictEqual(pwd.uid, -1);
+ assert.strictEqual(pwd.gid, -1);
+ assert.strictEqual(pwd.shell, null);
+ assert.strictEqual(pwdBuf.uid, -1);
+ assert.strictEqual(pwdBuf.gid, -1);
+ assert.strictEqual(pwdBuf.shell, null);
+} else {
+ is.number(pwd.uid);
+ is.number(pwd.gid);
+ assert.strictEqual(typeof pwd.shell, 'string');
+ // It's possible for /etc/passwd to leave the user's shell blank.
+ if (pwd.shell.length > 0) {
+ assert(pwd.shell.includes(path.sep));
+ }
+ assert.strictEqual(pwd.uid, pwdBuf.uid);
+ assert.strictEqual(pwd.gid, pwdBuf.gid);
+ assert.strictEqual(pwd.shell, pwdBuf.shell.toString('utf8'));
+}
+
+is.string(pwd.username);
+assert.ok(pwd.homedir.includes(path.sep));
+assert.strictEqual(pwd.username, pwdBuf.username.toString('utf8'));
+assert.strictEqual(pwd.homedir, pwdBuf.homedir.toString('utf8'));
+
+
+assert.strictEqual(`${os.hostname}`, os.hostname());
+assert.strictEqual(`${os.homedir}`, os.homedir());
+assert.strictEqual(`${os.release}`, os.release());
+assert.strictEqual(`${os.type}`, os.type());
+assert.strictEqual(`${os.endianness}`, os.endianness());
+// TODO(kt3k): Enable this test
+// assert.strictEqual(`${os.tmpdir}`, os.tmpdir());
+assert.strictEqual(`${os.arch}`, os.arch());
+assert.strictEqual(`${os.platform}`, os.platform());
+assert.strictEqual(`${os.version}`, os.version());
+
+assert.strictEqual(+os.totalmem, os.totalmem());
+
+// Assert that the following values are coercible to numbers.
+// On IBMi, os.uptime() returns 'undefined'
+if (!common.isIBMi) {
+ is.number(+os.uptime, 'uptime');
+ is.number(os.uptime(), 'uptime');
+}
+
+is.number(+os.freemem, 'freemem');
+is.number(os.freemem(), 'freemem');
+
+const devNull = os.devNull;
+if (common.isWindows) {
+ assert.strictEqual(devNull, '\\\\.\\nul');
+} else {
+ assert.strictEqual(devNull, '/dev/null');
+}
diff --git a/tests/node_compat/test/parallel/test-outgoing-message-destroy.js b/tests/node_compat/test/parallel/test-outgoing-message-destroy.js
new file mode 100644
index 000000000..d9a13796f
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-outgoing-message-destroy.js
@@ -0,0 +1,20 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+// Test that http.OutgoingMessage,prototype.destroy() returns `this`.
+require('../common');
+
+const assert = require('assert');
+const http = require('http');
+const outgoingMessage = new http.OutgoingMessage();
+
+assert.strictEqual(outgoingMessage.destroyed, false);
+assert.strictEqual(outgoingMessage.destroy(), outgoingMessage);
+assert.strictEqual(outgoingMessage.destroyed, true);
+assert.strictEqual(outgoingMessage.destroy(), outgoingMessage);
diff --git a/tests/node_compat/test/parallel/test-outgoing-message-pipe.js b/tests/node_compat/test/parallel/test-outgoing-message-pipe.js
new file mode 100644
index 000000000..ab9063c93
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-outgoing-message-pipe.js
@@ -0,0 +1,22 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+const OutgoingMessage = require('_http_outgoing').OutgoingMessage;
+
+// Verify that an error is thrown upon a call to `OutgoingMessage.pipe`.
+
+const outgoingMessage = new OutgoingMessage();
+assert.throws(
+ () => { outgoingMessage.pipe(outgoingMessage); },
+ {
+ code: 'ERR_STREAM_CANNOT_PIPE',
+ name: 'Error'
+ }
+);
diff --git a/tests/node_compat/test/parallel/test-parse-args.mjs b/tests/node_compat/test/parallel/test-parse-args.mjs
new file mode 100644
index 000000000..ae8332fa7
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-parse-args.mjs
@@ -0,0 +1,1001 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+import '../common/index.mjs';
+import assert from 'node:assert';
+import { test } from 'node:test';
+import { parseArgs } from 'node:util';
+
+test('when short option used as flag then stored as flag', () => {
+ const args = ['-f'];
+ const expected = { values: { __proto__: null, f: true }, positionals: [] };
+ const result = parseArgs({ strict: false, args });
+ assert.deepStrictEqual(result, expected);
+});
+
+test('when short option used as flag before positional then stored as flag and positional (and not value)', () => {
+ const args = ['-f', 'bar'];
+ const expected = { values: { __proto__: null, f: true }, positionals: [ 'bar' ] };
+ const result = parseArgs({ strict: false, args });
+ assert.deepStrictEqual(result, expected);
+});
+
+test('when short option `type: "string"` used with value then stored as value', () => {
+ const args = ['-f', 'bar'];
+ const options = { f: { type: 'string' } };
+ const expected = { values: { __proto__: null, f: 'bar' }, positionals: [] };
+ const result = parseArgs({ args, options });
+ assert.deepStrictEqual(result, expected);
+});
+
+test('when short option listed in short used as flag then long option stored as flag', () => {
+ const args = ['-f'];
+ const options = { foo: { short: 'f', type: 'boolean' } };
+ const expected = { values: { __proto__: null, foo: true }, positionals: [] };
+ const result = parseArgs({ args, options });
+ assert.deepStrictEqual(result, expected);
+});
+
+test('when short option listed in short and long listed in `type: "string"` and ' +
+ 'used with value then long option stored as value', () => {
+ const args = ['-f', 'bar'];
+ const options = { foo: { short: 'f', type: 'string' } };
+ const expected = { values: { __proto__: null, foo: 'bar' }, positionals: [] };
+ const result = parseArgs({ args, options });
+ assert.deepStrictEqual(result, expected);
+});
+
+test('when short option `type: "string"` used without value then stored as flag', () => {
+ const args = ['-f'];
+ const options = { f: { type: 'string' } };
+ const expected = { values: { __proto__: null, f: true }, positionals: [] };
+ const result = parseArgs({ strict: false, args, options });
+ assert.deepStrictEqual(result, expected);
+});
+
+test('short option group behaves like multiple short options', () => {
+ const args = ['-rf'];
+ const options = { };
+ const expected = { values: { __proto__: null, r: true, f: true }, positionals: [] };
+ const result = parseArgs({ strict: false, args, options });
+ assert.deepStrictEqual(result, expected);
+});
+
+test('short option group does not consume subsequent positional', () => {
+ const args = ['-rf', 'foo'];
+ const options = { };
+ const expected = { values: { __proto__: null, r: true, f: true }, positionals: ['foo'] };
+ const result = parseArgs({ strict: false, args, options });
+ assert.deepStrictEqual(result, expected);
+});
+
+// See: Guideline 5 https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html
+test('if terminal of short-option group configured `type: "string"`, subsequent positional is stored', () => {
+ const args = ['-rvf', 'foo'];
+ const options = { f: { type: 'string' } };
+ const expected = { values: { __proto__: null, r: true, v: true, f: 'foo' }, positionals: [] };
+ const result = parseArgs({ strict: false, args, options });
+ assert.deepStrictEqual(result, expected);
+});
+
+test('handles short-option groups in conjunction with long-options', () => {
+ const args = ['-rf', '--foo', 'foo'];
+ const options = { foo: { type: 'string' } };
+ const expected = { values: { __proto__: null, r: true, f: true, foo: 'foo' }, positionals: [] };
+ const result = parseArgs({ strict: false, args, options });
+ assert.deepStrictEqual(result, expected);
+});
+
+test('handles short-option groups with "short" alias configured', () => {
+ const args = ['-rf'];
+ const options = { remove: { short: 'r', type: 'boolean' } };
+ const expected = { values: { __proto__: null, remove: true, f: true }, positionals: [] };
+ const result = parseArgs({ strict: false, args, options });
+ assert.deepStrictEqual(result, expected);
+});
+
+test('handles short-option followed by its value', () => {
+ const args = ['-fFILE'];
+ const options = { foo: { short: 'f', type: 'string' } };
+ const expected = { values: { __proto__: null, foo: 'FILE' }, positionals: [] };
+ const result = parseArgs({ strict: false, args, options });
+ assert.deepStrictEqual(result, expected);
+});
+
+test('Everything after a bare `--` is considered a positional argument', () => {
+ const args = ['--', 'barepositionals', 'mopositionals'];
+ const expected = { values: { __proto__: null }, positionals: ['barepositionals', 'mopositionals'] };
+ const result = parseArgs({ allowPositionals: true, args });
+ assert.deepStrictEqual(result, expected, Error('testing bare positionals'));
+});
+
+test('args are true', () => {
+ const args = ['--foo', '--bar'];
+ const expected = { values: { __proto__: null, foo: true, bar: true }, positionals: [] };
+ const result = parseArgs({ strict: false, args });
+ assert.deepStrictEqual(result, expected, Error('args are true'));
+});
+
+test('arg is true and positional is identified', () => {
+ const args = ['--foo=a', '--foo', 'b'];
+ const expected = { values: { __proto__: null, foo: true }, positionals: ['b'] };
+ const result = parseArgs({ strict: false, args });
+ assert.deepStrictEqual(result, expected, Error('arg is true and positional is identified'));
+});
+
+test('args equals are passed `type: "string"`', () => {
+ const args = ['--so=wat'];
+ const options = { so: { type: 'string' } };
+ const expected = { values: { __proto__: null, so: 'wat' }, positionals: [] };
+ const result = parseArgs({ args, options });
+ assert.deepStrictEqual(result, expected, Error('arg value is passed'));
+});
+
+test('when args include single dash then result stores dash as positional', () => {
+ const args = ['-'];
+ const expected = { values: { __proto__: null }, positionals: ['-'] };
+ const result = parseArgs({ allowPositionals: true, args });
+ assert.deepStrictEqual(result, expected);
+});
+
+test('zero config args equals are parsed as if `type: "string"`', () => {
+ const args = ['--so=wat'];
+ const options = { };
+ const expected = { values: { __proto__: null, so: 'wat' }, positionals: [] };
+ const result = parseArgs({ strict: false, args, options });
+ assert.deepStrictEqual(result, expected, Error('arg value is passed'));
+});
+
+test('same arg is passed twice `type: "string"` and last value is recorded', () => {
+ const args = ['--foo=a', '--foo', 'b'];
+ const options = { foo: { type: 'string' } };
+ const expected = { values: { __proto__: null, foo: 'b' }, positionals: [] };
+ const result = parseArgs({ args, options });
+ assert.deepStrictEqual(result, expected, Error('last arg value is passed'));
+});
+
+test('args equals pass string including more equals', () => {
+ const args = ['--so=wat=bing'];
+ const options = { so: { type: 'string' } };
+ const expected = { values: { __proto__: null, so: 'wat=bing' }, positionals: [] };
+ const result = parseArgs({ args, options });
+ assert.deepStrictEqual(result, expected, Error('arg value is passed'));
+});
+
+test('first arg passed for `type: "string"` and "multiple" is in array', () => {
+ const args = ['--foo=a'];
+ const options = { foo: { type: 'string', multiple: true } };
+ const expected = { values: { __proto__: null, foo: ['a'] }, positionals: [] };
+ const result = parseArgs({ args, options });
+ assert.deepStrictEqual(result, expected, Error('first multiple in array'));
+});
+
+test('args are passed `type: "string"` and "multiple"', () => {
+ const args = ['--foo=a', '--foo', 'b'];
+ const options = {
+ foo: {
+ type: 'string',
+ multiple: true,
+ },
+ };
+ const expected = { values: { __proto__: null, foo: ['a', 'b'] }, positionals: [] };
+ const result = parseArgs({ args, options });
+ assert.deepStrictEqual(result, expected, Error('both arg values are passed'));
+});
+
+test('when expecting `multiple:true` boolean option and option used multiple times then result includes array of ' +
+ 'booleans matching usage', () => {
+ const args = ['--foo', '--foo'];
+ const options = {
+ foo: {
+ type: 'boolean',
+ multiple: true,
+ },
+ };
+ const expected = { values: { __proto__: null, foo: [true, true] }, positionals: [] };
+ const result = parseArgs({ args, options });
+ assert.deepStrictEqual(result, expected);
+});
+
+test('order of option and positional does not matter (per README)', () => {
+ const args1 = ['--foo=bar', 'baz'];
+ const args2 = ['baz', '--foo=bar'];
+ const options = { foo: { type: 'string' } };
+ const expected = { values: { __proto__: null, foo: 'bar' }, positionals: ['baz'] };
+ assert.deepStrictEqual(
+ parseArgs({ allowPositionals: true, args: args1, options }),
+ expected,
+ Error('option then positional')
+ );
+ assert.deepStrictEqual(
+ parseArgs({ allowPositionals: true, args: args2, options }),
+ expected,
+ Error('positional then option')
+ );
+});
+
+test('correct default args when use node -p', () => {
+ const holdArgv = process.argv;
+ process.argv = [process.argv0, '--foo'];
+ const holdExecArgv = process.execArgv;
+ process.execArgv = ['-p', '0'];
+ const result = parseArgs({ strict: false });
+
+ const expected = { values: { __proto__: null, foo: true },
+ positionals: [] };
+ assert.deepStrictEqual(result, expected);
+ process.argv = holdArgv;
+ process.execArgv = holdExecArgv;
+});
+
+test('correct default args when use node --print', () => {
+ const holdArgv = process.argv;
+ process.argv = [process.argv0, '--foo'];
+ const holdExecArgv = process.execArgv;
+ process.execArgv = ['--print', '0'];
+ const result = parseArgs({ strict: false });
+
+ const expected = { values: { __proto__: null, foo: true },
+ positionals: [] };
+ assert.deepStrictEqual(result, expected);
+ process.argv = holdArgv;
+ process.execArgv = holdExecArgv;
+});
+
+test('correct default args when use node -e', () => {
+ const holdArgv = process.argv;
+ process.argv = [process.argv0, '--foo'];
+ const holdExecArgv = process.execArgv;
+ process.execArgv = ['-e', '0'];
+ const result = parseArgs({ strict: false });
+
+ const expected = { values: { __proto__: null, foo: true },
+ positionals: [] };
+ assert.deepStrictEqual(result, expected);
+ process.argv = holdArgv;
+ process.execArgv = holdExecArgv;
+});
+
+test('correct default args when use node --eval', () => {
+ const holdArgv = process.argv;
+ process.argv = [process.argv0, '--foo'];
+ const holdExecArgv = process.execArgv;
+ process.execArgv = ['--eval', '0'];
+ const result = parseArgs({ strict: false });
+ const expected = { values: { __proto__: null, foo: true },
+ positionals: [] };
+ assert.deepStrictEqual(result, expected);
+ process.argv = holdArgv;
+ process.execArgv = holdExecArgv;
+});
+
+test('correct default args when normal arguments', () => {
+ const holdArgv = process.argv;
+ process.argv = [process.argv0, 'script.js', '--foo'];
+ const holdExecArgv = process.execArgv;
+ process.execArgv = [];
+ const result = parseArgs({ strict: false });
+
+ const expected = { values: { __proto__: null, foo: true },
+ positionals: [] };
+ assert.deepStrictEqual(result, expected);
+ process.argv = holdArgv;
+ process.execArgv = holdExecArgv;
+});
+
+test('excess leading dashes on options are retained', () => {
+ // Enforce a design decision for an edge case.
+ const args = ['---triple'];
+ const options = { };
+ const expected = {
+ values: { '__proto__': null, '-triple': true },
+ positionals: []
+ };
+ const result = parseArgs({ strict: false, args, options });
+ assert.deepStrictEqual(result, expected, Error('excess option dashes are retained'));
+});
+
+test('positional arguments are allowed by default in strict:false', () => {
+ const args = ['foo'];
+ const options = { };
+ const expected = {
+ values: { __proto__: null },
+ positionals: ['foo']
+ };
+ const result = parseArgs({ strict: false, args, options });
+ assert.deepStrictEqual(result, expected);
+});
+
+test('positional arguments may be explicitly disallowed in strict:false', () => {
+ const args = ['foo'];
+ const options = { };
+ assert.throws(() => { parseArgs({ strict: false, allowPositionals: false, args, options }); }, {
+ code: 'ERR_PARSE_ARGS_UNEXPECTED_POSITIONAL'
+ });
+});
+
+// Test bad inputs
+
+test('invalid argument passed for options', () => {
+ const args = ['--so=wat'];
+ const options = 'bad value';
+ assert.throws(() => { parseArgs({ args, options }); }, {
+ code: 'ERR_INVALID_ARG_TYPE'
+ });
+});
+
+test('type property missing for option then throw', () => {
+ const knownOptions = { foo: { } };
+ assert.throws(() => { parseArgs({ options: knownOptions }); }, {
+ code: 'ERR_INVALID_ARG_TYPE'
+ });
+});
+
+test('boolean passed to "type" option', () => {
+ const args = ['--so=wat'];
+ const options = { foo: { type: true } };
+ assert.throws(() => { parseArgs({ args, options }); }, {
+ code: 'ERR_INVALID_ARG_TYPE'
+ });
+});
+
+test('invalid union value passed to "type" option', () => {
+ const args = ['--so=wat'];
+ const options = { foo: { type: 'str' } };
+ assert.throws(() => { parseArgs({ args, options }); }, {
+ code: 'ERR_INVALID_ARG_TYPE'
+ });
+});
+
+// Test strict mode
+
+test('unknown long option --bar', () => {
+ const args = ['--foo', '--bar'];
+ const options = { foo: { type: 'boolean' } };
+ assert.throws(() => { parseArgs({ args, options }); }, {
+ code: 'ERR_PARSE_ARGS_UNKNOWN_OPTION'
+ });
+});
+
+test('unknown short option -b', () => {
+ const args = ['--foo', '-b'];
+ const options = { foo: { type: 'boolean' } };
+ assert.throws(() => { parseArgs({ args, options }); }, {
+ code: 'ERR_PARSE_ARGS_UNKNOWN_OPTION'
+ });
+});
+
+test('unknown option -r in short option group -bar', () => {
+ const args = ['-bar'];
+ const options = { b: { type: 'boolean' }, a: { type: 'boolean' } };
+ assert.throws(() => { parseArgs({ args, options }); }, {
+ code: 'ERR_PARSE_ARGS_UNKNOWN_OPTION'
+ });
+});
+
+test('unknown option with explicit value', () => {
+ const args = ['--foo', '--bar=baz'];
+ const options = { foo: { type: 'boolean' } };
+ assert.throws(() => { parseArgs({ args, options }); }, {
+ code: 'ERR_PARSE_ARGS_UNKNOWN_OPTION'
+ });
+});
+
+test('unexpected positional', () => {
+ const args = ['foo'];
+ const options = { foo: { type: 'boolean' } };
+ assert.throws(() => { parseArgs({ args, options }); }, {
+ code: 'ERR_PARSE_ARGS_UNEXPECTED_POSITIONAL'
+ });
+});
+
+test('unexpected positional after --', () => {
+ const args = ['--', 'foo'];
+ const options = { foo: { type: 'boolean' } };
+ assert.throws(() => { parseArgs({ args, options }); }, {
+ code: 'ERR_PARSE_ARGS_UNEXPECTED_POSITIONAL'
+ });
+});
+
+test('-- by itself is not a positional', () => {
+ const args = ['--foo', '--'];
+ const options = { foo: { type: 'boolean' } };
+ const result = parseArgs({ args, options });
+ const expected = { values: { __proto__: null, foo: true },
+ positionals: [] };
+ assert.deepStrictEqual(result, expected);
+});
+
+test('string option used as boolean', () => {
+ const args = ['--foo'];
+ const options = { foo: { type: 'string' } };
+ assert.throws(() => { parseArgs({ args, options }); }, {
+ code: 'ERR_PARSE_ARGS_INVALID_OPTION_VALUE'
+ });
+});
+
+test('boolean option used with value', () => {
+ const args = ['--foo=bar'];
+ const options = { foo: { type: 'boolean' } };
+ assert.throws(() => { parseArgs({ args, options }); }, {
+ code: 'ERR_PARSE_ARGS_INVALID_OPTION_VALUE'
+ });
+});
+
+test('invalid short option length', () => {
+ const args = [];
+ const options = { foo: { short: 'fo', type: 'boolean' } };
+ assert.throws(() => { parseArgs({ args, options }); }, {
+ code: 'ERR_INVALID_ARG_VALUE'
+ });
+});
+
+test('null prototype: when no options then values.toString is undefined', () => {
+ const result = parseArgs({ args: [] });
+ assert.strictEqual(result.values.toString, undefined);
+});
+
+test('null prototype: when --toString then values.toString is true', () => {
+ const args = ['--toString'];
+ const options = { toString: { type: 'boolean' } };
+ const expectedResult = { values: { __proto__: null, toString: true }, positionals: [] };
+
+ const result = parseArgs({ args, options });
+ assert.deepStrictEqual(result, expectedResult);
+});
+
+const candidateGreedyOptions = [
+ '',
+ '-',
+ '--',
+ 'abc',
+ '123',
+ '-s',
+ '--foo',
+];
+
+candidateGreedyOptions.forEach((value) => {
+ test(`greedy: when short option with value '${value}' then eaten`, () => {
+ const args = ['-w', value];
+ const options = { with: { type: 'string', short: 'w' } };
+ const expectedResult = { values: { __proto__: null, with: value }, positionals: [] };
+
+ const result = parseArgs({ args, options, strict: false });
+ assert.deepStrictEqual(result, expectedResult);
+ });
+
+ test(`greedy: when long option with value '${value}' then eaten`, () => {
+ const args = ['--with', value];
+ const options = { with: { type: 'string', short: 'w' } };
+ const expectedResult = { values: { __proto__: null, with: value }, positionals: [] };
+
+ const result = parseArgs({ args, options, strict: false });
+ assert.deepStrictEqual(result, expectedResult);
+ });
+});
+
+test('strict: when candidate option value is plain text then does not throw', () => {
+ const args = ['--with', 'abc'];
+ const options = { with: { type: 'string' } };
+ const expectedResult = { values: { __proto__: null, with: 'abc' }, positionals: [] };
+
+ const result = parseArgs({ args, options, strict: true });
+ assert.deepStrictEqual(result, expectedResult);
+});
+
+test("strict: when candidate option value is '-' then does not throw", () => {
+ const args = ['--with', '-'];
+ const options = { with: { type: 'string' } };
+ const expectedResult = { values: { __proto__: null, with: '-' }, positionals: [] };
+
+ const result = parseArgs({ args, options, strict: true });
+ assert.deepStrictEqual(result, expectedResult);
+});
+
+test("strict: when candidate option value is '--' then throws", () => {
+ const args = ['--with', '--'];
+ const options = { with: { type: 'string' } };
+
+ assert.throws(() => {
+ parseArgs({ args, options });
+ }, {
+ code: 'ERR_PARSE_ARGS_INVALID_OPTION_VALUE'
+ });
+});
+
+test('strict: when candidate option value is short option then throws', () => {
+ const args = ['--with', '-a'];
+ const options = { with: { type: 'string' } };
+
+ assert.throws(() => {
+ parseArgs({ args, options });
+ }, {
+ code: 'ERR_PARSE_ARGS_INVALID_OPTION_VALUE'
+ });
+});
+
+test('strict: when candidate option value is short option digit then throws', () => {
+ const args = ['--with', '-1'];
+ const options = { with: { type: 'string' } };
+
+ assert.throws(() => {
+ parseArgs({ args, options });
+ }, {
+ code: 'ERR_PARSE_ARGS_INVALID_OPTION_VALUE'
+ });
+});
+
+test('strict: when candidate option value is long option then throws', () => {
+ const args = ['--with', '--foo'];
+ const options = { with: { type: 'string' } };
+
+ assert.throws(() => {
+ parseArgs({ args, options });
+ }, {
+ code: 'ERR_PARSE_ARGS_INVALID_OPTION_VALUE'
+ });
+});
+
+test('strict: when short option and suspect value then throws with short option in error message', () => {
+ const args = ['-w', '--foo'];
+ const options = { with: { type: 'string', short: 'w' } };
+
+ assert.throws(() => {
+ parseArgs({ args, options });
+ }, /for '-w'/
+ );
+});
+
+test('strict: when long option and suspect value then throws with long option in error message', () => {
+ const args = ['--with', '--foo'];
+ const options = { with: { type: 'string' } };
+
+ assert.throws(() => {
+ parseArgs({ args, options });
+ }, /for '--with'/
+ );
+});
+
+test('strict: when short option and suspect value then throws with whole expected message', () => {
+ const args = ['-w', '--foo'];
+ const options = { with: { type: 'string', short: 'w' } };
+
+ try {
+ parseArgs({ args, options });
+ } catch (err) {
+ console.info(err.message);
+ }
+
+ assert.throws(() => {
+ parseArgs({ args, options });
+ }, /To specify an option argument starting with a dash use '--with=-XYZ' or '-w-XYZ'/
+ );
+});
+
+test('strict: when long option and suspect value then throws with whole expected message', () => {
+ const args = ['--with', '--foo'];
+ const options = { with: { type: 'string', short: 'w' } };
+
+ assert.throws(() => {
+ parseArgs({ args, options });
+ }, /To specify an option argument starting with a dash use '--with=-XYZ'/
+ );
+});
+
+test('tokens: positional', () => {
+ const args = ['one'];
+ const expectedTokens = [
+ { kind: 'positional', index: 0, value: 'one' },
+ ];
+ const { tokens } = parseArgs({ strict: false, args, tokens: true });
+ assert.deepStrictEqual(tokens, expectedTokens);
+});
+
+test('tokens: -- followed by option-like', () => {
+ const args = ['--', '--foo'];
+ const expectedTokens = [
+ { kind: 'option-terminator', index: 0 },
+ { kind: 'positional', index: 1, value: '--foo' },
+ ];
+ const { tokens } = parseArgs({ strict: false, args, tokens: true });
+ assert.deepStrictEqual(tokens, expectedTokens);
+});
+
+test('tokens: strict:true boolean short', () => {
+ const args = ['-f'];
+ const options = {
+ file: { short: 'f', type: 'boolean' }
+ };
+ const expectedTokens = [
+ { kind: 'option', name: 'file', rawName: '-f',
+ index: 0, value: undefined, inlineValue: undefined },
+ ];
+ const { tokens } = parseArgs({ strict: true, args, options, tokens: true });
+ assert.deepStrictEqual(tokens, expectedTokens);
+});
+
+test('tokens: strict:true boolean long', () => {
+ const args = ['--file'];
+ const options = {
+ file: { short: 'f', type: 'boolean' }
+ };
+ const expectedTokens = [
+ { kind: 'option', name: 'file', rawName: '--file',
+ index: 0, value: undefined, inlineValue: undefined },
+ ];
+ const { tokens } = parseArgs({ strict: true, args, options, tokens: true });
+ assert.deepStrictEqual(tokens, expectedTokens);
+});
+
+test('tokens: strict:false boolean short', () => {
+ const args = ['-f'];
+ const expectedTokens = [
+ { kind: 'option', name: 'f', rawName: '-f',
+ index: 0, value: undefined, inlineValue: undefined },
+ ];
+ const { tokens } = parseArgs({ strict: false, args, tokens: true });
+ assert.deepStrictEqual(tokens, expectedTokens);
+});
+
+test('tokens: strict:false boolean long', () => {
+ const args = ['--file'];
+ const expectedTokens = [
+ { kind: 'option', name: 'file', rawName: '--file',
+ index: 0, value: undefined, inlineValue: undefined },
+ ];
+ const { tokens } = parseArgs({ strict: false, args, tokens: true });
+ assert.deepStrictEqual(tokens, expectedTokens);
+});
+
+test('tokens: strict:false boolean option group', () => {
+ const args = ['-ab'];
+ const expectedTokens = [
+ { kind: 'option', name: 'a', rawName: '-a',
+ index: 0, value: undefined, inlineValue: undefined },
+ { kind: 'option', name: 'b', rawName: '-b',
+ index: 0, value: undefined, inlineValue: undefined },
+ ];
+ const { tokens } = parseArgs({ strict: false, args, tokens: true });
+ assert.deepStrictEqual(tokens, expectedTokens);
+});
+
+test('tokens: strict:false boolean option group with repeated option', () => {
+ // Also positional to check index correct after grouop
+ const args = ['-aa', 'pos'];
+ const expectedTokens = [
+ { kind: 'option', name: 'a', rawName: '-a',
+ index: 0, value: undefined, inlineValue: undefined },
+ { kind: 'option', name: 'a', rawName: '-a',
+ index: 0, value: undefined, inlineValue: undefined },
+ { kind: 'positional', index: 1, value: 'pos' },
+ ];
+ const { tokens } = parseArgs({ strict: false, allowPositionals: true, args, tokens: true });
+ assert.deepStrictEqual(tokens, expectedTokens);
+});
+
+test('tokens: strict:true string short with value after space', () => {
+ // Also positional to check index correct after out-of-line.
+ const args = ['-f', 'bar', 'ppp'];
+ const options = {
+ file: { short: 'f', type: 'string' }
+ };
+ const expectedTokens = [
+ { kind: 'option', name: 'file', rawName: '-f',
+ index: 0, value: 'bar', inlineValue: false },
+ { kind: 'positional', index: 2, value: 'ppp' },
+ ];
+ const { tokens } = parseArgs({ strict: true, allowPositionals: true, args, options, tokens: true });
+ assert.deepStrictEqual(tokens, expectedTokens);
+});
+
+test('tokens: strict:true string short with value inline', () => {
+ const args = ['-fBAR'];
+ const options = {
+ file: { short: 'f', type: 'string' }
+ };
+ const expectedTokens = [
+ { kind: 'option', name: 'file', rawName: '-f',
+ index: 0, value: 'BAR', inlineValue: true },
+ ];
+ const { tokens } = parseArgs({ strict: true, args, options, tokens: true });
+ assert.deepStrictEqual(tokens, expectedTokens);
+});
+
+test('tokens: strict:false string short missing value', () => {
+ const args = ['-f'];
+ const options = {
+ file: { short: 'f', type: 'string' }
+ };
+ const expectedTokens = [
+ { kind: 'option', name: 'file', rawName: '-f',
+ index: 0, value: undefined, inlineValue: undefined },
+ ];
+ const { tokens } = parseArgs({ strict: false, args, options, tokens: true });
+ assert.deepStrictEqual(tokens, expectedTokens);
+});
+
+test('tokens: strict:true string long with value after space', () => {
+ // Also positional to check index correct after out-of-line.
+ const args = ['--file', 'bar', 'ppp'];
+ const options = {
+ file: { short: 'f', type: 'string' }
+ };
+ const expectedTokens = [
+ { kind: 'option', name: 'file', rawName: '--file',
+ index: 0, value: 'bar', inlineValue: false },
+ { kind: 'positional', index: 2, value: 'ppp' },
+ ];
+ const { tokens } = parseArgs({ strict: true, allowPositionals: true, args, options, tokens: true });
+ assert.deepStrictEqual(tokens, expectedTokens);
+});
+
+test('tokens: strict:true string long with value inline', () => {
+ // Also positional to check index correct after out-of-line.
+ const args = ['--file=bar', 'pos'];
+ const options = {
+ file: { short: 'f', type: 'string' }
+ };
+ const expectedTokens = [
+ { kind: 'option', name: 'file', rawName: '--file',
+ index: 0, value: 'bar', inlineValue: true },
+ { kind: 'positional', index: 1, value: 'pos' },
+ ];
+ const { tokens } = parseArgs({ strict: true, allowPositionals: true, args, options, tokens: true });
+ assert.deepStrictEqual(tokens, expectedTokens);
+});
+
+test('tokens: strict:false string long with value inline', () => {
+ const args = ['--file=bar'];
+ const expectedTokens = [
+ { kind: 'option', name: 'file', rawName: '--file',
+ index: 0, value: 'bar', inlineValue: true },
+ ];
+ const { tokens } = parseArgs({ strict: false, args, tokens: true });
+ assert.deepStrictEqual(tokens, expectedTokens);
+});
+
+test('tokens: strict:false string long missing value', () => {
+ const args = ['--file'];
+ const options = {
+ file: { short: 'f', type: 'string' }
+ };
+ const expectedTokens = [
+ { kind: 'option', name: 'file', rawName: '--file',
+ index: 0, value: undefined, inlineValue: undefined },
+ ];
+ const { tokens } = parseArgs({ strict: false, args, options, tokens: true });
+ assert.deepStrictEqual(tokens, expectedTokens);
+});
+
+test('tokens: strict:true complex option group with value after space', () => {
+ // Also positional to check index correct afterwards.
+ const args = ['-ab', 'c', 'pos'];
+ const options = {
+ alpha: { short: 'a', type: 'boolean' },
+ beta: { short: 'b', type: 'string' },
+ };
+ const expectedTokens = [
+ { kind: 'option', name: 'alpha', rawName: '-a',
+ index: 0, value: undefined, inlineValue: undefined },
+ { kind: 'option', name: 'beta', rawName: '-b',
+ index: 0, value: 'c', inlineValue: false },
+ { kind: 'positional', index: 2, value: 'pos' },
+ ];
+ const { tokens } = parseArgs({ strict: true, allowPositionals: true, args, options, tokens: true });
+ assert.deepStrictEqual(tokens, expectedTokens);
+});
+
+test('tokens: strict:true complex option group with inline value', () => {
+ // Also positional to check index correct afterwards.
+ const args = ['-abc', 'pos'];
+ const options = {
+ alpha: { short: 'a', type: 'boolean' },
+ beta: { short: 'b', type: 'string' },
+ };
+ const expectedTokens = [
+ { kind: 'option', name: 'alpha', rawName: '-a',
+ index: 0, value: undefined, inlineValue: undefined },
+ { kind: 'option', name: 'beta', rawName: '-b',
+ index: 0, value: 'c', inlineValue: true },
+ { kind: 'positional', index: 1, value: 'pos' },
+ ];
+ const { tokens } = parseArgs({ strict: true, allowPositionals: true, args, options, tokens: true });
+ assert.deepStrictEqual(tokens, expectedTokens);
+});
+
+test('tokens: strict:false with single dashes', () => {
+ const args = ['--file', '-', '-'];
+ const options = {
+ file: { short: 'f', type: 'string' },
+ };
+ const expectedTokens = [
+ { kind: 'option', name: 'file', rawName: '--file',
+ index: 0, value: '-', inlineValue: false },
+ { kind: 'positional', index: 2, value: '-' },
+ ];
+ const { tokens } = parseArgs({ strict: false, args, options, tokens: true });
+ assert.deepStrictEqual(tokens, expectedTokens);
+});
+
+test('tokens: strict:false with -- --', () => {
+ const args = ['--', '--'];
+ const expectedTokens = [
+ { kind: 'option-terminator', index: 0 },
+ { kind: 'positional', index: 1, value: '--' },
+ ];
+ const { tokens } = parseArgs({ strict: false, args, tokens: true });
+ assert.deepStrictEqual(tokens, expectedTokens);
+});
+
+test('default must be a boolean when option type is boolean', () => {
+ const args = [];
+ const options = { alpha: { type: 'boolean', default: 'not a boolean' } };
+ assert.throws(() => {
+ parseArgs({ args, options });
+ }, /"options\.alpha\.default" property must be of type boolean/
+ );
+});
+
+test('default must accept undefined value', () => {
+ const args = [];
+ const options = { alpha: { type: 'boolean', default: undefined } };
+ const result = parseArgs({ args, options });
+ const expected = {
+ values: {
+ __proto__: null,
+ },
+ positionals: []
+ };
+ assert.deepStrictEqual(result, expected);
+});
+
+test('default must be a boolean array when option type is boolean and multiple', () => {
+ const args = [];
+ const options = { alpha: { type: 'boolean', multiple: true, default: 'not an array' } };
+ assert.throws(() => {
+ parseArgs({ args, options });
+ }, /"options\.alpha\.default" property must be an instance of Array/
+ );
+});
+
+test('default must be a boolean array when option type is string and multiple is true', () => {
+ const args = [];
+ const options = { alpha: { type: 'boolean', multiple: true, default: [true, true, 42] } };
+ assert.throws(() => {
+ parseArgs({ args, options });
+ }, /"options\.alpha\.default\[2\]" property must be of type boolean/
+ );
+});
+
+test('default must be a string when option type is string', () => {
+ const args = [];
+ const options = { alpha: { type: 'string', default: true } };
+ assert.throws(() => {
+ parseArgs({ args, options });
+ }, /"options\.alpha\.default" property must be of type string/
+ );
+});
+
+test('default must be an array when option type is string and multiple is true', () => {
+ const args = [];
+ const options = { alpha: { type: 'string', multiple: true, default: 'not an array' } };
+ assert.throws(() => {
+ parseArgs({ args, options });
+ }, /"options\.alpha\.default" property must be an instance of Array/
+ );
+});
+
+test('default must be a string array when option type is string and multiple is true', () => {
+ const args = [];
+ const options = { alpha: { type: 'string', multiple: true, default: ['str', 42] } };
+ assert.throws(() => {
+ parseArgs({ args, options });
+ }, /"options\.alpha\.default\[1\]" property must be of type string/
+ );
+});
+
+test('default accepted input when multiple is true', () => {
+ const args = ['--inputStringArr', 'c', '--inputStringArr', 'd', '--inputBoolArr', '--inputBoolArr'];
+ const options = {
+ inputStringArr: { type: 'string', multiple: true, default: ['a', 'b'] },
+ emptyStringArr: { type: 'string', multiple: true, default: [] },
+ fullStringArr: { type: 'string', multiple: true, default: ['a', 'b'] },
+ inputBoolArr: { type: 'boolean', multiple: true, default: [false, true, false] },
+ emptyBoolArr: { type: 'boolean', multiple: true, default: [] },
+ fullBoolArr: { type: 'boolean', multiple: true, default: [false, true, false] },
+ };
+ const expected = { values: { __proto__: null,
+ inputStringArr: ['c', 'd'],
+ inputBoolArr: [true, true],
+ emptyStringArr: [],
+ fullStringArr: ['a', 'b'],
+ emptyBoolArr: [],
+ fullBoolArr: [false, true, false] },
+ positionals: [] };
+ const result = parseArgs({ args, options });
+ assert.deepStrictEqual(result, expected);
+});
+
+test('when default is set, the option must be added as result', () => {
+ const args = [];
+ const options = {
+ a: { type: 'string', default: 'HELLO' },
+ b: { type: 'boolean', default: false },
+ c: { type: 'boolean', default: true }
+ };
+ const expected = { values: { __proto__: null, a: 'HELLO', b: false, c: true }, positionals: [] };
+
+ const result = parseArgs({ args, options });
+ assert.deepStrictEqual(result, expected);
+});
+
+test('when default is set, the args value takes precedence', () => {
+ const args = ['--a', 'WORLD', '--b', '-c'];
+ const options = {
+ a: { type: 'string', default: 'HELLO' },
+ b: { type: 'boolean', default: false },
+ c: { type: 'boolean', default: true }
+ };
+ const expected = { values: { __proto__: null, a: 'WORLD', b: true, c: true }, positionals: [] };
+
+ const result = parseArgs({ args, options });
+ assert.deepStrictEqual(result, expected);
+});
+
+test('tokens should not include the default options', () => {
+ const args = [];
+ const options = {
+ a: { type: 'string', default: 'HELLO' },
+ b: { type: 'boolean', default: false },
+ c: { type: 'boolean', default: true }
+ };
+
+ const expectedTokens = [];
+
+ const { tokens } = parseArgs({ args, options, tokens: true });
+ assert.deepStrictEqual(tokens, expectedTokens);
+});
+
+test('tokens:true should not include the default options after the args input', () => {
+ const args = ['--z', 'zero', 'positional-item'];
+ const options = {
+ z: { type: 'string' },
+ a: { type: 'string', default: 'HELLO' },
+ b: { type: 'boolean', default: false },
+ c: { type: 'boolean', default: true }
+ };
+
+ const expectedTokens = [
+ { kind: 'option', name: 'z', rawName: '--z', index: 0, value: 'zero', inlineValue: false },
+ { kind: 'positional', index: 2, value: 'positional-item' },
+ ];
+
+ const { tokens } = parseArgs({ args, options, tokens: true, allowPositionals: true });
+ assert.deepStrictEqual(tokens, expectedTokens);
+});
+
+test('proto as default value must be ignored', () => {
+ const args = [];
+ const options = Object.create(null);
+
+ // eslint-disable-next-line no-proto
+ options.__proto__ = { type: 'string', default: 'HELLO' };
+
+ const result = parseArgs({ args, options, allowPositionals: true });
+ const expected = { values: { __proto__: null }, positionals: [] };
+ assert.deepStrictEqual(result, expected);
+});
+
+
+test('multiple as false should expect a String', () => {
+ const args = [];
+ const options = { alpha: { type: 'string', multiple: false, default: ['array'] } };
+ assert.throws(() => {
+ parseArgs({ args, options });
+ }, /"options\.alpha\.default" property must be of type string/
+ );
+});
diff --git a/tests/node_compat/test/parallel/test-path-basename.js b/tests/node_compat/test/parallel/test-path-basename.js
new file mode 100644
index 000000000..9e8e9ecf8
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-path-basename.js
@@ -0,0 +1,83 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+const path = require('path');
+
+assert.strictEqual(path.basename(__filename), 'test-path-basename.js');
+assert.strictEqual(path.basename(__filename, '.js'), 'test-path-basename');
+assert.strictEqual(path.basename('.js', '.js'), '');
+assert.strictEqual(path.basename('js', '.js'), 'js');
+assert.strictEqual(path.basename('file.js', '.ts'), 'file.js');
+assert.strictEqual(path.basename('file', '.js'), 'file');
+assert.strictEqual(path.basename('file.js.old', '.js.old'), 'file');
+assert.strictEqual(path.basename(''), '');
+assert.strictEqual(path.basename('/dir/basename.ext'), 'basename.ext');
+assert.strictEqual(path.basename('/basename.ext'), 'basename.ext');
+assert.strictEqual(path.basename('basename.ext'), 'basename.ext');
+assert.strictEqual(path.basename('basename.ext/'), 'basename.ext');
+assert.strictEqual(path.basename('basename.ext//'), 'basename.ext');
+assert.strictEqual(path.basename('aaa/bbb', '/bbb'), 'bbb');
+assert.strictEqual(path.basename('aaa/bbb', 'a/bbb'), 'bbb');
+assert.strictEqual(path.basename('aaa/bbb', 'bbb'), 'bbb');
+assert.strictEqual(path.basename('aaa/bbb//', 'bbb'), 'bbb');
+assert.strictEqual(path.basename('aaa/bbb', 'bb'), 'b');
+assert.strictEqual(path.basename('aaa/bbb', 'b'), 'bb');
+assert.strictEqual(path.basename('/aaa/bbb', '/bbb'), 'bbb');
+assert.strictEqual(path.basename('/aaa/bbb', 'a/bbb'), 'bbb');
+assert.strictEqual(path.basename('/aaa/bbb', 'bbb'), 'bbb');
+assert.strictEqual(path.basename('/aaa/bbb//', 'bbb'), 'bbb');
+assert.strictEqual(path.basename('/aaa/bbb', 'bb'), 'b');
+assert.strictEqual(path.basename('/aaa/bbb', 'b'), 'bb');
+assert.strictEqual(path.basename('/aaa/bbb'), 'bbb');
+assert.strictEqual(path.basename('/aaa/'), 'aaa');
+assert.strictEqual(path.basename('/aaa/b'), 'b');
+assert.strictEqual(path.basename('/a/b'), 'b');
+assert.strictEqual(path.basename('//a'), 'a');
+assert.strictEqual(path.basename('a', 'a'), '');
+
+// On Windows a backslash acts as a path separator.
+assert.strictEqual(path.win32.basename('\\dir\\basename.ext'), 'basename.ext');
+assert.strictEqual(path.win32.basename('\\basename.ext'), 'basename.ext');
+assert.strictEqual(path.win32.basename('basename.ext'), 'basename.ext');
+assert.strictEqual(path.win32.basename('basename.ext\\'), 'basename.ext');
+assert.strictEqual(path.win32.basename('basename.ext\\\\'), 'basename.ext');
+assert.strictEqual(path.win32.basename('foo'), 'foo');
+assert.strictEqual(path.win32.basename('aaa\\bbb', '\\bbb'), 'bbb');
+assert.strictEqual(path.win32.basename('aaa\\bbb', 'a\\bbb'), 'bbb');
+assert.strictEqual(path.win32.basename('aaa\\bbb', 'bbb'), 'bbb');
+assert.strictEqual(path.win32.basename('aaa\\bbb\\\\\\\\', 'bbb'), 'bbb');
+assert.strictEqual(path.win32.basename('aaa\\bbb', 'bb'), 'b');
+assert.strictEqual(path.win32.basename('aaa\\bbb', 'b'), 'bb');
+assert.strictEqual(path.win32.basename('C:'), '');
+assert.strictEqual(path.win32.basename('C:.'), '.');
+assert.strictEqual(path.win32.basename('C:\\'), '');
+assert.strictEqual(path.win32.basename('C:\\dir\\base.ext'), 'base.ext');
+assert.strictEqual(path.win32.basename('C:\\basename.ext'), 'basename.ext');
+assert.strictEqual(path.win32.basename('C:basename.ext'), 'basename.ext');
+assert.strictEqual(path.win32.basename('C:basename.ext\\'), 'basename.ext');
+assert.strictEqual(path.win32.basename('C:basename.ext\\\\'), 'basename.ext');
+assert.strictEqual(path.win32.basename('C:foo'), 'foo');
+assert.strictEqual(path.win32.basename('file:stream'), 'file:stream');
+assert.strictEqual(path.win32.basename('a', 'a'), '');
+
+// On unix a backslash is just treated as any other character.
+assert.strictEqual(path.posix.basename('\\dir\\basename.ext'),
+ '\\dir\\basename.ext');
+assert.strictEqual(path.posix.basename('\\basename.ext'), '\\basename.ext');
+assert.strictEqual(path.posix.basename('basename.ext'), 'basename.ext');
+assert.strictEqual(path.posix.basename('basename.ext\\'), 'basename.ext\\');
+assert.strictEqual(path.posix.basename('basename.ext\\\\'), 'basename.ext\\\\');
+assert.strictEqual(path.posix.basename('foo'), 'foo');
+
+// POSIX filenames may include control characters
+// c.f. http://www.dwheeler.com/essays/fixing-unix-linux-filenames.html
+const controlCharFilename = `Icon${String.fromCharCode(13)}`;
+assert.strictEqual(path.posix.basename(`/a/b/${controlCharFilename}`),
+ controlCharFilename);
diff --git a/tests/node_compat/test/parallel/test-path-dirname.js b/tests/node_compat/test/parallel/test-path-dirname.js
new file mode 100644
index 000000000..0b123fcdf
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-path-dirname.js
@@ -0,0 +1,66 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const path = require('path');
+
+assert.strictEqual(path.dirname(__filename).substr(-13),
+ common.isWindows ? 'test\\parallel' : 'test/parallel');
+
+assert.strictEqual(path.posix.dirname('/a/b/'), '/a');
+assert.strictEqual(path.posix.dirname('/a/b'), '/a');
+assert.strictEqual(path.posix.dirname('/a'), '/');
+assert.strictEqual(path.posix.dirname(''), '.');
+assert.strictEqual(path.posix.dirname('/'), '/');
+assert.strictEqual(path.posix.dirname('////'), '/');
+assert.strictEqual(path.posix.dirname('//a'), '//');
+assert.strictEqual(path.posix.dirname('foo'), '.');
+
+assert.strictEqual(path.win32.dirname('c:\\'), 'c:\\');
+assert.strictEqual(path.win32.dirname('c:\\foo'), 'c:\\');
+assert.strictEqual(path.win32.dirname('c:\\foo\\'), 'c:\\');
+assert.strictEqual(path.win32.dirname('c:\\foo\\bar'), 'c:\\foo');
+assert.strictEqual(path.win32.dirname('c:\\foo\\bar\\'), 'c:\\foo');
+assert.strictEqual(path.win32.dirname('c:\\foo\\bar\\baz'), 'c:\\foo\\bar');
+assert.strictEqual(path.win32.dirname('c:\\foo bar\\baz'), 'c:\\foo bar');
+assert.strictEqual(path.win32.dirname('\\'), '\\');
+assert.strictEqual(path.win32.dirname('\\foo'), '\\');
+assert.strictEqual(path.win32.dirname('\\foo\\'), '\\');
+assert.strictEqual(path.win32.dirname('\\foo\\bar'), '\\foo');
+assert.strictEqual(path.win32.dirname('\\foo\\bar\\'), '\\foo');
+assert.strictEqual(path.win32.dirname('\\foo\\bar\\baz'), '\\foo\\bar');
+assert.strictEqual(path.win32.dirname('\\foo bar\\baz'), '\\foo bar');
+assert.strictEqual(path.win32.dirname('c:'), 'c:');
+assert.strictEqual(path.win32.dirname('c:foo'), 'c:');
+assert.strictEqual(path.win32.dirname('c:foo\\'), 'c:');
+assert.strictEqual(path.win32.dirname('c:foo\\bar'), 'c:foo');
+assert.strictEqual(path.win32.dirname('c:foo\\bar\\'), 'c:foo');
+assert.strictEqual(path.win32.dirname('c:foo\\bar\\baz'), 'c:foo\\bar');
+assert.strictEqual(path.win32.dirname('c:foo bar\\baz'), 'c:foo bar');
+assert.strictEqual(path.win32.dirname('file:stream'), '.');
+assert.strictEqual(path.win32.dirname('dir\\file:stream'), 'dir');
+assert.strictEqual(path.win32.dirname('\\\\unc\\share'),
+ '\\\\unc\\share');
+assert.strictEqual(path.win32.dirname('\\\\unc\\share\\foo'),
+ '\\\\unc\\share\\');
+assert.strictEqual(path.win32.dirname('\\\\unc\\share\\foo\\'),
+ '\\\\unc\\share\\');
+assert.strictEqual(path.win32.dirname('\\\\unc\\share\\foo\\bar'),
+ '\\\\unc\\share\\foo');
+assert.strictEqual(path.win32.dirname('\\\\unc\\share\\foo\\bar\\'),
+ '\\\\unc\\share\\foo');
+assert.strictEqual(path.win32.dirname('\\\\unc\\share\\foo\\bar\\baz'),
+ '\\\\unc\\share\\foo\\bar');
+assert.strictEqual(path.win32.dirname('/a/b/'), '/a');
+assert.strictEqual(path.win32.dirname('/a/b'), '/a');
+assert.strictEqual(path.win32.dirname('/a'), '/');
+assert.strictEqual(path.win32.dirname(''), '.');
+assert.strictEqual(path.win32.dirname('/'), '/');
+assert.strictEqual(path.win32.dirname('////'), '/');
+assert.strictEqual(path.win32.dirname('foo'), '.');
diff --git a/tests/node_compat/test/parallel/test-path-extname.js b/tests/node_compat/test/parallel/test-path-extname.js
new file mode 100644
index 000000000..d1ed0342b
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-path-extname.js
@@ -0,0 +1,106 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+const path = require('path');
+
+const failures = [];
+const slashRE = /\//g;
+
+[
+ [__filename, '.js'],
+ ['', ''],
+ ['/path/to/file', ''],
+ ['/path/to/file.ext', '.ext'],
+ ['/path.to/file.ext', '.ext'],
+ ['/path.to/file', ''],
+ ['/path.to/.file', ''],
+ ['/path.to/.file.ext', '.ext'],
+ ['/path/to/f.ext', '.ext'],
+ ['/path/to/..ext', '.ext'],
+ ['/path/to/..', ''],
+ ['file', ''],
+ ['file.ext', '.ext'],
+ ['.file', ''],
+ ['.file.ext', '.ext'],
+ ['/file', ''],
+ ['/file.ext', '.ext'],
+ ['/.file', ''],
+ ['/.file.ext', '.ext'],
+ ['.path/file.ext', '.ext'],
+ ['file.ext.ext', '.ext'],
+ ['file.', '.'],
+ ['.', ''],
+ ['./', ''],
+ ['.file.ext', '.ext'],
+ ['.file', ''],
+ ['.file.', '.'],
+ ['.file..', '.'],
+ ['..', ''],
+ ['../', ''],
+ ['..file.ext', '.ext'],
+ ['..file', '.file'],
+ ['..file.', '.'],
+ ['..file..', '.'],
+ ['...', '.'],
+ ['...ext', '.ext'],
+ ['....', '.'],
+ ['file.ext/', '.ext'],
+ ['file.ext//', '.ext'],
+ ['file/', ''],
+ ['file//', ''],
+ ['file./', '.'],
+ ['file.//', '.'],
+].forEach((test) => {
+ const expected = test[1];
+ [path.posix.extname, path.win32.extname].forEach((extname) => {
+ let input = test[0];
+ let os;
+ if (extname === path.win32.extname) {
+ input = input.replace(slashRE, '\\');
+ os = 'win32';
+ } else {
+ os = 'posix';
+ }
+ const actual = extname(input);
+ const message = `path.${os}.extname(${JSON.stringify(input)})\n expect=${
+ JSON.stringify(expected)}\n actual=${JSON.stringify(actual)}`;
+ if (actual !== expected)
+ failures.push(`\n${message}`);
+ });
+ {
+ const input = `C:${test[0].replace(slashRE, '\\')}`;
+ const actual = path.win32.extname(input);
+ const message = `path.win32.extname(${JSON.stringify(input)})\n expect=${
+ JSON.stringify(expected)}\n actual=${JSON.stringify(actual)}`;
+ if (actual !== expected)
+ failures.push(`\n${message}`);
+ }
+});
+assert.strictEqual(failures.length, 0, failures.join(''));
+
+// On Windows, backslash is a path separator.
+assert.strictEqual(path.win32.extname('.\\'), '');
+assert.strictEqual(path.win32.extname('..\\'), '');
+assert.strictEqual(path.win32.extname('file.ext\\'), '.ext');
+assert.strictEqual(path.win32.extname('file.ext\\\\'), '.ext');
+assert.strictEqual(path.win32.extname('file\\'), '');
+assert.strictEqual(path.win32.extname('file\\\\'), '');
+assert.strictEqual(path.win32.extname('file.\\'), '.');
+assert.strictEqual(path.win32.extname('file.\\\\'), '.');
+
+// On *nix, backslash is a valid name component like any other character.
+assert.strictEqual(path.posix.extname('.\\'), '');
+assert.strictEqual(path.posix.extname('..\\'), '.\\');
+assert.strictEqual(path.posix.extname('file.ext\\'), '.ext\\');
+assert.strictEqual(path.posix.extname('file.ext\\\\'), '.ext\\\\');
+assert.strictEqual(path.posix.extname('file\\'), '');
+assert.strictEqual(path.posix.extname('file\\\\'), '');
+assert.strictEqual(path.posix.extname('file.\\'), '.\\');
+assert.strictEqual(path.posix.extname('file.\\\\'), '.\\\\');
diff --git a/tests/node_compat/test/parallel/test-path-isabsolute.js b/tests/node_compat/test/parallel/test-path-isabsolute.js
new file mode 100644
index 000000000..ff64fc7ff
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-path-isabsolute.js
@@ -0,0 +1,35 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+const path = require('path');
+
+assert.strictEqual(path.win32.isAbsolute('/'), true);
+assert.strictEqual(path.win32.isAbsolute('//'), true);
+assert.strictEqual(path.win32.isAbsolute('//server'), true);
+assert.strictEqual(path.win32.isAbsolute('//server/file'), true);
+assert.strictEqual(path.win32.isAbsolute('\\\\server\\file'), true);
+assert.strictEqual(path.win32.isAbsolute('\\\\server'), true);
+assert.strictEqual(path.win32.isAbsolute('\\\\'), true);
+assert.strictEqual(path.win32.isAbsolute('c'), false);
+assert.strictEqual(path.win32.isAbsolute('c:'), false);
+assert.strictEqual(path.win32.isAbsolute('c:\\'), true);
+assert.strictEqual(path.win32.isAbsolute('c:/'), true);
+assert.strictEqual(path.win32.isAbsolute('c://'), true);
+assert.strictEqual(path.win32.isAbsolute('C:/Users/'), true);
+assert.strictEqual(path.win32.isAbsolute('C:\\Users\\'), true);
+assert.strictEqual(path.win32.isAbsolute('C:cwd/another'), false);
+assert.strictEqual(path.win32.isAbsolute('C:cwd\\another'), false);
+assert.strictEqual(path.win32.isAbsolute('directory/directory'), false);
+assert.strictEqual(path.win32.isAbsolute('directory\\directory'), false);
+
+assert.strictEqual(path.posix.isAbsolute('/home/foo'), true);
+assert.strictEqual(path.posix.isAbsolute('/home/foo/..'), true);
+assert.strictEqual(path.posix.isAbsolute('bar/'), false);
+assert.strictEqual(path.posix.isAbsolute('./baz'), false);
diff --git a/tests/node_compat/test/parallel/test-path-join.js b/tests/node_compat/test/parallel/test-path-join.js
new file mode 100644
index 000000000..2b958b720
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-path-join.js
@@ -0,0 +1,150 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+const path = require('path');
+
+const failures = [];
+const backslashRE = /\\/g;
+
+const joinTests = [
+ [ [path.posix.join, path.win32.join],
+ // Arguments result
+ [[['.', 'x/b', '..', '/b/c.js'], 'x/b/c.js'],
+ [[], '.'],
+ [['/.', 'x/b', '..', '/b/c.js'], '/x/b/c.js'],
+ [['/foo', '../../../bar'], '/bar'],
+ [['foo', '../../../bar'], '../../bar'],
+ [['foo/', '../../../bar'], '../../bar'],
+ [['foo/x', '../../../bar'], '../bar'],
+ [['foo/x', './bar'], 'foo/x/bar'],
+ [['foo/x/', './bar'], 'foo/x/bar'],
+ [['foo/x/', '.', 'bar'], 'foo/x/bar'],
+ [['./'], './'],
+ [['.', './'], './'],
+ [['.', '.', '.'], '.'],
+ [['.', './', '.'], '.'],
+ [['.', '/./', '.'], '.'],
+ [['.', '/////./', '.'], '.'],
+ [['.'], '.'],
+ [['', '.'], '.'],
+ [['', 'foo'], 'foo'],
+ [['foo', '/bar'], 'foo/bar'],
+ [['', '/foo'], '/foo'],
+ [['', '', '/foo'], '/foo'],
+ [['', '', 'foo'], 'foo'],
+ [['foo', ''], 'foo'],
+ [['foo/', ''], 'foo/'],
+ [['foo', '', '/bar'], 'foo/bar'],
+ [['./', '..', '/foo'], '../foo'],
+ [['./', '..', '..', '/foo'], '../../foo'],
+ [['.', '..', '..', '/foo'], '../../foo'],
+ [['', '..', '..', '/foo'], '../../foo'],
+ [['/'], '/'],
+ [['/', '.'], '/'],
+ [['/', '..'], '/'],
+ [['/', '..', '..'], '/'],
+ [[''], '.'],
+ [['', ''], '.'],
+ [[' /foo'], ' /foo'],
+ [[' ', 'foo'], ' /foo'],
+ [[' ', '.'], ' '],
+ [[' ', '/'], ' /'],
+ [[' ', ''], ' '],
+ [['/', 'foo'], '/foo'],
+ [['/', '/foo'], '/foo'],
+ [['/', '//foo'], '/foo'],
+ [['/', '', '/foo'], '/foo'],
+ [['', '/', 'foo'], '/foo'],
+ [['', '/', '/foo'], '/foo'],
+ ],
+ ],
+];
+
+// Windows-specific join tests
+joinTests.push([
+ path.win32.join,
+ joinTests[0][1].slice(0).concat(
+ [// Arguments result
+ // UNC path expected
+ [['//foo/bar'], '\\\\foo\\bar\\'],
+ [['\\/foo/bar'], '\\\\foo\\bar\\'],
+ [['\\\\foo/bar'], '\\\\foo\\bar\\'],
+ // UNC path expected - server and share separate
+ [['//foo', 'bar'], '\\\\foo\\bar\\'],
+ [['//foo/', 'bar'], '\\\\foo\\bar\\'],
+ [['//foo', '/bar'], '\\\\foo\\bar\\'],
+ // UNC path expected - questionable
+ [['//foo', '', 'bar'], '\\\\foo\\bar\\'],
+ [['//foo/', '', 'bar'], '\\\\foo\\bar\\'],
+ [['//foo/', '', '/bar'], '\\\\foo\\bar\\'],
+ // UNC path expected - even more questionable
+ [['', '//foo', 'bar'], '\\\\foo\\bar\\'],
+ [['', '//foo/', 'bar'], '\\\\foo\\bar\\'],
+ [['', '//foo/', '/bar'], '\\\\foo\\bar\\'],
+ // No UNC path expected (no double slash in first component)
+ [['\\', 'foo/bar'], '\\foo\\bar'],
+ [['\\', '/foo/bar'], '\\foo\\bar'],
+ [['', '/', '/foo/bar'], '\\foo\\bar'],
+ // No UNC path expected (no non-slashes in first component -
+ // questionable)
+ [['//', 'foo/bar'], '\\foo\\bar'],
+ [['//', '/foo/bar'], '\\foo\\bar'],
+ [['\\\\', '/', '/foo/bar'], '\\foo\\bar'],
+ [['//'], '\\'],
+ // No UNC path expected (share name missing - questionable).
+ [['//foo'], '\\foo'],
+ [['//foo/'], '\\foo\\'],
+ [['//foo', '/'], '\\foo\\'],
+ [['//foo', '', '/'], '\\foo\\'],
+ // No UNC path expected (too many leading slashes - questionable)
+ [['///foo/bar'], '\\foo\\bar'],
+ [['////foo', 'bar'], '\\foo\\bar'],
+ [['\\\\\\/foo/bar'], '\\foo\\bar'],
+ // Drive-relative vs drive-absolute paths. This merely describes the
+ // status quo, rather than being obviously right
+ [['c:'], 'c:.'],
+ [['c:.'], 'c:.'],
+ [['c:', ''], 'c:.'],
+ [['', 'c:'], 'c:.'],
+ [['c:.', '/'], 'c:.\\'],
+ [['c:.', 'file'], 'c:file'],
+ [['c:', '/'], 'c:\\'],
+ [['c:', 'file'], 'c:\\file'],
+ ]
+ ),
+]);
+joinTests.forEach((test) => {
+ if (!Array.isArray(test[0]))
+ test[0] = [test[0]];
+ test[0].forEach((join) => {
+ test[1].forEach((test) => {
+ const actual = join.apply(null, test[0]);
+ const expected = test[1];
+ // For non-Windows specific tests with the Windows join(), we need to try
+ // replacing the slashes since the non-Windows specific tests' `expected`
+ // use forward slashes
+ let actualAlt;
+ let os;
+ if (join === path.win32.join) {
+ actualAlt = actual.replace(backslashRE, '/');
+ os = 'win32';
+ } else {
+ os = 'posix';
+ }
+ if (actual !== expected && actualAlt !== expected) {
+ const delimiter = test[0].map(JSON.stringify).join(',');
+ const message = `path.${os}.join(${delimiter})\n expect=${
+ JSON.stringify(expected)}\n actual=${JSON.stringify(actual)}`;
+ failures.push(`\n${message}`);
+ }
+ });
+ });
+});
+assert.strictEqual(failures.length, 0, failures.join(''));
diff --git a/tests/node_compat/test/parallel/test-path-makelong.js b/tests/node_compat/test/parallel/test-path-makelong.js
new file mode 100644
index 000000000..694240109
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-path-makelong.js
@@ -0,0 +1,94 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const fixtures = require('../common/fixtures');
+const assert = require('assert');
+const path = require('path');
+
+if (common.isWindows) {
+ const file = fixtures.path('a.js');
+ const resolvedFile = path.resolve(file);
+
+ assert.strictEqual(path.toNamespacedPath(file),
+ `\\\\?\\${resolvedFile}`);
+ assert.strictEqual(path.toNamespacedPath(`\\\\?\\${file}`),
+ `\\\\?\\${resolvedFile}`);
+ assert.strictEqual(path.toNamespacedPath(
+ '\\\\someserver\\someshare\\somefile'),
+ '\\\\?\\UNC\\someserver\\someshare\\somefile');
+ assert.strictEqual(path.toNamespacedPath(
+ '\\\\?\\UNC\\someserver\\someshare\\somefile'),
+ '\\\\?\\UNC\\someserver\\someshare\\somefile');
+ assert.strictEqual(path.toNamespacedPath('\\\\.\\pipe\\somepipe'),
+ '\\\\.\\pipe\\somepipe');
+}
+
+assert.strictEqual(path.toNamespacedPath(''), '');
+assert.strictEqual(path.toNamespacedPath(null), null);
+assert.strictEqual(path.toNamespacedPath(100), 100);
+assert.strictEqual(path.toNamespacedPath(path), path);
+assert.strictEqual(path.toNamespacedPath(false), false);
+assert.strictEqual(path.toNamespacedPath(true), true);
+
+const emptyObj = {};
+assert.strictEqual(path.posix.toNamespacedPath('/foo/bar'), '/foo/bar');
+assert.strictEqual(path.posix.toNamespacedPath('foo/bar'), 'foo/bar');
+assert.strictEqual(path.posix.toNamespacedPath(null), null);
+assert.strictEqual(path.posix.toNamespacedPath(true), true);
+assert.strictEqual(path.posix.toNamespacedPath(1), 1);
+assert.strictEqual(path.posix.toNamespacedPath(), undefined);
+assert.strictEqual(path.posix.toNamespacedPath(emptyObj), emptyObj);
+if (common.isWindows) {
+ // These tests cause resolve() to insert the cwd, so we cannot test them from
+ // non-Windows platforms (easily)
+ assert.strictEqual(path.toNamespacedPath(''), '');
+ assert.strictEqual(path.win32.toNamespacedPath('foo\\bar').toLowerCase(),
+ `\\\\?\\${process.cwd().toLowerCase()}\\foo\\bar`);
+ assert.strictEqual(path.win32.toNamespacedPath('foo/bar').toLowerCase(),
+ `\\\\?\\${process.cwd().toLowerCase()}\\foo\\bar`);
+ const currentDeviceLetter = path.parse(process.cwd()).root.substring(0, 2);
+ assert.strictEqual(
+ path.win32.toNamespacedPath(currentDeviceLetter).toLowerCase(),
+ `\\\\?\\${process.cwd().toLowerCase()}`);
+ assert.strictEqual(path.win32.toNamespacedPath('C').toLowerCase(),
+ `\\\\?\\${process.cwd().toLowerCase()}\\c`);
+}
+assert.strictEqual(path.win32.toNamespacedPath('C:\\foo'), '\\\\?\\C:\\foo');
+assert.strictEqual(path.win32.toNamespacedPath('C:/foo'), '\\\\?\\C:\\foo');
+assert.strictEqual(path.win32.toNamespacedPath('\\\\foo\\bar'),
+ '\\\\?\\UNC\\foo\\bar\\');
+assert.strictEqual(path.win32.toNamespacedPath('//foo//bar'),
+ '\\\\?\\UNC\\foo\\bar\\');
+assert.strictEqual(path.win32.toNamespacedPath('\\\\?\\foo'), '\\\\?\\foo');
+assert.strictEqual(path.win32.toNamespacedPath(null), null);
+assert.strictEqual(path.win32.toNamespacedPath(true), true);
+assert.strictEqual(path.win32.toNamespacedPath(1), 1);
+assert.strictEqual(path.win32.toNamespacedPath(), undefined);
+assert.strictEqual(path.win32.toNamespacedPath(emptyObj), emptyObj);
diff --git a/tests/node_compat/test/parallel/test-path-normalize.js b/tests/node_compat/test/parallel/test-path-normalize.js
new file mode 100644
index 000000000..543be42e6
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-path-normalize.js
@@ -0,0 +1,79 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+const path = require('path');
+
+assert.strictEqual(path.win32.normalize('./fixtures///b/../b/c.js'),
+ 'fixtures\\b\\c.js');
+assert.strictEqual(path.win32.normalize('/foo/../../../bar'), '\\bar');
+assert.strictEqual(path.win32.normalize('a//b//../b'), 'a\\b');
+assert.strictEqual(path.win32.normalize('a//b//./c'), 'a\\b\\c');
+assert.strictEqual(path.win32.normalize('a//b//.'), 'a\\b');
+assert.strictEqual(path.win32.normalize('//server/share/dir/file.ext'),
+ '\\\\server\\share\\dir\\file.ext');
+assert.strictEqual(path.win32.normalize('/a/b/c/../../../x/y/z'), '\\x\\y\\z');
+assert.strictEqual(path.win32.normalize('C:'), 'C:.');
+assert.strictEqual(path.win32.normalize('C:..\\abc'), 'C:..\\abc');
+assert.strictEqual(path.win32.normalize('C:..\\..\\abc\\..\\def'),
+ 'C:..\\..\\def');
+assert.strictEqual(path.win32.normalize('C:\\.'), 'C:\\');
+assert.strictEqual(path.win32.normalize('file:stream'), 'file:stream');
+assert.strictEqual(path.win32.normalize('bar\\foo..\\..\\'), 'bar\\');
+assert.strictEqual(path.win32.normalize('bar\\foo..\\..'), 'bar');
+assert.strictEqual(path.win32.normalize('bar\\foo..\\..\\baz'), 'bar\\baz');
+assert.strictEqual(path.win32.normalize('bar\\foo..\\'), 'bar\\foo..\\');
+assert.strictEqual(path.win32.normalize('bar\\foo..'), 'bar\\foo..');
+assert.strictEqual(path.win32.normalize('..\\foo..\\..\\..\\bar'),
+ '..\\..\\bar');
+assert.strictEqual(path.win32.normalize('..\\...\\..\\.\\...\\..\\..\\bar'),
+ '..\\..\\bar');
+assert.strictEqual(path.win32.normalize('../../../foo/../../../bar'),
+ '..\\..\\..\\..\\..\\bar');
+assert.strictEqual(path.win32.normalize('../../../foo/../../../bar/../../'),
+ '..\\..\\..\\..\\..\\..\\');
+assert.strictEqual(
+ path.win32.normalize('../foobar/barfoo/foo/../../../bar/../../'),
+ '..\\..\\'
+);
+assert.strictEqual(
+ path.win32.normalize('../.../../foobar/../../../bar/../../baz'),
+ '..\\..\\..\\..\\baz'
+);
+assert.strictEqual(path.win32.normalize('foo/bar\\baz'), 'foo\\bar\\baz');
+
+assert.strictEqual(path.posix.normalize('./fixtures///b/../b/c.js'),
+ 'fixtures/b/c.js');
+assert.strictEqual(path.posix.normalize('/foo/../../../bar'), '/bar');
+assert.strictEqual(path.posix.normalize('a//b//../b'), 'a/b');
+assert.strictEqual(path.posix.normalize('a//b//./c'), 'a/b/c');
+assert.strictEqual(path.posix.normalize('a//b//.'), 'a/b');
+assert.strictEqual(path.posix.normalize('/a/b/c/../../../x/y/z'), '/x/y/z');
+assert.strictEqual(path.posix.normalize('///..//./foo/.//bar'), '/foo/bar');
+assert.strictEqual(path.posix.normalize('bar/foo../../'), 'bar/');
+assert.strictEqual(path.posix.normalize('bar/foo../..'), 'bar');
+assert.strictEqual(path.posix.normalize('bar/foo../../baz'), 'bar/baz');
+assert.strictEqual(path.posix.normalize('bar/foo../'), 'bar/foo../');
+assert.strictEqual(path.posix.normalize('bar/foo..'), 'bar/foo..');
+assert.strictEqual(path.posix.normalize('../foo../../../bar'), '../../bar');
+assert.strictEqual(path.posix.normalize('../.../.././.../../../bar'),
+ '../../bar');
+assert.strictEqual(path.posix.normalize('../../../foo/../../../bar'),
+ '../../../../../bar');
+assert.strictEqual(path.posix.normalize('../../../foo/../../../bar/../../'),
+ '../../../../../../');
+assert.strictEqual(
+ path.posix.normalize('../foobar/barfoo/foo/../../../bar/../../'),
+ '../../'
+);
+assert.strictEqual(
+ path.posix.normalize('../.../../foobar/../../../bar/../../baz'),
+ '../../../../baz'
+);
+assert.strictEqual(path.posix.normalize('foo/bar\\baz'), 'foo/bar\\baz');
diff --git a/tests/node_compat/test/parallel/test-path-parse-format.js b/tests/node_compat/test/parallel/test-path-parse-format.js
new file mode 100644
index 000000000..657503d3c
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-path-parse-format.js
@@ -0,0 +1,233 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const path = require('path');
+
+const winPaths = [
+ // [path, root]
+ ['C:\\path\\dir\\index.html', 'C:\\'],
+ ['C:\\another_path\\DIR\\1\\2\\33\\\\index', 'C:\\'],
+ ['another_path\\DIR with spaces\\1\\2\\33\\index', ''],
+ ['\\', '\\'],
+ ['\\foo\\C:', '\\'],
+ ['file', ''],
+ ['file:stream', ''],
+ ['.\\file', ''],
+ ['C:', 'C:'],
+ ['C:.', 'C:'],
+ ['C:..', 'C:'],
+ ['C:abc', 'C:'],
+ ['C:\\', 'C:\\'],
+ ['C:\\abc', 'C:\\' ],
+ ['', ''],
+
+ // unc
+ ['\\\\server\\share\\file_path', '\\\\server\\share\\'],
+ ['\\\\server two\\shared folder\\file path.zip',
+ '\\\\server two\\shared folder\\'],
+ ['\\\\teela\\admin$\\system32', '\\\\teela\\admin$\\'],
+ ['\\\\?\\UNC\\server\\share', '\\\\?\\UNC\\'],
+];
+
+const winSpecialCaseParseTests = [
+ ['t', { base: 't', name: 't', root: '', dir: '', ext: '' }],
+ ['/foo/bar', { root: '/', dir: '/foo', base: 'bar', ext: '', name: 'bar' }],
+];
+
+const winSpecialCaseFormatTests = [
+ [{ dir: 'some\\dir' }, 'some\\dir\\'],
+ [{ base: 'index.html' }, 'index.html'],
+ [{ root: 'C:\\' }, 'C:\\'],
+ [{ name: 'index', ext: '.html' }, 'index.html'],
+ [{ dir: 'some\\dir', name: 'index', ext: '.html' }, 'some\\dir\\index.html'],
+ [{ root: 'C:\\', name: 'index', ext: '.html' }, 'C:\\index.html'],
+ [{}, ''],
+];
+
+const unixPaths = [
+ // [path, root]
+ ['/home/user/dir/file.txt', '/'],
+ ['/home/user/a dir/another File.zip', '/'],
+ ['/home/user/a dir//another&File.', '/'],
+ ['/home/user/a$$$dir//another File.zip', '/'],
+ ['user/dir/another File.zip', ''],
+ ['file', ''],
+ ['.\\file', ''],
+ ['./file', ''],
+ ['C:\\foo', ''],
+ ['/', '/'],
+ ['', ''],
+ ['.', ''],
+ ['..', ''],
+ ['/foo', '/'],
+ ['/foo.', '/'],
+ ['/foo.bar', '/'],
+ ['/.', '/'],
+ ['/.foo', '/'],
+ ['/.foo.bar', '/'],
+ ['/foo/bar.baz', '/'],
+];
+
+const unixSpecialCaseFormatTests = [
+ [{ dir: 'some/dir' }, 'some/dir/'],
+ [{ base: 'index.html' }, 'index.html'],
+ [{ root: '/' }, '/'],
+ [{ name: 'index', ext: '.html' }, 'index.html'],
+ [{ dir: 'some/dir', name: 'index', ext: '.html' }, 'some/dir/index.html'],
+ [{ root: '/', name: 'index', ext: '.html' }, '/index.html'],
+ [{}, ''],
+];
+
+const errors = [
+ { method: 'parse', input: [null] },
+ { method: 'parse', input: [{}] },
+ { method: 'parse', input: [true] },
+ { method: 'parse', input: [1] },
+ { method: 'parse', input: [] },
+ { method: 'format', input: [null] },
+ { method: 'format', input: [''] },
+ { method: 'format', input: [true] },
+ { method: 'format', input: [1] },
+];
+
+checkParseFormat(path.win32, winPaths);
+checkParseFormat(path.posix, unixPaths);
+checkSpecialCaseParseFormat(path.win32, winSpecialCaseParseTests);
+checkErrors(path.win32);
+checkErrors(path.posix);
+checkFormat(path.win32, winSpecialCaseFormatTests);
+checkFormat(path.posix, unixSpecialCaseFormatTests);
+
+// Test removal of trailing path separators
+const trailingTests = [
+ [ path.win32.parse,
+ [['.\\', { root: '', dir: '', base: '.', ext: '', name: '.' }],
+ ['\\\\', { root: '\\', dir: '\\', base: '', ext: '', name: '' }],
+ ['\\\\', { root: '\\', dir: '\\', base: '', ext: '', name: '' }],
+ ['c:\\foo\\\\\\',
+ { root: 'c:\\', dir: 'c:\\', base: 'foo', ext: '', name: 'foo' }],
+ ['D:\\foo\\\\\\bar.baz',
+ { root: 'D:\\',
+ dir: 'D:\\foo\\\\',
+ base: 'bar.baz',
+ ext: '.baz',
+ name: 'bar' },
+ ],
+ ],
+ ],
+ [ path.posix.parse,
+ [['./', { root: '', dir: '', base: '.', ext: '', name: '.' }],
+ ['//', { root: '/', dir: '/', base: '', ext: '', name: '' }],
+ ['///', { root: '/', dir: '/', base: '', ext: '', name: '' }],
+ ['/foo///', { root: '/', dir: '/', base: 'foo', ext: '', name: 'foo' }],
+ ['/foo///bar.baz',
+ { root: '/', dir: '/foo//', base: 'bar.baz', ext: '.baz', name: 'bar' },
+ ],
+ ],
+ ],
+];
+const failures = [];
+trailingTests.forEach((test) => {
+ const parse = test[0];
+ const os = parse === path.win32.parse ? 'win32' : 'posix';
+ test[1].forEach((test) => {
+ const actual = parse(test[0]);
+ const expected = test[1];
+ const message = `path.${os}.parse(${JSON.stringify(test[0])})\n expect=${
+ JSON.stringify(expected)}\n actual=${JSON.stringify(actual)}`;
+ const actualKeys = Object.keys(actual);
+ const expectedKeys = Object.keys(expected);
+ let failed = (actualKeys.length !== expectedKeys.length);
+ if (!failed) {
+ for (let i = 0; i < actualKeys.length; ++i) {
+ const key = actualKeys[i];
+ if (!expectedKeys.includes(key) || actual[key] !== expected[key]) {
+ failed = true;
+ break;
+ }
+ }
+ }
+ if (failed)
+ failures.push(`\n${message}`);
+ });
+});
+assert.strictEqual(failures.length, 0, failures.join(''));
+
+function checkErrors(path) {
+ errors.forEach(({ method, input }) => {
+ assert.throws(() => {
+ path[method].apply(path, input);
+ }, {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError'
+ });
+ });
+}
+
+function checkParseFormat(path, paths) {
+ paths.forEach(([element, root]) => {
+ const output = path.parse(element);
+ assert.strictEqual(typeof output.root, 'string');
+ assert.strictEqual(typeof output.dir, 'string');
+ assert.strictEqual(typeof output.base, 'string');
+ assert.strictEqual(typeof output.ext, 'string');
+ assert.strictEqual(typeof output.name, 'string');
+ assert.strictEqual(path.format(output), element);
+ assert.strictEqual(output.root, root);
+ assert(output.dir.startsWith(output.root));
+ assert.strictEqual(output.dir, output.dir ? path.dirname(element) : '');
+ assert.strictEqual(output.base, path.basename(element));
+ assert.strictEqual(output.ext, path.extname(element));
+ });
+}
+
+function checkSpecialCaseParseFormat(path, testCases) {
+ testCases.forEach(([element, expect]) => {
+ assert.deepStrictEqual(path.parse(element), expect);
+ });
+}
+
+function checkFormat(path, testCases) {
+ testCases.forEach(([element, expect]) => {
+ assert.strictEqual(path.format(element), expect);
+ });
+
+ [null, undefined, 1, true, false, 'string'].forEach((pathObject) => {
+ assert.throws(() => {
+ path.format(pathObject);
+ }, {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: 'The "pathObject" argument must be of type object.' +
+ common.invalidArgTypeHelper(pathObject)
+ });
+ });
+}
diff --git a/tests/node_compat/test/parallel/test-path-posix-exists.js b/tests/node_compat/test/parallel/test-path-posix-exists.js
new file mode 100644
index 000000000..97f2c4ae6
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-path-posix-exists.js
@@ -0,0 +1,13 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+require('../common');
+const assert = require('assert');
+
+assert.strictEqual(require('path/posix'), require('path').posix);
diff --git a/tests/node_compat/test/parallel/test-path-relative.js b/tests/node_compat/test/parallel/test-path-relative.js
new file mode 100644
index 000000000..7b89cc2cd
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-path-relative.js
@@ -0,0 +1,76 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+const path = require('path');
+
+const failures = [];
+
+const relativeTests = [
+ [ path.win32.relative,
+ // Arguments result
+ [['c:/blah\\blah', 'd:/games', 'd:\\games'],
+ ['c:/aaaa/bbbb', 'c:/aaaa', '..'],
+ ['c:/aaaa/bbbb', 'c:/cccc', '..\\..\\cccc'],
+ ['c:/aaaa/bbbb', 'c:/aaaa/bbbb', ''],
+ ['c:/aaaa/bbbb', 'c:/aaaa/cccc', '..\\cccc'],
+ ['c:/aaaa/', 'c:/aaaa/cccc', 'cccc'],
+ ['c:/', 'c:\\aaaa\\bbbb', 'aaaa\\bbbb'],
+ ['c:/aaaa/bbbb', 'd:\\', 'd:\\'],
+ ['c:/AaAa/bbbb', 'c:/aaaa/bbbb', ''],
+ ['c:/aaaaa/', 'c:/aaaa/cccc', '..\\aaaa\\cccc'],
+ ['C:\\foo\\bar\\baz\\quux', 'C:\\', '..\\..\\..\\..'],
+ ['C:\\foo\\test', 'C:\\foo\\test\\bar\\package.json', 'bar\\package.json'],
+ ['C:\\foo\\bar\\baz-quux', 'C:\\foo\\bar\\baz', '..\\baz'],
+ ['C:\\foo\\bar\\baz', 'C:\\foo\\bar\\baz-quux', '..\\baz-quux'],
+ ['\\\\foo\\bar', '\\\\foo\\bar\\baz', 'baz'],
+ ['\\\\foo\\bar\\baz', '\\\\foo\\bar', '..'],
+ ['\\\\foo\\bar\\baz-quux', '\\\\foo\\bar\\baz', '..\\baz'],
+ ['\\\\foo\\bar\\baz', '\\\\foo\\bar\\baz-quux', '..\\baz-quux'],
+ ['C:\\baz-quux', 'C:\\baz', '..\\baz'],
+ ['C:\\baz', 'C:\\baz-quux', '..\\baz-quux'],
+ ['\\\\foo\\baz-quux', '\\\\foo\\baz', '..\\baz'],
+ ['\\\\foo\\baz', '\\\\foo\\baz-quux', '..\\baz-quux'],
+ ['C:\\baz', '\\\\foo\\bar\\baz', '\\\\foo\\bar\\baz'],
+ ['\\\\foo\\bar\\baz', 'C:\\baz', 'C:\\baz'],
+ ],
+ ],
+ [ path.posix.relative,
+ // Arguments result
+ [['/var/lib', '/var', '..'],
+ ['/var/lib', '/bin', '../../bin'],
+ ['/var/lib', '/var/lib', ''],
+ ['/var/lib', '/var/apache', '../apache'],
+ ['/var/', '/var/lib', 'lib'],
+ ['/', '/var/lib', 'var/lib'],
+ ['/foo/test', '/foo/test/bar/package.json', 'bar/package.json'],
+ ['/Users/a/web/b/test/mails', '/Users/a/web/b', '../..'],
+ ['/foo/bar/baz-quux', '/foo/bar/baz', '../baz'],
+ ['/foo/bar/baz', '/foo/bar/baz-quux', '../baz-quux'],
+ ['/baz-quux', '/baz', '../baz'],
+ ['/baz', '/baz-quux', '../baz-quux'],
+ ['/page1/page2/foo', '/', '../../..'],
+ ],
+ ],
+];
+relativeTests.forEach((test) => {
+ const relative = test[0];
+ test[1].forEach((test) => {
+ const actual = relative(test[0], test[1]);
+ const expected = test[2];
+ if (actual !== expected) {
+ const os = relative === path.win32.relative ? 'win32' : 'posix';
+ const message = `path.${os}.relative(${
+ test.slice(0, 2).map(JSON.stringify).join(',')})\n expect=${
+ JSON.stringify(expected)}\n actual=${JSON.stringify(actual)}`;
+ failures.push(`\n${message}`);
+ }
+ });
+});
+assert.strictEqual(failures.length, 0, failures.join(''));
diff --git a/tests/node_compat/test/parallel/test-path-resolve.js b/tests/node_compat/test/parallel/test-path-resolve.js
new file mode 100644
index 000000000..be010ed83
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-path-resolve.js
@@ -0,0 +1,96 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 16.13.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+'use strict';
+const common = require('../common');
+const fixtures = require('../common/fixtures');
+const assert = require('assert');
+const child = require('child_process');
+const path = require('path');
+
+const failures = [];
+const slashRE = /\//g;
+const backslashRE = /\\/g;
+
+const posixyCwd = common.isWindows ?
+ (() => {
+ const _ = process.cwd()
+ .replaceAll(path.sep, path.posix.sep);
+ return _.slice(_.indexOf(path.posix.sep));
+ })() :
+ process.cwd();
+
+const resolveTests = [
+ [ path.win32.resolve,
+ // Arguments result
+ [[['c:/blah\\blah', 'd:/games', 'c:../a'], 'c:\\blah\\a'],
+ [['c:/ignore', 'd:\\a/b\\c/d', '\\e.exe'], 'd:\\e.exe'],
+ [['c:/ignore', 'c:/some/file'], 'c:\\some\\file'],
+ [['d:/ignore', 'd:some/dir//'], 'd:\\ignore\\some\\dir'],
+ [['.'], process.cwd()],
+ [['//server/share', '..', 'relative\\'], '\\\\server\\share\\relative'],
+ [['c:/', '//'], 'c:\\'],
+ [['c:/', '//dir'], 'c:\\dir'],
+ [['c:/', '//server/share'], '\\\\server\\share\\'],
+ [['c:/', '//server//share'], '\\\\server\\share\\'],
+ [['c:/', '///some//dir'], 'c:\\some\\dir'],
+ [['C:\\foo\\tmp.3\\', '..\\tmp.3\\cycles\\root.js'],
+ 'C:\\foo\\tmp.3\\cycles\\root.js'],
+ ],
+ ],
+ [ path.posix.resolve,
+ // Arguments result
+ [[['/var/lib', '../', 'file/'], '/var/file'],
+ [['/var/lib', '/../', 'file/'], '/file'],
+ // TODO(wafuwafu13): Enable this
+ // [['a/b/c/', '../../..'], posixyCwd],
+ // [['.'], posixyCwd],
+ [['/some/dir', '.', '/absolute/'], '/absolute'],
+ [['/foo/tmp.3/', '../tmp.3/cycles/root.js'], '/foo/tmp.3/cycles/root.js'],
+ ],
+ ],
+];
+resolveTests.forEach(([resolve, tests]) => {
+ tests.forEach(([test, expected]) => {
+ const actual = resolve.apply(null, test);
+ let actualAlt;
+ const os = resolve === path.win32.resolve ? 'win32' : 'posix';
+ if (resolve === path.win32.resolve && !common.isWindows)
+ actualAlt = actual.replace(backslashRE, '/');
+ else if (resolve !== path.win32.resolve && common.isWindows)
+ actualAlt = actual.replace(slashRE, '\\');
+
+ const message =
+ `path.${os}.resolve(${test.map(JSON.stringify).join(',')})\n expect=${
+ JSON.stringify(expected)}\n actual=${JSON.stringify(actual)}`;
+ if (actual !== expected && actualAlt !== expected)
+ failures.push(message);
+ });
+});
+assert.strictEqual(failures.length, 0, failures.join('\n'));
+
+if (common.isWindows) {
+ // Test resolving the current Windows drive letter from a spawned process.
+ // See https://github.com/nodejs/node/issues/7215
+ const currentDriveLetter = path.parse(process.cwd()).root.substring(0, 2);
+ const resolveFixture = fixtures.path('path-resolve.js');
+ // TODO(wafuwafu13): Enable this
+ // const spawnResult = child.spawnSync(
+ // process.argv[0], [resolveFixture, currentDriveLetter]);
+ // const resolvedPath = spawnResult.stdout.toString().trim();
+ // assert.strictEqual(resolvedPath.toLowerCase(), process.cwd().toLowerCase());
+}
+
+if (!common.isWindows) {
+ // Test handling relative paths to be safe when process.cwd() fails.
+ process.cwd = () => '';
+ assert.strictEqual(process.cwd(), '');
+ const resolved = path.resolve();
+ const expected = '.';
+ // TODO(wafuwafu13): Enable this
+ // assert.strictEqual(resolved, expected);
+}
diff --git a/tests/node_compat/test/parallel/test-path-win32-exists.js b/tests/node_compat/test/parallel/test-path-win32-exists.js
new file mode 100644
index 000000000..8bb1850dc
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-path-win32-exists.js
@@ -0,0 +1,13 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+require('../common');
+const assert = require('assert');
+
+assert.strictEqual(require('path/win32'), require('path').win32);
diff --git a/tests/node_compat/test/parallel/test-path-zero-length-strings.js b/tests/node_compat/test/parallel/test-path-zero-length-strings.js
new file mode 100644
index 000000000..5fa1eafbf
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-path-zero-length-strings.js
@@ -0,0 +1,46 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+// These testcases are specific to one uncommon behavior in path module. Few
+// of the functions in path module, treat '' strings as current working
+// directory. This test makes sure that the behavior is intact between commits.
+// See: https://github.com/nodejs/node/pull/2106
+
+require('../common');
+const assert = require('assert');
+const path = require('path');
+const pwd = process.cwd();
+
+// Join will internally ignore all the zero-length strings and it will return
+// '.' if the joined string is a zero-length string.
+assert.strictEqual(path.posix.join(''), '.');
+assert.strictEqual(path.posix.join('', ''), '.');
+assert.strictEqual(path.win32.join(''), '.');
+assert.strictEqual(path.win32.join('', ''), '.');
+assert.strictEqual(path.join(pwd), pwd);
+assert.strictEqual(path.join(pwd, ''), pwd);
+
+// Normalize will return '.' if the input is a zero-length string
+assert.strictEqual(path.posix.normalize(''), '.');
+assert.strictEqual(path.win32.normalize(''), '.');
+assert.strictEqual(path.normalize(pwd), pwd);
+
+// Since '' is not a valid path in any of the common environments, return false
+assert.strictEqual(path.posix.isAbsolute(''), false);
+assert.strictEqual(path.win32.isAbsolute(''), false);
+
+// Resolve, internally ignores all the zero-length strings and returns the
+// current working directory
+assert.strictEqual(path.resolve(''), pwd);
+assert.strictEqual(path.resolve('', ''), pwd);
+
+// Relative, internally calls resolve. So, '' is actually the current directory
+assert.strictEqual(path.relative('', pwd), '');
+assert.strictEqual(path.relative(pwd, ''), '');
+assert.strictEqual(path.relative(pwd, pwd), '');
diff --git a/tests/node_compat/test/parallel/test-path.js b/tests/node_compat/test/parallel/test-path.js
new file mode 100644
index 000000000..b68f0c2d4
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-path.js
@@ -0,0 +1,80 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const path = require('path');
+
+// Test thrown TypeErrors
+const typeErrorTests = [true, false, 7, null, {}, undefined, [], NaN];
+
+function fail(fn) {
+ const args = Array.from(arguments).slice(1);
+
+ assert.throws(() => {
+ fn.apply(null, args);
+ }, { code: 'ERR_INVALID_ARG_TYPE', name: 'TypeError' });
+}
+
+typeErrorTests.forEach((test) => {
+ [path.posix, path.win32].forEach((namespace) => {
+ fail(namespace.join, test);
+ fail(namespace.resolve, test);
+ fail(namespace.normalize, test);
+ fail(namespace.isAbsolute, test);
+ fail(namespace.relative, test, 'foo');
+ fail(namespace.relative, 'foo', test);
+ fail(namespace.parse, test);
+ fail(namespace.dirname, test);
+ fail(namespace.basename, test);
+ fail(namespace.extname, test);
+
+ // Undefined is a valid value as the second argument to basename
+ if (test !== undefined) {
+ fail(namespace.basename, 'foo', test);
+ }
+ });
+});
+
+// path.sep tests
+// windows
+assert.strictEqual(path.win32.sep, '\\');
+// posix
+assert.strictEqual(path.posix.sep, '/');
+
+// path.delimiter tests
+// windows
+assert.strictEqual(path.win32.delimiter, ';');
+// posix
+assert.strictEqual(path.posix.delimiter, ':');
+
+if (common.isWindows)
+ assert.strictEqual(path, path.win32);
+else
+ assert.strictEqual(path, path.posix);
diff --git a/tests/node_compat/test/parallel/test-process-beforeexit.js b/tests/node_compat/test/parallel/test-process-beforeexit.js
new file mode 100644
index 000000000..7ac789c69
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-process-beforeexit.js
@@ -0,0 +1,88 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const net = require('net');
+
+process.once('beforeExit', common.mustCall(tryImmediate));
+
+function tryImmediate() {
+ setImmediate(common.mustCall(() => {
+ process.once('beforeExit', common.mustCall(tryTimer));
+ }));
+}
+
+function tryTimer() {
+ setTimeout(common.mustCall(() => {
+ process.once('beforeExit', common.mustCall(tryListen));
+ }), 1);
+}
+
+function tryListen() {
+ net.createServer()
+ .listen(0)
+ .on('listening', common.mustCall(function() {
+ this.close();
+ process.once('beforeExit', common.mustCall(tryRepeatedTimer));
+ }));
+}
+
+// Test that a function invoked from the beforeExit handler can use a timer
+// to keep the event loop open, which can use another timer to keep the event
+// loop open, etc.
+//
+// After N times, call function `tryNextTick` to test behaviors of the
+// `process.nextTick`.
+function tryRepeatedTimer() {
+ const N = 5;
+ let n = 0;
+ const repeatedTimer = common.mustCall(function() {
+ if (++n < N)
+ setTimeout(repeatedTimer, 1);
+ else // n == N
+ process.once('beforeExit', common.mustCall(tryNextTickSetImmediate));
+ }, N);
+ setTimeout(repeatedTimer, 1);
+}
+
+// Test if the callback of `process.nextTick` can be invoked.
+function tryNextTickSetImmediate() {
+ process.nextTick(common.mustCall(function() {
+ setImmediate(common.mustCall(() => {
+ process.once('beforeExit', common.mustCall(tryNextTick));
+ }));
+ }));
+}
+
+// Test that `process.nextTick` won't keep the event loop running by itself.
+function tryNextTick() {
+ process.nextTick(common.mustCall(function() {
+ process.once('beforeExit', common.mustNotCall());
+ }));
+}
diff --git a/tests/node_compat/test/parallel/test-process-binding-internalbinding-allowlist.js b/tests/node_compat/test/parallel/test-process-binding-internalbinding-allowlist.js
new file mode 100644
index 000000000..28a9a31e9
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-process-binding-internalbinding-allowlist.js
@@ -0,0 +1,48 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Flags: --no-warnings
+'use strict';
+
+const common = require('../common');
+const assert = require('assert');
+
+// Assert that allowed internalBinding modules are accessible via
+// process.binding().
+assert(process.binding('async_wrap'));
+assert(process.binding('buffer'));
+assert(process.binding('cares_wrap'));
+assert(process.binding('constants'));
+assert(process.binding('contextify'));
+if (common.hasCrypto) { // eslint-disable-line node-core/crypto-check
+ assert(process.binding('crypto'));
+}
+assert(process.binding('fs'));
+assert(process.binding('fs_event_wrap'));
+assert(process.binding('http_parser'));
+if (common.hasIntl) {
+ assert(process.binding('icu'));
+}
+assert(process.binding('inspector'));
+assert(process.binding('js_stream'));
+assert(process.binding('natives'));
+assert(process.binding('os'));
+assert(process.binding('pipe_wrap'));
+assert(process.binding('signal_wrap'));
+assert(process.binding('spawn_sync'));
+assert(process.binding('stream_wrap'));
+assert(process.binding('tcp_wrap'));
+if (common.hasCrypto) { // eslint-disable-line node-core/crypto-check
+ assert(process.binding('tls_wrap'));
+}
+assert(process.binding('tty_wrap'));
+assert(process.binding('udp_wrap'));
+assert(process.binding('url'));
+assert(process.binding('util'));
+assert(process.binding('uv'));
+assert(process.binding('v8'));
+assert(process.binding('zlib'));
diff --git a/tests/node_compat/test/parallel/test-process-env-allowed-flags.js b/tests/node_compat/test/parallel/test-process-env-allowed-flags.js
new file mode 100644
index 000000000..1b2c96e68
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-process-env-allowed-flags.js
@@ -0,0 +1,109 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const assert = require('assert');
+
+// Assert legit flags are allowed, and bogus flags are disallowed
+{
+ const goodFlags = [
+ '--perf_basic_prof',
+ '--perf-basic-prof',
+ 'perf-basic-prof',
+ '--perf_basic-prof',
+ 'perf_basic-prof',
+ 'perf_basic_prof',
+ '-r',
+ 'r',
+ '--stack-trace-limit=100',
+ '--stack-trace-limit=-=xX_nodejs_Xx=-',
+ ].concat(process.features.inspector ? [
+ '--inspect-brk',
+ 'inspect-brk',
+ '--inspect_brk',
+ ] : []);
+
+ const badFlags = [
+ 'INSPECT-BRK',
+ '--INSPECT-BRK',
+ '--r',
+ '-R',
+ '---inspect-brk',
+ '--cheeseburgers',
+ ];
+
+ goodFlags.forEach((flag) => {
+ assert.strictEqual(
+ process.allowedNodeEnvironmentFlags.has(flag),
+ true,
+ `flag should be in set: ${flag}`
+ );
+ });
+
+ badFlags.forEach((flag) => {
+ assert.strictEqual(
+ process.allowedNodeEnvironmentFlags.has(flag),
+ false,
+ `flag should not be in set: ${flag}`
+ );
+ });
+}
+
+// Assert all "canonical" flags begin with dash(es)
+{
+ process.allowedNodeEnvironmentFlags.forEach((flag) => {
+ assert.match(flag, /^--?[a-zA-Z0-9._-]+$/);
+ });
+}
+
+// Assert immutability of process.allowedNodeEnvironmentFlags
+{
+ assert.strictEqual(Object.isFrozen(process.allowedNodeEnvironmentFlags),
+ true);
+
+ process.allowedNodeEnvironmentFlags.add('foo');
+ assert.strictEqual(process.allowedNodeEnvironmentFlags.has('foo'), false);
+ Set.prototype.add.call(process.allowedNodeEnvironmentFlags, 'foo');
+ assert.strictEqual(process.allowedNodeEnvironmentFlags.has('foo'), false);
+
+ const thisArg = {};
+ process.allowedNodeEnvironmentFlags.forEach(
+ common.mustCallAtLeast(function(flag, _, set) {
+ assert.notStrictEqual(flag, 'foo');
+ assert.strictEqual(this, thisArg);
+ assert.strictEqual(set, process.allowedNodeEnvironmentFlags);
+ }),
+ thisArg
+ );
+
+ for (const flag of process.allowedNodeEnvironmentFlags.keys()) {
+ assert.notStrictEqual(flag, 'foo');
+ }
+ for (const flag of process.allowedNodeEnvironmentFlags.values()) {
+ assert.notStrictEqual(flag, 'foo');
+ }
+ for (const flag of process.allowedNodeEnvironmentFlags) {
+ assert.notStrictEqual(flag, 'foo');
+ }
+ for (const [flag] of process.allowedNodeEnvironmentFlags.entries()) {
+ assert.notStrictEqual(flag, 'foo');
+ }
+
+ const size = process.allowedNodeEnvironmentFlags.size;
+
+ process.allowedNodeEnvironmentFlags.clear();
+ assert.strictEqual(process.allowedNodeEnvironmentFlags.size, size);
+ Set.prototype.clear.call(process.allowedNodeEnvironmentFlags);
+ assert.strictEqual(process.allowedNodeEnvironmentFlags.size, size);
+
+ process.allowedNodeEnvironmentFlags.delete('-r');
+ assert.strictEqual(process.allowedNodeEnvironmentFlags.size, size);
+ Set.prototype.delete.call(process.allowedNodeEnvironmentFlags, '-r');
+ assert.strictEqual(process.allowedNodeEnvironmentFlags.size, size);
+}
diff --git a/tests/node_compat/test/parallel/test-process-exit-from-before-exit.js b/tests/node_compat/test/parallel/test-process-exit-from-before-exit.js
new file mode 100644
index 000000000..a1472e538
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-process-exit-from-before-exit.js
@@ -0,0 +1,37 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+
+process.on('beforeExit', common.mustCall(function() {
+ setTimeout(common.mustNotCall(), 5);
+ process.exit(0); // Should execute immediately even if we schedule new work.
+ assert.fail();
+}));
diff --git a/tests/node_compat/test/parallel/test-process-exit-handler.js b/tests/node_compat/test/parallel/test-process-exit-handler.js
new file mode 100644
index 000000000..7069c73e9
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-process-exit-handler.js
@@ -0,0 +1,21 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+
+if (!common.isMainThread)
+ common.skip('execArgv does not affect Workers');
+
+// This test ensures that no asynchronous operations are performed in the 'exit'
+// handler.
+// https://github.com/nodejs/node/issues/12322
+
+process.on('exit', () => {
+ setTimeout(() => process.abort(), 0); // Should not run.
+ for (const start = Date.now(); Date.now() - start < 10;);
+});
diff --git a/tests/node_compat/test/parallel/test-process-exit-recursive.js b/tests/node_compat/test/parallel/test-process-exit-recursive.js
new file mode 100644
index 000000000..054b23271
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-process-exit-recursive.js
@@ -0,0 +1,44 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+
+// Recursively calling .exit() should not overflow the call stack
+let nexits = 0;
+
+process.on('exit', function(code) {
+ assert.strictEqual(nexits++, 0);
+ assert.strictEqual(code, 1);
+
+ // Now override the exit code of 1 with 0 so that the test passes
+ process.exit(0);
+});
+
+process.exit(1);
diff --git a/tests/node_compat/test/parallel/test-process-exit.js b/tests/node_compat/test/parallel/test-process-exit.js
new file mode 100644
index 000000000..50a3bd3b1
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-process-exit.js
@@ -0,0 +1,42 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+
+// Calling .exit() from within "exit" should not overflow the call stack
+let nexits = 0;
+
+process.on('exit', function(code) {
+ assert.strictEqual(nexits++, 0);
+ assert.strictEqual(code, 0);
+ process.exit();
+});
+
+// "exit" should be emitted unprovoked
diff --git a/tests/node_compat/test/parallel/test-process-kill-pid.js b/tests/node_compat/test/parallel/test-process-kill-pid.js
new file mode 100644
index 000000000..f6e612f2b
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-process-kill-pid.js
@@ -0,0 +1,116 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+
+// Test variants of pid
+//
+// null: TypeError
+// undefined: TypeError
+//
+// 'SIGTERM': TypeError
+//
+// String(process.pid): TypeError
+//
+// Nan, Infinity, -Infinity: TypeError
+//
+// 0, String(0): our group process
+//
+// process.pid, String(process.pid): ourself
+
+['SIGTERM', null, undefined, NaN, Infinity, -Infinity].forEach((val) => {
+ assert.throws(() => process.kill(val), {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: 'The "pid" argument must be of type number.' +
+ common.invalidArgTypeHelper(val)
+ });
+});
+
+// Test that kill throws an error for unknown signal names
+assert.throws(() => process.kill(0, 'test'), {
+ code: 'ERR_UNKNOWN_SIGNAL',
+ name: 'TypeError',
+ message: 'Unknown signal: test'
+});
+
+// Test that kill throws an error for invalid signal numbers
+assert.throws(() => process.kill(0, 987), {
+ code: 'EINVAL',
+ name: 'Error',
+ message: 'kill EINVAL'
+});
+
+// Test kill argument processing in valid cases.
+//
+// Monkey patch _kill so that we don't actually send any signals, particularly
+// that we don't kill our process group, or try to actually send ANY signals on
+// windows, which doesn't support them.
+function kill(tryPid, trySig, expectPid, expectSig) {
+ let getPid;
+ let getSig;
+ const origKill = process._kill;
+ process._kill = function(pid, sig) {
+ getPid = pid;
+ getSig = sig;
+
+ // un-monkey patch process._kill
+ process._kill = origKill;
+ };
+
+ process.kill(tryPid, trySig);
+
+ assert.strictEqual(getPid.toString(), expectPid.toString());
+ assert.strictEqual(getSig, expectSig);
+}
+
+// Note that SIGHUP and SIGTERM map to 1 and 15 respectively, even on Windows
+// (for Windows, libuv maps 1 and 15 to the correct behavior).
+
+kill(0, 'SIGHUP', 0, 1);
+kill(0, undefined, 0, 15);
+kill('0', 'SIGHUP', 0, 1);
+kill('0', undefined, 0, 15);
+
+// Confirm that numeric signal arguments are supported
+
+kill(0, 1, 0, 1);
+kill(0, 15, 0, 15);
+
+// Negative numbers are meaningful on unix
+kill(-1, 'SIGHUP', -1, 1);
+kill(-1, undefined, -1, 15);
+kill('-1', 'SIGHUP', -1, 1);
+kill('-1', undefined, -1, 15);
+
+kill(process.pid, 'SIGHUP', process.pid, 1);
+kill(process.pid, undefined, process.pid, 15);
+kill(String(process.pid), 'SIGHUP', process.pid, 1);
+kill(String(process.pid), undefined, process.pid, 15);
diff --git a/tests/node_compat/test/parallel/test-process-uptime.js b/tests/node_compat/test/parallel/test-process-uptime.js
new file mode 100644
index 000000000..74d2c13bd
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-process-uptime.js
@@ -0,0 +1,44 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+
+console.error(process.uptime());
+// Add some wiggle room for different platforms.
+// Verify that the returned value is in seconds -
+// 15 seconds should be a good estimate.
+assert.ok(process.uptime() <= 15);
+
+const original = process.uptime();
+
+setTimeout(function() {
+ const uptime = process.uptime();
+ assert.ok(original < uptime);
+}, 10);
diff --git a/tests/node_compat/test/parallel/test-promise-unhandled-silent.js b/tests/node_compat/test/parallel/test-promise-unhandled-silent.js
new file mode 100644
index 000000000..3b2dcde15
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-promise-unhandled-silent.js
@@ -0,0 +1,28 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Flags: --unhandled-rejections=none
+'use strict';
+
+const common = require('../common');
+
+// Verify that ignoring unhandled rejection works fine and that no warning is
+// logged.
+
+new Promise(() => {
+ throw new Error('One');
+});
+
+Promise.reject('test');
+
+process.on('warning', common.mustNotCall('warning'));
+process.on('uncaughtException', common.mustNotCall('uncaughtException'));
+process.on('rejectionHandled', common.mustNotCall('rejectionHandled'));
+
+process.on('unhandledRejection', common.mustCall(2));
+
+setTimeout(common.mustCall(), 2);
diff --git a/tests/node_compat/test/parallel/test-promise-unhandled-throw-handler.js b/tests/node_compat/test/parallel/test-promise-unhandled-throw-handler.js
new file mode 100644
index 000000000..a911f096a
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-promise-unhandled-throw-handler.js
@@ -0,0 +1,43 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Flags: --unhandled-rejections=throw
+'use strict';
+
+const common = require('../common');
+const Countdown = require('../common/countdown');
+const assert = require('assert');
+
+// Verify that the unhandledRejection handler prevents triggering
+// uncaught exceptions
+
+const err1 = new Error('One');
+
+const errors = [err1, null];
+
+const ref = new Promise(() => {
+ throw err1;
+});
+// Explicitly reject `null`.
+Promise.reject(null);
+
+process.on('warning', common.mustNotCall('warning'));
+process.on('rejectionHandled', common.mustNotCall('rejectionHandled'));
+process.on('exit', assert.strictEqual.bind(null, 0));
+process.on('uncaughtException', common.mustNotCall('uncaughtException'));
+
+const timer = setTimeout(() => console.log(ref), 1000);
+
+const counter = new Countdown(2, () => {
+ clearTimeout(timer);
+});
+
+process.on('unhandledRejection', common.mustCall((err) => {
+ counter.dec();
+ const knownError = errors.shift();
+ assert.deepStrictEqual(err, knownError);
+}, 2));
diff --git a/tests/node_compat/test/parallel/test-querystring-escape.js b/tests/node_compat/test/parallel/test-querystring-escape.js
new file mode 100644
index 000000000..f4f635af1
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-querystring-escape.js
@@ -0,0 +1,48 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+
+const qs = require('querystring');
+
+assert.strictEqual(qs.escape(5), '5');
+assert.strictEqual(qs.escape('test'), 'test');
+assert.strictEqual(qs.escape({}), '%5Bobject%20Object%5D');
+assert.strictEqual(qs.escape([5, 10]), '5%2C10');
+assert.strictEqual(qs.escape('Ŋōđĕ'), '%C5%8A%C5%8D%C4%91%C4%95');
+assert.strictEqual(qs.escape('testŊōđĕ'), 'test%C5%8A%C5%8D%C4%91%C4%95');
+assert.strictEqual(qs.escape(`${String.fromCharCode(0xD800 + 1)}test`),
+ '%F0%90%91%B4est');
+
+assert.throws(
+ () => qs.escape(String.fromCharCode(0xD800 + 1)),
+ {
+ code: 'ERR_INVALID_URI',
+ name: 'URIError',
+ message: 'URI malformed'
+ }
+);
+
+// Using toString for objects
+assert.strictEqual(
+ qs.escape({ test: 5, toString: () => 'test', valueOf: () => 10 }),
+ 'test'
+);
+
+// `toString` is not callable, must throw an error.
+// Error message will vary between different JavaScript engines, so only check
+// that it is a `TypeError`.
+assert.throws(() => qs.escape({ toString: 5 }), TypeError);
+
+// Should use valueOf instead of non-callable toString.
+assert.strictEqual(qs.escape({ toString: 5, valueOf: () => 'test' }), 'test');
+
+// Error message will vary between different JavaScript engines, so only check
+// that it is a `TypeError`.
+assert.throws(() => qs.escape(Symbol('test')), TypeError);
diff --git a/tests/node_compat/test/parallel/test-querystring-maxKeys-non-finite.js b/tests/node_compat/test/parallel/test-querystring-maxKeys-non-finite.js
new file mode 100644
index 000000000..4a8c7ab0d
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-querystring-maxKeys-non-finite.js
@@ -0,0 +1,65 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+// This test was originally written to test a regression
+// that was introduced by
+// https://github.com/nodejs/node/pull/2288#issuecomment-179543894
+require('../common');
+
+const assert = require('assert');
+const parse = require('querystring').parse;
+
+// Taken from express-js/body-parser
+// https://github.com/expressjs/body-parser/blob/ed25264fb494cf0c8bc992b8257092cd4f694d5e/test/urlencoded.js#L636-L651
+function createManyParams(count) {
+ let str = '';
+
+ if (count === 0) {
+ return str;
+ }
+
+ str += '0=0';
+
+ for (let i = 1; i < count; i++) {
+ const n = i.toString(36);
+ str += `&${n}=${n}`;
+ }
+
+ return str;
+}
+
+const count = 10000;
+const originalMaxLength = 1000;
+const params = createManyParams(count);
+
+// thealphanerd
+// 27def4f introduced a change to parse that would cause Infinity
+// to be passed to String.prototype.split as an argument for limit
+// In this instance split will always return an empty array
+// this test confirms that the output of parse is the expected length
+// when passed Infinity as the argument for maxKeys
+const resultInfinity = parse(params, undefined, undefined, {
+ maxKeys: Infinity
+});
+const resultNaN = parse(params, undefined, undefined, {
+ maxKeys: NaN
+});
+const resultInfinityString = parse(params, undefined, undefined, {
+ maxKeys: 'Infinity'
+});
+const resultNaNString = parse(params, undefined, undefined, {
+ maxKeys: 'NaN'
+});
+
+// Non Finite maxKeys should return the length of input
+assert.strictEqual(Object.keys(resultInfinity).length, count);
+assert.strictEqual(Object.keys(resultNaN).length, count);
+// Strings maxKeys should return the maxLength
+// defined by parses internals
+assert.strictEqual(Object.keys(resultInfinityString).length, originalMaxLength);
+assert.strictEqual(Object.keys(resultNaNString).length, originalMaxLength);
diff --git a/tests/node_compat/test/parallel/test-querystring-multichar-separator.js b/tests/node_compat/test/parallel/test-querystring-multichar-separator.js
new file mode 100644
index 000000000..3234dcd60
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-querystring-multichar-separator.js
@@ -0,0 +1,32 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+const qs = require('querystring');
+
+function check(actual, expected) {
+ assert(!(actual instanceof Object));
+ assert.deepStrictEqual(Object.keys(actual).sort(),
+ Object.keys(expected).sort());
+ Object.keys(expected).forEach(function(key) {
+ assert.deepStrictEqual(actual[key], expected[key]);
+ });
+}
+
+check(qs.parse('foo=>bar&&bar=>baz', '&&', '=>'),
+ { foo: 'bar', bar: 'baz' });
+
+check(qs.stringify({ foo: 'bar', bar: 'baz' }, '&&', '=>'),
+ 'foo=>bar&&bar=>baz');
+
+check(qs.parse('foo==>bar, bar==>baz', ', ', '==>'),
+ { foo: 'bar', bar: 'baz' });
+
+check(qs.stringify({ foo: 'bar', bar: 'baz' }, ', ', '==>'),
+ 'foo==>bar, bar==>baz');
diff --git a/tests/node_compat/test/parallel/test-querystring.js b/tests/node_compat/test/parallel/test-querystring.js
new file mode 100644
index 000000000..fb8176da5
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-querystring.js
@@ -0,0 +1,489 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 16.12.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+const inspect = require('util').inspect;
+
+// test using assert
+const qs = require('querystring');
+
+function createWithNoPrototype(properties) {
+ const noProto = Object.create(null);
+ properties.forEach((property) => {
+ noProto[property.key] = property.value;
+ });
+ return noProto;
+}
+// Folding block, commented to pass gjslint
+// {{{
+// [ wonkyQS, canonicalQS, obj ]
+const qsTestCases = [
+ ['__proto__=1',
+ '__proto__=1',
+ createWithNoPrototype([{ key: '__proto__', value: '1' }])],
+ ['__defineGetter__=asdf',
+ '__defineGetter__=asdf',
+ JSON.parse('{"__defineGetter__":"asdf"}')],
+ ['foo=918854443121279438895193',
+ 'foo=918854443121279438895193',
+ { 'foo': '918854443121279438895193' }],
+ ['foo=bar', 'foo=bar', { 'foo': 'bar' }],
+ ['foo=bar&foo=quux', 'foo=bar&foo=quux', { 'foo': ['bar', 'quux'] }],
+ ['foo=1&bar=2', 'foo=1&bar=2', { 'foo': '1', 'bar': '2' }],
+ ['my+weird+field=q1%212%22%27w%245%267%2Fz8%29%3F',
+ 'my%20weird%20field=q1!2%22\'w%245%267%2Fz8)%3F',
+ { 'my weird field': 'q1!2"\'w$5&7/z8)?' }],
+ ['foo%3Dbaz=bar', 'foo%3Dbaz=bar', { 'foo=baz': 'bar' }],
+ ['foo=baz=bar', 'foo=baz%3Dbar', { 'foo': 'baz=bar' }],
+ ['str=foo&arr=1&arr=2&arr=3&somenull=&undef=',
+ 'str=foo&arr=1&arr=2&arr=3&somenull=&undef=',
+ { 'str': 'foo',
+ 'arr': ['1', '2', '3'],
+ 'somenull': '',
+ 'undef': '' }],
+ [' foo = bar ', '%20foo%20=%20bar%20', { ' foo ': ' bar ' }],
+ ['foo=%zx', 'foo=%25zx', { 'foo': '%zx' }],
+ ['foo=%EF%BF%BD', 'foo=%EF%BF%BD', { 'foo': '\ufffd' }],
+ // See: https://github.com/joyent/node/issues/1707
+ ['hasOwnProperty=x&toString=foo&valueOf=bar&__defineGetter__=baz',
+ 'hasOwnProperty=x&toString=foo&valueOf=bar&__defineGetter__=baz',
+ { hasOwnProperty: 'x',
+ toString: 'foo',
+ valueOf: 'bar',
+ __defineGetter__: 'baz' }],
+ // See: https://github.com/joyent/node/issues/3058
+ ['foo&bar=baz', 'foo=&bar=baz', { foo: '', bar: 'baz' }],
+ ['a=b&c&d=e', 'a=b&c=&d=e', { a: 'b', c: '', d: 'e' }],
+ ['a=b&c=&d=e', 'a=b&c=&d=e', { a: 'b', c: '', d: 'e' }],
+ ['a=b&=c&d=e', 'a=b&=c&d=e', { 'a': 'b', '': 'c', 'd': 'e' }],
+ ['a=b&=&c=d', 'a=b&=&c=d', { 'a': 'b', '': '', 'c': 'd' }],
+ ['&&foo=bar&&', 'foo=bar', { foo: 'bar' }],
+ ['&', '', {}],
+ ['&&&&', '', {}],
+ ['&=&', '=', { '': '' }],
+ ['&=&=', '=&=', { '': [ '', '' ] }],
+ ['=', '=', { '': '' }],
+ ['+', '%20=', { ' ': '' }],
+ ['+=', '%20=', { ' ': '' }],
+ ['+&', '%20=', { ' ': '' }],
+ ['=+', '=%20', { '': ' ' }],
+ ['+=&', '%20=', { ' ': '' }],
+ ['a&&b', 'a=&b=', { 'a': '', 'b': '' }],
+ ['a=a&&b=b', 'a=a&b=b', { 'a': 'a', 'b': 'b' }],
+ ['&a', 'a=', { 'a': '' }],
+ ['&=', '=', { '': '' }],
+ ['a&a&', 'a=&a=', { a: [ '', '' ] }],
+ ['a&a&a&', 'a=&a=&a=', { a: [ '', '', '' ] }],
+ ['a&a&a&a&', 'a=&a=&a=&a=', { a: [ '', '', '', '' ] }],
+ ['a=&a=value&a=', 'a=&a=value&a=', { a: [ '', 'value', '' ] }],
+ ['foo+bar=baz+quux', 'foo%20bar=baz%20quux', { 'foo bar': 'baz quux' }],
+ ['+foo=+bar', '%20foo=%20bar', { ' foo': ' bar' }],
+ ['a+', 'a%20=', { 'a ': '' }],
+ ['=a+', '=a%20', { '': 'a ' }],
+ ['a+&', 'a%20=', { 'a ': '' }],
+ ['=a+&', '=a%20', { '': 'a ' }],
+ ['%20+', '%20%20=', { ' ': '' }],
+ ['=%20+', '=%20%20', { '': ' ' }],
+ ['%20+&', '%20%20=', { ' ': '' }],
+ ['=%20+&', '=%20%20', { '': ' ' }],
+ [null, '', {}],
+ [undefined, '', {}],
+];
+
+// [ wonkyQS, canonicalQS, obj ]
+const qsColonTestCases = [
+ ['foo:bar', 'foo:bar', { 'foo': 'bar' }],
+ ['foo:bar;foo:quux', 'foo:bar;foo:quux', { 'foo': ['bar', 'quux'] }],
+ ['foo:1&bar:2;baz:quux',
+ 'foo:1%26bar%3A2;baz:quux',
+ { 'foo': '1&bar:2', 'baz': 'quux' }],
+ ['foo%3Abaz:bar', 'foo%3Abaz:bar', { 'foo:baz': 'bar' }],
+ ['foo:baz:bar', 'foo:baz%3Abar', { 'foo': 'baz:bar' }],
+];
+
+// [wonkyObj, qs, canonicalObj]
+function extendedFunction() {}
+extendedFunction.prototype = { a: 'b' };
+const qsWeirdObjects = [
+ // eslint-disable-next-line node-core/no-unescaped-regexp-dot
+ [{ regexp: /./g }, 'regexp=', { 'regexp': '' }],
+ // eslint-disable-next-line node-core/no-unescaped-regexp-dot
+ [{ regexp: new RegExp('.', 'g') }, 'regexp=', { 'regexp': '' }],
+ [{ fn: () => {} }, 'fn=', { 'fn': '' }],
+ [{ fn: new Function('') }, 'fn=', { 'fn': '' }],
+ [{ math: Math }, 'math=', { 'math': '' }],
+ [{ e: extendedFunction }, 'e=', { 'e': '' }],
+ [{ d: new Date() }, 'd=', { 'd': '' }],
+ [{ d: Date }, 'd=', { 'd': '' }],
+ [
+ { f: new Boolean(false), t: new Boolean(true) },
+ 'f=&t=',
+ { 'f': '', 't': '' },
+ ],
+ [{ f: false, t: true }, 'f=false&t=true', { 'f': 'false', 't': 'true' }],
+ [{ n: null }, 'n=', { 'n': '' }],
+ [{ nan: NaN }, 'nan=', { 'nan': '' }],
+ [{ inf: Infinity }, 'inf=', { 'inf': '' }],
+ [{ a: [], b: [] }, '', {}],
+ [{ a: 1, b: [] }, 'a=1', { 'a': '1' }],
+];
+
+const vm = require('vm');
+const foreignObject = vm.runInNewContext('({"foo": ["bar", "baz"]})');
+
+const qsNoMungeTestCases = [
+ ['', {}],
+ ['foo=bar&foo=baz', { 'foo': ['bar', 'baz'] }],
+ ['foo=bar&foo=baz', foreignObject],
+ ['blah=burp', { 'blah': 'burp' }],
+ ['a=!-._~\'()*', { 'a': '!-._~\'()*' }],
+ ['a=abcdefghijklmnopqrstuvwxyz', { 'a': 'abcdefghijklmnopqrstuvwxyz' }],
+ ['a=ABCDEFGHIJKLMNOPQRSTUVWXYZ', { 'a': 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' }],
+ ['a=0123456789', { 'a': '0123456789' }],
+ ['gragh=1&gragh=3&goo=2', { 'gragh': ['1', '3'], 'goo': '2' }],
+ ['frappucino=muffin&goat%5B%5D=scone&pond=moose',
+ { 'frappucino': 'muffin', 'goat[]': 'scone', 'pond': 'moose' }],
+ ['trololol=yes&lololo=no', { 'trololol': 'yes', 'lololo': 'no' }],
+];
+
+const qsUnescapeTestCases = [
+ ['there is nothing to unescape here',
+ 'there is nothing to unescape here'],
+ ['there%20are%20several%20spaces%20that%20need%20to%20be%20unescaped',
+ 'there are several spaces that need to be unescaped'],
+ ['there%2Qare%0-fake%escaped values in%%%%this%9Hstring',
+ 'there%2Qare%0-fake%escaped values in%%%%this%9Hstring'],
+ ['%20%21%22%23%24%25%26%27%28%29%2A%2B%2C%2D%2E%2F%30%31%32%33%34%35%36%37',
+ ' !"#$%&\'()*+,-./01234567'],
+ ['%%2a', '%*'],
+ ['%2sf%2a', '%2sf*'],
+ ['%2%2af%2a', '%2*f*'],
+];
+
+assert.strictEqual(qs.parse('id=918854443121279438895193').id,
+ '918854443121279438895193');
+
+function check(actual, expected, input) {
+ assert(!(actual instanceof Object));
+ const actualKeys = Object.keys(actual).sort();
+ const expectedKeys = Object.keys(expected).sort();
+ let msg;
+ if (typeof input === 'string') {
+ msg = `Input: ${inspect(input)}\n` +
+ `Actual keys: ${inspect(actualKeys)}\n` +
+ `Expected keys: ${inspect(expectedKeys)}`;
+ }
+ assert.deepStrictEqual(actualKeys, expectedKeys, msg);
+ expectedKeys.forEach((key) => {
+ if (typeof input === 'string') {
+ msg = `Input: ${inspect(input)}\n` +
+ `Key: ${inspect(key)}\n` +
+ `Actual value: ${inspect(actual[key])}\n` +
+ `Expected value: ${inspect(expected[key])}`;
+ } else {
+ msg = undefined;
+ }
+ assert.deepStrictEqual(actual[key], expected[key], msg);
+ });
+}
+
+// Test that the canonical qs is parsed properly.
+qsTestCases.forEach((testCase) => {
+ check(qs.parse(testCase[0]), testCase[2], testCase[0]);
+});
+
+// Test that the colon test cases can do the same
+qsColonTestCases.forEach((testCase) => {
+ check(qs.parse(testCase[0], ';', ':'), testCase[2], testCase[0]);
+});
+
+// Test the weird objects, that they get parsed properly
+qsWeirdObjects.forEach((testCase) => {
+ check(qs.parse(testCase[1]), testCase[2], testCase[1]);
+});
+
+qsNoMungeTestCases.forEach((testCase) => {
+ assert.deepStrictEqual(qs.stringify(testCase[1], '&', '='), testCase[0]);
+});
+
+// Test the nested qs-in-qs case
+{
+ const f = qs.parse('a=b&q=x%3Dy%26y%3Dz');
+ check(f, createWithNoPrototype([
+ { key: 'a', value: 'b' },
+ { key: 'q', value: 'x=y&y=z' },
+ ]));
+
+ f.q = qs.parse(f.q);
+ const expectedInternal = createWithNoPrototype([
+ { key: 'x', value: 'y' },
+ { key: 'y', value: 'z' },
+ ]);
+ check(f.q, expectedInternal);
+}
+
+// nested in colon
+{
+ const f = qs.parse('a:b;q:x%3Ay%3By%3Az', ';', ':');
+ check(f, createWithNoPrototype([
+ { key: 'a', value: 'b' },
+ { key: 'q', value: 'x:y;y:z' },
+ ]));
+ f.q = qs.parse(f.q, ';', ':');
+ const expectedInternal = createWithNoPrototype([
+ { key: 'x', value: 'y' },
+ { key: 'y', value: 'z' },
+ ]);
+ check(f.q, expectedInternal);
+}
+
+// Now test stringifying
+
+// basic
+qsTestCases.forEach((testCase) => {
+ assert.strictEqual(qs.stringify(testCase[2]), testCase[1]);
+});
+
+qsColonTestCases.forEach((testCase) => {
+ assert.strictEqual(qs.stringify(testCase[2], ';', ':'), testCase[1]);
+});
+
+qsWeirdObjects.forEach((testCase) => {
+ assert.strictEqual(qs.stringify(testCase[0]), testCase[1]);
+});
+
+// BigInt values
+
+assert.strictEqual(qs.stringify({ foo: 2n ** 1023n }),
+ 'foo=' + 2n ** 1023n);
+assert.strictEqual(qs.stringify([0n, 1n, 2n]),
+ '0=0&1=1&2=2');
+
+assert.strictEqual(qs.stringify({ foo: 2n ** 1023n },
+ null,
+ null,
+ { encodeURIComponent: (c) => c }),
+ 'foo=' + 2n ** 1023n);
+assert.strictEqual(qs.stringify([0n, 1n, 2n],
+ null,
+ null,
+ { encodeURIComponent: (c) => c }),
+ '0=0&1=1&2=2');
+
+// Invalid surrogate pair throws URIError
+assert.throws(
+ () => qs.stringify({ foo: '\udc00' }),
+ {
+ code: 'ERR_INVALID_URI',
+ name: 'URIError',
+ message: 'URI malformed'
+ }
+);
+
+// Coerce numbers to string
+assert.strictEqual(qs.stringify({ foo: 0 }), 'foo=0');
+assert.strictEqual(qs.stringify({ foo: -0 }), 'foo=0');
+assert.strictEqual(qs.stringify({ foo: 3 }), 'foo=3');
+assert.strictEqual(qs.stringify({ foo: -72.42 }), 'foo=-72.42');
+assert.strictEqual(qs.stringify({ foo: NaN }), 'foo=');
+assert.strictEqual(qs.stringify({ foo: 1e21 }), 'foo=1e%2B21');
+assert.strictEqual(qs.stringify({ foo: Infinity }), 'foo=');
+
+// nested
+{
+ const f = qs.stringify({
+ a: 'b',
+ q: qs.stringify({
+ x: 'y',
+ y: 'z'
+ })
+ });
+ assert.strictEqual(f, 'a=b&q=x%3Dy%26y%3Dz');
+}
+
+qs.parse(undefined); // Should not throw.
+
+// nested in colon
+{
+ const f = qs.stringify({
+ a: 'b',
+ q: qs.stringify({
+ x: 'y',
+ y: 'z'
+ }, ';', ':')
+ }, ';', ':');
+ assert.strictEqual(f, 'a:b;q:x%3Ay%3By%3Az');
+}
+
+// empty string
+assert.strictEqual(qs.stringify(), '');
+assert.strictEqual(qs.stringify(0), '');
+assert.strictEqual(qs.stringify([]), '');
+assert.strictEqual(qs.stringify(null), '');
+assert.strictEqual(qs.stringify(true), '');
+
+check(qs.parse(), {});
+
+// empty sep
+check(qs.parse('a', []), { a: '' });
+
+// empty eq
+check(qs.parse('a', null, []), { '': 'a' });
+
+// Test limiting
+assert.strictEqual(
+ Object.keys(qs.parse('a=1&b=1&c=1', null, null, { maxKeys: 1 })).length,
+ 1);
+
+// Test limiting with a case that starts from `&`
+assert.strictEqual(
+ Object.keys(qs.parse('&a', null, null, { maxKeys: 1 })).length,
+ 0);
+
+// Test removing limit
+{
+ function testUnlimitedKeys() {
+ const query = {};
+
+ for (let i = 0; i < 2000; i++) query[i] = i;
+
+ const url = qs.stringify(query);
+
+ assert.strictEqual(
+ Object.keys(qs.parse(url, null, null, { maxKeys: 0 })).length,
+ 2000);
+ }
+
+ testUnlimitedKeys();
+}
+
+{
+ const b = qs.unescapeBuffer('%d3%f2Ug%1f6v%24%5e%98%cb' +
+ '%0d%ac%a2%2f%9d%eb%d8%a2%e6');
+ // <Buffer d3 f2 55 67 1f 36 76 24 5e 98 cb 0d ac a2 2f 9d eb d8 a2 e6>
+ assert.strictEqual(b[0], 0xd3);
+ assert.strictEqual(b[1], 0xf2);
+ assert.strictEqual(b[2], 0x55);
+ assert.strictEqual(b[3], 0x67);
+ assert.strictEqual(b[4], 0x1f);
+ assert.strictEqual(b[5], 0x36);
+ assert.strictEqual(b[6], 0x76);
+ assert.strictEqual(b[7], 0x24);
+ assert.strictEqual(b[8], 0x5e);
+ assert.strictEqual(b[9], 0x98);
+ assert.strictEqual(b[10], 0xcb);
+ assert.strictEqual(b[11], 0x0d);
+ assert.strictEqual(b[12], 0xac);
+ assert.strictEqual(b[13], 0xa2);
+ assert.strictEqual(b[14], 0x2f);
+ assert.strictEqual(b[15], 0x9d);
+ assert.strictEqual(b[16], 0xeb);
+ assert.strictEqual(b[17], 0xd8);
+ assert.strictEqual(b[18], 0xa2);
+ assert.strictEqual(b[19], 0xe6);
+}
+
+assert.strictEqual(qs.unescapeBuffer('a+b', true).toString(), 'a b');
+assert.strictEqual(qs.unescapeBuffer('a+b').toString(), 'a+b');
+assert.strictEqual(qs.unescapeBuffer('a%').toString(), 'a%');
+assert.strictEqual(qs.unescapeBuffer('a%2').toString(), 'a%2');
+assert.strictEqual(qs.unescapeBuffer('a%20').toString(), 'a ');
+assert.strictEqual(qs.unescapeBuffer('a%2g').toString(), 'a%2g');
+assert.strictEqual(qs.unescapeBuffer('a%%').toString(), 'a%%');
+
+// Test invalid encoded string
+check(qs.parse('%\u0100=%\u0101'), { '%Ā': '%ā' });
+
+// Test custom decode
+{
+ function demoDecode(str) {
+ return str + str;
+ }
+
+ check(
+ qs.parse('a=a&b=b&c=c', null, null, { decodeURIComponent: demoDecode }),
+ { aa: 'aa', bb: 'bb', cc: 'cc' });
+ check(
+ qs.parse('a=a&b=b&c=c', null, '==', { decodeURIComponent: (str) => str }),
+ { 'a=a': '', 'b=b': '', 'c=c': '' });
+}
+
+// TODO(wafuwafu13): Enable this
+// // Test QueryString.unescape
+// {
+// function errDecode(str) {
+// throw new Error('To jump to the catch scope');
+// }
+
+// check(qs.parse('a=a', null, null, { decodeURIComponent: errDecode }),
+// { a: 'a' });
+// }
+
+// Test custom encode
+{
+ function demoEncode(str) {
+ return str[0];
+ }
+
+ const obj = { aa: 'aa', bb: 'bb', cc: 'cc' };
+ assert.strictEqual(
+ qs.stringify(obj, null, null, { encodeURIComponent: demoEncode }),
+ 'a=a&b=b&c=c');
+}
+
+// Test custom encode for different types
+{
+ const obj = { number: 1, bigint: 2n, true: true, false: false, object: {} };
+ assert.strictEqual(
+ qs.stringify(obj, null, null, { encodeURIComponent: (v) => v }),
+ 'number=1&bigint=2&true=true&false=false&object=');
+}
+
+// Test QueryString.unescapeBuffer
+qsUnescapeTestCases.forEach((testCase) => {
+ assert.strictEqual(qs.unescape(testCase[0]), testCase[1]);
+ assert.strictEqual(qs.unescapeBuffer(testCase[0]).toString(), testCase[1]);
+});
+
+// TODO(wafuwafu13): Enable this
+// // Test overriding .unescape
+// {
+// const prevUnescape = qs.unescape;
+// qs.unescape = (str) => {
+// return str.replace(/o/g, '_');
+// };
+// check(
+// qs.parse('foo=bor'),
+// createWithNoPrototype([{ key: 'f__', value: 'b_r' }]));
+// qs.unescape = prevUnescape;
+// }
+
+// Test separator and "equals" parsing order
+check(qs.parse('foo&bar', '&', '&'), { foo: '', bar: '' });
diff --git a/tests/node_compat/test/parallel/test-readline-emit-keypress-events.js b/tests/node_compat/test/parallel/test-readline-emit-keypress-events.js
new file mode 100644
index 000000000..542616424
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-readline-emit-keypress-events.js
@@ -0,0 +1,79 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+// emitKeypressEvents is thoroughly tested in test-readline-keys.js.
+// However, that test calls it implicitly. This is just a quick sanity check
+// to verify that it works when called explicitly.
+
+require('../common');
+const assert = require('assert');
+const readline = require('readline');
+const PassThrough = require('stream').PassThrough;
+
+const expectedSequence = ['f', 'o', 'o'];
+const expectedKeys = [
+ { sequence: 'f', name: 'f', ctrl: false, meta: false, shift: false },
+ { sequence: 'o', name: 'o', ctrl: false, meta: false, shift: false },
+ { sequence: 'o', name: 'o', ctrl: false, meta: false, shift: false },
+];
+
+{
+ const stream = new PassThrough();
+ const sequence = [];
+ const keys = [];
+
+ readline.emitKeypressEvents(stream);
+ stream.on('keypress', (s, k) => {
+ sequence.push(s);
+ keys.push(k);
+ });
+ stream.write('foo');
+
+ assert.deepStrictEqual(sequence, expectedSequence);
+ assert.deepStrictEqual(keys, expectedKeys);
+}
+
+{
+ const stream = new PassThrough();
+ const sequence = [];
+ const keys = [];
+
+ stream.on('keypress', (s, k) => {
+ sequence.push(s);
+ keys.push(k);
+ });
+ readline.emitKeypressEvents(stream);
+ stream.write('foo');
+
+ assert.deepStrictEqual(sequence, expectedSequence);
+ assert.deepStrictEqual(keys, expectedKeys);
+}
+
+{
+ const stream = new PassThrough();
+ const sequence = [];
+ const keys = [];
+ const keypressListener = (s, k) => {
+ sequence.push(s);
+ keys.push(k);
+ };
+
+ stream.on('keypress', keypressListener);
+ readline.emitKeypressEvents(stream);
+ stream.removeListener('keypress', keypressListener);
+ stream.write('foo');
+
+ assert.deepStrictEqual(sequence, []);
+ assert.deepStrictEqual(keys, []);
+
+ stream.on('keypress', keypressListener);
+ stream.write('foo');
+
+ assert.deepStrictEqual(sequence, expectedSequence);
+ assert.deepStrictEqual(keys, expectedKeys);
+}
diff --git a/tests/node_compat/test/parallel/test-readline-interface-escapecodetimeout.js b/tests/node_compat/test/parallel/test-readline-interface-escapecodetimeout.js
new file mode 100644
index 000000000..584dc1110
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-readline-interface-escapecodetimeout.js
@@ -0,0 +1,53 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+require('../common');
+
+// This test ensures that the escapeCodeTimeout option set correctly
+
+const assert = require('assert');
+const readline = require('readline');
+const EventEmitter = require('events').EventEmitter;
+
+class FakeInput extends EventEmitter {
+ resume() {}
+ pause() {}
+ write() {}
+ end() {}
+}
+
+{
+ const fi = new FakeInput();
+ const rli = new readline.Interface({
+ input: fi,
+ output: fi,
+ escapeCodeTimeout: 50
+ });
+ assert.strictEqual(rli.escapeCodeTimeout, 50);
+ rli.close();
+}
+
+[
+ null,
+ {},
+ NaN,
+ '50',
+].forEach((invalidInput) => {
+ assert.throws(() => {
+ const fi = new FakeInput();
+ const rli = new readline.Interface({
+ input: fi,
+ output: fi,
+ escapeCodeTimeout: invalidInput
+ });
+ rli.close();
+ }, {
+ name: 'TypeError',
+ code: 'ERR_INVALID_ARG_VALUE'
+ });
+});
diff --git a/tests/node_compat/test/parallel/test-readline-interface.js b/tests/node_compat/test/parallel/test-readline-interface.js
new file mode 100644
index 000000000..e8e48dd1e
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-readline-interface.js
@@ -0,0 +1,1217 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 16.13.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// Flags: --expose-internals
+'use strict';
+const common = require('../common');
+common.skipIfDumbTerminal();
+
+const assert = require('assert');
+const readline = require('readline');
+const util = require('util');
+const {
+ getStringWidth,
+ stripVTControlCharacters
+} = require('internal/util/inspect');
+const { EventEmitter, getEventListeners } = require('events');
+const { Writable, Readable } = require('stream');
+
+class FakeInput extends EventEmitter {
+ resume() {}
+ pause() {}
+ write() {}
+ end() {}
+}
+
+function isWarned(emitter) {
+ for (const name in emitter) {
+ const listeners = emitter[name];
+ if (listeners.warned) return true;
+ }
+ return false;
+}
+
+function getInterface(options) {
+ const fi = new FakeInput();
+ const rli = new readline.Interface({
+ input: fi,
+ output: fi,
+ ...options,
+ });
+ return [rli, fi];
+}
+
+function assertCursorRowsAndCols(rli, rows, cols) {
+ const cursorPos = rli.getCursorPos();
+ assert.strictEqual(cursorPos.rows, rows);
+ assert.strictEqual(cursorPos.cols, cols);
+}
+
+{
+ const input = new FakeInput();
+ const rl = readline.Interface({ input });
+ assert(rl instanceof readline.Interface);
+}
+
+[
+ undefined,
+ 50,
+ 0,
+ 100.5,
+ 5000,
+].forEach((crlfDelay) => {
+ const [rli] = getInterface({ crlfDelay });
+ assert.strictEqual(rli.crlfDelay, Math.max(crlfDelay || 100, 100));
+ rli.close();
+});
+
+{
+ const input = new FakeInput();
+
+ // Constructor throws if completer is not a function or undefined
+ ['not an array', 123, 123n, {}, true, Symbol(), null].forEach((invalid) => {
+ assert.throws(() => {
+ readline.createInterface({
+ input,
+ completer: invalid
+ });
+ }, {
+ name: 'TypeError',
+ code: 'ERR_INVALID_ARG_VALUE'
+ });
+ });
+
+ // Constructor throws if history is not an array
+ ['not an array', 123, 123n, {}, true, Symbol(), null].forEach((history) => {
+ assert.throws(() => {
+ readline.createInterface({
+ input,
+ history,
+ });
+ }, {
+ name: 'TypeError',
+ code: 'ERR_INVALID_ARG_TYPE'
+ });
+ });
+
+ // Constructor throws if historySize is not a positive number
+ ['not a number', -1, NaN, {}, true, Symbol(), null].forEach((historySize) => {
+ assert.throws(() => {
+ readline.createInterface({
+ input,
+ historySize,
+ });
+ }, {
+ name: 'RangeError',
+ code: 'ERR_INVALID_ARG_VALUE'
+ });
+ });
+
+ // Check for invalid tab sizes.
+ assert.throws(
+ () => new readline.Interface({
+ input,
+ tabSize: 0
+ }),
+ {
+ message: 'The value of "tabSize" is out of range. ' +
+ 'It must be >= 1 && < 4294967296. Received 0',
+ code: 'ERR_OUT_OF_RANGE'
+ }
+ );
+
+ assert.throws(
+ () => new readline.Interface({
+ input,
+ tabSize: '4'
+ }),
+ { code: 'ERR_INVALID_ARG_TYPE' }
+ );
+
+ assert.throws(
+ () => new readline.Interface({
+ input,
+ tabSize: 4.5
+ }),
+ {
+ code: 'ERR_OUT_OF_RANGE',
+ message: 'The value of "tabSize" is out of range. ' +
+ 'It must be an integer. Received 4.5'
+ }
+ );
+}
+
+// Sending a single character with no newline
+{
+ const fi = new FakeInput();
+ const rli = new readline.Interface(fi, {});
+ rli.on('line', common.mustNotCall());
+ fi.emit('data', 'a');
+ rli.close();
+}
+
+// Sending multiple newlines at once that does not end with a new line and a
+// `end` event(last line is). \r should behave like \n when alone.
+{
+ const [rli, fi] = getInterface({ terminal: true });
+ const expectedLines = ['foo', 'bar', 'baz', 'bat'];
+ rli.on('line', common.mustCall((line) => {
+ assert.strictEqual(line, expectedLines.shift());
+ }, expectedLines.length - 1));
+ fi.emit('data', expectedLines.join('\r'));
+ rli.close();
+}
+
+// \r at start of input should output blank line
+{
+ const [rli, fi] = getInterface({ terminal: true });
+ const expectedLines = ['', 'foo' ];
+ rli.on('line', common.mustCall((line) => {
+ assert.strictEqual(line, expectedLines.shift());
+ }, expectedLines.length));
+ fi.emit('data', '\rfoo\r');
+ rli.close();
+}
+
+// \t does not become part of the input when there is a completer function
+{
+ const completer = (line) => [[], line];
+ const [rli, fi] = getInterface({ terminal: true, completer });
+ rli.on('line', common.mustCall((line) => {
+ assert.strictEqual(line, 'foo');
+ }));
+ for (const character of '\tfo\to\t') {
+ fi.emit('data', character);
+ }
+ fi.emit('data', '\n');
+ rli.close();
+}
+
+// \t when there is no completer function should behave like an ordinary
+// character
+{
+ const [rli, fi] = getInterface({ terminal: true });
+ rli.on('line', common.mustCall((line) => {
+ assert.strictEqual(line, '\t');
+ }));
+ fi.emit('data', '\t');
+ fi.emit('data', '\n');
+ rli.close();
+}
+
+// Adding history lines should emit the history event with
+// the history array
+{
+ const [rli, fi] = getInterface({ terminal: true });
+ const expectedLines = ['foo', 'bar', 'baz', 'bat'];
+ rli.on('history', common.mustCall((history) => {
+ const expectedHistory = expectedLines.slice(0, history.length).reverse();
+ assert.deepStrictEqual(history, expectedHistory);
+ }, expectedLines.length));
+ for (const line of expectedLines) {
+ fi.emit('data', `${line}\n`);
+ }
+ rli.close();
+}
+
+// Altering the history array in the listener should not alter
+// the line being processed
+{
+ const [rli, fi] = getInterface({ terminal: true });
+ const expectedLine = 'foo';
+ rli.on('history', common.mustCall((history) => {
+ assert.strictEqual(history[0], expectedLine);
+ history.shift();
+ }));
+ rli.on('line', common.mustCall((line) => {
+ assert.strictEqual(line, expectedLine);
+ assert.strictEqual(rli.history.length, 0);
+ }));
+ fi.emit('data', `${expectedLine}\n`);
+ rli.close();
+}
+
+// Duplicate lines are removed from history when
+// `options.removeHistoryDuplicates` is `true`
+{
+ const [rli, fi] = getInterface({
+ terminal: true,
+ removeHistoryDuplicates: true
+ });
+ const expectedLines = ['foo', 'bar', 'baz', 'bar', 'bat', 'bat'];
+ // ['foo', 'baz', 'bar', bat'];
+ let callCount = 0;
+ rli.on('line', (line) => {
+ assert.strictEqual(line, expectedLines[callCount]);
+ callCount++;
+ });
+ fi.emit('data', `${expectedLines.join('\n')}\n`);
+ assert.strictEqual(callCount, expectedLines.length);
+ fi.emit('keypress', '.', { name: 'up' }); // 'bat'
+ assert.strictEqual(rli.line, expectedLines[--callCount]);
+ fi.emit('keypress', '.', { name: 'up' }); // 'bar'
+ assert.notStrictEqual(rli.line, expectedLines[--callCount]);
+ assert.strictEqual(rli.line, expectedLines[--callCount]);
+ fi.emit('keypress', '.', { name: 'up' }); // 'baz'
+ assert.strictEqual(rli.line, expectedLines[--callCount]);
+ fi.emit('keypress', '.', { name: 'up' }); // 'foo'
+ assert.notStrictEqual(rli.line, expectedLines[--callCount]);
+ assert.strictEqual(rli.line, expectedLines[--callCount]);
+ assert.strictEqual(callCount, 0);
+ fi.emit('keypress', '.', { name: 'down' }); // 'baz'
+ assert.strictEqual(rli.line, 'baz');
+ assert.strictEqual(rli.historyIndex, 2);
+ fi.emit('keypress', '.', { name: 'n', ctrl: true }); // 'bar'
+ assert.strictEqual(rli.line, 'bar');
+ assert.strictEqual(rli.historyIndex, 1);
+ fi.emit('keypress', '.', { name: 'n', ctrl: true });
+ assert.strictEqual(rli.line, 'bat');
+ assert.strictEqual(rli.historyIndex, 0);
+ // Activate the substring history search.
+ fi.emit('keypress', '.', { name: 'down' }); // 'bat'
+ assert.strictEqual(rli.line, 'bat');
+ assert.strictEqual(rli.historyIndex, -1);
+ // Deactivate substring history search.
+ fi.emit('keypress', '.', { name: 'backspace' }); // 'ba'
+ assert.strictEqual(rli.historyIndex, -1);
+ assert.strictEqual(rli.line, 'ba');
+ // Activate the substring history search.
+ fi.emit('keypress', '.', { name: 'down' }); // 'ba'
+ assert.strictEqual(rli.historyIndex, -1);
+ assert.strictEqual(rli.line, 'ba');
+ fi.emit('keypress', '.', { name: 'down' }); // 'ba'
+ assert.strictEqual(rli.historyIndex, -1);
+ assert.strictEqual(rli.line, 'ba');
+ fi.emit('keypress', '.', { name: 'up' }); // 'bat'
+ assert.strictEqual(rli.historyIndex, 0);
+ assert.strictEqual(rli.line, 'bat');
+ fi.emit('keypress', '.', { name: 'up' }); // 'bar'
+ assert.strictEqual(rli.historyIndex, 1);
+ assert.strictEqual(rli.line, 'bar');
+ fi.emit('keypress', '.', { name: 'up' }); // 'baz'
+ assert.strictEqual(rli.historyIndex, 2);
+ assert.strictEqual(rli.line, 'baz');
+ fi.emit('keypress', '.', { name: 'up' }); // 'ba'
+ assert.strictEqual(rli.historyIndex, 4);
+ assert.strictEqual(rli.line, 'ba');
+ fi.emit('keypress', '.', { name: 'up' }); // 'ba'
+ assert.strictEqual(rli.historyIndex, 4);
+ assert.strictEqual(rli.line, 'ba');
+ // Deactivate substring history search and reset history index.
+ fi.emit('keypress', '.', { name: 'right' }); // 'ba'
+ assert.strictEqual(rli.historyIndex, -1);
+ assert.strictEqual(rli.line, 'ba');
+ // Substring history search activated.
+ fi.emit('keypress', '.', { name: 'up' }); // 'ba'
+ assert.strictEqual(rli.historyIndex, 0);
+ assert.strictEqual(rli.line, 'bat');
+ rli.close();
+}
+
+// Duplicate lines are not removed from history when
+// `options.removeHistoryDuplicates` is `false`
+{
+ const [rli, fi] = getInterface({
+ terminal: true,
+ removeHistoryDuplicates: false
+ });
+ const expectedLines = ['foo', 'bar', 'baz', 'bar', 'bat', 'bat'];
+ let callCount = 0;
+ rli.on('line', (line) => {
+ assert.strictEqual(line, expectedLines[callCount]);
+ callCount++;
+ });
+ fi.emit('data', `${expectedLines.join('\n')}\n`);
+ assert.strictEqual(callCount, expectedLines.length);
+ fi.emit('keypress', '.', { name: 'up' }); // 'bat'
+ assert.strictEqual(rli.line, expectedLines[--callCount]);
+ fi.emit('keypress', '.', { name: 'up' }); // 'bar'
+ assert.notStrictEqual(rli.line, expectedLines[--callCount]);
+ assert.strictEqual(rli.line, expectedLines[--callCount]);
+ fi.emit('keypress', '.', { name: 'up' }); // 'baz'
+ assert.strictEqual(rli.line, expectedLines[--callCount]);
+ fi.emit('keypress', '.', { name: 'up' }); // 'bar'
+ assert.strictEqual(rli.line, expectedLines[--callCount]);
+ fi.emit('keypress', '.', { name: 'up' }); // 'foo'
+ assert.strictEqual(rli.line, expectedLines[--callCount]);
+ assert.strictEqual(callCount, 0);
+ rli.close();
+}
+
+// Regression test for repl freeze, #1968:
+// check that nothing fails if 'keypress' event throws.
+{
+ const [rli, fi] = getInterface({ terminal: true });
+ const keys = [];
+ const err = new Error('bad thing happened');
+ fi.on('keypress', (key) => {
+ keys.push(key);
+ if (key === 'X') {
+ throw err;
+ }
+ });
+ assert.throws(
+ () => fi.emit('data', 'fooX'),
+ (e) => {
+ assert.strictEqual(e, err);
+ return true;
+ }
+ );
+ fi.emit('data', 'bar');
+ assert.strictEqual(keys.join(''), 'fooXbar');
+ rli.close();
+}
+
+// History is bound
+{
+ const [rli, fi] = getInterface({ terminal: true, historySize: 2 });
+ const lines = ['line 1', 'line 2', 'line 3'];
+ fi.emit('data', lines.join('\n') + '\n');
+ assert.strictEqual(rli.history.length, 2);
+ assert.strictEqual(rli.history[0], 'line 3');
+ assert.strictEqual(rli.history[1], 'line 2');
+}
+
+// Question
+{
+ const [rli] = getInterface({ terminal: true });
+ const expectedLines = ['foo'];
+ rli.question(expectedLines[0], () => rli.close());
+ assertCursorRowsAndCols(rli, 0, expectedLines[0].length);
+ rli.close();
+}
+
+// Sending a multi-line question
+{
+ const [rli] = getInterface({ terminal: true });
+ const expectedLines = ['foo', 'bar'];
+ rli.question(expectedLines.join('\n'), () => rli.close());
+ assertCursorRowsAndCols(
+ rli, expectedLines.length - 1, expectedLines.slice(-1)[0].length);
+ rli.close();
+}
+
+{
+ // Beginning and end of line
+ const [rli, fi] = getInterface({ terminal: true, prompt: '' });
+ fi.emit('data', 'the quick brown fox');
+ fi.emit('keypress', '.', { ctrl: true, name: 'a' });
+ assertCursorRowsAndCols(rli, 0, 0);
+ fi.emit('keypress', '.', { ctrl: true, name: 'e' });
+ assertCursorRowsAndCols(rli, 0, 19);
+ rli.close();
+}
+
+{
+ // Back and Forward one character
+ const [rli, fi] = getInterface({ terminal: true, prompt: '' });
+ fi.emit('data', 'the quick brown fox');
+ assertCursorRowsAndCols(rli, 0, 19);
+
+ // Back one character
+ fi.emit('keypress', '.', { ctrl: true, name: 'b' });
+ assertCursorRowsAndCols(rli, 0, 18);
+ // Back one character
+ fi.emit('keypress', '.', { ctrl: true, name: 'b' });
+ assertCursorRowsAndCols(rli, 0, 17);
+ // Forward one character
+ fi.emit('keypress', '.', { ctrl: true, name: 'f' });
+ assertCursorRowsAndCols(rli, 0, 18);
+ // Forward one character
+ fi.emit('keypress', '.', { ctrl: true, name: 'f' });
+ assertCursorRowsAndCols(rli, 0, 19);
+ rli.close();
+}
+
+// Back and Forward one astral character
+{
+ const [rli, fi] = getInterface({ terminal: true, prompt: '' });
+ fi.emit('data', '💻');
+
+ // Move left one character/code point
+ fi.emit('keypress', '.', { name: 'left' });
+ assertCursorRowsAndCols(rli, 0, 0);
+
+ // Move right one character/code point
+ fi.emit('keypress', '.', { name: 'right' });
+ assertCursorRowsAndCols(rli, 0, 2);
+
+ rli.on('line', common.mustCall((line) => {
+ assert.strictEqual(line, '💻');
+ }));
+ fi.emit('data', '\n');
+ rli.close();
+}
+
+// Two astral characters left
+{
+ const [rli, fi] = getInterface({ terminal: true, prompt: '' });
+ fi.emit('data', '💻');
+
+ // Move left one character/code point
+ fi.emit('keypress', '.', { name: 'left' });
+ assertCursorRowsAndCols(rli, 0, 0);
+
+ fi.emit('data', '🐕');
+ assertCursorRowsAndCols(rli, 0, 2);
+
+ rli.on('line', common.mustCall((line) => {
+ assert.strictEqual(line, '🐕💻');
+ }));
+ fi.emit('data', '\n');
+ rli.close();
+}
+
+// Two astral characters right
+{
+ const [rli, fi] = getInterface({ terminal: true, prompt: '' });
+ fi.emit('data', '💻');
+
+ // Move left one character/code point
+ fi.emit('keypress', '.', { name: 'right' });
+ assertCursorRowsAndCols(rli, 0, 2);
+
+ fi.emit('data', '🐕');
+ assertCursorRowsAndCols(rli, 0, 4);
+
+ rli.on('line', common.mustCall((line) => {
+ assert.strictEqual(line, '💻🐕');
+ }));
+ fi.emit('data', '\n');
+ rli.close();
+}
+
+{
+ // `wordLeft` and `wordRight`
+ const [rli, fi] = getInterface({ terminal: true, prompt: '' });
+ fi.emit('data', 'the quick brown fox');
+ fi.emit('keypress', '.', { ctrl: true, name: 'left' });
+ assertCursorRowsAndCols(rli, 0, 16);
+ fi.emit('keypress', '.', { meta: true, name: 'b' });
+ assertCursorRowsAndCols(rli, 0, 10);
+ fi.emit('keypress', '.', { ctrl: true, name: 'right' });
+ assertCursorRowsAndCols(rli, 0, 16);
+ fi.emit('keypress', '.', { meta: true, name: 'f' });
+ assertCursorRowsAndCols(rli, 0, 19);
+ rli.close();
+}
+
+// `deleteWordLeft`
+[
+ { ctrl: true, name: 'w' },
+ { ctrl: true, name: 'backspace' },
+ { meta: true, name: 'backspace' },
+].forEach((deleteWordLeftKey) => {
+ let [rli, fi] = getInterface({ terminal: true, prompt: '' });
+ fi.emit('data', 'the quick brown fox');
+ fi.emit('keypress', '.', { ctrl: true, name: 'left' });
+ rli.on('line', common.mustCall((line) => {
+ assert.strictEqual(line, 'the quick fox');
+ }));
+ fi.emit('keypress', '.', deleteWordLeftKey);
+ fi.emit('data', '\n');
+ rli.close();
+
+ // No effect if pressed at beginning of line
+ [rli, fi] = getInterface({ terminal: true, prompt: '' });
+ fi.emit('data', 'the quick brown fox');
+ fi.emit('keypress', '.', { ctrl: true, name: 'a' });
+ rli.on('line', common.mustCall((line) => {
+ assert.strictEqual(line, 'the quick brown fox');
+ }));
+ fi.emit('keypress', '.', deleteWordLeftKey);
+ fi.emit('data', '\n');
+ rli.close();
+});
+
+// `deleteWordRight`
+[
+ { ctrl: true, name: 'delete' },
+ { meta: true, name: 'delete' },
+ { meta: true, name: 'd' },
+].forEach((deleteWordRightKey) => {
+ let [rli, fi] = getInterface({ terminal: true, prompt: '' });
+ fi.emit('data', 'the quick brown fox');
+ fi.emit('keypress', '.', { ctrl: true, name: 'left' });
+ fi.emit('keypress', '.', { ctrl: true, name: 'left' });
+ rli.on('line', common.mustCall((line) => {
+ assert.strictEqual(line, 'the quick fox');
+ }));
+ fi.emit('keypress', '.', deleteWordRightKey);
+ fi.emit('data', '\n');
+ rli.close();
+
+ // No effect if pressed at end of line
+ [rli, fi] = getInterface({ terminal: true, prompt: '' });
+ fi.emit('data', 'the quick brown fox');
+ rli.on('line', common.mustCall((line) => {
+ assert.strictEqual(line, 'the quick brown fox');
+ }));
+ fi.emit('keypress', '.', deleteWordRightKey);
+ fi.emit('data', '\n');
+ rli.close();
+});
+
+// deleteLeft
+{
+ const [rli, fi] = getInterface({ terminal: true, prompt: '' });
+ fi.emit('data', 'the quick brown fox');
+ assertCursorRowsAndCols(rli, 0, 19);
+
+ // Delete left character
+ fi.emit('keypress', '.', { ctrl: true, name: 'h' });
+ assertCursorRowsAndCols(rli, 0, 18);
+ rli.on('line', common.mustCall((line) => {
+ assert.strictEqual(line, 'the quick brown fo');
+ }));
+ fi.emit('data', '\n');
+ rli.close();
+}
+
+// deleteLeft astral character
+{
+ const [rli, fi] = getInterface({ terminal: true, prompt: '' });
+ fi.emit('data', '💻');
+ assertCursorRowsAndCols(rli, 0, 2);
+ // Delete left character
+ fi.emit('keypress', '.', { ctrl: true, name: 'h' });
+ assertCursorRowsAndCols(rli, 0, 0);
+ rli.on('line', common.mustCall((line) => {
+ assert.strictEqual(line, '');
+ }));
+ fi.emit('data', '\n');
+ rli.close();
+}
+
+// deleteRight
+{
+ const [rli, fi] = getInterface({ terminal: true, prompt: '' });
+ fi.emit('data', 'the quick brown fox');
+
+ // Go to the start of the line
+ fi.emit('keypress', '.', { ctrl: true, name: 'a' });
+ assertCursorRowsAndCols(rli, 0, 0);
+
+ // Delete right character
+ fi.emit('keypress', '.', { ctrl: true, name: 'd' });
+ assertCursorRowsAndCols(rli, 0, 0);
+ rli.on('line', common.mustCall((line) => {
+ assert.strictEqual(line, 'he quick brown fox');
+ }));
+ fi.emit('data', '\n');
+ rli.close();
+}
+
+// deleteRight astral character
+{
+ const [rli, fi] = getInterface({ terminal: true, prompt: '' });
+ fi.emit('data', '💻');
+
+ // Go to the start of the line
+ fi.emit('keypress', '.', { ctrl: true, name: 'a' });
+ assertCursorRowsAndCols(rli, 0, 0);
+
+ // Delete right character
+ fi.emit('keypress', '.', { ctrl: true, name: 'd' });
+ assertCursorRowsAndCols(rli, 0, 0);
+ rli.on('line', common.mustCall((line) => {
+ assert.strictEqual(line, '');
+ }));
+ fi.emit('data', '\n');
+ rli.close();
+}
+
+// deleteLineLeft
+{
+ const [rli, fi] = getInterface({ terminal: true, prompt: '' });
+ fi.emit('data', 'the quick brown fox');
+ assertCursorRowsAndCols(rli, 0, 19);
+
+ // Delete from current to start of line
+ fi.emit('keypress', '.', { ctrl: true, shift: true, name: 'backspace' });
+ assertCursorRowsAndCols(rli, 0, 0);
+ rli.on('line', common.mustCall((line) => {
+ assert.strictEqual(line, '');
+ }));
+ fi.emit('data', '\n');
+ rli.close();
+}
+
+// deleteLineRight
+{
+ const [rli, fi] = getInterface({ terminal: true, prompt: '' });
+ fi.emit('data', 'the quick brown fox');
+
+ // Go to the start of the line
+ fi.emit('keypress', '.', { ctrl: true, name: 'a' });
+ assertCursorRowsAndCols(rli, 0, 0);
+
+ // Delete from current to end of line
+ fi.emit('keypress', '.', { ctrl: true, shift: true, name: 'delete' });
+ assertCursorRowsAndCols(rli, 0, 0);
+ rli.on('line', common.mustCall((line) => {
+ assert.strictEqual(line, '');
+ }));
+ fi.emit('data', '\n');
+ rli.close();
+}
+
+// Close readline interface
+{
+ const [rli, fi] = getInterface({ terminal: true, prompt: '' });
+ fi.emit('keypress', '.', { ctrl: true, name: 'c' });
+ assert(rli.closed);
+}
+
+// Multi-line input cursor position
+{
+ const [rli, fi] = getInterface({ terminal: true, prompt: '' });
+ fi.columns = 10;
+ fi.emit('data', 'multi-line text');
+ assertCursorRowsAndCols(rli, 1, 5);
+ rli.close();
+}
+
+// Multi-line input cursor position and long tabs
+{
+ const [rli, fi] = getInterface({ tabSize: 16, terminal: true, prompt: '' });
+ fi.columns = 10;
+ fi.emit('data', 'multi-line\ttext \t');
+ assert.strictEqual(rli.cursor, 17);
+ assertCursorRowsAndCols(rli, 3, 2);
+ rli.close();
+}
+
+// Check for the default tab size.
+{
+ const [rli, fi] = getInterface({ terminal: true, prompt: '' });
+ fi.emit('data', 'the quick\tbrown\tfox');
+ assert.strictEqual(rli.cursor, 19);
+ // The first tab is 7 spaces long, the second one 3 spaces.
+ assertCursorRowsAndCols(rli, 0, 27);
+}
+
+// Multi-line prompt cursor position
+{
+ const [rli, fi] = getInterface({
+ terminal: true,
+ prompt: '\nfilledline\nwraping text\n> '
+ });
+ fi.columns = 10;
+ fi.emit('data', 't');
+ assertCursorRowsAndCols(rli, 4, 3);
+ rli.close();
+}
+
+// Clear the whole screen
+{
+ const [rli, fi] = getInterface({ terminal: true, prompt: '' });
+ const lines = ['line 1', 'line 2', 'line 3'];
+ fi.emit('data', lines.join('\n'));
+ fi.emit('keypress', '.', { ctrl: true, name: 'l' });
+ assertCursorRowsAndCols(rli, 0, 6);
+ rli.on('line', common.mustCall((line) => {
+ assert.strictEqual(line, 'line 3');
+ }));
+ fi.emit('data', '\n');
+ rli.close();
+}
+
+// Wide characters should be treated as two columns.
+assert.strictEqual(getStringWidth('a'), 1);
+assert.strictEqual(getStringWidth('あ'), 2);
+assert.strictEqual(getStringWidth('谢'), 2);
+assert.strictEqual(getStringWidth('고'), 2);
+assert.strictEqual(getStringWidth(String.fromCodePoint(0x1f251)), 2);
+assert.strictEqual(getStringWidth('abcde'), 5);
+assert.strictEqual(getStringWidth('古池や'), 6);
+assert.strictEqual(getStringWidth('ノード.js'), 9);
+assert.strictEqual(getStringWidth('你好'), 4);
+assert.strictEqual(getStringWidth('안녕하세요'), 10);
+assert.strictEqual(getStringWidth('A\ud83c\ude00BC'), 5);
+assert.strictEqual(getStringWidth('👨‍👩‍👦‍👦'), 8);
+assert.strictEqual(getStringWidth('🐕𐐷あ💻😀'), 9);
+// TODO(BridgeAR): This should have a width of 4.
+assert.strictEqual(getStringWidth('⓬⓪'), 2);
+assert.strictEqual(getStringWidth('\u0301\u200D\u200E'), 0);
+
+// Check if vt control chars are stripped
+assert.strictEqual(stripVTControlCharacters('\u001b[31m> \u001b[39m'), '> ');
+assert.strictEqual(
+ stripVTControlCharacters('\u001b[31m> \u001b[39m> '),
+ '> > '
+);
+assert.strictEqual(stripVTControlCharacters('\u001b[31m\u001b[39m'), '');
+assert.strictEqual(stripVTControlCharacters('> '), '> ');
+assert.strictEqual(getStringWidth('\u001b[31m> \u001b[39m'), 2);
+assert.strictEqual(getStringWidth('\u001b[31m> \u001b[39m> '), 4);
+assert.strictEqual(getStringWidth('\u001b[31m\u001b[39m'), 0);
+assert.strictEqual(getStringWidth('> '), 2);
+
+// FIXME(bartlomieju): this causes hang
+// Check EventEmitter memory leak
+// for (let i = 0; i < 12; i++) {
+// const rl = readline.createInterface({
+// input: process.stdin,
+// output: process.stdout
+// });
+// rl.close();
+// assert.strictEqual(isWarned(process.stdin._events), false);
+// assert.strictEqual(isWarned(process.stdout._events), false);
+// }
+
+[true, false].forEach((terminal) => {
+ // Disable history
+ {
+ const [rli, fi] = getInterface({ terminal, historySize: 0 });
+ assert.strictEqual(rli.historySize, 0);
+
+ fi.emit('data', 'asdf\n');
+ assert.deepStrictEqual(rli.history, []);
+ rli.close();
+ }
+
+ // Default history size 30
+ {
+ const [rli, fi] = getInterface({ terminal });
+ assert.strictEqual(rli.historySize, 30);
+
+ fi.emit('data', 'asdf\n');
+ assert.deepStrictEqual(rli.history, terminal ? ['asdf'] : []);
+ rli.close();
+ }
+
+ // Sending a full line
+ {
+ const [rli, fi] = getInterface({ terminal });
+ rli.on('line', common.mustCall((line) => {
+ assert.strictEqual(line, 'asdf');
+ }));
+ fi.emit('data', 'asdf\n');
+ }
+
+ // Sending a blank line
+ {
+ const [rli, fi] = getInterface({ terminal });
+ rli.on('line', common.mustCall((line) => {
+ assert.strictEqual(line, '');
+ }));
+ fi.emit('data', '\n');
+ }
+
+ // Sending a single character with no newline and then a newline
+ {
+ const [rli, fi] = getInterface({ terminal });
+ let called = false;
+ rli.on('line', (line) => {
+ called = true;
+ assert.strictEqual(line, 'a');
+ });
+ fi.emit('data', 'a');
+ assert.ok(!called);
+ fi.emit('data', '\n');
+ assert.ok(called);
+ rli.close();
+ }
+
+ // Sending multiple newlines at once
+ {
+ const [rli, fi] = getInterface({ terminal });
+ const expectedLines = ['foo', 'bar', 'baz'];
+ rli.on('line', common.mustCall((line) => {
+ assert.strictEqual(line, expectedLines.shift());
+ }, expectedLines.length));
+ fi.emit('data', `${expectedLines.join('\n')}\n`);
+ rli.close();
+ }
+
+ // Sending multiple newlines at once that does not end with a new line
+ {
+ const [rli, fi] = getInterface({ terminal });
+ const expectedLines = ['foo', 'bar', 'baz', 'bat'];
+ rli.on('line', common.mustCall((line) => {
+ assert.strictEqual(line, expectedLines.shift());
+ }, expectedLines.length - 1));
+ fi.emit('data', expectedLines.join('\n'));
+ rli.close();
+ }
+
+ // Sending multiple newlines at once that does not end with a new(empty)
+ // line and a `end` event
+ {
+ const [rli, fi] = getInterface({ terminal });
+ const expectedLines = ['foo', 'bar', 'baz', ''];
+ rli.on('line', common.mustCall((line) => {
+ assert.strictEqual(line, expectedLines.shift());
+ }, expectedLines.length - 1));
+ rli.on('close', common.mustCall());
+ fi.emit('data', expectedLines.join('\n'));
+ fi.emit('end');
+ rli.close();
+ }
+
+ // Sending a multi-byte utf8 char over multiple writes
+ {
+ const buf = Buffer.from('☮', 'utf8');
+ const [rli, fi] = getInterface({ terminal });
+ let callCount = 0;
+ rli.on('line', (line) => {
+ callCount++;
+ assert.strictEqual(line, buf.toString('utf8'));
+ });
+ for (const i of buf) {
+ fi.emit('data', Buffer.from([i]));
+ }
+ assert.strictEqual(callCount, 0);
+ fi.emit('data', '\n');
+ assert.strictEqual(callCount, 1);
+ rli.close();
+ }
+
+ // Calling readline without `new`
+ {
+ const [rli, fi] = getInterface({ terminal });
+ rli.on('line', common.mustCall((line) => {
+ assert.strictEqual(line, 'asdf');
+ }));
+ fi.emit('data', 'asdf\n');
+ rli.close();
+ }
+
+ // Calling the question callback
+ {
+ const [rli] = getInterface({ terminal });
+ rli.question('foo?', common.mustCall((answer) => {
+ assert.strictEqual(answer, 'bar');
+ }));
+ rli.write('bar\n');
+ rli.close();
+ }
+
+ // Calling the question multiple times
+ {
+ const [rli] = getInterface({ terminal });
+ rli.question('foo?', common.mustCall((answer) => {
+ assert.strictEqual(answer, 'baz');
+ }));
+ rli.question('bar?', common.mustNotCall(() => {
+ }));
+ rli.write('baz\n');
+ rli.close();
+ }
+
+ // Calling the promisified question
+ {
+ const [rli] = getInterface({ terminal });
+ const question = util.promisify(rli.question).bind(rli);
+ question('foo?')
+ .then(common.mustCall((answer) => {
+ assert.strictEqual(answer, 'bar');
+ }));
+ rli.write('bar\n');
+ rli.close();
+ }
+
+ // Aborting a question
+ {
+ const ac = new AbortController();
+ const signal = ac.signal;
+ const [rli] = getInterface({ terminal });
+ rli.on('line', common.mustCall((line) => {
+ assert.strictEqual(line, 'bar');
+ }));
+ rli.question('hello?', { signal }, common.mustNotCall());
+ ac.abort();
+ rli.write('bar\n');
+ rli.close();
+ }
+
+ // Aborting a promisified question
+ {
+ const ac = new AbortController();
+ const signal = ac.signal;
+ const [rli] = getInterface({ terminal });
+ const question = util.promisify(rli.question).bind(rli);
+ rli.on('line', common.mustCall((line) => {
+ assert.strictEqual(line, 'bar');
+ }));
+ question('hello?', { signal })
+ .then(common.mustNotCall())
+ .catch(common.mustCall((error) => {
+ assert.strictEqual(error.name, 'AbortError');
+ }));
+ ac.abort();
+ rli.write('bar\n');
+ rli.close();
+ }
+
+ // pre-aborted signal
+ {
+ const signal = AbortSignal.abort();
+ const [rli] = getInterface({ terminal });
+ rli.pause();
+ rli.on('resume', common.mustNotCall());
+ rli.question('hello?', { signal }, common.mustNotCall());
+ rli.close();
+ }
+
+ // pre-aborted signal promisified question
+ {
+ const signal = AbortSignal.abort();
+ const [rli] = getInterface({ terminal });
+ const question = util.promisify(rli.question).bind(rli);
+ rli.on('resume', common.mustNotCall());
+ rli.pause();
+ question('hello?', { signal })
+ .then(common.mustNotCall())
+ .catch(common.mustCall((error) => {
+ assert.strictEqual(error.name, 'AbortError');
+ }));
+ rli.close();
+ }
+
+ // Can create a new readline Interface with a null output argument
+ {
+ const [rli, fi] = getInterface({ output: null, terminal });
+ rli.on('line', common.mustCall((line) => {
+ assert.strictEqual(line, 'asdf');
+ }));
+ fi.emit('data', 'asdf\n');
+
+ rli.setPrompt('ddd> ');
+ rli.prompt();
+ rli.write("really shouldn't be seeing this");
+ rli.question('What do you think of node.js? ', (answer) => {
+ console.log('Thank you for your valuable feedback:', answer);
+ rli.close();
+ });
+ }
+
+ // Calling the getPrompt method
+ {
+ const expectedPrompts = ['$ ', '> '];
+ const [rli] = getInterface({ terminal });
+ for (const prompt of expectedPrompts) {
+ rli.setPrompt(prompt);
+ assert.strictEqual(rli.getPrompt(), prompt);
+ }
+ }
+
+ {
+ const expected = terminal ?
+ ['\u001b[1G', '\u001b[0J', '$ ', '\u001b[3G'] :
+ ['$ '];
+
+ const output = new Writable({
+ write: common.mustCall((chunk, enc, cb) => {
+ assert.strictEqual(chunk.toString(), expected.shift());
+ cb();
+ rl.close();
+ }, expected.length)
+ });
+
+ const rl = readline.createInterface({
+ input: new Readable({ read: common.mustCall() }),
+ output,
+ prompt: '$ ',
+ terminal
+ });
+
+ rl.prompt();
+
+ assert.strictEqual(rl.getPrompt(), '$ ');
+ }
+
+ {
+ const fi = new FakeInput();
+ assert.deepStrictEqual(fi.listeners(terminal ? 'keypress' : 'data'), []);
+ }
+
+ // Emit two line events when the delay
+ // between \r and \n exceeds crlfDelay
+ {
+ const crlfDelay = 200;
+ const [rli, fi] = getInterface({ terminal, crlfDelay });
+ let callCount = 0;
+ rli.on('line', () => {
+ callCount++;
+ });
+ fi.emit('data', '\r');
+ setTimeout(common.mustCall(() => {
+ fi.emit('data', '\n');
+ assert.strictEqual(callCount, 2);
+ rli.close();
+ }), crlfDelay + 10);
+ }
+
+ // For the purposes of the following tests, we do not care about the exact
+ // value of crlfDelay, only that the behaviour conforms to what's expected.
+ // Setting it to Infinity allows the test to succeed even under extreme
+ // CPU stress.
+ const crlfDelay = Infinity;
+
+ // Set crlfDelay to `Infinity` is allowed
+ {
+ const delay = 200;
+ const [rli, fi] = getInterface({ terminal, crlfDelay });
+ let callCount = 0;
+ rli.on('line', () => {
+ callCount++;
+ });
+ fi.emit('data', '\r');
+ setTimeout(common.mustCall(() => {
+ fi.emit('data', '\n');
+ assert.strictEqual(callCount, 1);
+ rli.close();
+ }), delay);
+ }
+
+ // Sending multiple newlines at once that does not end with a new line
+ // and a `end` event(last line is)
+
+ // \r\n should emit one line event, not two
+ {
+ const [rli, fi] = getInterface({ terminal, crlfDelay });
+ const expectedLines = ['foo', 'bar', 'baz', 'bat'];
+ rli.on('line', common.mustCall((line) => {
+ assert.strictEqual(line, expectedLines.shift());
+ }, expectedLines.length - 1));
+ fi.emit('data', expectedLines.join('\r\n'));
+ rli.close();
+ }
+
+ // \r\n should emit one line event when split across multiple writes.
+ {
+ const [rli, fi] = getInterface({ terminal, crlfDelay });
+ const expectedLines = ['foo', 'bar', 'baz', 'bat'];
+ let callCount = 0;
+ rli.on('line', common.mustCall((line) => {
+ assert.strictEqual(line, expectedLines[callCount]);
+ callCount++;
+ }, expectedLines.length));
+ expectedLines.forEach((line) => {
+ fi.emit('data', `${line}\r`);
+ fi.emit('data', '\n');
+ });
+ rli.close();
+ }
+
+ // Emit one line event when the delay between \r and \n is
+ // over the default crlfDelay but within the setting value.
+ {
+ const delay = 125;
+ const [rli, fi] = getInterface({ terminal, crlfDelay });
+ let callCount = 0;
+ rli.on('line', () => callCount++);
+ fi.emit('data', '\r');
+ setTimeout(common.mustCall(() => {
+ fi.emit('data', '\n');
+ assert.strictEqual(callCount, 1);
+ rli.close();
+ }), delay);
+ }
+});
+
+// Ensure that the _wordLeft method works even for large input
+{
+ const input = new Readable({
+ read() {
+ this.push('\x1B[1;5D'); // CTRL + Left
+ this.push(null);
+ },
+ });
+ const output = new Writable({
+ write: common.mustCall((data, encoding, cb) => {
+ assert.strictEqual(rl.cursor, rl.line.length - 1);
+ cb();
+ }),
+ });
+ const rl = new readline.createInterface({
+ input,
+ output,
+ terminal: true,
+ });
+ rl.line = `a${' '.repeat(1e6)}a`;
+ rl.cursor = rl.line.length;
+}
+
+// FIXME(bartlomieju): these tests depend on "event_target" module
+// {
+// const fi = new FakeInput();
+// const signal = AbortSignal.abort();
+
+// const rl = readline.createInterface({
+// input: fi,
+// output: fi,
+// signal,
+// });
+// rl.on('close', common.mustCall());
+// assert.strictEqual(getEventListeners(signal, 'abort').length, 0);
+// }
+
+// {
+// const fi = new FakeInput();
+// const ac = new AbortController();
+// const { signal } = ac;
+// const rl = readline.createInterface({
+// input: fi,
+// output: fi,
+// signal,
+// });
+// assert.strictEqual(getEventListeners(signal, 'abort').length, 1);
+// rl.on('close', common.mustCall());
+// ac.abort();
+// assert.strictEqual(getEventListeners(signal, 'abort').length, 0);
+// }
+
+// {
+// const fi = new FakeInput();
+// const ac = new AbortController();
+// const { signal } = ac;
+// const rl = readline.createInterface({
+// input: fi,
+// output: fi,
+// signal,
+// });
+// assert.strictEqual(getEventListeners(signal, 'abort').length, 1);
+// rl.close();
+// assert.strictEqual(getEventListeners(signal, 'abort').length, 0);
+// }
+
+{
+ // Constructor throws if signal is not an abort signal
+ assert.throws(() => {
+ readline.createInterface({
+ input: new FakeInput(),
+ signal: {},
+ });
+ }, {
+ name: 'TypeError',
+ code: 'ERR_INVALID_ARG_TYPE'
+ });
+}
diff --git a/tests/node_compat/test/parallel/test-readline-keys.js b/tests/node_compat/test/parallel/test-readline-keys.js
new file mode 100644
index 000000000..aeeb5fffc
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-readline-keys.js
@@ -0,0 +1,351 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const PassThrough = require('stream').PassThrough;
+const assert = require('assert');
+const Interface = require('readline').Interface;
+
+class FakeInput extends PassThrough {}
+
+function extend(k) {
+ return Object.assign({ ctrl: false, meta: false, shift: false }, k);
+}
+
+
+const fi = new FakeInput();
+const fo = new FakeInput();
+new Interface({ input: fi, output: fo, terminal: true });
+
+let keys = [];
+fi.on('keypress', (s, k) => {
+ keys.push(k);
+});
+
+
+function addTest(sequences, expectedKeys) {
+ if (!Array.isArray(sequences)) {
+ sequences = [ sequences ];
+ }
+
+ if (!Array.isArray(expectedKeys)) {
+ expectedKeys = [ expectedKeys ];
+ }
+
+ expectedKeys = expectedKeys.map(extend);
+
+ keys = [];
+
+ sequences.forEach((sequence) => {
+ fi.write(sequence);
+ });
+ assert.deepStrictEqual(keys, expectedKeys);
+}
+
+// Simulate key interval test cases
+// Returns a function that takes `next` test case and returns a thunk
+// that can be called to run tests in sequence
+// e.g.
+// addKeyIntervalTest(..)
+// (addKeyIntervalTest(..)
+// (addKeyIntervalTest(..)(noop)))()
+// where noop is a terminal function(() => {}).
+
+const addKeyIntervalTest = (sequences, expectedKeys, interval = 550,
+ assertDelay = 550) => {
+ const fn = common.mustCall((next) => () => {
+
+ if (!Array.isArray(sequences)) {
+ sequences = [ sequences ];
+ }
+
+ if (!Array.isArray(expectedKeys)) {
+ expectedKeys = [ expectedKeys ];
+ }
+
+ expectedKeys = expectedKeys.map(extend);
+
+ const keys = [];
+ fi.on('keypress', (s, k) => keys.push(k));
+
+ const emitKeys = ([head, ...tail]) => {
+ if (head) {
+ fi.write(head);
+ setTimeout(() => emitKeys(tail), interval);
+ } else {
+ setTimeout(() => {
+ next();
+ assert.deepStrictEqual(keys, expectedKeys);
+ }, assertDelay);
+ }
+ };
+ emitKeys(sequences);
+ });
+ return fn;
+};
+
+// Regular alphanumerics
+addTest('io.JS', [
+ { name: 'i', sequence: 'i' },
+ { name: 'o', sequence: 'o' },
+ { name: undefined, sequence: '.' },
+ { name: 'j', sequence: 'J', shift: true },
+ { name: 's', sequence: 'S', shift: true },
+]);
+
+// Named characters
+addTest('\n\r\t\x1b\n\x1b\r\x1b\t', [
+ { name: 'enter', sequence: '\n' },
+ { name: 'return', sequence: '\r' },
+ { name: 'tab', sequence: '\t' },
+ { name: 'enter', sequence: '\x1b\n', meta: true },
+ { name: 'return', sequence: '\x1b\r', meta: true },
+ { name: 'tab', sequence: '\x1b\t', meta: true },
+]);
+
+// Space and backspace
+addTest('\b\x7f\x1b\b\x1b\x7f\x1b\x1b \x1b ', [
+ { name: 'backspace', sequence: '\b' },
+ { name: 'backspace', sequence: '\x7f' },
+ { name: 'backspace', sequence: '\x1b\b', meta: true },
+ { name: 'backspace', sequence: '\x1b\x7f', meta: true },
+ { name: 'space', sequence: '\x1b\x1b ', meta: true },
+ { name: 'space', sequence: ' ' },
+ { name: 'space', sequence: '\x1b ', meta: true },
+]);
+
+// Escape key
+addTest('\x1b\x1b\x1b', [
+ { name: 'escape', sequence: '\x1b\x1b\x1b', meta: true },
+]);
+
+// Escape sequence
+addTest('\x1b]', [{ name: undefined, sequence: '\x1B]', meta: true }]);
+
+// Control keys
+addTest('\x01\x0b\x10', [
+ { name: 'a', sequence: '\x01', ctrl: true },
+ { name: 'k', sequence: '\x0b', ctrl: true },
+ { name: 'p', sequence: '\x10', ctrl: true },
+]);
+
+// Alt keys
+addTest('a\x1baA\x1bA', [
+ { name: 'a', sequence: 'a' },
+ { name: 'a', sequence: '\x1ba', meta: true },
+ { name: 'a', sequence: 'A', shift: true },
+ { name: 'a', sequence: '\x1bA', meta: true, shift: true },
+]);
+
+// xterm/gnome ESC [ letter (with modifiers)
+addTest('\x1b[2P\x1b[3P\x1b[4P\x1b[5P\x1b[6P\x1b[7P\x1b[8P\x1b[3Q\x1b[8Q\x1b[3R\x1b[8R\x1b[3S\x1b[8S', [
+ { name: 'f1', sequence: '\x1b[2P', code: '[P', shift: true, meta: false, ctrl: false },
+ { name: 'f1', sequence: '\x1b[3P', code: '[P', shift: false, meta: true, ctrl: false },
+ { name: 'f1', sequence: '\x1b[4P', code: '[P', shift: true, meta: true, ctrl: false },
+ { name: 'f1', sequence: '\x1b[5P', code: '[P', shift: false, meta: false, ctrl: true },
+ { name: 'f1', sequence: '\x1b[6P', code: '[P', shift: true, meta: false, ctrl: true },
+ { name: 'f1', sequence: '\x1b[7P', code: '[P', shift: false, meta: true, ctrl: true },
+ { name: 'f1', sequence: '\x1b[8P', code: '[P', shift: true, meta: true, ctrl: true },
+ { name: 'f2', sequence: '\x1b[3Q', code: '[Q', meta: true },
+ { name: 'f2', sequence: '\x1b[8Q', code: '[Q', shift: true, meta: true, ctrl: true },
+ { name: 'f3', sequence: '\x1b[3R', code: '[R', meta: true },
+ { name: 'f3', sequence: '\x1b[8R', code: '[R', shift: true, meta: true, ctrl: true },
+ { name: 'f4', sequence: '\x1b[3S', code: '[S', meta: true },
+ { name: 'f4', sequence: '\x1b[8S', code: '[S', shift: true, meta: true, ctrl: true },
+]);
+
+// xterm/gnome ESC O letter
+addTest('\x1bOP\x1bOQ\x1bOR\x1bOS', [
+ { name: 'f1', sequence: '\x1bOP', code: 'OP' },
+ { name: 'f2', sequence: '\x1bOQ', code: 'OQ' },
+ { name: 'f3', sequence: '\x1bOR', code: 'OR' },
+ { name: 'f4', sequence: '\x1bOS', code: 'OS' },
+]);
+
+// xterm/rxvt ESC [ number ~ */
+addTest('\x1b[11~\x1b[12~\x1b[13~\x1b[14~', [
+ { name: 'f1', sequence: '\x1b[11~', code: '[11~' },
+ { name: 'f2', sequence: '\x1b[12~', code: '[12~' },
+ { name: 'f3', sequence: '\x1b[13~', code: '[13~' },
+ { name: 'f4', sequence: '\x1b[14~', code: '[14~' },
+]);
+
+// From Cygwin and used in libuv
+addTest('\x1b[[A\x1b[[B\x1b[[C\x1b[[D\x1b[[E', [
+ { name: 'f1', sequence: '\x1b[[A', code: '[[A' },
+ { name: 'f2', sequence: '\x1b[[B', code: '[[B' },
+ { name: 'f3', sequence: '\x1b[[C', code: '[[C' },
+ { name: 'f4', sequence: '\x1b[[D', code: '[[D' },
+ { name: 'f5', sequence: '\x1b[[E', code: '[[E' },
+]);
+
+// Common
+addTest('\x1b[15~\x1b[17~\x1b[18~\x1b[19~\x1b[20~\x1b[21~\x1b[23~\x1b[24~', [
+ { name: 'f5', sequence: '\x1b[15~', code: '[15~' },
+ { name: 'f6', sequence: '\x1b[17~', code: '[17~' },
+ { name: 'f7', sequence: '\x1b[18~', code: '[18~' },
+ { name: 'f8', sequence: '\x1b[19~', code: '[19~' },
+ { name: 'f9', sequence: '\x1b[20~', code: '[20~' },
+ { name: 'f10', sequence: '\x1b[21~', code: '[21~' },
+ { name: 'f11', sequence: '\x1b[23~', code: '[23~' },
+ { name: 'f12', sequence: '\x1b[24~', code: '[24~' },
+]);
+
+// xterm ESC [ letter
+addTest('\x1b[A\x1b[B\x1b[C\x1b[D\x1b[E\x1b[F\x1b[H', [
+ { name: 'up', sequence: '\x1b[A', code: '[A' },
+ { name: 'down', sequence: '\x1b[B', code: '[B' },
+ { name: 'right', sequence: '\x1b[C', code: '[C' },
+ { name: 'left', sequence: '\x1b[D', code: '[D' },
+ { name: 'clear', sequence: '\x1b[E', code: '[E' },
+ { name: 'end', sequence: '\x1b[F', code: '[F' },
+ { name: 'home', sequence: '\x1b[H', code: '[H' },
+]);
+
+// xterm/gnome ESC O letter
+addTest('\x1bOA\x1bOB\x1bOC\x1bOD\x1bOE\x1bOF\x1bOH', [
+ { name: 'up', sequence: '\x1bOA', code: 'OA' },
+ { name: 'down', sequence: '\x1bOB', code: 'OB' },
+ { name: 'right', sequence: '\x1bOC', code: 'OC' },
+ { name: 'left', sequence: '\x1bOD', code: 'OD' },
+ { name: 'clear', sequence: '\x1bOE', code: 'OE' },
+ { name: 'end', sequence: '\x1bOF', code: 'OF' },
+ { name: 'home', sequence: '\x1bOH', code: 'OH' },
+]);
+
+// Old xterm shift-arrows
+addTest('\x1bO2A\x1bO2B', [
+ { name: 'up', sequence: '\x1bO2A', code: 'OA', shift: true },
+ { name: 'down', sequence: '\x1bO2B', code: 'OB', shift: true },
+]);
+
+// xterm/rxvt ESC [ number ~
+addTest('\x1b[1~\x1b[2~\x1b[3~\x1b[4~\x1b[5~\x1b[6~', [
+ { name: 'home', sequence: '\x1b[1~', code: '[1~' },
+ { name: 'insert', sequence: '\x1b[2~', code: '[2~' },
+ { name: 'delete', sequence: '\x1b[3~', code: '[3~' },
+ { name: 'end', sequence: '\x1b[4~', code: '[4~' },
+ { name: 'pageup', sequence: '\x1b[5~', code: '[5~' },
+ { name: 'pagedown', sequence: '\x1b[6~', code: '[6~' },
+]);
+
+// putty
+addTest('\x1b[[5~\x1b[[6~', [
+ { name: 'pageup', sequence: '\x1b[[5~', code: '[[5~' },
+ { name: 'pagedown', sequence: '\x1b[[6~', code: '[[6~' },
+]);
+
+// rxvt
+addTest('\x1b[7~\x1b[8~', [
+ { name: 'home', sequence: '\x1b[7~', code: '[7~' },
+ { name: 'end', sequence: '\x1b[8~', code: '[8~' },
+]);
+
+// gnome terminal
+addTest('\x1b[A\x1b[B\x1b[2A\x1b[2B', [
+ { name: 'up', sequence: '\x1b[A', code: '[A' },
+ { name: 'down', sequence: '\x1b[B', code: '[B' },
+ { name: 'up', sequence: '\x1b[2A', code: '[A', shift: true },
+ { name: 'down', sequence: '\x1b[2B', code: '[B', shift: true },
+]);
+
+// `rxvt` keys with modifiers.
+addTest('\x1b[20~\x1b[2$\x1b[2^\x1b[3$\x1b[3^\x1b[5$\x1b[5^\x1b[6$\x1b[6^\x1b[7$\x1b[7^\x1b[8$\x1b[8^', [
+ { name: 'f9', sequence: '\x1b[20~', code: '[20~' },
+ { name: 'insert', sequence: '\x1b[2$', code: '[2$', shift: true },
+ { name: 'insert', sequence: '\x1b[2^', code: '[2^', ctrl: true },
+ { name: 'delete', sequence: '\x1b[3$', code: '[3$', shift: true },
+ { name: 'delete', sequence: '\x1b[3^', code: '[3^', ctrl: true },
+ { name: 'pageup', sequence: '\x1b[5$', code: '[5$', shift: true },
+ { name: 'pageup', sequence: '\x1b[5^', code: '[5^', ctrl: true },
+ { name: 'pagedown', sequence: '\x1b[6$', code: '[6$', shift: true },
+ { name: 'pagedown', sequence: '\x1b[6^', code: '[6^', ctrl: true },
+ { name: 'home', sequence: '\x1b[7$', code: '[7$', shift: true },
+ { name: 'home', sequence: '\x1b[7^', code: '[7^', ctrl: true },
+ { name: 'end', sequence: '\x1b[8$', code: '[8$', shift: true },
+ { name: 'end', sequence: '\x1b[8^', code: '[8^', ctrl: true },
+]);
+
+// Misc
+addTest('\x1b[Z', [
+ { name: 'tab', sequence: '\x1b[Z', code: '[Z', shift: true },
+]);
+
+// xterm + modifiers
+addTest('\x1b[20;5~\x1b[6;5^', [
+ { name: 'f9', sequence: '\x1b[20;5~', code: '[20~', ctrl: true },
+ { name: 'pagedown', sequence: '\x1b[6;5^', code: '[6^', ctrl: true },
+]);
+
+addTest('\x1b[H\x1b[5H\x1b[1;5H', [
+ { name: 'home', sequence: '\x1b[H', code: '[H' },
+ { name: 'home', sequence: '\x1b[5H', code: '[H', ctrl: true },
+ { name: 'home', sequence: '\x1b[1;5H', code: '[H', ctrl: true },
+]);
+
+// Escape sequences broken into multiple data chunks
+addTest('\x1b[D\x1b[C\x1b[D\x1b[C'.split(''), [
+ { name: 'left', sequence: '\x1b[D', code: '[D' },
+ { name: 'right', sequence: '\x1b[C', code: '[C' },
+ { name: 'left', sequence: '\x1b[D', code: '[D' },
+ { name: 'right', sequence: '\x1b[C', code: '[C' },
+]);
+
+// Escape sequences mixed with regular ones
+addTest('\x1b[DD\x1b[2DD\x1b[2^D', [
+ { name: 'left', sequence: '\x1b[D', code: '[D' },
+ { name: 'd', sequence: 'D', shift: true },
+ { name: 'left', sequence: '\x1b[2D', code: '[D', shift: true },
+ { name: 'd', sequence: 'D', shift: true },
+ { name: 'insert', sequence: '\x1b[2^', code: '[2^', ctrl: true },
+ { name: 'd', sequence: 'D', shift: true },
+]);
+
+// Color sequences
+addTest('\x1b[31ma\x1b[39ma', [
+ { name: 'undefined', sequence: '\x1b[31m', code: '[31m' },
+ { name: 'a', sequence: 'a' },
+ { name: 'undefined', sequence: '\x1b[39m', code: '[39m' },
+ { name: 'a', sequence: 'a' },
+]);
+
+// `rxvt` keys with modifiers.
+addTest('\x1b[a\x1b[b\x1b[c\x1b[d\x1b[e', [
+ { name: 'up', sequence: '\x1b[a', code: '[a', shift: true },
+ { name: 'down', sequence: '\x1b[b', code: '[b', shift: true },
+ { name: 'right', sequence: '\x1b[c', code: '[c', shift: true },
+ { name: 'left', sequence: '\x1b[d', code: '[d', shift: true },
+ { name: 'clear', sequence: '\x1b[e', code: '[e', shift: true },
+]);
+
+addTest('\x1bOa\x1bOb\x1bOc\x1bOd\x1bOe', [
+ { name: 'up', sequence: '\x1bOa', code: 'Oa', ctrl: true },
+ { name: 'down', sequence: '\x1bOb', code: 'Ob', ctrl: true },
+ { name: 'right', sequence: '\x1bOc', code: 'Oc', ctrl: true },
+ { name: 'left', sequence: '\x1bOd', code: 'Od', ctrl: true },
+ { name: 'clear', sequence: '\x1bOe', code: 'Oe', ctrl: true },
+]);
+
+// Reduce array of addKeyIntervalTest(..) right to left
+// with () => {} as initial function.
+const runKeyIntervalTests = [
+ // Escape character
+ addKeyIntervalTest('\x1b', [
+ { name: 'escape', sequence: '\x1b', meta: true },
+ ]),
+ // Chain of escape characters.
+ addKeyIntervalTest('\x1b\x1b\x1b\x1b'.split(''), [
+ { name: 'escape', sequence: '\x1b', meta: true },
+ { name: 'escape', sequence: '\x1b', meta: true },
+ { name: 'escape', sequence: '\x1b', meta: true },
+ { name: 'escape', sequence: '\x1b', meta: true },
+ ]),
+].reverse().reduce((acc, fn) => fn(acc), () => {});
+
+// Run key interval tests one after another.
+runKeyIntervalTests();
diff --git a/tests/node_compat/test/parallel/test-readline-position.js b/tests/node_compat/test/parallel/test-readline-position.js
new file mode 100644
index 000000000..5ee445c8e
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-readline-position.js
@@ -0,0 +1,43 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Flags: --expose-internals
+'use strict';
+const common = require('../common');
+const { PassThrough } = require('stream');
+const readline = require('readline');
+const assert = require('assert');
+
+const ctrlU = { ctrl: true, name: 'u' };
+
+common.skipIfDumbTerminal();
+
+{
+ const input = new PassThrough();
+ const rl = readline.createInterface({
+ terminal: true,
+ input: input,
+ prompt: ''
+ });
+
+ const tests = [
+ [1, 'a'],
+ [2, 'ab'],
+ [2, '丁'],
+ [0, '\u0301'], // COMBINING ACUTE ACCENT
+ [1, 'a\u0301'], // á
+ [0, '\u20DD'], // COMBINING ENCLOSING CIRCLE
+ [2, 'a\u20DDb'], // a⃝b
+ [0, '\u200E'], // LEFT-TO-RIGHT MARK
+ ];
+
+ for (const [cursor, string] of tests) {
+ rl.write(string);
+ assert.strictEqual(rl.getCursorPos().cols, cursor);
+ rl.write(null, ctrlU);
+ }
+}
diff --git a/tests/node_compat/test/parallel/test-readline-reopen.js b/tests/node_compat/test/parallel/test-readline-reopen.js
new file mode 100644
index 000000000..6d3207220
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-readline-reopen.js
@@ -0,0 +1,51 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+// Regression test for https://github.com/nodejs/node/issues/13557
+// Tests that multiple subsequent readline instances can re-use an input stream.
+
+const common = require('../common');
+const assert = require('assert');
+const readline = require('readline');
+const { PassThrough } = require('stream');
+
+const input = new PassThrough();
+const output = new PassThrough();
+
+const rl1 = readline.createInterface({
+ input,
+ output,
+ terminal: true
+});
+
+rl1.on('line', common.mustCall(rl1OnLine));
+
+// Write a line plus the first byte of a UTF-8 multibyte character to make sure
+// that it doesn’t get lost when closing the readline instance.
+input.write(Buffer.concat([
+ Buffer.from('foo\n'),
+ Buffer.from([ 0xe2 ]), // Exactly one third of a ☃ snowman.
+]));
+
+function rl1OnLine(line) {
+ assert.strictEqual(line, 'foo');
+ rl1.close();
+ const rl2 = readline.createInterface({
+ input,
+ output,
+ terminal: true
+ });
+
+ rl2.on('line', common.mustCall((line) => {
+ assert.strictEqual(line, '☃bar');
+ rl2.close();
+ }));
+ input.write(Buffer.from([0x98, 0x83])); // The rest of the ☃ snowman.
+ input.write('bar\n');
+}
diff --git a/tests/node_compat/test/parallel/test-readline-set-raw-mode.js b/tests/node_compat/test/parallel/test-readline-set-raw-mode.js
new file mode 100644
index 000000000..a1f4f743d
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-readline-set-raw-mode.js
@@ -0,0 +1,97 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+const readline = require('readline');
+const Stream = require('stream');
+
+const stream = new Stream();
+let expectedRawMode = true;
+let rawModeCalled = false;
+let resumeCalled = false;
+let pauseCalled = false;
+
+stream.setRawMode = function(mode) {
+ rawModeCalled = true;
+ assert.strictEqual(mode, expectedRawMode);
+};
+stream.resume = function() {
+ resumeCalled = true;
+};
+stream.pause = function() {
+ pauseCalled = true;
+};
+
+// When the "readline" starts in "terminal" mode,
+// then setRawMode(true) should be called
+const rli = readline.createInterface({
+ input: stream,
+ output: stream,
+ terminal: true
+});
+assert(rli.terminal);
+assert(rawModeCalled);
+assert(resumeCalled);
+assert(!pauseCalled);
+
+
+// pause() should call *not* call setRawMode()
+rawModeCalled = false;
+resumeCalled = false;
+pauseCalled = false;
+rli.pause();
+assert(!rawModeCalled);
+assert(!resumeCalled);
+assert(pauseCalled);
+
+
+// resume() should *not* call setRawMode()
+rawModeCalled = false;
+resumeCalled = false;
+pauseCalled = false;
+rli.resume();
+assert(!rawModeCalled);
+assert(resumeCalled);
+assert(!pauseCalled);
+
+
+// close() should call setRawMode(false)
+expectedRawMode = false;
+rawModeCalled = false;
+resumeCalled = false;
+pauseCalled = false;
+rli.close();
+assert(rawModeCalled);
+assert(!resumeCalled);
+assert(pauseCalled);
+
+assert.deepStrictEqual(stream.listeners('keypress'), []);
+// One data listener for the keypress events.
+assert.strictEqual(stream.listeners('data').length, 1);
diff --git a/tests/node_compat/test/parallel/test-readline-undefined-columns.js b/tests/node_compat/test/parallel/test-readline-undefined-columns.js
new file mode 100644
index 000000000..e41798ae3
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-readline-undefined-columns.js
@@ -0,0 +1,53 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const assert = require('assert');
+const PassThrough = require('stream').PassThrough;
+const readline = require('readline');
+
+common.skipIfDumbTerminal();
+
+// Checks that tab completion still works
+// when output column size is undefined
+
+const iStream = new PassThrough();
+const oStream = new PassThrough();
+
+readline.createInterface({
+ terminal: true,
+ input: iStream,
+ output: oStream,
+ completer: function(line, cb) {
+ cb(null, [['process.stdout', 'process.stdin', 'process.stderr'], line]);
+ }
+});
+
+let output = '';
+
+oStream.on('data', function(data) {
+ output += data;
+});
+
+oStream.on('end', common.mustCall(() => {
+ const expect = 'process.stdout\r\n' +
+ 'process.stdin\r\n' +
+ 'process.stderr';
+ assert.match(output, new RegExp(expect));
+}));
+
+iStream.write('process.s\t');
+
+// Completion works.
+assert.match(output, /process\.std\b/);
+// Completion doesn’t show all results yet.
+assert.doesNotMatch(output, /stdout/);
+
+iStream.write('\t');
+oStream.end();
diff --git a/tests/node_compat/test/parallel/test-readline.js b/tests/node_compat/test/parallel/test-readline.js
new file mode 100644
index 000000000..15f1b4f0c
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-readline.js
@@ -0,0 +1,158 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const { PassThrough } = require('stream');
+const readline = require('readline');
+const assert = require('assert');
+
+common.skipIfDumbTerminal();
+
+{
+ const input = new PassThrough();
+ const rl = readline.createInterface({
+ terminal: true,
+ input: input
+ });
+
+ rl.on('line', common.mustCall((data) => {
+ assert.strictEqual(data, 'abc');
+ }));
+
+ input.end('abc');
+}
+
+{
+ const input = new PassThrough();
+ const rl = readline.createInterface({
+ terminal: true,
+ input: input
+ });
+
+ rl.on('line', common.mustNotCall('must not be called before newline'));
+
+ input.write('abc');
+}
+
+{
+ const input = new PassThrough();
+ const rl = readline.createInterface({
+ terminal: true,
+ input: input
+ });
+
+ rl.on('line', common.mustCall((data) => {
+ assert.strictEqual(data, 'abc');
+ }));
+
+ input.write('abc\n');
+}
+
+{
+ const input = new PassThrough();
+ const rl = readline.createInterface({
+ terminal: true,
+ input: input
+ });
+
+ rl.write('foo');
+ assert.strictEqual(rl.cursor, 3);
+
+ const key = {
+ xterm: {
+ home: ['\x1b[H', { ctrl: true, name: 'a' }],
+ end: ['\x1b[F', { ctrl: true, name: 'e' }],
+ },
+ gnome: {
+ home: ['\x1bOH', { ctrl: true, name: 'a' }],
+ end: ['\x1bOF', { ctrl: true, name: 'e' }]
+ },
+ rxvt: {
+ home: ['\x1b[7', { ctrl: true, name: 'a' }],
+ end: ['\x1b[8', { ctrl: true, name: 'e' }]
+ },
+ putty: {
+ home: ['\x1b[1~', { ctrl: true, name: 'a' }],
+ end: ['\x1b[>~', { ctrl: true, name: 'e' }]
+ }
+ };
+
+ [key.xterm, key.gnome, key.rxvt, key.putty].forEach(function(key) {
+ rl.write.apply(rl, key.home);
+ assert.strictEqual(rl.cursor, 0);
+ rl.write.apply(rl, key.end);
+ assert.strictEqual(rl.cursor, 3);
+ });
+
+}
+
+{
+ const input = new PassThrough();
+ const rl = readline.createInterface({
+ terminal: true,
+ input: input
+ });
+
+ const key = {
+ xterm: {
+ home: ['\x1b[H', { ctrl: true, name: 'a' }],
+ metab: ['\x1bb', { meta: true, name: 'b' }],
+ metaf: ['\x1bf', { meta: true, name: 'f' }],
+ }
+ };
+
+ rl.write('foo bar.hop/zoo');
+ rl.write.apply(rl, key.xterm.home);
+ [
+ { cursor: 4, key: key.xterm.metaf },
+ { cursor: 7, key: key.xterm.metaf },
+ { cursor: 8, key: key.xterm.metaf },
+ { cursor: 11, key: key.xterm.metaf },
+ { cursor: 12, key: key.xterm.metaf },
+ { cursor: 15, key: key.xterm.metaf },
+ { cursor: 12, key: key.xterm.metab },
+ { cursor: 11, key: key.xterm.metab },
+ { cursor: 8, key: key.xterm.metab },
+ { cursor: 7, key: key.xterm.metab },
+ { cursor: 4, key: key.xterm.metab },
+ { cursor: 0, key: key.xterm.metab },
+ ].forEach(function(action) {
+ rl.write.apply(rl, action.key);
+ assert.strictEqual(rl.cursor, action.cursor);
+ });
+}
+
+{
+ const input = new PassThrough();
+ const rl = readline.createInterface({
+ terminal: true,
+ input: input
+ });
+
+ const key = {
+ xterm: {
+ home: ['\x1b[H', { ctrl: true, name: 'a' }],
+ metad: ['\x1bd', { meta: true, name: 'd' }]
+ }
+ };
+
+ rl.write('foo bar.hop/zoo');
+ rl.write.apply(rl, key.xterm.home);
+ [
+ 'bar.hop/zoo',
+ '.hop/zoo',
+ 'hop/zoo',
+ '/zoo',
+ 'zoo',
+ '',
+ ].forEach(function(expectedLine) {
+ rl.write.apply(rl, key.xterm.metad);
+ assert.strictEqual(rl.cursor, 0);
+ assert.strictEqual(rl.line, expectedLine);
+ });
+}
diff --git a/tests/node_compat/test/parallel/test-stdin-from-file-spawn.js b/tests/node_compat/test/parallel/test-stdin-from-file-spawn.js
new file mode 100644
index 000000000..2f6b41898
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stdin-from-file-spawn.js
@@ -0,0 +1,52 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.8.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// TODO(cjihrig): 'run -A runner.ts' should not be needed in
+// execSync() call at the bottom of this test.
+
+'use strict';
+const common = require('../common');
+const process = require('process');
+
+let defaultShell;
+if (process.platform === 'linux' || process.platform === 'darwin') {
+ defaultShell = '/bin/sh';
+} else if (process.platform === 'win32') {
+ defaultShell = 'cmd.exe';
+} else {
+ common.skip('This is test exists only on Linux/Win32/OSX');
+}
+
+const { execSync } = require('child_process');
+const fs = require('fs');
+const path = require('path');
+const tmpdir = require('../common/tmpdir');
+
+const tmpDir = tmpdir.path;
+tmpdir.refresh();
+const tmpCmdFile = path.join(tmpDir, 'test-stdin-from-file-spawn-cmd');
+const tmpJsFile = path.join(tmpDir, 'test-stdin-from-file-spawn.js');
+fs.writeFileSync(tmpCmdFile, 'echo hello');
+fs.writeFileSync(tmpJsFile, `
+'use strict';
+const { spawn } = require('child_process');
+// Reference the object to invoke the getter
+process.stdin;
+setTimeout(() => {
+ let ok = false;
+ const child = spawn(process.env.SHELL || '${defaultShell}',
+ [], { stdio: ['inherit', 'pipe'] });
+ child.stdout.on('data', () => {
+ ok = true;
+ });
+ child.on('close', () => {
+ process.exit(ok ? 0 : -1);
+ });
+}, 100);
+`);
+
+execSync(`${process.argv[0]} run -A runner.ts ${tmpJsFile} < ${tmpCmdFile}`);
diff --git a/tests/node_compat/test/parallel/test-stream-add-abort-signal.js b/tests/node_compat/test/parallel/test-stream-add-abort-signal.js
new file mode 100644
index 000000000..cf598b547
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-add-abort-signal.js
@@ -0,0 +1,34 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Flags: --expose-internals
+'use strict';
+
+require('../common');
+const assert = require('assert');
+const { addAbortSignal, Readable } = require('stream');
+const {
+ addAbortSignalNoValidate,
+} = require('internal/streams/add-abort-signal');
+
+{
+ assert.throws(() => {
+ addAbortSignal('INVALID_SIGNAL');
+ }, /ERR_INVALID_ARG_TYPE/);
+
+ const ac = new AbortController();
+ assert.throws(() => {
+ addAbortSignal(ac.signal, 'INVALID_STREAM');
+ }, /ERR_INVALID_ARG_TYPE/);
+}
+
+{
+ const r = new Readable({
+ read: () => {},
+ });
+ assert.deepStrictEqual(r, addAbortSignalNoValidate('INVALID_SIGNAL', r));
+}
diff --git a/tests/node_compat/test/parallel/test-stream-aliases-legacy.js b/tests/node_compat/test/parallel/test-stream-aliases-legacy.js
new file mode 100644
index 000000000..e0af8bb47
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-aliases-legacy.js
@@ -0,0 +1,21 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+require('../common');
+
+const assert = require('assert');
+const stream = require('stream');
+
+// Verify that all individual aliases are left in place.
+
+assert.strictEqual(stream.Readable, require('_stream_readable'));
+assert.strictEqual(stream.Writable, require('_stream_writable'));
+assert.strictEqual(stream.Duplex, require('_stream_duplex'));
+assert.strictEqual(stream.Transform, require('_stream_transform'));
+assert.strictEqual(stream.PassThrough, require('_stream_passthrough'));
diff --git a/tests/node_compat/test/parallel/test-stream-auto-destroy.js b/tests/node_compat/test/parallel/test-stream-auto-destroy.js
new file mode 100644
index 000000000..a0947ba39
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-auto-destroy.js
@@ -0,0 +1,119 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const stream = require('stream');
+const assert = require('assert');
+
+{
+ const r = new stream.Readable({
+ autoDestroy: true,
+ read() {
+ this.push('hello');
+ this.push('world');
+ this.push(null);
+ },
+ destroy: common.mustCall((err, cb) => cb())
+ });
+
+ let ended = false;
+
+ r.resume();
+
+ r.on('end', common.mustCall(() => {
+ ended = true;
+ }));
+
+ r.on('close', common.mustCall(() => {
+ assert(ended);
+ }));
+}
+
+{
+ const w = new stream.Writable({
+ autoDestroy: true,
+ write(data, enc, cb) {
+ cb(null);
+ },
+ destroy: common.mustCall((err, cb) => cb())
+ });
+
+ let finished = false;
+
+ w.write('hello');
+ w.write('world');
+ w.end();
+
+ w.on('finish', common.mustCall(() => {
+ finished = true;
+ }));
+
+ w.on('close', common.mustCall(() => {
+ assert(finished);
+ }));
+}
+
+{
+ const t = new stream.Transform({
+ autoDestroy: true,
+ transform(data, enc, cb) {
+ cb(null, data);
+ },
+ destroy: common.mustCall((err, cb) => cb())
+ });
+
+ let ended = false;
+ let finished = false;
+
+ t.write('hello');
+ t.write('world');
+ t.end();
+
+ t.resume();
+
+ t.on('end', common.mustCall(() => {
+ ended = true;
+ }));
+
+ t.on('finish', common.mustCall(() => {
+ finished = true;
+ }));
+
+ t.on('close', common.mustCall(() => {
+ assert(ended);
+ assert(finished);
+ }));
+}
+
+{
+ const r = new stream.Readable({
+ read() {
+ r2.emit('error', new Error('fail'));
+ }
+ });
+ const r2 = new stream.Readable({
+ autoDestroy: true,
+ destroy: common.mustCall((err, cb) => cb())
+ });
+
+ r.pipe(r2);
+}
+
+{
+ const r = new stream.Readable({
+ read() {
+ w.emit('error', new Error('fail'));
+ }
+ });
+ const w = new stream.Writable({
+ autoDestroy: true,
+ destroy: common.mustCall((err, cb) => cb())
+ });
+
+ r.pipe(w);
+}
diff --git a/tests/node_compat/test/parallel/test-stream-await-drain-writers-in-synchronously-recursion-write.js b/tests/node_compat/test/parallel/test-stream-await-drain-writers-in-synchronously-recursion-write.js
new file mode 100644
index 000000000..84095dbf1
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-await-drain-writers-in-synchronously-recursion-write.js
@@ -0,0 +1,35 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const { PassThrough } = require('stream');
+
+const encode = new PassThrough({
+ highWaterMark: 1
+});
+
+const decode = new PassThrough({
+ highWaterMark: 1
+});
+
+const send = common.mustCall((buf) => {
+ encode.write(buf);
+}, 4);
+
+let i = 0;
+const onData = common.mustCall(() => {
+ if (++i === 2) {
+ send(Buffer.from([0x3]));
+ send(Buffer.from([0x4]));
+ }
+}, 4);
+
+encode.pipe(decode).on('data', onData);
+
+send(Buffer.from([0x1]));
+send(Buffer.from([0x2]));
diff --git a/tests/node_compat/test/parallel/test-stream-backpressure.js b/tests/node_compat/test/parallel/test-stream-backpressure.js
new file mode 100644
index 000000000..f1e14bb5d
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-backpressure.js
@@ -0,0 +1,46 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const assert = require('assert');
+const stream = require('stream');
+
+let pushes = 0;
+const total = 65500 + 40 * 1024;
+const rs = new stream.Readable({
+ read: common.mustCall(function() {
+ if (pushes++ === 10) {
+ this.push(null);
+ return;
+ }
+
+ const length = this._readableState.length;
+
+ // We are at most doing two full runs of _reads
+ // before stopping, because Readable is greedy
+ // to keep its buffer full
+ assert(length <= total);
+
+ this.push(Buffer.alloc(65500));
+ for (let i = 0; i < 40; i++) {
+ this.push(Buffer.alloc(1024));
+ }
+
+ // We will be over highWaterMark at this point
+ // but a new call to _read is scheduled anyway.
+ }, 11)
+});
+
+const ws = stream.Writable({
+ write: common.mustCall(function(data, enc, cb) {
+ setImmediate(cb);
+ }, 41 * 10)
+});
+
+rs.pipe(ws);
diff --git a/tests/node_compat/test/parallel/test-stream-big-packet.js b/tests/node_compat/test/parallel/test-stream-big-packet.js
new file mode 100644
index 000000000..4e816cc2d
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-big-packet.js
@@ -0,0 +1,72 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+const stream = require('stream');
+
+let passed = false;
+
+class TestStream extends stream.Transform {
+ _transform(chunk, encoding, done) {
+ if (!passed) {
+ // Char 'a' only exists in the last write
+ passed = chunk.toString().includes('a');
+ }
+ done();
+ }
+}
+
+const s1 = new stream.Transform({
+ transform(chunk, encoding, cb) {
+ process.nextTick(cb, null, chunk);
+ }
+});
+const s2 = new stream.PassThrough();
+const s3 = new TestStream();
+s1.pipe(s3);
+// Don't let s2 auto close which may close s3
+s2.pipe(s3, { end: false });
+
+// We must write a buffer larger than highWaterMark
+const big = Buffer.alloc(s1.writableHighWaterMark + 1, 'x');
+
+// Since big is larger than highWaterMark, it will be buffered internally.
+assert(!s1.write(big));
+// 'tiny' is small enough to pass through internal buffer.
+assert(s2.write('tiny'));
+
+// Write some small data in next IO loop, which will never be written to s3
+// Because 'drain' event is not emitted from s1 and s1 is still paused
+setImmediate(s1.write.bind(s1), 'later');
+
+// Assert after two IO loops when all operations have been done.
+process.on('exit', function() {
+ assert(passed, 'Large buffer is not handled properly by Writable Stream');
+});
diff --git a/tests/node_compat/test/parallel/test-stream-big-push.js b/tests/node_compat/test/parallel/test-stream-big-push.js
new file mode 100644
index 000000000..2e6d01fe2
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-big-push.js
@@ -0,0 +1,81 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const stream = require('stream');
+const str = 'asdfasdfasdfasdfasdf';
+
+const r = new stream.Readable({
+ highWaterMark: 5,
+ encoding: 'utf8'
+});
+
+let reads = 0;
+
+function _read() {
+ if (reads === 0) {
+ setTimeout(() => {
+ r.push(str);
+ }, 1);
+ reads++;
+ } else if (reads === 1) {
+ const ret = r.push(str);
+ assert.strictEqual(ret, false);
+ reads++;
+ } else {
+ r.push(null);
+ }
+}
+
+r._read = common.mustCall(_read, 3);
+
+r.on('end', common.mustCall());
+
+// Push some data in to start.
+// We've never gotten any read event at this point.
+const ret = r.push(str);
+// Should be false. > hwm
+assert(!ret);
+let chunk = r.read();
+assert.strictEqual(chunk, str);
+chunk = r.read();
+assert.strictEqual(chunk, null);
+
+r.once('readable', () => {
+ // This time, we'll get *all* the remaining data, because
+ // it's been added synchronously, as the read WOULD take
+ // us below the hwm, and so it triggered a _read() again,
+ // which synchronously added more, which we then return.
+ chunk = r.read();
+ assert.strictEqual(chunk, str + str);
+
+ chunk = r.read();
+ assert.strictEqual(chunk, null);
+});
diff --git a/tests/node_compat/test/parallel/test-stream-buffer-list.js b/tests/node_compat/test/parallel/test-stream-buffer-list.js
new file mode 100644
index 000000000..7b16f5d83
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-buffer-list.js
@@ -0,0 +1,91 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Flags: --expose-internals
+'use strict';
+require('../common');
+const assert = require('assert');
+const BufferList = require('internal/streams/buffer_list');
+
+// Test empty buffer list.
+const emptyList = new BufferList();
+
+emptyList.shift();
+assert.deepStrictEqual(emptyList, new BufferList());
+
+assert.strictEqual(emptyList.join(','), '');
+
+assert.deepStrictEqual(emptyList.concat(0), Buffer.alloc(0));
+
+const buf = Buffer.from('foo');
+
+function testIterator(list, count) {
+ // test iterator
+ let len = 0;
+ // eslint-disable-next-line no-unused-vars
+ for (const x of list) {
+ len++;
+ }
+ assert.strictEqual(len, count);
+}
+
+// Test buffer list with one element.
+const list = new BufferList();
+testIterator(list, 0);
+
+list.push(buf);
+testIterator(list, 1);
+for (const x of list) {
+ assert.strictEqual(x, buf);
+}
+
+const copy = list.concat(3);
+testIterator(copy, 3);
+
+assert.notStrictEqual(copy, buf);
+assert.deepStrictEqual(copy, buf);
+
+assert.strictEqual(list.join(','), 'foo');
+
+const shifted = list.shift();
+testIterator(list, 0);
+assert.strictEqual(shifted, buf);
+assert.deepStrictEqual(list, new BufferList());
+
+{
+ const list = new BufferList();
+ list.push('foo');
+ list.push('bar');
+ list.push('foo');
+ list.push('bar');
+ assert.strictEqual(list.consume(6, true), 'foobar');
+ assert.strictEqual(list.consume(6, true), 'foobar');
+}
+
+{
+ const list = new BufferList();
+ list.push('foo');
+ list.push('bar');
+ assert.strictEqual(list.consume(5, true), 'fooba');
+}
+
+{
+ const list = new BufferList();
+ list.push(buf);
+ list.push(buf);
+ list.push(buf);
+ list.push(buf);
+ assert.strictEqual(list.consume(6).toString(), 'foofoo');
+ assert.strictEqual(list.consume(6).toString(), 'foofoo');
+}
+
+{
+ const list = new BufferList();
+ list.push(buf);
+ list.push(buf);
+ assert.strictEqual(list.consume(5).toString(), 'foofo');
+}
diff --git a/tests/node_compat/test/parallel/test-stream-construct.js b/tests/node_compat/test/parallel/test-stream-construct.js
new file mode 100644
index 000000000..0cd93c9e9
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-construct.js
@@ -0,0 +1,287 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const { Writable, Readable, Duplex } = require('stream');
+const assert = require('assert');
+
+{
+ // Multiple callback.
+ new Writable({
+ construct: common.mustCall((callback) => {
+ callback();
+ callback();
+ })
+ }).on('error', common.expectsError({
+ name: 'Error',
+ code: 'ERR_MULTIPLE_CALLBACK'
+ }));
+}
+
+{
+ // Multiple callback.
+ new Readable({
+ construct: common.mustCall((callback) => {
+ callback();
+ callback();
+ })
+ }).on('error', common.expectsError({
+ name: 'Error',
+ code: 'ERR_MULTIPLE_CALLBACK'
+ }));
+}
+
+{
+ // Synchronous error.
+
+ new Writable({
+ construct: common.mustCall((callback) => {
+ callback(new Error('test'));
+ })
+ }).on('error', common.expectsError({
+ name: 'Error',
+ message: 'test'
+ }));
+}
+
+{
+ // Synchronous error.
+
+ new Readable({
+ construct: common.mustCall((callback) => {
+ callback(new Error('test'));
+ })
+ }).on('error', common.expectsError({
+ name: 'Error',
+ message: 'test'
+ }));
+}
+
+{
+ // Asynchronous error.
+
+ new Writable({
+ construct: common.mustCall((callback) => {
+ process.nextTick(callback, new Error('test'));
+ })
+ }).on('error', common.expectsError({
+ name: 'Error',
+ message: 'test'
+ }));
+}
+
+{
+ // Asynchronous error.
+
+ new Readable({
+ construct: common.mustCall((callback) => {
+ process.nextTick(callback, new Error('test'));
+ })
+ }).on('error', common.expectsError({
+ name: 'Error',
+ message: 'test'
+ }));
+}
+
+function testDestroy(factory) {
+ {
+ let constructed = false;
+ const s = factory({
+ construct: common.mustCall((cb) => {
+ constructed = true;
+ process.nextTick(cb);
+ })
+ });
+ s.on('close', common.mustCall(() => {
+ assert.strictEqual(constructed, true);
+ }));
+ s.destroy();
+ }
+
+ {
+ let constructed = false;
+ const s = factory({
+ construct: common.mustCall((cb) => {
+ constructed = true;
+ process.nextTick(cb);
+ })
+ });
+ s.on('close', common.mustCall(() => {
+ assert.strictEqual(constructed, true);
+ }));
+ s.destroy(null, () => {
+ assert.strictEqual(constructed, true);
+ });
+ }
+
+ {
+ let constructed = false;
+ const s = factory({
+ construct: common.mustCall((cb) => {
+ constructed = true;
+ process.nextTick(cb);
+ })
+ });
+ s.on('close', common.mustCall(() => {
+ assert.strictEqual(constructed, true);
+ }));
+ s.destroy();
+ }
+
+
+ {
+ let constructed = false;
+ const s = factory({
+ construct: common.mustCall((cb) => {
+ constructed = true;
+ process.nextTick(cb);
+ })
+ });
+ s.on('close', common.mustCall(() => {
+ assert.strictEqual(constructed, true);
+ }));
+ s.on('error', common.mustCall((err) => {
+ assert.strictEqual(err.message, 'kaboom');
+ }));
+ s.destroy(new Error('kaboom'), (err) => {
+ assert.strictEqual(err.message, 'kaboom');
+ assert.strictEqual(constructed, true);
+ });
+ }
+
+ {
+ let constructed = false;
+ const s = factory({
+ construct: common.mustCall((cb) => {
+ constructed = true;
+ process.nextTick(cb);
+ })
+ });
+ s.on('error', common.mustCall(() => {
+ assert.strictEqual(constructed, true);
+ }));
+ s.on('close', common.mustCall(() => {
+ assert.strictEqual(constructed, true);
+ }));
+ s.destroy(new Error());
+ }
+}
+testDestroy((opts) => new Readable({
+ read: common.mustNotCall(),
+ ...opts
+}));
+testDestroy((opts) => new Writable({
+ write: common.mustNotCall(),
+ final: common.mustNotCall(),
+ ...opts
+}));
+
+{
+ let constructed = false;
+ const r = new Readable({
+ autoDestroy: true,
+ construct: common.mustCall((cb) => {
+ constructed = true;
+ process.nextTick(cb);
+ }),
+ read: common.mustCall(() => {
+ assert.strictEqual(constructed, true);
+ r.push(null);
+ })
+ });
+ r.on('close', common.mustCall(() => {
+ assert.strictEqual(constructed, true);
+ }));
+ r.on('data', common.mustNotCall());
+}
+
+{
+ let constructed = false;
+ const w = new Writable({
+ autoDestroy: true,
+ construct: common.mustCall((cb) => {
+ constructed = true;
+ process.nextTick(cb);
+ }),
+ write: common.mustCall((chunk, encoding, cb) => {
+ assert.strictEqual(constructed, true);
+ process.nextTick(cb);
+ }),
+ final: common.mustCall((cb) => {
+ assert.strictEqual(constructed, true);
+ process.nextTick(cb);
+ })
+ });
+ w.on('close', common.mustCall(() => {
+ assert.strictEqual(constructed, true);
+ }));
+ w.end('data');
+}
+
+{
+ let constructed = false;
+ const w = new Writable({
+ autoDestroy: true,
+ construct: common.mustCall((cb) => {
+ constructed = true;
+ process.nextTick(cb);
+ }),
+ write: common.mustNotCall(),
+ final: common.mustCall((cb) => {
+ assert.strictEqual(constructed, true);
+ process.nextTick(cb);
+ })
+ });
+ w.on('close', common.mustCall(() => {
+ assert.strictEqual(constructed, true);
+ }));
+ w.end();
+}
+
+{
+ new Duplex({
+ construct: common.mustCall()
+ });
+}
+
+{
+ // https://github.com/nodejs/node/issues/34448
+
+ let constructed = false;
+ const d = new Duplex({
+ readable: false,
+ construct: common.mustCall((callback) => {
+ setImmediate(common.mustCall(() => {
+ constructed = true;
+ callback();
+ }));
+ }),
+ write(chunk, encoding, callback) {
+ callback();
+ },
+ read() {
+ this.push(null);
+ }
+ });
+ d.resume();
+ d.end('foo');
+ d.on('close', common.mustCall(() => {
+ assert.strictEqual(constructed, true);
+ }));
+}
+
+{
+ // Construct should not cause stream to read.
+ new Readable({
+ construct: common.mustCall((callback) => {
+ callback();
+ }),
+ read: common.mustNotCall()
+ });
+}
diff --git a/tests/node_compat/test/parallel/test-stream-destroy-event-order.js b/tests/node_compat/test/parallel/test-stream-destroy-event-order.js
new file mode 100644
index 000000000..09802b2a3
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-destroy-event-order.js
@@ -0,0 +1,31 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const assert = require('assert');
+const { Readable } = require('stream');
+
+const rs = new Readable({
+ read() {}
+});
+
+let closed = false;
+let errored = false;
+
+rs.on('close', common.mustCall(() => {
+ closed = true;
+ assert(errored);
+}));
+
+rs.on('error', common.mustCall((err) => {
+ errored = true;
+ assert(!closed);
+}));
+
+rs.destroy(new Error('kaboom'));
diff --git a/tests/node_compat/test/parallel/test-stream-duplex-destroy.js b/tests/node_compat/test/parallel/test-stream-duplex-destroy.js
new file mode 100644
index 000000000..73cf75fe3
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-duplex-destroy.js
@@ -0,0 +1,264 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const { Duplex } = require('stream');
+const assert = require('assert');
+
+{
+ const duplex = new Duplex({
+ write(chunk, enc, cb) { cb(); },
+ read() {}
+ });
+
+ duplex.resume();
+
+ duplex.on('end', common.mustNotCall());
+ duplex.on('finish', common.mustNotCall());
+ duplex.on('close', common.mustCall());
+
+ duplex.destroy();
+ assert.strictEqual(duplex.destroyed, true);
+}
+
+{
+ const duplex = new Duplex({
+ write(chunk, enc, cb) { cb(); },
+ read() {}
+ });
+ duplex.resume();
+
+ const expected = new Error('kaboom');
+
+ duplex.on('end', common.mustNotCall());
+ duplex.on('finish', common.mustNotCall());
+ duplex.on('error', common.mustCall((err) => {
+ assert.strictEqual(err, expected);
+ }));
+
+ duplex.destroy(expected);
+ assert.strictEqual(duplex.destroyed, true);
+}
+
+{
+ const duplex = new Duplex({
+ write(chunk, enc, cb) { cb(); },
+ read() {}
+ });
+
+ duplex._destroy = common.mustCall(function(err, cb) {
+ assert.strictEqual(err, expected);
+ cb(err);
+ });
+
+ const expected = new Error('kaboom');
+
+ duplex.on('finish', common.mustNotCall('no finish event'));
+ duplex.on('error', common.mustCall((err) => {
+ assert.strictEqual(err, expected);
+ }));
+
+ duplex.destroy(expected);
+ assert.strictEqual(duplex.destroyed, true);
+}
+
+{
+ const expected = new Error('kaboom');
+ const duplex = new Duplex({
+ write(chunk, enc, cb) { cb(); },
+ read() {},
+ destroy: common.mustCall(function(err, cb) {
+ assert.strictEqual(err, expected);
+ cb();
+ })
+ });
+ duplex.resume();
+
+ duplex.on('end', common.mustNotCall('no end event'));
+ duplex.on('finish', common.mustNotCall('no finish event'));
+
+ // Error is swallowed by the custom _destroy
+ duplex.on('error', common.mustNotCall('no error event'));
+ duplex.on('close', common.mustCall());
+
+ duplex.destroy(expected);
+ assert.strictEqual(duplex.destroyed, true);
+}
+
+{
+ const duplex = new Duplex({
+ write(chunk, enc, cb) { cb(); },
+ read() {}
+ });
+
+ duplex._destroy = common.mustCall(function(err, cb) {
+ assert.strictEqual(err, null);
+ cb();
+ });
+
+ duplex.destroy();
+ assert.strictEqual(duplex.destroyed, true);
+}
+
+{
+ const duplex = new Duplex({
+ write(chunk, enc, cb) { cb(); },
+ read() {}
+ });
+ duplex.resume();
+
+ duplex._destroy = common.mustCall(function(err, cb) {
+ assert.strictEqual(err, null);
+ process.nextTick(() => {
+ this.push(null);
+ this.end();
+ cb();
+ });
+ });
+
+ const fail = common.mustNotCall('no finish or end event');
+
+ duplex.on('finish', fail);
+ duplex.on('end', fail);
+
+ duplex.destroy();
+
+ duplex.removeListener('end', fail);
+ duplex.removeListener('finish', fail);
+ duplex.on('end', common.mustNotCall());
+ duplex.on('finish', common.mustNotCall());
+ assert.strictEqual(duplex.destroyed, true);
+}
+
+{
+ const duplex = new Duplex({
+ write(chunk, enc, cb) { cb(); },
+ read() {}
+ });
+
+ const expected = new Error('kaboom');
+
+ duplex._destroy = common.mustCall(function(err, cb) {
+ assert.strictEqual(err, null);
+ cb(expected);
+ });
+
+ duplex.on('finish', common.mustNotCall('no finish event'));
+ duplex.on('end', common.mustNotCall('no end event'));
+ duplex.on('error', common.mustCall((err) => {
+ assert.strictEqual(err, expected);
+ }));
+
+ duplex.destroy();
+ assert.strictEqual(duplex.destroyed, true);
+}
+
+{
+ const duplex = new Duplex({
+ write(chunk, enc, cb) { cb(); },
+ read() {},
+ allowHalfOpen: true
+ });
+ duplex.resume();
+
+ duplex.on('finish', common.mustNotCall());
+ duplex.on('end', common.mustNotCall());
+
+ duplex.destroy();
+ assert.strictEqual(duplex.destroyed, true);
+}
+
+{
+ const duplex = new Duplex({
+ write(chunk, enc, cb) { cb(); },
+ read() {},
+ });
+
+ duplex.destroyed = true;
+ assert.strictEqual(duplex.destroyed, true);
+
+ // The internal destroy() mechanism should not be triggered
+ duplex.on('finish', common.mustNotCall());
+ duplex.on('end', common.mustNotCall());
+ duplex.destroy();
+}
+
+{
+ function MyDuplex() {
+ assert.strictEqual(this.destroyed, false);
+ this.destroyed = false;
+ Duplex.call(this);
+ }
+
+ Object.setPrototypeOf(MyDuplex.prototype, Duplex.prototype);
+ Object.setPrototypeOf(MyDuplex, Duplex);
+
+ new MyDuplex();
+}
+
+{
+ const duplex = new Duplex({
+ writable: false,
+ autoDestroy: true,
+ write(chunk, enc, cb) { cb(); },
+ read() {},
+ });
+ duplex.push(null);
+ duplex.resume();
+ duplex.on('close', common.mustCall());
+}
+
+{
+ const duplex = new Duplex({
+ readable: false,
+ autoDestroy: true,
+ write(chunk, enc, cb) { cb(); },
+ read() {},
+ });
+ duplex.end();
+ duplex.on('close', common.mustCall());
+}
+
+{
+ const duplex = new Duplex({
+ allowHalfOpen: false,
+ autoDestroy: true,
+ write(chunk, enc, cb) { cb(); },
+ read() {},
+ });
+ duplex.push(null);
+ duplex.resume();
+ const orgEnd = duplex.end;
+ duplex.end = common.mustNotCall();
+ duplex.on('end', () => {
+ // Ensure end() is called in next tick to allow
+ // any pending writes to be invoked first.
+ process.nextTick(() => {
+ duplex.end = common.mustCall(orgEnd);
+ });
+ });
+ duplex.on('close', common.mustCall());
+}
+{
+ // Check abort signal
+ const controller = new AbortController();
+ const { signal } = controller;
+ const duplex = new Duplex({
+ write(chunk, enc, cb) { cb(); },
+ read() {},
+ signal,
+ });
+ let count = 0;
+ duplex.on('error', common.mustCall((e) => {
+ assert.strictEqual(count++, 0); // Ensure not called twice
+ assert.strictEqual(e.name, 'AbortError');
+ }));
+ duplex.on('close', common.mustCall());
+ controller.abort();
+}
diff --git a/tests/node_compat/test/parallel/test-stream-duplex-end.js b/tests/node_compat/test/parallel/test-stream-duplex-end.js
new file mode 100644
index 000000000..b6d95a448
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-duplex-end.js
@@ -0,0 +1,48 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const assert = require('assert');
+const Duplex = require('stream').Duplex;
+
+{
+ const stream = new Duplex({
+ read() {}
+ });
+ assert.strictEqual(stream.allowHalfOpen, true);
+ stream.on('finish', common.mustNotCall());
+ assert.strictEqual(stream.listenerCount('end'), 0);
+ stream.resume();
+ stream.push(null);
+}
+
+{
+ const stream = new Duplex({
+ read() {},
+ allowHalfOpen: false
+ });
+ assert.strictEqual(stream.allowHalfOpen, false);
+ stream.on('finish', common.mustCall());
+ assert.strictEqual(stream.listenerCount('end'), 0);
+ stream.resume();
+ stream.push(null);
+}
+
+{
+ const stream = new Duplex({
+ read() {},
+ allowHalfOpen: false
+ });
+ assert.strictEqual(stream.allowHalfOpen, false);
+ stream._writableState.ended = true;
+ stream.on('finish', common.mustNotCall());
+ assert.strictEqual(stream.listenerCount('end'), 0);
+ stream.resume();
+ stream.push(null);
+}
diff --git a/tests/node_compat/test/parallel/test-stream-duplex-from.js b/tests/node_compat/test/parallel/test-stream-duplex-from.js
new file mode 100644
index 000000000..c91a040c5
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-duplex-from.js
@@ -0,0 +1,413 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const assert = require('assert');
+const { Duplex, Readable, Writable, pipeline, PassThrough } = require('stream');
+const { ReadableStream, WritableStream } = require('stream/web');
+const { Blob } = require('buffer');
+
+{
+ const d = Duplex.from({
+ readable: new Readable({
+ read() {
+ this.push('asd');
+ this.push(null);
+ }
+ })
+ });
+ assert.strictEqual(d.readable, true);
+ assert.strictEqual(d.writable, false);
+ d.once('readable', common.mustCall(function() {
+ assert.strictEqual(d.read().toString(), 'asd');
+ }));
+ d.once('end', common.mustCall(function() {
+ assert.strictEqual(d.readable, false);
+ }));
+}
+
+{
+ const d = Duplex.from(new Readable({
+ read() {
+ this.push('asd');
+ this.push(null);
+ }
+ }));
+ assert.strictEqual(d.readable, true);
+ assert.strictEqual(d.writable, false);
+ d.once('readable', common.mustCall(function() {
+ assert.strictEqual(d.read().toString(), 'asd');
+ }));
+ d.once('end', common.mustCall(function() {
+ assert.strictEqual(d.readable, false);
+ }));
+}
+
+{
+ let ret = '';
+ const d = Duplex.from(new Writable({
+ write(chunk, encoding, callback) {
+ ret += chunk;
+ callback();
+ }
+ }));
+ assert.strictEqual(d.readable, false);
+ assert.strictEqual(d.writable, true);
+ d.end('asd');
+ d.on('finish', common.mustCall(function() {
+ assert.strictEqual(d.writable, false);
+ assert.strictEqual(ret, 'asd');
+ }));
+}
+
+{
+ let ret = '';
+ const d = Duplex.from({
+ writable: new Writable({
+ write(chunk, encoding, callback) {
+ ret += chunk;
+ callback();
+ }
+ })
+ });
+ assert.strictEqual(d.readable, false);
+ assert.strictEqual(d.writable, true);
+ d.end('asd');
+ d.on('finish', common.mustCall(function() {
+ assert.strictEqual(d.writable, false);
+ assert.strictEqual(ret, 'asd');
+ }));
+}
+
+{
+ let ret = '';
+ const d = Duplex.from({
+ readable: new Readable({
+ read() {
+ this.push('asd');
+ this.push(null);
+ }
+ }),
+ writable: new Writable({
+ write(chunk, encoding, callback) {
+ ret += chunk;
+ callback();
+ }
+ })
+ });
+ assert.strictEqual(d.readable, true);
+ assert.strictEqual(d.writable, true);
+ d.once('readable', common.mustCall(function() {
+ assert.strictEqual(d.read().toString(), 'asd');
+ }));
+ d.once('end', common.mustCall(function() {
+ assert.strictEqual(d.readable, false);
+ }));
+ d.end('asd');
+ d.once('finish', common.mustCall(function() {
+ assert.strictEqual(d.writable, false);
+ assert.strictEqual(ret, 'asd');
+ }));
+}
+
+{
+ const d = Duplex.from(Promise.resolve('asd'));
+ assert.strictEqual(d.readable, true);
+ assert.strictEqual(d.writable, false);
+ d.once('readable', common.mustCall(function() {
+ assert.strictEqual(d.read().toString(), 'asd');
+ }));
+ d.once('end', common.mustCall(function() {
+ assert.strictEqual(d.readable, false);
+ }));
+}
+
+{
+ // https://github.com/nodejs/node/issues/40497
+ pipeline(
+ ['abc\ndef\nghi'],
+ Duplex.from(async function * (source) {
+ let rest = '';
+ for await (const chunk of source) {
+ const lines = (rest + chunk.toString()).split('\n');
+ rest = lines.pop();
+ for (const line of lines) {
+ yield line;
+ }
+ }
+ yield rest;
+ }),
+ async function * (source) { // eslint-disable-line require-yield
+ let ret = '';
+ for await (const x of source) {
+ ret += x;
+ }
+ assert.strictEqual(ret, 'abcdefghi');
+ },
+ common.mustSucceed(),
+ );
+}
+
+// Ensure that isDuplexNodeStream was called
+{
+ const duplex = new Duplex();
+ assert.strictEqual(Duplex.from(duplex), duplex);
+}
+
+// Ensure that Duplex.from works for blobs
+{
+ const blob = new Blob(['blob']);
+ const expectedByteLength = blob.size;
+ const duplex = Duplex.from(blob);
+ duplex.on('data', common.mustCall((arrayBuffer) => {
+ assert.strictEqual(arrayBuffer.byteLength, expectedByteLength);
+ }));
+}
+
+// Ensure that given a promise rejection it emits an error
+{
+ const myErrorMessage = 'myCustomError';
+ Duplex.from(Promise.reject(myErrorMessage))
+ .on('error', common.mustCall((error) => {
+ assert.strictEqual(error, myErrorMessage);
+ }));
+}
+
+// Ensure that given a promise rejection on an async function it emits an error
+{
+ const myErrorMessage = 'myCustomError';
+ async function asyncFn() {
+ return Promise.reject(myErrorMessage);
+ }
+
+ Duplex.from(asyncFn)
+ .on('error', common.mustCall((error) => {
+ assert.strictEqual(error, myErrorMessage);
+ }));
+}
+
+// Ensure that Duplex.from throws an Invalid return value when function is void
+{
+ assert.throws(() => Duplex.from(() => {}), {
+ code: 'ERR_INVALID_RETURN_VALUE',
+ });
+}
+
+// Ensure data if a sub object has a readable stream it's duplexified
+{
+ const msg = Buffer.from('hello');
+ const duplex = Duplex.from({
+ readable: Readable({
+ read() {
+ this.push(msg);
+ this.push(null);
+ }
+ })
+ }).on('data', common.mustCall((data) => {
+ assert.strictEqual(data, msg);
+ }));
+
+ assert.strictEqual(duplex.writable, false);
+}
+
+// Ensure data if a sub object has a writable stream it's duplexified
+{
+ const msg = Buffer.from('hello');
+ const duplex = Duplex.from({
+ writable: Writable({
+ write: common.mustCall((data) => {
+ assert.strictEqual(data, msg);
+ })
+ })
+ });
+
+ duplex.write(msg);
+ assert.strictEqual(duplex.readable, false);
+}
+
+// Ensure data if a sub object has a writable and readable stream it's duplexified
+{
+ const msg = Buffer.from('hello');
+
+ const duplex = Duplex.from({
+ readable: Readable({
+ read() {
+ this.push(msg);
+ this.push(null);
+ }
+ }),
+ writable: Writable({
+ write: common.mustCall((data) => {
+ assert.strictEqual(data, msg);
+ })
+ })
+ });
+
+ duplex.pipe(duplex)
+ .on('data', common.mustCall((data) => {
+ assert.strictEqual(data, msg);
+ assert.strictEqual(duplex.readable, true);
+ assert.strictEqual(duplex.writable, true);
+ }))
+ .on('end', common.mustCall());
+}
+
+// Ensure that given readable stream that throws an error it calls destroy
+{
+ const myErrorMessage = 'error!';
+ const duplex = Duplex.from(Readable({
+ read() {
+ throw new Error(myErrorMessage);
+ }
+ }));
+ duplex.on('error', common.mustCall((msg) => {
+ assert.strictEqual(msg.message, myErrorMessage);
+ }));
+}
+
+// Ensure that given writable stream that throws an error it calls destroy
+{
+ const myErrorMessage = 'error!';
+ const duplex = Duplex.from(Writable({
+ write(chunk, enc, cb) {
+ cb(myErrorMessage);
+ }
+ }));
+
+ duplex.on('error', common.mustCall((msg) => {
+ assert.strictEqual(msg, myErrorMessage);
+ }));
+
+ duplex.write('test');
+}
+
+{
+ const through = new PassThrough({ objectMode: true });
+
+ let res = '';
+ const d = Readable.from(['foo', 'bar'], { objectMode: true })
+ .pipe(Duplex.from({
+ writable: through,
+ readable: through
+ }));
+
+ d.on('data', (data) => {
+ d.pause();
+ setImmediate(() => {
+ d.resume();
+ });
+ res += data;
+ }).on('end', common.mustCall(() => {
+ assert.strictEqual(res, 'foobar');
+ })).on('close', common.mustCall());
+}
+
+function makeATestReadableStream(value) {
+ return new ReadableStream({
+ start(controller) {
+ controller.enqueue(value);
+ controller.close();
+ }
+ });
+}
+
+function makeATestWritableStream(writeFunc) {
+ return new WritableStream({
+ write(chunk) {
+ writeFunc(chunk);
+ }
+ });
+}
+
+{
+ const d = Duplex.from({
+ readable: makeATestReadableStream('foo'),
+ });
+ assert.strictEqual(d.readable, true);
+ assert.strictEqual(d.writable, false);
+
+ d.on('data', common.mustCall((data) => {
+ assert.strictEqual(data.toString(), 'foo');
+ }));
+
+ d.on('end', common.mustCall(() => {
+ assert.strictEqual(d.readable, false);
+ }));
+}
+
+{
+ const d = Duplex.from(makeATestReadableStream('foo'));
+
+ assert.strictEqual(d.readable, true);
+ assert.strictEqual(d.writable, false);
+
+ d.on('data', common.mustCall((data) => {
+ assert.strictEqual(data.toString(), 'foo');
+ }));
+
+ d.on('end', common.mustCall(() => {
+ assert.strictEqual(d.readable, false);
+ }));
+}
+
+/*
+TODO(kt3k): Enable this test case
+{
+ let ret = '';
+ const d = Duplex.from({
+ writable: makeATestWritableStream((chunk) => ret += chunk),
+ });
+
+ assert.strictEqual(d.readable, false);
+ assert.strictEqual(d.writable, true);
+
+ d.end('foo');
+ d.on('finish', common.mustCall(() => {
+ assert.strictEqual(ret, 'foo');
+ assert.strictEqual(d.writable, false);
+ }));
+}
+
+{
+ let ret = '';
+ const d = Duplex.from(makeATestWritableStream((chunk) => ret += chunk));
+
+ assert.strictEqual(d.readable, false);
+ assert.strictEqual(d.writable, true);
+
+ d.end('foo');
+ d.on('finish', common.mustCall(() => {
+ assert.strictEqual(ret, 'foo');
+ assert.strictEqual(d.writable, false);
+ }));
+}
+
+{
+ let ret = '';
+ const d = Duplex.from({
+ readable: makeATestReadableStream('foo'),
+ writable: makeATestWritableStream((chunk) => ret += chunk),
+ });
+
+ d.end('bar');
+
+ d.on('data', common.mustCall((data) => {
+ assert.strictEqual(data.toString(), 'foo');
+ }));
+
+ d.on('end', common.mustCall(() => {
+ assert.strictEqual(d.readable, false);
+ }));
+
+ d.on('finish', common.mustCall(() => {
+ assert.strictEqual(ret, 'bar');
+ assert.strictEqual(d.writable, false);
+ }));
+}
+*/
diff --git a/tests/node_compat/test/parallel/test-stream-duplex-props.js b/tests/node_compat/test/parallel/test-stream-duplex-props.js
new file mode 100644
index 000000000..1eedc9404
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-duplex-props.js
@@ -0,0 +1,38 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+require('../common');
+const assert = require('assert');
+const { Duplex } = require('stream');
+
+{
+ const d = new Duplex({
+ objectMode: true,
+ highWaterMark: 100
+ });
+
+ assert.strictEqual(d.writableObjectMode, true);
+ assert.strictEqual(d.writableHighWaterMark, 100);
+ assert.strictEqual(d.readableObjectMode, true);
+ assert.strictEqual(d.readableHighWaterMark, 100);
+}
+
+{
+ const d = new Duplex({
+ readableObjectMode: false,
+ readableHighWaterMark: 10,
+ writableObjectMode: true,
+ writableHighWaterMark: 100
+ });
+
+ assert.strictEqual(d.writableObjectMode, true);
+ assert.strictEqual(d.writableHighWaterMark, 100);
+ assert.strictEqual(d.readableObjectMode, false);
+ assert.strictEqual(d.readableHighWaterMark, 10);
+}
diff --git a/tests/node_compat/test/parallel/test-stream-duplex-readable-end.js b/tests/node_compat/test/parallel/test-stream-duplex-readable-end.js
new file mode 100644
index 000000000..87327814c
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-duplex-readable-end.js
@@ -0,0 +1,36 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+// https://github.com/nodejs/node/issues/35926
+const common = require('../common');
+const assert = require('assert');
+const stream = require('stream');
+
+let loops = 5;
+
+const src = new stream.Readable({
+ read() {
+ if (loops--)
+ this.push(Buffer.alloc(20000));
+ }
+});
+
+const dst = new stream.Transform({
+ transform(chunk, output, fn) {
+ this.push(null);
+ fn();
+ }
+});
+
+src.pipe(dst);
+
+dst.on('data', () => { });
+dst.on('end', common.mustCall(() => {
+ assert.strictEqual(loops, 3);
+ assert.ok(src.isPaused());
+}));
diff --git a/tests/node_compat/test/parallel/test-stream-duplex-writable-finished.js b/tests/node_compat/test/parallel/test-stream-duplex-writable-finished.js
new file mode 100644
index 000000000..c556d14ef
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-duplex-writable-finished.js
@@ -0,0 +1,37 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const { Duplex } = require('stream');
+const assert = require('assert');
+
+// basic
+{
+ // Find it on Duplex.prototype
+ assert(Object.hasOwn(Duplex.prototype, 'writableFinished'));
+}
+
+// event
+{
+ const duplex = new Duplex();
+
+ duplex._write = (chunk, encoding, cb) => {
+ // The state finished should start in false.
+ assert.strictEqual(duplex.writableFinished, false);
+ cb();
+ };
+
+ duplex.on('finish', common.mustCall(() => {
+ assert.strictEqual(duplex.writableFinished, true);
+ }));
+
+ duplex.end('testing finished state', common.mustCall(() => {
+ assert.strictEqual(duplex.writableFinished, true);
+ }));
+}
diff --git a/tests/node_compat/test/parallel/test-stream-duplex.js b/tests/node_compat/test/parallel/test-stream-duplex.js
new file mode 100644
index 000000000..d7210e49e
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-duplex.js
@@ -0,0 +1,140 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+'use strict';
+
+const common = require('../common');
+const assert = require('assert');
+const Duplex = require('stream').Duplex;
+const { ReadableStream, WritableStream } = require('stream/web');
+
+const stream = new Duplex({ objectMode: true });
+
+assert(Duplex() instanceof Duplex);
+assert(stream._readableState.objectMode);
+assert(stream._writableState.objectMode);
+assert(stream.allowHalfOpen);
+assert.strictEqual(stream.listenerCount('end'), 0);
+
+let written;
+let read;
+
+stream._write = (obj, _, cb) => {
+ written = obj;
+ cb();
+};
+
+stream._read = () => {};
+
+stream.on('data', (obj) => {
+ read = obj;
+});
+
+stream.push({ val: 1 });
+stream.end({ val: 2 });
+
+process.on('exit', () => {
+ assert.strictEqual(read.val, 1);
+ assert.strictEqual(written.val, 2);
+});
+
+// Duplex.fromWeb
+{
+ const dataToRead = Buffer.from('hello');
+ const dataToWrite = Buffer.from('world');
+
+ const readable = new ReadableStream({
+ start(controller) {
+ controller.enqueue(dataToRead);
+ },
+ });
+
+ const writable = new WritableStream({
+ write: common.mustCall((chunk) => {
+ assert.strictEqual(chunk, dataToWrite);
+ })
+ });
+
+ const pair = { readable, writable };
+ const duplex = Duplex.fromWeb(pair);
+
+ duplex.write(dataToWrite);
+ duplex.once('data', common.mustCall((chunk) => {
+ assert.strictEqual(chunk, dataToRead);
+ }));
+}
+
+// Duplex.fromWeb - using utf8 and objectMode
+{
+ const dataToRead = 'hello';
+ const dataToWrite = 'world';
+
+ const readable = new ReadableStream({
+ start(controller) {
+ controller.enqueue(dataToRead);
+ },
+ });
+
+ const writable = new WritableStream({
+ write: common.mustCall((chunk) => {
+ assert.strictEqual(chunk, dataToWrite);
+ })
+ });
+
+ const pair = {
+ readable,
+ writable
+ };
+ const duplex = Duplex.fromWeb(pair, { encoding: 'utf8', objectMode: true });
+
+ duplex.write(dataToWrite);
+ duplex.once('data', common.mustCall((chunk) => {
+ assert.strictEqual(chunk, dataToRead);
+ }));
+}
+// Duplex.toWeb
+{
+ const dataToRead = Buffer.from('hello');
+ const dataToWrite = Buffer.from('world');
+
+ const duplex = Duplex({
+ read() {
+ this.push(dataToRead);
+ this.push(null);
+ },
+ write: common.mustCall((chunk) => {
+ assert.strictEqual(chunk, dataToWrite);
+ })
+ });
+
+ const { writable, readable } = Duplex.toWeb(duplex);
+ writable.getWriter().write(dataToWrite);
+
+ readable.getReader().read().then(common.mustCall((result) => {
+ assert.deepStrictEqual(Buffer.from(result.value), dataToRead);
+ }));
+}
diff --git a/tests/node_compat/test/parallel/test-stream-end-paused.js b/tests/node_compat/test/parallel/test-stream-end-paused.js
new file mode 100644
index 000000000..12c05243d
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-end-paused.js
@@ -0,0 +1,57 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+
+// Make sure we don't miss the end event for paused 0-length streams
+
+const Readable = require('stream').Readable;
+const stream = new Readable();
+let calledRead = false;
+stream._read = function() {
+ assert(!calledRead);
+ calledRead = true;
+ this.push(null);
+};
+
+stream.on('data', function() {
+ throw new Error('should not ever get data');
+});
+stream.pause();
+
+setTimeout(common.mustCall(function() {
+ stream.on('end', common.mustCall());
+ stream.resume();
+}), 1);
+
+process.on('exit', function() {
+ assert(calledRead);
+ console.log('ok');
+});
diff --git a/tests/node_compat/test/parallel/test-stream-error-once.js b/tests/node_compat/test/parallel/test-stream-error-once.js
new file mode 100644
index 000000000..592788d4f
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-error-once.js
@@ -0,0 +1,26 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const { Writable, Readable } = require('stream');
+
+{
+ const writable = new Writable();
+ writable.on('error', common.mustCall());
+ writable.end();
+ writable.write('h');
+ writable.write('h');
+}
+
+{
+ const readable = new Readable();
+ readable.on('error', common.mustCall());
+ readable.push(null);
+ readable.push('h');
+ readable.push('h');
+}
diff --git a/tests/node_compat/test/parallel/test-stream-events-prepend.js b/tests/node_compat/test/parallel/test-stream-events-prepend.js
new file mode 100644
index 000000000..7245977f1
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-events-prepend.js
@@ -0,0 +1,33 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const stream = require('stream');
+
+class Writable extends stream.Writable {
+ constructor() {
+ super();
+ this.prependListener = undefined;
+ }
+
+ _write(chunk, end, cb) {
+ cb();
+ }
+}
+
+class Readable extends stream.Readable {
+ _read() {
+ this.push(null);
+ }
+}
+
+const w = new Writable();
+w.on('pipe', common.mustCall());
+
+const r = new Readable();
+r.pipe(w);
diff --git a/tests/node_compat/test/parallel/test-stream-inheritance.js b/tests/node_compat/test/parallel/test-stream-inheritance.js
new file mode 100644
index 000000000..296e12996
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-inheritance.js
@@ -0,0 +1,70 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+const { Readable, Writable, Duplex, Transform } = require('stream');
+
+const readable = new Readable({ read() {} });
+const writable = new Writable({ write() {} });
+const duplex = new Duplex({ read() {}, write() {} });
+const transform = new Transform({ transform() {} });
+
+assert.ok(readable instanceof Readable);
+assert.ok(!(writable instanceof Readable));
+assert.ok(duplex instanceof Readable);
+assert.ok(transform instanceof Readable);
+
+assert.ok(!(readable instanceof Writable));
+assert.ok(writable instanceof Writable);
+assert.ok(duplex instanceof Writable);
+assert.ok(transform instanceof Writable);
+
+assert.ok(!(readable instanceof Duplex));
+assert.ok(!(writable instanceof Duplex));
+assert.ok(duplex instanceof Duplex);
+assert.ok(transform instanceof Duplex);
+
+assert.ok(!(readable instanceof Transform));
+assert.ok(!(writable instanceof Transform));
+assert.ok(!(duplex instanceof Transform));
+assert.ok(transform instanceof Transform);
+
+assert.ok(!(null instanceof Writable));
+assert.ok(!(undefined instanceof Writable));
+
+// Simple inheritance check for `Writable` works fine in a subclass constructor.
+function CustomWritable() {
+ assert.ok(
+ this instanceof CustomWritable,
+ `${this} does not inherit from CustomWritable`
+ );
+ assert.ok(
+ this instanceof Writable,
+ `${this} does not inherit from Writable`
+ );
+}
+
+Object.setPrototypeOf(CustomWritable, Writable);
+Object.setPrototypeOf(CustomWritable.prototype, Writable.prototype);
+
+new CustomWritable();
+
+assert.throws(
+ CustomWritable,
+ {
+ code: 'ERR_ASSERTION',
+ constructor: assert.AssertionError,
+ message: 'undefined does not inherit from CustomWritable'
+ }
+);
+
+class OtherCustomWritable extends Writable {}
+
+assert(!(new OtherCustomWritable() instanceof CustomWritable));
+assert(!(new CustomWritable() instanceof OtherCustomWritable));
diff --git a/tests/node_compat/test/parallel/test-stream-ispaused.js b/tests/node_compat/test/parallel/test-stream-ispaused.js
new file mode 100644
index 000000000..8f4897047
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-ispaused.js
@@ -0,0 +1,51 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+const stream = require('stream');
+
+const readable = new stream.Readable();
+
+// _read is a noop, here.
+readable._read = Function();
+
+// Default state of a stream is not "paused"
+assert.ok(!readable.isPaused());
+
+// Make the stream start flowing...
+readable.on('data', Function());
+
+// still not paused.
+assert.ok(!readable.isPaused());
+
+readable.pause();
+assert.ok(readable.isPaused());
+readable.resume();
+assert.ok(!readable.isPaused());
diff --git a/tests/node_compat/test/parallel/test-stream-objectmode-undefined.js b/tests/node_compat/test/parallel/test-stream-objectmode-undefined.js
new file mode 100644
index 000000000..0478b0ee7
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-objectmode-undefined.js
@@ -0,0 +1,51 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const { Readable, Writable, Transform } = require('stream');
+
+{
+ const stream = new Readable({
+ objectMode: true,
+ read: common.mustCall(() => {
+ stream.push(undefined);
+ stream.push(null);
+ })
+ });
+
+ stream.on('data', common.mustCall((chunk) => {
+ assert.strictEqual(chunk, undefined);
+ }));
+}
+
+{
+ const stream = new Writable({
+ objectMode: true,
+ write: common.mustCall((chunk) => {
+ assert.strictEqual(chunk, undefined);
+ })
+ });
+
+ stream.write(undefined);
+}
+
+{
+ const stream = new Transform({
+ objectMode: true,
+ transform: common.mustCall((chunk) => {
+ stream.push(chunk);
+ })
+ });
+
+ stream.on('data', common.mustCall((chunk) => {
+ assert.strictEqual(chunk, undefined);
+ }));
+
+ stream.write(undefined);
+}
diff --git a/tests/node_compat/test/parallel/test-stream-once-readable-pipe.js b/tests/node_compat/test/parallel/test-stream-once-readable-pipe.js
new file mode 100644
index 000000000..f273b9602
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-once-readable-pipe.js
@@ -0,0 +1,68 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const assert = require('assert');
+const { Readable, Writable } = require('stream');
+
+// This test ensures that if have 'readable' listener
+// on Readable instance it will not disrupt the pipe.
+
+{
+ let receivedData = '';
+ const w = new Writable({
+ write: (chunk, env, callback) => {
+ receivedData += chunk;
+ callback();
+ },
+ });
+
+ const data = ['foo', 'bar', 'baz'];
+ const r = new Readable({
+ read: () => {},
+ });
+
+ r.once('readable', common.mustCall());
+
+ r.pipe(w);
+ r.push(data[0]);
+ r.push(data[1]);
+ r.push(data[2]);
+ r.push(null);
+
+ w.on('finish', common.mustCall(() => {
+ assert.strictEqual(receivedData, data.join(''));
+ }));
+}
+
+{
+ let receivedData = '';
+ const w = new Writable({
+ write: (chunk, env, callback) => {
+ receivedData += chunk;
+ callback();
+ },
+ });
+
+ const data = ['foo', 'bar', 'baz'];
+ const r = new Readable({
+ read: () => {},
+ });
+
+ r.pipe(w);
+ r.push(data[0]);
+ r.push(data[1]);
+ r.push(data[2]);
+ r.push(null);
+ r.once('readable', common.mustCall());
+
+ w.on('finish', common.mustCall(() => {
+ assert.strictEqual(receivedData, data.join(''));
+ }));
+}
diff --git a/tests/node_compat/test/parallel/test-stream-pipe-after-end.js b/tests/node_compat/test/parallel/test-stream-pipe-after-end.js
new file mode 100644
index 000000000..a7af22b94
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-pipe-after-end.js
@@ -0,0 +1,76 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const { Readable, Writable } = require('stream');
+
+class TestReadable extends Readable {
+ constructor(opt) {
+ super(opt);
+ this._ended = false;
+ }
+
+ _read() {
+ if (this._ended)
+ this.emit('error', new Error('_read called twice'));
+ this._ended = true;
+ this.push(null);
+ }
+}
+
+class TestWritable extends Writable {
+ constructor(opt) {
+ super(opt);
+ this._written = [];
+ }
+
+ _write(chunk, encoding, cb) {
+ this._written.push(chunk);
+ cb();
+ }
+}
+
+// This one should not emit 'end' until we read() from it later.
+const ender = new TestReadable();
+
+// What happens when you pipe() a Readable that's already ended?
+const piper = new TestReadable();
+// pushes EOF null, and length=0, so this will trigger 'end'
+piper.read();
+
+setTimeout(common.mustCall(function() {
+ ender.on('end', common.mustCall());
+ const c = ender.read();
+ assert.strictEqual(c, null);
+
+ const w = new TestWritable();
+ w.on('finish', common.mustCall());
+ piper.pipe(w);
+}), 1);
diff --git a/tests/node_compat/test/parallel/test-stream-pipe-await-drain-manual-resume.js b/tests/node_compat/test/parallel/test-stream-pipe-await-drain-manual-resume.js
new file mode 100644
index 000000000..e49c99033
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-pipe-await-drain-manual-resume.js
@@ -0,0 +1,82 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const stream = require('stream');
+const assert = require('assert');
+
+// A consumer stream with a very low highWaterMark, which starts in a state
+// where it buffers the chunk it receives rather than indicating that they
+// have been consumed.
+const writable = new stream.Writable({
+ highWaterMark: 5
+});
+
+let isCurrentlyBufferingWrites = true;
+const queue = [];
+
+writable._write = (chunk, encoding, cb) => {
+ if (isCurrentlyBufferingWrites)
+ queue.push({ chunk, cb });
+ else
+ cb();
+};
+
+const readable = new stream.Readable({
+ read() {}
+});
+
+readable.pipe(writable);
+
+readable.once('pause', common.mustCall(() => {
+ assert.strictEqual(
+ readable._readableState.awaitDrainWriters,
+ writable,
+ 'Expected awaitDrainWriters to be a Writable but instead got ' +
+ `${readable._readableState.awaitDrainWriters}`
+ );
+ // First pause, resume manually. The next write() to writable will still
+ // return false, because chunks are still being buffered, so it will increase
+ // the awaitDrain counter again.
+
+ process.nextTick(common.mustCall(() => {
+ readable.resume();
+ }));
+
+ readable.once('pause', common.mustCall(() => {
+ assert.strictEqual(
+ readable._readableState.awaitDrainWriters,
+ writable,
+ '.resume() should not reset the awaitDrainWriters, but instead got ' +
+ `${readable._readableState.awaitDrainWriters}`
+ );
+ // Second pause, handle all chunks from now on. Once all callbacks that
+ // are currently queued up are handled, the awaitDrain drain counter should
+ // fall back to 0 and all chunks that are pending on the readable side
+ // should be flushed.
+ isCurrentlyBufferingWrites = false;
+ for (const queued of queue)
+ queued.cb();
+ }));
+}));
+
+readable.push(Buffer.alloc(100)); // Fill the writable HWM, first 'pause'.
+readable.push(Buffer.alloc(100)); // Second 'pause'.
+readable.push(Buffer.alloc(100)); // Should get through to the writable.
+readable.push(null);
+
+writable.on('finish', common.mustCall(() => {
+ assert.strictEqual(
+ readable._readableState.awaitDrainWriters,
+ null,
+ `awaitDrainWriters should be reset to null
+ after all chunks are written but instead got
+ ${readable._readableState.awaitDrainWriters}`
+ );
+ // Everything okay, all chunks were written.
+}));
diff --git a/tests/node_compat/test/parallel/test-stream-pipe-await-drain-push-while-write.js b/tests/node_compat/test/parallel/test-stream-pipe-await-drain-push-while-write.js
new file mode 100644
index 000000000..54fbe9e89
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-pipe-await-drain-push-while-write.js
@@ -0,0 +1,43 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const stream = require('stream');
+const assert = require('assert');
+
+const writable = new stream.Writable({
+ write: common.mustCall(function(chunk, encoding, cb) {
+ assert.strictEqual(
+ readable._readableState.awaitDrainWriters,
+ null,
+ );
+
+ if (chunk.length === 32 * 1024) { // first chunk
+ readable.push(Buffer.alloc(34 * 1024)); // above hwm
+ // We should check if awaitDrain counter is increased in the next
+ // tick, because awaitDrain is incremented after this method finished
+ process.nextTick(() => {
+ assert.strictEqual(readable._readableState.awaitDrainWriters, writable);
+ });
+ }
+
+ process.nextTick(cb);
+ }, 3)
+});
+
+// A readable stream which produces two buffers.
+const bufs = [Buffer.alloc(32 * 1024), Buffer.alloc(33 * 1024)]; // above hwm
+const readable = new stream.Readable({
+ read: function() {
+ while (bufs.length > 0) {
+ this.push(bufs.shift());
+ }
+ }
+});
+
+readable.pipe(writable);
diff --git a/tests/node_compat/test/parallel/test-stream-pipe-await-drain.js b/tests/node_compat/test/parallel/test-stream-pipe-await-drain.js
new file mode 100644
index 000000000..49062fe0b
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-pipe-await-drain.js
@@ -0,0 +1,74 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const stream = require('stream');
+const assert = require('assert');
+
+// This is very similar to test-stream-pipe-cleanup-pause.js.
+
+const reader = new stream.Readable();
+const writer1 = new stream.Writable();
+const writer2 = new stream.Writable();
+const writer3 = new stream.Writable();
+
+// 560000 is chosen here because it is larger than the (default) highWaterMark
+// and will cause `.write()` to return false
+// See: https://github.com/nodejs/node/issues/5820
+const buffer = Buffer.allocUnsafe(560000);
+
+reader._read = () => {};
+
+writer1._write = common.mustCall(function(chunk, encoding, cb) {
+ this.emit('chunk-received');
+ process.nextTick(cb);
+}, 1);
+
+writer1.once('chunk-received', () => {
+ assert.strictEqual(
+ reader._readableState.awaitDrainWriters.size,
+ 0,
+ 'awaitDrain initial value should be 0, actual is ' +
+ reader._readableState.awaitDrainWriters.size
+ );
+ setImmediate(() => {
+ // This one should *not* get through to writer1 because writer2 is not
+ // "done" processing.
+ reader.push(buffer);
+ });
+});
+
+// A "slow" consumer:
+writer2._write = common.mustCall((chunk, encoding, cb) => {
+ assert.strictEqual(
+ reader._readableState.awaitDrainWriters.size,
+ 1,
+ 'awaitDrain should be 1 after first push, actual is ' +
+ reader._readableState.awaitDrainWriters.size
+ );
+ // Not calling cb here to "simulate" slow stream.
+ // This should be called exactly once, since the first .write() call
+ // will return false.
+}, 1);
+
+writer3._write = common.mustCall((chunk, encoding, cb) => {
+ assert.strictEqual(
+ reader._readableState.awaitDrainWriters.size,
+ 2,
+ 'awaitDrain should be 2 after second push, actual is ' +
+ reader._readableState.awaitDrainWriters.size
+ );
+ // Not calling cb here to "simulate" slow stream.
+ // This should be called exactly once, since the first .write() call
+ // will return false.
+}, 1);
+
+reader.pipe(writer1);
+reader.pipe(writer2);
+reader.pipe(writer3);
+reader.push(buffer);
diff --git a/tests/node_compat/test/parallel/test-stream-pipe-cleanup-pause.js b/tests/node_compat/test/parallel/test-stream-pipe-cleanup-pause.js
new file mode 100644
index 000000000..279ce10d5
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-pipe-cleanup-pause.js
@@ -0,0 +1,44 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const stream = require('stream');
+
+const reader = new stream.Readable();
+const writer1 = new stream.Writable();
+const writer2 = new stream.Writable();
+
+// 560000 is chosen here because it is larger than the (default) highWaterMark
+// and will cause `.write()` to return false
+// See: https://github.com/nodejs/node/issues/2323
+const buffer = Buffer.allocUnsafe(560000);
+
+reader._read = () => {};
+
+writer1._write = common.mustCall(function(chunk, encoding, cb) {
+ this.emit('chunk-received');
+ cb();
+}, 1);
+writer1.once('chunk-received', function() {
+ reader.unpipe(writer1);
+ reader.pipe(writer2);
+ reader.push(buffer);
+ setImmediate(function() {
+ reader.push(buffer);
+ setImmediate(function() {
+ reader.push(buffer);
+ });
+ });
+});
+
+writer2._write = common.mustCall(function(chunk, encoding, cb) {
+ cb();
+}, 3);
+
+reader.pipe(writer1);
+reader.push(buffer);
diff --git a/tests/node_compat/test/parallel/test-stream-pipe-cleanup.js b/tests/node_compat/test/parallel/test-stream-pipe-cleanup.js
new file mode 100644
index 000000000..8106ab4f1
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-pipe-cleanup.js
@@ -0,0 +1,132 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+// This test asserts that Stream.prototype.pipe does not leave listeners
+// hanging on the source or dest.
+require('../common');
+const stream = require('stream');
+const assert = require('assert');
+
+function Writable() {
+ this.writable = true;
+ this.endCalls = 0;
+ stream.Stream.call(this);
+}
+Object.setPrototypeOf(Writable.prototype, stream.Stream.prototype);
+Object.setPrototypeOf(Writable, stream.Stream);
+Writable.prototype.end = function() {
+ this.endCalls++;
+};
+
+Writable.prototype.destroy = function() {
+ this.endCalls++;
+};
+
+function Readable() {
+ this.readable = true;
+ stream.Stream.call(this);
+}
+Object.setPrototypeOf(Readable.prototype, stream.Stream.prototype);
+Object.setPrototypeOf(Readable, stream.Stream);
+
+function Duplex() {
+ this.readable = true;
+ Writable.call(this);
+}
+Object.setPrototypeOf(Duplex.prototype, Writable.prototype);
+Object.setPrototypeOf(Duplex, Writable);
+
+let i = 0;
+const limit = 100;
+
+let w = new Writable();
+
+let r;
+
+for (i = 0; i < limit; i++) {
+ r = new Readable();
+ r.pipe(w);
+ r.emit('end');
+}
+assert.strictEqual(r.listeners('end').length, 0);
+assert.strictEqual(w.endCalls, limit);
+
+w.endCalls = 0;
+
+for (i = 0; i < limit; i++) {
+ r = new Readable();
+ r.pipe(w);
+ r.emit('close');
+}
+assert.strictEqual(r.listeners('close').length, 0);
+assert.strictEqual(w.endCalls, limit);
+
+w.endCalls = 0;
+
+r = new Readable();
+
+for (i = 0; i < limit; i++) {
+ w = new Writable();
+ r.pipe(w);
+ w.emit('close');
+}
+assert.strictEqual(w.listeners('close').length, 0);
+
+r = new Readable();
+w = new Writable();
+const d = new Duplex();
+r.pipe(d); // pipeline A
+d.pipe(w); // pipeline B
+assert.strictEqual(r.listeners('end').length, 2); // A.onend, A.cleanup
+assert.strictEqual(r.listeners('close').length, 2); // A.onclose, A.cleanup
+assert.strictEqual(d.listeners('end').length, 2); // B.onend, B.cleanup
+// A.cleanup, B.onclose, B.cleanup
+assert.strictEqual(d.listeners('close').length, 3);
+assert.strictEqual(w.listeners('end').length, 0);
+assert.strictEqual(w.listeners('close').length, 1); // B.cleanup
+
+r.emit('end');
+assert.strictEqual(d.endCalls, 1);
+assert.strictEqual(w.endCalls, 0);
+assert.strictEqual(r.listeners('end').length, 0);
+assert.strictEqual(r.listeners('close').length, 0);
+assert.strictEqual(d.listeners('end').length, 2); // B.onend, B.cleanup
+assert.strictEqual(d.listeners('close').length, 2); // B.onclose, B.cleanup
+assert.strictEqual(w.listeners('end').length, 0);
+assert.strictEqual(w.listeners('close').length, 1); // B.cleanup
+
+d.emit('end');
+assert.strictEqual(d.endCalls, 1);
+assert.strictEqual(w.endCalls, 1);
+assert.strictEqual(r.listeners('end').length, 0);
+assert.strictEqual(r.listeners('close').length, 0);
+assert.strictEqual(d.listeners('end').length, 0);
+assert.strictEqual(d.listeners('close').length, 0);
+assert.strictEqual(w.listeners('end').length, 0);
+assert.strictEqual(w.listeners('close').length, 0);
diff --git a/tests/node_compat/test/parallel/test-stream-pipe-error-handling.js b/tests/node_compat/test/parallel/test-stream-pipe-error-handling.js
new file mode 100644
index 000000000..356bb1cd9
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-pipe-error-handling.js
@@ -0,0 +1,131 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const { Stream, PassThrough } = require('stream');
+
+{
+ const source = new Stream();
+ const dest = new Stream();
+
+ source.pipe(dest);
+
+ let gotErr = null;
+ source.on('error', function(err) {
+ gotErr = err;
+ });
+
+ const err = new Error('This stream turned into bacon.');
+ source.emit('error', err);
+ assert.strictEqual(gotErr, err);
+}
+
+{
+ const source = new Stream();
+ const dest = new Stream();
+
+ source.pipe(dest);
+
+ const err = new Error('This stream turned into bacon.');
+
+ let gotErr = null;
+ try {
+ source.emit('error', err);
+ } catch (e) {
+ gotErr = e;
+ }
+
+ assert.strictEqual(gotErr, err);
+}
+
+{
+ const R = Stream.Readable;
+ const W = Stream.Writable;
+
+ const r = new R({ autoDestroy: false });
+ const w = new W({ autoDestroy: false });
+ let removed = false;
+
+ r._read = common.mustCall(function() {
+ setTimeout(common.mustCall(function() {
+ assert(removed);
+ assert.throws(function() {
+ w.emit('error', new Error('fail'));
+ }, /^Error: fail$/);
+ }), 1);
+ });
+
+ w.on('error', myOnError);
+ r.pipe(w);
+ w.removeListener('error', myOnError);
+ removed = true;
+
+ function myOnError() {
+ throw new Error('this should not happen');
+ }
+}
+
+{
+ const R = Stream.Readable;
+ const W = Stream.Writable;
+
+ const r = new R();
+ const w = new W();
+ let removed = false;
+
+ r._read = common.mustCall(function() {
+ setTimeout(common.mustCall(function() {
+ assert(removed);
+ w.emit('error', new Error('fail'));
+ }), 1);
+ });
+
+ w.on('error', common.mustCall());
+ w._write = () => {};
+
+ r.pipe(w);
+ // Removing some OTHER random listener should not do anything
+ w.removeListener('error', () => {});
+ removed = true;
+}
+
+{
+ const _err = new Error('this should be handled');
+ const destination = new PassThrough();
+ destination.once('error', common.mustCall((err) => {
+ assert.strictEqual(err, _err);
+ }));
+
+ const stream = new Stream();
+ stream
+ .pipe(destination);
+
+ destination.destroy(_err);
+}
diff --git a/tests/node_compat/test/parallel/test-stream-pipe-event.js b/tests/node_compat/test/parallel/test-stream-pipe-event.js
new file mode 100644
index 000000000..a2721c053
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-pipe-event.js
@@ -0,0 +1,58 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+require('../common');
+const stream = require('stream');
+const assert = require('assert');
+
+function Writable() {
+ this.writable = true;
+ stream.Stream.call(this);
+}
+Object.setPrototypeOf(Writable.prototype, stream.Stream.prototype);
+Object.setPrototypeOf(Writable, stream.Stream);
+
+function Readable() {
+ this.readable = true;
+ stream.Stream.call(this);
+}
+Object.setPrototypeOf(Readable.prototype, stream.Stream.prototype);
+Object.setPrototypeOf(Readable, stream.Stream);
+
+let passed = false;
+
+const w = new Writable();
+w.on('pipe', function(src) {
+ passed = true;
+});
+
+const r = new Readable();
+r.pipe(w);
+
+assert.ok(passed);
diff --git a/tests/node_compat/test/parallel/test-stream-pipe-flow-after-unpipe.js b/tests/node_compat/test/parallel/test-stream-pipe-flow-after-unpipe.js
new file mode 100644
index 000000000..c0b144c18
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-pipe-flow-after-unpipe.js
@@ -0,0 +1,36 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const { Readable, Writable } = require('stream');
+
+// Tests that calling .unpipe() un-blocks a stream that is paused because
+// it is waiting on the writable side to finish a write().
+
+const rs = new Readable({
+ highWaterMark: 1,
+ // That this gets called at least 20 times is the real test here.
+ read: common.mustCallAtLeast(() => rs.push('foo'), 20)
+});
+
+const ws = new Writable({
+ highWaterMark: 1,
+ write: common.mustCall(() => {
+ // Ignore the callback, this write() simply never finishes.
+ setImmediate(() => rs.unpipe(ws));
+ })
+});
+
+let chunks = 0;
+rs.on('data', common.mustCallAtLeast(() => {
+ chunks++;
+ if (chunks >= 20)
+ rs.pause(); // Finish this test.
+}));
+
+rs.pipe(ws);
diff --git a/tests/node_compat/test/parallel/test-stream-pipe-flow.js b/tests/node_compat/test/parallel/test-stream-pipe-flow.js
new file mode 100644
index 000000000..8e877312f
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-pipe-flow.js
@@ -0,0 +1,97 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const { Readable, Writable, PassThrough } = require('stream');
+
+{
+ let ticks = 17;
+
+ const rs = new Readable({
+ objectMode: true,
+ read: () => {
+ if (ticks-- > 0)
+ return process.nextTick(() => rs.push({}));
+ rs.push({});
+ rs.push(null);
+ }
+ });
+
+ const ws = new Writable({
+ highWaterMark: 0,
+ objectMode: true,
+ write: (data, end, cb) => setImmediate(cb)
+ });
+
+ rs.on('end', common.mustCall());
+ ws.on('finish', common.mustCall());
+ rs.pipe(ws);
+}
+
+{
+ let missing = 8;
+
+ const rs = new Readable({
+ objectMode: true,
+ read: () => {
+ if (missing--) rs.push({});
+ else rs.push(null);
+ }
+ });
+
+ const pt = rs
+ .pipe(new PassThrough({ objectMode: true, highWaterMark: 2 }))
+ .pipe(new PassThrough({ objectMode: true, highWaterMark: 2 }));
+
+ pt.on('end', () => {
+ wrapper.push(null);
+ });
+
+ const wrapper = new Readable({
+ objectMode: true,
+ read: () => {
+ process.nextTick(() => {
+ let data = pt.read();
+ if (data === null) {
+ pt.once('readable', () => {
+ data = pt.read();
+ if (data !== null) wrapper.push(data);
+ });
+ } else {
+ wrapper.push(data);
+ }
+ });
+ }
+ });
+
+ wrapper.resume();
+ wrapper.on('end', common.mustCall());
+}
+
+{
+ // Only register drain if there is backpressure.
+ const rs = new Readable({ read() {} });
+
+ const pt = rs
+ .pipe(new PassThrough({ objectMode: true, highWaterMark: 2 }));
+ assert.strictEqual(pt.listenerCount('drain'), 0);
+ pt.on('finish', () => {
+ assert.strictEqual(pt.listenerCount('drain'), 0);
+ });
+
+ rs.push('asd');
+ assert.strictEqual(pt.listenerCount('drain'), 0);
+
+ process.nextTick(() => {
+ rs.push('asd');
+ assert.strictEqual(pt.listenerCount('drain'), 0);
+ rs.push(null);
+ assert.strictEqual(pt.listenerCount('drain'), 0);
+ });
+}
diff --git a/tests/node_compat/test/parallel/test-stream-pipe-manual-resume.js b/tests/node_compat/test/parallel/test-stream-pipe-manual-resume.js
new file mode 100644
index 000000000..0666e44d6
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-pipe-manual-resume.js
@@ -0,0 +1,42 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const stream = require('stream');
+
+function test(throwCodeInbetween) {
+ // Check that a pipe does not stall if .read() is called unexpectedly
+ // (i.e. the stream is not resumed by the pipe).
+
+ const n = 1000;
+ let counter = n;
+ const rs = stream.Readable({
+ objectMode: true,
+ read: common.mustCallAtLeast(() => {
+ if (--counter >= 0)
+ rs.push({ counter });
+ else
+ rs.push(null);
+ }, n)
+ });
+
+ const ws = stream.Writable({
+ objectMode: true,
+ write: common.mustCall((data, enc, cb) => {
+ setImmediate(cb);
+ }, n)
+ });
+
+ setImmediate(() => throwCodeInbetween(rs, ws));
+
+ rs.pipe(ws);
+}
+
+test((rs) => rs.read());
+test((rs) => rs.resume());
+test(() => 0);
diff --git a/tests/node_compat/test/parallel/test-stream-pipe-multiple-pipes.js b/tests/node_compat/test/parallel/test-stream-pipe-multiple-pipes.js
new file mode 100644
index 000000000..cd24dd4ca
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-pipe-multiple-pipes.js
@@ -0,0 +1,58 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const stream = require('stream');
+const assert = require('assert');
+
+const readable = new stream.Readable({
+ read: () => {}
+});
+
+const writables = [];
+
+for (let i = 0; i < 5; i++) {
+ const target = new stream.Writable({
+ write: common.mustCall((chunk, encoding, callback) => {
+ target.output.push(chunk);
+ callback();
+ }, 1)
+ });
+ target.output = [];
+
+ target.on('pipe', common.mustCall());
+ readable.pipe(target);
+
+
+ writables.push(target);
+}
+
+const input = Buffer.from([1, 2, 3, 4, 5]);
+
+readable.push(input);
+
+// The pipe() calls will postpone emission of the 'resume' event using nextTick,
+// so no data will be available to the writable streams until then.
+process.nextTick(common.mustCall(() => {
+ for (const target of writables) {
+ assert.deepStrictEqual(target.output, [input]);
+
+ target.on('unpipe', common.mustCall());
+ readable.unpipe(target);
+ }
+
+ readable.push('something else'); // This does not get through.
+ readable.push(null);
+ readable.resume(); // Make sure the 'end' event gets emitted.
+}));
+
+readable.on('end', common.mustCall(() => {
+ for (const target of writables) {
+ assert.deepStrictEqual(target.output, [input]);
+ }
+}));
diff --git a/tests/node_compat/test/parallel/test-stream-pipe-needDrain.js b/tests/node_compat/test/parallel/test-stream-pipe-needDrain.js
new file mode 100644
index 000000000..f8b724de9
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-pipe-needDrain.js
@@ -0,0 +1,38 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const assert = require('assert');
+const { Readable, Writable } = require('stream');
+
+// Pipe should pause temporarily if writable needs drain.
+{
+ const w = new Writable({
+ write(buf, encoding, callback) {
+ process.nextTick(callback);
+ },
+ highWaterMark: 1
+ });
+
+ while (w.write('asd'));
+
+ assert.strictEqual(w.writableNeedDrain, true);
+
+ const r = new Readable({
+ read() {
+ this.push('asd');
+ this.push(null);
+ }
+ });
+
+ r.on('pause', common.mustCall(2));
+ r.on('end', common.mustCall());
+
+ r.pipe(w);
+}
diff --git a/tests/node_compat/test/parallel/test-stream-pipe-same-destination-twice.js b/tests/node_compat/test/parallel/test-stream-pipe-same-destination-twice.js
new file mode 100644
index 000000000..7e1215733
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-pipe-same-destination-twice.js
@@ -0,0 +1,85 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+
+// Regression test for https://github.com/nodejs/node/issues/12718.
+// Tests that piping a source stream twice to the same destination stream
+// works, and that a subsequent unpipe() call only removes the pipe *once*.
+const assert = require('assert');
+const { PassThrough, Writable } = require('stream');
+
+{
+ const passThrough = new PassThrough();
+ const dest = new Writable({
+ write: common.mustCall((chunk, encoding, cb) => {
+ assert.strictEqual(`${chunk}`, 'foobar');
+ cb();
+ })
+ });
+
+ passThrough.pipe(dest);
+ passThrough.pipe(dest);
+
+ assert.strictEqual(passThrough._events.data.length, 2);
+ assert.strictEqual(passThrough._readableState.pipes.length, 2);
+ assert.strictEqual(passThrough._readableState.pipes[0], dest);
+ assert.strictEqual(passThrough._readableState.pipes[1], dest);
+
+ passThrough.unpipe(dest);
+
+ assert.strictEqual(passThrough._events.data.length, 1);
+ assert.strictEqual(passThrough._readableState.pipes.length, 1);
+ assert.deepStrictEqual(passThrough._readableState.pipes, [dest]);
+
+ passThrough.write('foobar');
+ passThrough.pipe(dest);
+}
+
+{
+ const passThrough = new PassThrough();
+ const dest = new Writable({
+ write: common.mustCall((chunk, encoding, cb) => {
+ assert.strictEqual(`${chunk}`, 'foobar');
+ cb();
+ }, 2)
+ });
+
+ passThrough.pipe(dest);
+ passThrough.pipe(dest);
+
+ assert.strictEqual(passThrough._events.data.length, 2);
+ assert.strictEqual(passThrough._readableState.pipes.length, 2);
+ assert.strictEqual(passThrough._readableState.pipes[0], dest);
+ assert.strictEqual(passThrough._readableState.pipes[1], dest);
+
+ passThrough.write('foobar');
+}
+
+{
+ const passThrough = new PassThrough();
+ const dest = new Writable({
+ write: common.mustNotCall()
+ });
+
+ passThrough.pipe(dest);
+ passThrough.pipe(dest);
+
+ assert.strictEqual(passThrough._events.data.length, 2);
+ assert.strictEqual(passThrough._readableState.pipes.length, 2);
+ assert.strictEqual(passThrough._readableState.pipes[0], dest);
+ assert.strictEqual(passThrough._readableState.pipes[1], dest);
+
+ passThrough.unpipe(dest);
+ passThrough.unpipe(dest);
+
+ assert.strictEqual(passThrough._events.data, undefined);
+ assert.strictEqual(passThrough._readableState.pipes.length, 0);
+
+ passThrough.write('foobar');
+}
diff --git a/tests/node_compat/test/parallel/test-stream-pipe-unpipe-streams.js b/tests/node_compat/test/parallel/test-stream-pipe-unpipe-streams.js
new file mode 100644
index 000000000..a51dcfbad
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-pipe-unpipe-streams.js
@@ -0,0 +1,103 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+
+const { Readable, Writable } = require('stream');
+
+const source = Readable({ read: () => {} });
+const dest1 = Writable({ write: () => {} });
+const dest2 = Writable({ write: () => {} });
+
+source.pipe(dest1);
+source.pipe(dest2);
+
+dest1.on('unpipe', common.mustCall());
+dest2.on('unpipe', common.mustCall());
+
+assert.strictEqual(source._readableState.pipes[0], dest1);
+assert.strictEqual(source._readableState.pipes[1], dest2);
+assert.strictEqual(source._readableState.pipes.length, 2);
+
+// Should be able to unpipe them in the reverse order that they were piped.
+
+source.unpipe(dest2);
+
+assert.deepStrictEqual(source._readableState.pipes, [dest1]);
+assert.notStrictEqual(source._readableState.pipes, dest2);
+
+dest2.on('unpipe', common.mustNotCall());
+source.unpipe(dest2);
+
+source.unpipe(dest1);
+
+assert.strictEqual(source._readableState.pipes.length, 0);
+
+{
+ // Test `cleanup()` if we unpipe all streams.
+ const source = Readable({ read: () => {} });
+ const dest1 = Writable({ write: () => {} });
+ const dest2 = Writable({ write: () => {} });
+
+ let destCount = 0;
+ const srcCheckEventNames = ['end', 'data'];
+ const destCheckEventNames = ['close', 'finish', 'drain', 'error', 'unpipe'];
+
+ const checkSrcCleanup = common.mustCall(() => {
+ assert.strictEqual(source._readableState.pipes.length, 0);
+ assert.strictEqual(source._readableState.flowing, false);
+
+ srcCheckEventNames.forEach((eventName) => {
+ assert.strictEqual(
+ source.listenerCount(eventName), 0,
+ `source's '${eventName}' event listeners not removed`
+ );
+ });
+ });
+
+ function checkDestCleanup(dest) {
+ const currentDestId = ++destCount;
+ source.pipe(dest);
+
+ const unpipeChecker = common.mustCall(() => {
+ assert.deepStrictEqual(
+ dest.listeners('unpipe'), [unpipeChecker],
+ `destination{${currentDestId}} should have a 'unpipe' event ` +
+ 'listener which is `unpipeChecker`'
+ );
+ dest.removeListener('unpipe', unpipeChecker);
+ destCheckEventNames.forEach((eventName) => {
+ assert.strictEqual(
+ dest.listenerCount(eventName), 0,
+ `destination{${currentDestId}}'s '${eventName}' event ` +
+ 'listeners not removed'
+ );
+ });
+
+ if (--destCount === 0)
+ checkSrcCleanup();
+ });
+
+ dest.on('unpipe', unpipeChecker);
+ }
+
+ checkDestCleanup(dest1);
+ checkDestCleanup(dest2);
+ source.unpipe();
+}
+
+{
+ const src = Readable({ read: () => {} });
+ const dst = Writable({ write: () => {} });
+ src.pipe(dst);
+ src.on('resume', common.mustCall(() => {
+ src.on('pause', common.mustCall());
+ src.unpipe(dst);
+ }));
+}
diff --git a/tests/node_compat/test/parallel/test-stream-pipe-without-listenerCount.js b/tests/node_compat/test/parallel/test-stream-pipe-without-listenerCount.js
new file mode 100644
index 000000000..7a1719be3
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-pipe-without-listenerCount.js
@@ -0,0 +1,24 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const stream = require('stream');
+
+const r = new stream.Stream();
+r.listenerCount = undefined;
+
+const w = new stream.Stream();
+w.listenerCount = undefined;
+
+w.on('pipe', function() {
+ r.emit('error', new Error('Readable Error'));
+ w.emit('error', new Error('Writable Error'));
+});
+r.on('error', common.mustCall());
+w.on('error', common.mustCall());
+r.pipe(w);
diff --git a/tests/node_compat/test/parallel/test-stream-pipeline-async-iterator.js b/tests/node_compat/test/parallel/test-stream-pipeline-async-iterator.js
new file mode 100644
index 000000000..3d3ce96cc
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-pipeline-async-iterator.js
@@ -0,0 +1,38 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const { Readable, PassThrough, pipeline } = require('stream');
+const assert = require('assert');
+
+const _err = new Error('kaboom');
+
+async function run() {
+ const source = new Readable({
+ read() {
+ }
+ });
+ source.push('hello');
+ source.push('world');
+
+ setImmediate(() => { source.destroy(_err); });
+
+ const iterator = pipeline(
+ source,
+ new PassThrough(),
+ () => {});
+
+ iterator.setEncoding('utf8');
+
+ for await (const k of iterator) {
+ assert.strictEqual(k, 'helloworld');
+ }
+}
+
+run().catch(common.mustCall((err) => assert.strictEqual(err, _err)));
diff --git a/tests/node_compat/test/parallel/test-stream-pipeline-queued-end-in-destroy.js b/tests/node_compat/test/parallel/test-stream-pipeline-queued-end-in-destroy.js
new file mode 100644
index 000000000..e785a0008
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-pipeline-queued-end-in-destroy.js
@@ -0,0 +1,46 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const { Readable, Duplex, pipeline } = require('stream');
+
+// Test that the callback for pipeline() is called even when the ._destroy()
+// method of the stream places an .end() request to itself that does not
+// get processed before the destruction of the stream (i.e. the 'close' event).
+// Refs: https://github.com/nodejs/node/issues/24456
+
+const readable = new Readable({
+ read: common.mustCall()
+});
+
+const duplex = new Duplex({
+ write(chunk, enc, cb) {
+ // Simulate messages queueing up.
+ },
+ read() {},
+ destroy(err, cb) {
+ // Call end() from inside the destroy() method, like HTTP/2 streams
+ // do at the time of writing.
+ this.end();
+ cb(err);
+ }
+});
+
+duplex.on('finished', common.mustNotCall());
+
+pipeline(readable, duplex, common.mustCall((err) => {
+ assert.strictEqual(err.code, 'ERR_STREAM_PREMATURE_CLOSE');
+}));
+
+// Write one chunk of data, and destroy the stream later.
+// That should trigger the pipeline destruction.
+readable.push('foo');
+setImmediate(() => {
+ readable.destroy();
+});
diff --git a/tests/node_compat/test/parallel/test-stream-pipeline-with-empty-string.js b/tests/node_compat/test/parallel/test-stream-pipeline-with-empty-string.js
new file mode 100644
index 000000000..a03fe17dd
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-pipeline-with-empty-string.js
@@ -0,0 +1,25 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const {
+ pipeline,
+ PassThrough
+} = require('stream');
+
+
+async function runTest() {
+ await pipeline(
+ '',
+ new PassThrough({ objectMode: true }),
+ common.mustCall(),
+ );
+}
+
+runTest().then(common.mustCall());
diff --git a/tests/node_compat/test/parallel/test-stream-push-strings.js b/tests/node_compat/test/parallel/test-stream-push-strings.js
new file mode 100644
index 000000000..4d88e082b
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-push-strings.js
@@ -0,0 +1,74 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+
+const Readable = require('stream').Readable;
+
+class MyStream extends Readable {
+ constructor(options) {
+ super(options);
+ this._chunks = 3;
+ }
+
+ _read(n) {
+ switch (this._chunks--) {
+ case 0:
+ return this.push(null);
+ case 1:
+ return setTimeout(() => {
+ this.push('last chunk');
+ }, 100);
+ case 2:
+ return this.push('second to last chunk');
+ case 3:
+ return process.nextTick(() => {
+ this.push('first chunk');
+ });
+ default:
+ throw new Error('?');
+ }
+ }
+}
+
+const ms = new MyStream();
+const results = [];
+ms.on('readable', function() {
+ let chunk;
+ while (null !== (chunk = ms.read()))
+ results.push(String(chunk));
+});
+
+const expect = [ 'first chunksecond to last chunk', 'last chunk' ];
+process.on('exit', function() {
+ assert.strictEqual(ms._chunks, -1);
+ assert.deepStrictEqual(results, expect);
+ console.log('ok');
+});
diff --git a/tests/node_compat/test/parallel/test-stream-readable-aborted.js b/tests/node_compat/test/parallel/test-stream-readable-aborted.js
new file mode 100644
index 000000000..3e6550e7e
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-readable-aborted.js
@@ -0,0 +1,73 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const assert = require('assert');
+const { Readable, Duplex } = require('stream');
+
+{
+ const readable = new Readable({
+ read() {
+ }
+ });
+ assert.strictEqual(readable.readableAborted, false);
+ readable.destroy();
+ assert.strictEqual(readable.readableAborted, true);
+}
+
+{
+ const readable = new Readable({
+ read() {
+ }
+ });
+ assert.strictEqual(readable.readableAborted, false);
+ readable.push(null);
+ readable.destroy();
+ assert.strictEqual(readable.readableAborted, true);
+}
+
+{
+ const readable = new Readable({
+ read() {
+ }
+ });
+ assert.strictEqual(readable.readableAborted, false);
+ readable.push('asd');
+ readable.destroy();
+ assert.strictEqual(readable.readableAborted, true);
+}
+
+{
+ const readable = new Readable({
+ read() {
+ }
+ });
+ assert.strictEqual(readable.readableAborted, false);
+ readable.push('asd');
+ readable.push(null);
+ assert.strictEqual(readable.readableAborted, false);
+ readable.on('end', common.mustCall(() => {
+ assert.strictEqual(readable.readableAborted, false);
+ readable.destroy();
+ assert.strictEqual(readable.readableAborted, false);
+ queueMicrotask(() => {
+ assert.strictEqual(readable.readableAborted, false);
+ });
+ }));
+ readable.resume();
+}
+
+{
+ const duplex = new Duplex({
+ readable: false,
+ write() {}
+ });
+ duplex.destroy();
+ assert.strictEqual(duplex.readableAborted, false);
+}
diff --git a/tests/node_compat/test/parallel/test-stream-readable-add-chunk-during-data.js b/tests/node_compat/test/parallel/test-stream-readable-add-chunk-during-data.js
new file mode 100644
index 000000000..50939ac81
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-readable-add-chunk-during-data.js
@@ -0,0 +1,28 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const { Readable } = require('stream');
+
+// Verify that .push() and .unshift() can be called from 'data' listeners.
+
+for (const method of ['push', 'unshift']) {
+ const r = new Readable({ read() {} });
+ r.once('data', common.mustCall((chunk) => {
+ assert.strictEqual(r.readableLength, 0);
+ r[method](chunk);
+ assert.strictEqual(r.readableLength, chunk.length);
+
+ r.on('data', common.mustCall((chunk) => {
+ assert.strictEqual(chunk.toString(), 'Hello, world');
+ }));
+ }));
+
+ r.push('Hello, world');
+}
diff --git a/tests/node_compat/test/parallel/test-stream-readable-constructor-set-methods.js b/tests/node_compat/test/parallel/test-stream-readable-constructor-set-methods.js
new file mode 100644
index 000000000..b11ae8fca
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-readable-constructor-set-methods.js
@@ -0,0 +1,18 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+
+const Readable = require('stream').Readable;
+
+const _read = common.mustCall(function _read(n) {
+ this.push(null);
+});
+
+const r = new Readable({ read: _read });
+r.resume();
diff --git a/tests/node_compat/test/parallel/test-stream-readable-data.js b/tests/node_compat/test/parallel/test-stream-readable-data.js
new file mode 100644
index 000000000..d33f9f248
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-readable-data.js
@@ -0,0 +1,26 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+
+const { Readable } = require('stream');
+
+const readable = new Readable({
+ read() {}
+});
+
+function read() {}
+
+readable.setEncoding('utf8');
+readable.on('readable', read);
+readable.removeListener('readable', read);
+
+process.nextTick(function() {
+ readable.on('data', common.mustCall());
+ readable.push('hello');
+});
diff --git a/tests/node_compat/test/parallel/test-stream-readable-destroy.js b/tests/node_compat/test/parallel/test-stream-readable-destroy.js
new file mode 100644
index 000000000..0a780c98e
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-readable-destroy.js
@@ -0,0 +1,412 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const { Readable, addAbortSignal } = require('stream');
+const assert = require('assert');
+
+{
+ const read = new Readable({
+ read() {}
+ });
+ read.resume();
+
+ read.on('close', common.mustCall());
+
+ read.destroy();
+ assert.strictEqual(read.errored, null);
+ assert.strictEqual(read.destroyed, true);
+}
+
+{
+ const read = new Readable({
+ read() {}
+ });
+ read.resume();
+
+ const expected = new Error('kaboom');
+
+ read.on('end', common.mustNotCall('no end event'));
+ read.on('close', common.mustCall());
+ read.on('error', common.mustCall((err) => {
+ assert.strictEqual(err, expected);
+ }));
+
+ read.destroy(expected);
+ assert.strictEqual(read.errored, expected);
+ assert.strictEqual(read.destroyed, true);
+}
+
+{
+ const read = new Readable({
+ read() {}
+ });
+
+ read._destroy = common.mustCall(function(err, cb) {
+ assert.strictEqual(err, expected);
+ cb(err);
+ });
+
+ const expected = new Error('kaboom');
+
+ read.on('end', common.mustNotCall('no end event'));
+ read.on('close', common.mustCall());
+ read.on('error', common.mustCall((err) => {
+ assert.strictEqual(err, expected);
+ }));
+
+ read.destroy(expected);
+ assert.strictEqual(read.destroyed, true);
+}
+
+{
+ const read = new Readable({
+ read() {},
+ destroy: common.mustCall(function(err, cb) {
+ assert.strictEqual(err, expected);
+ cb();
+ })
+ });
+
+ const expected = new Error('kaboom');
+
+ read.on('end', common.mustNotCall('no end event'));
+
+ // Error is swallowed by the custom _destroy
+ read.on('error', common.mustNotCall('no error event'));
+ read.on('close', common.mustCall());
+
+ read.destroy(expected);
+ assert.strictEqual(read.destroyed, true);
+}
+
+{
+ const read = new Readable({
+ read() {}
+ });
+
+ read._destroy = common.mustCall(function(err, cb) {
+ assert.strictEqual(err, null);
+ cb();
+ });
+
+ read.destroy();
+ assert.strictEqual(read.destroyed, true);
+}
+
+{
+ const read = new Readable({
+ read() {}
+ });
+ read.resume();
+
+ read._destroy = common.mustCall(function(err, cb) {
+ assert.strictEqual(err, null);
+ process.nextTick(() => {
+ this.push(null);
+ cb();
+ });
+ });
+
+ const fail = common.mustNotCall('no end event');
+
+ read.on('end', fail);
+ read.on('close', common.mustCall());
+
+ read.destroy();
+
+ read.removeListener('end', fail);
+ read.on('end', common.mustNotCall());
+ assert.strictEqual(read.destroyed, true);
+}
+
+{
+ const read = new Readable({
+ read() {}
+ });
+
+ const expected = new Error('kaboom');
+
+ read._destroy = common.mustCall(function(err, cb) {
+ assert.strictEqual(err, null);
+ cb(expected);
+ });
+
+ let ticked = false;
+ read.on('end', common.mustNotCall('no end event'));
+ read.on('error', common.mustCall((err) => {
+ assert.strictEqual(ticked, true);
+ assert.strictEqual(read._readableState.errorEmitted, true);
+ assert.strictEqual(read._readableState.errored, expected);
+ assert.strictEqual(err, expected);
+ }));
+
+ read.destroy();
+ assert.strictEqual(read._readableState.errorEmitted, false);
+ assert.strictEqual(read._readableState.errored, expected);
+ assert.strictEqual(read.destroyed, true);
+ ticked = true;
+}
+
+{
+ const read = new Readable({
+ read() {}
+ });
+ read.resume();
+
+ read.destroyed = true;
+ assert.strictEqual(read.destroyed, true);
+
+ // The internal destroy() mechanism should not be triggered
+ read.on('end', common.mustNotCall());
+ read.destroy();
+}
+
+{
+ function MyReadable() {
+ assert.strictEqual(this.destroyed, false);
+ this.destroyed = false;
+ Readable.call(this);
+ }
+
+ Object.setPrototypeOf(MyReadable.prototype, Readable.prototype);
+ Object.setPrototypeOf(MyReadable, Readable);
+
+ new MyReadable();
+}
+
+{
+ // Destroy and destroy callback
+ const read = new Readable({
+ read() {}
+ });
+ read.resume();
+
+ const expected = new Error('kaboom');
+
+ let ticked = false;
+ read.on('close', common.mustCall(() => {
+ assert.strictEqual(read._readableState.errorEmitted, true);
+ assert.strictEqual(ticked, true);
+ }));
+ read.on('error', common.mustCall((err) => {
+ assert.strictEqual(err, expected);
+ }));
+
+ assert.strictEqual(read._readableState.errored, null);
+ assert.strictEqual(read._readableState.errorEmitted, false);
+
+ read.destroy(expected, common.mustCall(function(err) {
+ assert.strictEqual(read._readableState.errored, expected);
+ assert.strictEqual(err, expected);
+ }));
+ assert.strictEqual(read._readableState.errorEmitted, false);
+ assert.strictEqual(read._readableState.errored, expected);
+ ticked = true;
+}
+
+{
+ const readable = new Readable({
+ destroy: common.mustCall(function(err, cb) {
+ process.nextTick(cb, new Error('kaboom 1'));
+ }),
+ read() {}
+ });
+
+ let ticked = false;
+ readable.on('close', common.mustCall(() => {
+ assert.strictEqual(ticked, true);
+ assert.strictEqual(readable._readableState.errorEmitted, true);
+ }));
+ readable.on('error', common.mustCall((err) => {
+ assert.strictEqual(ticked, true);
+ assert.strictEqual(err.message, 'kaboom 1');
+ assert.strictEqual(readable._readableState.errorEmitted, true);
+ }));
+
+ readable.destroy();
+ assert.strictEqual(readable.destroyed, true);
+ assert.strictEqual(readable._readableState.errored, null);
+ assert.strictEqual(readable._readableState.errorEmitted, false);
+
+ // Test case where `readable.destroy()` is called again with an error before
+ // the `_destroy()` callback is called.
+ readable.destroy(new Error('kaboom 2'));
+ assert.strictEqual(readable._readableState.errorEmitted, false);
+ assert.strictEqual(readable._readableState.errored, null);
+
+ ticked = true;
+}
+
+{
+ const read = new Readable({
+ read() {}
+ });
+
+ read.destroy();
+ read.push('hi');
+ read.on('data', common.mustNotCall());
+}
+
+{
+ const read = new Readable({
+ read: common.mustNotCall()
+ });
+ read.destroy();
+ assert.strictEqual(read.destroyed, true);
+ read.read();
+}
+
+{
+ const read = new Readable({
+ autoDestroy: false,
+ read() {
+ this.push(null);
+ this.push('asd');
+ }
+ });
+
+ read.on('error', common.mustCall(() => {
+ assert(read._readableState.errored);
+ }));
+ read.resume();
+}
+
+{
+ const controller = new AbortController();
+ const read = addAbortSignal(controller.signal, new Readable({
+ read() {
+ this.push('asd');
+ },
+ }));
+
+ read.on('error', common.mustCall((e) => {
+ assert.strictEqual(e.name, 'AbortError');
+ }));
+ controller.abort();
+ read.on('data', common.mustNotCall());
+}
+
+{
+ const controller = new AbortController();
+ const read = new Readable({
+ signal: controller.signal,
+ read() {
+ this.push('asd');
+ },
+ });
+
+ read.on('error', common.mustCall((e) => {
+ assert.strictEqual(e.name, 'AbortError');
+ }));
+ controller.abort();
+ read.on('data', common.mustNotCall());
+}
+
+{
+ const controller = new AbortController();
+ const read = addAbortSignal(controller.signal, new Readable({
+ objectMode: true,
+ read() {
+ return false;
+ }
+ }));
+ read.push('asd');
+
+ read.on('error', common.mustCall((e) => {
+ assert.strictEqual(e.name, 'AbortError');
+ }));
+ assert.rejects((async () => {
+ // eslint-disable-next-line no-unused-vars, no-empty
+ for await (const chunk of read) { }
+ })(), /AbortError/);
+ setTimeout(() => controller.abort(), 0);
+}
+
+{
+ const read = new Readable({
+ read() {
+ },
+ });
+
+ read.on('data', common.mustNotCall());
+ read.on('error', common.mustCall((e) => {
+ read.push('asd');
+ read.read();
+ }));
+ read.on('close', common.mustCall((e) => {
+ read.push('asd');
+ read.read();
+ }));
+ read.destroy(new Error('asd'));
+}
+
+{
+ const read = new Readable({
+ read() {
+ },
+ });
+
+ read.on('data', common.mustNotCall());
+ read.on('close', common.mustCall((e) => {
+ read.push('asd');
+ read.read();
+ }));
+ read.destroy();
+}
+
+{
+ const read = new Readable({
+ read() {
+ },
+ });
+
+ read.on('data', common.mustNotCall());
+ read.on('close', common.mustCall((e) => {
+ read.push('asd');
+ read.unshift('asd');
+ }));
+ read.destroy();
+}
+
+{
+ const read = new Readable({
+ read() {
+ },
+ });
+
+ read.on('data', common.mustNotCall());
+ read.destroy();
+ read.unshift('asd');
+}
+
+{
+ const read = new Readable({
+ read() {
+ },
+ });
+
+ read.resume();
+ read.on('data', common.mustNotCall());
+ read.on('close', common.mustCall((e) => {
+ read.push('asd');
+ }));
+ read.destroy();
+}
+
+{
+ const read = new Readable({
+ read() {
+ },
+ });
+
+ read.on('data', common.mustNotCall());
+ read.destroy();
+ read.push('asd');
+}
diff --git a/tests/node_compat/test/parallel/test-stream-readable-didRead.js b/tests/node_compat/test/parallel/test-stream-readable-didRead.js
new file mode 100644
index 000000000..2d9cfa40f
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-readable-didRead.js
@@ -0,0 +1,118 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const { isDisturbed, isErrored, Readable } = require('stream');
+
+function noop() {}
+
+function check(readable, data, fn) {
+ assert.strictEqual(readable.readableDidRead, false);
+ assert.strictEqual(isDisturbed(readable), false);
+ assert.strictEqual(isErrored(readable), false);
+ if (data === -1) {
+ readable.on('error', common.mustCall(() => {
+ assert.strictEqual(isErrored(readable), true);
+ }));
+ readable.on('data', common.mustNotCall());
+ readable.on('end', common.mustNotCall());
+ } else {
+ readable.on('error', common.mustNotCall());
+ if (data === -2) {
+ readable.on('end', common.mustNotCall());
+ } else {
+ readable.on('end', common.mustCall());
+ }
+ if (data > 0) {
+ readable.on('data', common.mustCallAtLeast(data));
+ } else {
+ readable.on('data', common.mustNotCall());
+ }
+ }
+ readable.on('close', common.mustCall());
+ fn();
+ setImmediate(() => {
+ assert.strictEqual(readable.readableDidRead, data > 0);
+ if (data > 0) {
+ assert.strictEqual(isDisturbed(readable), true);
+ }
+ });
+}
+
+{
+ const readable = new Readable({
+ read() {
+ this.push(null);
+ }
+ });
+ check(readable, 0, () => {
+ readable.read();
+ });
+}
+
+{
+ const readable = new Readable({
+ read() {
+ this.push(null);
+ }
+ });
+ check(readable, 0, () => {
+ readable.resume();
+ });
+}
+
+{
+ const readable = new Readable({
+ read() {
+ this.push(null);
+ }
+ });
+ check(readable, -2, () => {
+ readable.destroy();
+ });
+}
+
+{
+ const readable = new Readable({
+ read() {
+ this.push(null);
+ }
+ });
+
+ check(readable, -1, () => {
+ readable.destroy(new Error());
+ });
+}
+
+{
+ const readable = new Readable({
+ read() {
+ this.push('data');
+ this.push(null);
+ }
+ });
+
+ check(readable, 1, () => {
+ readable.on('data', noop);
+ });
+}
+
+{
+ const readable = new Readable({
+ read() {
+ this.push('data');
+ this.push(null);
+ }
+ });
+
+ check(readable, 1, () => {
+ readable.on('data', noop);
+ readable.off('data', noop);
+ });
+}
diff --git a/tests/node_compat/test/parallel/test-stream-readable-emit-readable-short-stream.js b/tests/node_compat/test/parallel/test-stream-readable-emit-readable-short-stream.js
new file mode 100644
index 000000000..fac562092
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-readable-emit-readable-short-stream.js
@@ -0,0 +1,153 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const stream = require('stream');
+const assert = require('assert');
+
+{
+ const r = new stream.Readable({
+ read: common.mustCall(function() {
+ this.push('content');
+ this.push(null);
+ })
+ });
+
+ const t = new stream.Transform({
+ transform: common.mustCall(function(chunk, encoding, callback) {
+ this.push(chunk);
+ return callback();
+ }),
+ flush: common.mustCall(function(callback) {
+ return callback();
+ })
+ });
+
+ r.pipe(t);
+ t.on('readable', common.mustCall(function() {
+ while (true) {
+ const chunk = t.read();
+ if (!chunk)
+ break;
+
+ assert.strictEqual(chunk.toString(), 'content');
+ }
+ }, 2));
+}
+
+{
+ const t = new stream.Transform({
+ transform: common.mustCall(function(chunk, encoding, callback) {
+ this.push(chunk);
+ return callback();
+ }),
+ flush: common.mustCall(function(callback) {
+ return callback();
+ })
+ });
+
+ t.end('content');
+
+ t.on('readable', common.mustCall(function() {
+ while (true) {
+ const chunk = t.read();
+ if (!chunk)
+ break;
+ assert.strictEqual(chunk.toString(), 'content');
+ }
+ }));
+}
+
+{
+ const t = new stream.Transform({
+ transform: common.mustCall(function(chunk, encoding, callback) {
+ this.push(chunk);
+ return callback();
+ }),
+ flush: common.mustCall(function(callback) {
+ return callback();
+ })
+ });
+
+ t.write('content');
+ t.end();
+
+ t.on('readable', common.mustCall(function() {
+ while (true) {
+ const chunk = t.read();
+ if (!chunk)
+ break;
+ assert.strictEqual(chunk.toString(), 'content');
+ }
+ }));
+}
+
+{
+ const t = new stream.Readable({
+ read() {
+ }
+ });
+
+ t.on('readable', common.mustCall(function() {
+ while (true) {
+ const chunk = t.read();
+ if (!chunk)
+ break;
+ assert.strictEqual(chunk.toString(), 'content');
+ }
+ }));
+
+ t.push('content');
+ t.push(null);
+}
+
+{
+ const t = new stream.Readable({
+ read() {
+ }
+ });
+
+ t.on('readable', common.mustCall(function() {
+ while (true) {
+ const chunk = t.read();
+ if (!chunk)
+ break;
+ assert.strictEqual(chunk.toString(), 'content');
+ }
+ }, 2));
+
+ process.nextTick(() => {
+ t.push('content');
+ t.push(null);
+ });
+}
+
+{
+ const t = new stream.Transform({
+ transform: common.mustCall(function(chunk, encoding, callback) {
+ this.push(chunk);
+ return callback();
+ }),
+ flush: common.mustCall(function(callback) {
+ return callback();
+ })
+ });
+
+ t.on('readable', common.mustCall(function() {
+ while (true) {
+ const chunk = t.read();
+ if (!chunk)
+ break;
+ assert.strictEqual(chunk.toString(), 'content');
+ }
+ }, 2));
+
+ t.write('content');
+ t.end();
+}
diff --git a/tests/node_compat/test/parallel/test-stream-readable-emittedReadable.js b/tests/node_compat/test/parallel/test-stream-readable-emittedReadable.js
new file mode 100644
index 000000000..a05130737
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-readable-emittedReadable.js
@@ -0,0 +1,80 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const Readable = require('stream').Readable;
+
+const readable = new Readable({
+ read: () => {}
+});
+
+// Initialized to false.
+assert.strictEqual(readable._readableState.emittedReadable, false);
+
+const expected = [Buffer.from('foobar'), Buffer.from('quo'), null];
+readable.on('readable', common.mustCall(() => {
+ // emittedReadable should be true when the readable event is emitted
+ assert.strictEqual(readable._readableState.emittedReadable, true);
+ assert.deepStrictEqual(readable.read(), expected.shift());
+ // emittedReadable is reset to false during read()
+ assert.strictEqual(readable._readableState.emittedReadable, false);
+}, 3));
+
+// When the first readable listener is just attached,
+// emittedReadable should be false
+assert.strictEqual(readable._readableState.emittedReadable, false);
+
+// These trigger a single 'readable', as things are batched up
+process.nextTick(common.mustCall(() => {
+ readable.push('foo');
+}));
+process.nextTick(common.mustCall(() => {
+ readable.push('bar');
+}));
+
+// These triggers two readable events
+setImmediate(common.mustCall(() => {
+ readable.push('quo');
+ process.nextTick(common.mustCall(() => {
+ readable.push(null);
+ }));
+}));
+
+const noRead = new Readable({
+ read: () => {}
+});
+
+noRead.on('readable', common.mustCall(() => {
+ // emittedReadable should be true when the readable event is emitted
+ assert.strictEqual(noRead._readableState.emittedReadable, true);
+ noRead.read(0);
+ // emittedReadable is not reset during read(0)
+ assert.strictEqual(noRead._readableState.emittedReadable, true);
+}));
+
+noRead.push('foo');
+noRead.push(null);
+
+const flowing = new Readable({
+ read: () => {}
+});
+
+flowing.on('data', common.mustCall(() => {
+ // When in flowing mode, emittedReadable is always false.
+ assert.strictEqual(flowing._readableState.emittedReadable, false);
+ flowing.read();
+ assert.strictEqual(flowing._readableState.emittedReadable, false);
+}, 3));
+
+flowing.push('foooo');
+flowing.push('bar');
+flowing.push('quo');
+process.nextTick(common.mustCall(() => {
+ flowing.push(null);
+}));
diff --git a/tests/node_compat/test/parallel/test-stream-readable-end-destroyed.js b/tests/node_compat/test/parallel/test-stream-readable-end-destroyed.js
new file mode 100644
index 000000000..7c542f330
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-readable-end-destroyed.js
@@ -0,0 +1,24 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const { Readable } = require('stream');
+
+{
+ // Don't emit 'end' after 'close'.
+
+ const r = new Readable();
+
+ r.on('end', common.mustNotCall());
+ r.resume();
+ r.destroy();
+ r.on('close', common.mustCall(() => {
+ r.push(null);
+ }));
+}
diff --git a/tests/node_compat/test/parallel/test-stream-readable-ended.js b/tests/node_compat/test/parallel/test-stream-readable-ended.js
new file mode 100644
index 000000000..b8f59e2df
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-readable-ended.js
@@ -0,0 +1,53 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const { Readable } = require('stream');
+const assert = require('assert');
+
+// basic
+{
+ // Find it on Readable.prototype
+ assert(Object.hasOwn(Readable.prototype, 'readableEnded'));
+}
+
+// event
+{
+ const readable = new Readable();
+
+ readable._read = () => {
+ // The state ended should start in false.
+ assert.strictEqual(readable.readableEnded, false);
+ readable.push('asd');
+ assert.strictEqual(readable.readableEnded, false);
+ readable.push(null);
+ assert.strictEqual(readable.readableEnded, false);
+ };
+
+ readable.on('end', common.mustCall(() => {
+ assert.strictEqual(readable.readableEnded, true);
+ }));
+
+ readable.on('data', common.mustCall(() => {
+ assert.strictEqual(readable.readableEnded, false);
+ }));
+}
+
+// Verifies no `error` triggered on multiple .push(null) invocations
+{
+ const readable = new Readable();
+
+ readable.on('readable', () => { readable.read(); });
+ readable.on('error', common.mustNotCall());
+ readable.on('end', common.mustCall());
+
+ readable.push('a');
+ readable.push(null);
+ readable.push(null);
+}
diff --git a/tests/node_compat/test/parallel/test-stream-readable-error-end.js b/tests/node_compat/test/parallel/test-stream-readable-error-end.js
new file mode 100644
index 000000000..821a5f458
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-readable-error-end.js
@@ -0,0 +1,22 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const { Readable } = require('stream');
+
+{
+ const r = new Readable({ read() {} });
+
+ r.on('end', common.mustNotCall());
+ r.on('data', common.mustCall());
+ r.on('error', common.mustCall());
+ r.push('asd');
+ r.push(null);
+ r.destroy(new Error('kaboom'));
+}
diff --git a/tests/node_compat/test/parallel/test-stream-readable-event.js b/tests/node_compat/test/parallel/test-stream-readable-event.js
new file mode 100644
index 000000000..87a4e0feb
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-readable-event.js
@@ -0,0 +1,135 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+
+const Readable = require('stream').Readable;
+
+{
+ // First test, not reading when the readable is added.
+ // make sure that on('readable', ...) triggers a readable event.
+ const r = new Readable({
+ highWaterMark: 3
+ });
+
+ r._read = common.mustNotCall();
+
+ // This triggers a 'readable' event, which is lost.
+ r.push(Buffer.from('blerg'));
+
+ setTimeout(function() {
+ // We're testing what we think we are
+ assert(!r._readableState.reading);
+ r.on('readable', common.mustCall());
+ }, 1);
+}
+
+{
+ // Second test, make sure that readable is re-emitted if there's
+ // already a length, while it IS reading.
+
+ const r = new Readable({
+ highWaterMark: 3
+ });
+
+ r._read = common.mustCall();
+
+ // This triggers a 'readable' event, which is lost.
+ r.push(Buffer.from('bl'));
+
+ setTimeout(function() {
+ // Assert we're testing what we think we are
+ assert(r._readableState.reading);
+ r.on('readable', common.mustCall());
+ }, 1);
+}
+
+{
+ // Third test, not reading when the stream has not passed
+ // the highWaterMark but *has* reached EOF.
+ const r = new Readable({
+ highWaterMark: 30
+ });
+
+ r._read = common.mustNotCall();
+
+ // This triggers a 'readable' event, which is lost.
+ r.push(Buffer.from('blerg'));
+ r.push(null);
+
+ setTimeout(function() {
+ // Assert we're testing what we think we are
+ assert(!r._readableState.reading);
+ r.on('readable', common.mustCall());
+ }, 1);
+}
+
+{
+ // Pushing an empty string in non-objectMode should
+ // trigger next `read()`.
+ const underlyingData = ['', 'x', 'y', '', 'z'];
+ const expected = underlyingData.filter((data) => data);
+ const result = [];
+
+ const r = new Readable({
+ encoding: 'utf8',
+ });
+ r._read = function() {
+ process.nextTick(() => {
+ if (!underlyingData.length) {
+ this.push(null);
+ } else {
+ this.push(underlyingData.shift());
+ }
+ });
+ };
+
+ r.on('readable', () => {
+ const data = r.read();
+ if (data !== null) result.push(data);
+ });
+
+ r.on('end', common.mustCall(() => {
+ assert.deepStrictEqual(result, expected);
+ }));
+}
+
+{
+ // #20923
+ const r = new Readable();
+ r._read = function() {
+ // Actually doing thing here
+ };
+ r.on('data', function() {});
+
+ r.removeAllListeners();
+
+ assert.strictEqual(r.eventNames().length, 0);
+}
diff --git a/tests/node_compat/test/parallel/test-stream-readable-flow-recursion.js b/tests/node_compat/test/parallel/test-stream-readable-flow-recursion.js
new file mode 100644
index 000000000..1ac657197
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-readable-flow-recursion.js
@@ -0,0 +1,84 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+
+// This test verifies that passing a huge number to read(size)
+// will push up the highWaterMark, and cause the stream to read
+// more data continuously, but without triggering a nextTick
+// warning or RangeError.
+
+const Readable = require('stream').Readable;
+
+// Throw an error if we trigger a nextTick warning.
+process.throwDeprecation = true;
+
+const stream = new Readable({ highWaterMark: 2 });
+let reads = 0;
+let total = 5000;
+stream._read = function(size) {
+ reads++;
+ size = Math.min(size, total);
+ total -= size;
+ if (size === 0)
+ stream.push(null);
+ else
+ stream.push(Buffer.allocUnsafe(size));
+};
+
+let depth = 0;
+
+function flow(stream, size, callback) {
+ depth += 1;
+ const chunk = stream.read(size);
+
+ if (!chunk)
+ stream.once('readable', flow.bind(null, stream, size, callback));
+ else
+ callback(chunk);
+
+ depth -= 1;
+ console.log(`flow(${depth}): exit`);
+}
+
+flow(stream, 5000, function() {
+ console.log(`complete (${depth})`);
+});
+
+process.on('exit', function(code) {
+ assert.strictEqual(reads, 2);
+ // We pushed up the high water mark
+ assert.strictEqual(stream.readableHighWaterMark, 8192);
+ // Length is 0 right now, because we pulled it all out.
+ assert.strictEqual(stream.readableLength, 0);
+ assert(!code);
+ assert.strictEqual(depth, 0);
+ console.log('ok');
+});
diff --git a/tests/node_compat/test/parallel/test-stream-readable-hwm-0-async.js b/tests/node_compat/test/parallel/test-stream-readable-hwm-0-async.js
new file mode 100644
index 000000000..c797129ee
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-readable-hwm-0-async.js
@@ -0,0 +1,34 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+
+// This test ensures that Readable stream will continue to call _read
+// for streams with highWaterMark === 0 once the stream returns data
+// by calling push() asynchronously.
+
+const { Readable } = require('stream');
+
+let count = 5;
+
+const r = new Readable({
+ // Called 6 times: First 5 return data, last one signals end of stream.
+ read: common.mustCall(() => {
+ process.nextTick(common.mustCall(() => {
+ if (count--)
+ r.push('a');
+ else
+ r.push(null);
+ }));
+ }, 6),
+ highWaterMark: 0,
+});
+
+r.on('end', common.mustCall());
+r.on('data', common.mustCall(5));
diff --git a/tests/node_compat/test/parallel/test-stream-readable-hwm-0-no-flow-data.js b/tests/node_compat/test/parallel/test-stream-readable-hwm-0-no-flow-data.js
new file mode 100644
index 000000000..3d9c0507a
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-readable-hwm-0-no-flow-data.js
@@ -0,0 +1,111 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+
+// Ensure that subscribing the 'data' event will not make the stream flow.
+// The 'data' event will require calling read() by hand.
+//
+// The test is written for the (somewhat rare) highWaterMark: 0 streams to
+// specifically catch any regressions that might occur with these streams.
+
+const assert = require('assert');
+const { Readable } = require('stream');
+
+const streamData = [ 'a', null ];
+
+// Track the calls so we can assert their order later.
+const calls = [];
+const r = new Readable({
+ read: common.mustCall(() => {
+ calls.push('_read:' + streamData[0]);
+ process.nextTick(() => {
+ calls.push('push:' + streamData[0]);
+ r.push(streamData.shift());
+ });
+ }, streamData.length),
+ highWaterMark: 0,
+
+ // Object mode is used here just for testing convenience. It really
+ // shouldn't affect the order of events. Just the data and its format.
+ objectMode: true,
+});
+
+assert.strictEqual(r.readableFlowing, null);
+r.on('readable', common.mustCall(() => {
+ calls.push('readable');
+}, 2));
+assert.strictEqual(r.readableFlowing, false);
+r.on('data', common.mustCall((data) => {
+ calls.push('data:' + data);
+}, 1));
+r.on('end', common.mustCall(() => {
+ calls.push('end');
+}));
+assert.strictEqual(r.readableFlowing, false);
+
+// The stream emits the events asynchronously but that's not guaranteed to
+// happen on the next tick (especially since the _read implementation above
+// uses process.nextTick).
+//
+// We use setImmediate here to give the stream enough time to emit all the
+// events it's about to emit.
+setImmediate(() => {
+
+ // Only the _read, push, readable calls have happened. No data must be
+ // emitted yet.
+ assert.deepStrictEqual(calls, ['_read:a', 'push:a', 'readable']);
+
+ // Calling 'r.read()' should trigger the data event.
+ assert.strictEqual(r.read(), 'a');
+ assert.deepStrictEqual(
+ calls,
+ ['_read:a', 'push:a', 'readable', 'data:a']);
+
+ // The next 'read()' will return null because hwm: 0 does not buffer any
+ // data and the _read implementation above does the push() asynchronously.
+ //
+ // Note: This 'null' signals "no data available". It isn't the end-of-stream
+ // null value as the stream doesn't know yet that it is about to reach the
+ // end.
+ //
+ // Using setImmediate again to give the stream enough time to emit all the
+ // events it wants to emit.
+ assert.strictEqual(r.read(), null);
+ setImmediate(() => {
+
+ // There's a new 'readable' event after the data has been pushed.
+ // The 'end' event will be emitted only after a 'read()'.
+ //
+ // This is somewhat special for the case where the '_read' implementation
+ // calls 'push' asynchronously. If 'push' was synchronous, the 'end' event
+ // would be emitted here _before_ we call read().
+ assert.deepStrictEqual(
+ calls,
+ ['_read:a', 'push:a', 'readable', 'data:a',
+ '_read:null', 'push:null', 'readable']);
+
+ assert.strictEqual(r.read(), null);
+
+ // While it isn't really specified whether the 'end' event should happen
+ // synchronously with read() or not, we'll assert the current behavior
+ // ('end' event happening on the next tick after read()) so any changes
+ // to it are noted and acknowledged in the future.
+ assert.deepStrictEqual(
+ calls,
+ ['_read:a', 'push:a', 'readable', 'data:a',
+ '_read:null', 'push:null', 'readable']);
+ process.nextTick(() => {
+ assert.deepStrictEqual(
+ calls,
+ ['_read:a', 'push:a', 'readable', 'data:a',
+ '_read:null', 'push:null', 'readable', 'end']);
+ });
+ });
+});
diff --git a/tests/node_compat/test/parallel/test-stream-readable-hwm-0.js b/tests/node_compat/test/parallel/test-stream-readable-hwm-0.js
new file mode 100644
index 000000000..cfbfac8ab
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-readable-hwm-0.js
@@ -0,0 +1,37 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+
+// This test ensures that Readable stream will call _read() for streams
+// with highWaterMark === 0 upon .read(0) instead of just trying to
+// emit 'readable' event.
+
+const assert = require('assert');
+const { Readable } = require('stream');
+
+const r = new Readable({
+ // Must be called only once upon setting 'readable' listener
+ read: common.mustCall(),
+ highWaterMark: 0,
+});
+
+let pushedNull = false;
+// This will trigger read(0) but must only be called after push(null)
+// because the we haven't pushed any data
+r.on('readable', common.mustCall(() => {
+ assert.strictEqual(r.read(), null);
+ assert.strictEqual(pushedNull, true);
+}));
+r.on('end', common.mustCall());
+process.nextTick(() => {
+ assert.strictEqual(r.read(), null);
+ pushedNull = true;
+ r.push(null);
+});
diff --git a/tests/node_compat/test/parallel/test-stream-readable-infinite-read.js b/tests/node_compat/test/parallel/test-stream-readable-infinite-read.js
new file mode 100644
index 000000000..e3819cad9
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-readable-infinite-read.js
@@ -0,0 +1,39 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const assert = require('assert');
+const { Readable } = require('stream');
+
+const buf = Buffer.alloc(8192);
+
+const readable = new Readable({
+ read: common.mustCall(function() {
+ this.push(buf);
+ }, 31)
+});
+
+let i = 0;
+
+readable.on('readable', common.mustCall(function() {
+ if (i++ === 10) {
+ // We will just terminate now.
+ process.removeAllListeners('readable');
+ return;
+ }
+
+ const data = readable.read();
+ // TODO(mcollina): there is something odd in the highWaterMark logic
+ // investigate.
+ if (i === 1) {
+ assert.strictEqual(data.length, 8192 * 2);
+ } else {
+ assert.strictEqual(data.length, 8192 * 3);
+ }
+}, 11));
diff --git a/tests/node_compat/test/parallel/test-stream-readable-invalid-chunk.js b/tests/node_compat/test/parallel/test-stream-readable-invalid-chunk.js
new file mode 100644
index 000000000..a40526389
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-readable-invalid-chunk.js
@@ -0,0 +1,41 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const stream = require('stream');
+
+function testPushArg(val) {
+ const readable = new stream.Readable({
+ read: () => {}
+ });
+ readable.on('error', common.expectsError({
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError'
+ }));
+ readable.push(val);
+}
+
+testPushArg([]);
+testPushArg({});
+testPushArg(0);
+
+function testUnshiftArg(val) {
+ const readable = new stream.Readable({
+ read: () => {}
+ });
+ readable.on('error', common.expectsError({
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError'
+ }));
+ readable.unshift(val);
+}
+
+testUnshiftArg([]);
+testUnshiftArg({});
+testUnshiftArg(0);
diff --git a/tests/node_compat/test/parallel/test-stream-readable-needReadable.js b/tests/node_compat/test/parallel/test-stream-readable-needReadable.js
new file mode 100644
index 000000000..675e5e872
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-readable-needReadable.js
@@ -0,0 +1,106 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const Readable = require('stream').Readable;
+
+const readable = new Readable({
+ read: () => {}
+});
+
+// Initialized to false.
+assert.strictEqual(readable._readableState.needReadable, false);
+
+readable.on('readable', common.mustCall(() => {
+ // When the readable event fires, needReadable is reset.
+ assert.strictEqual(readable._readableState.needReadable, false);
+ readable.read();
+}));
+
+// If a readable listener is attached, then a readable event is needed.
+assert.strictEqual(readable._readableState.needReadable, true);
+
+readable.push('foo');
+readable.push(null);
+
+readable.on('end', common.mustCall(() => {
+ // No need to emit readable anymore when the stream ends.
+ assert.strictEqual(readable._readableState.needReadable, false);
+}));
+
+const asyncReadable = new Readable({
+ read: () => {}
+});
+
+asyncReadable.on('readable', common.mustCall(() => {
+ if (asyncReadable.read() !== null) {
+ // After each read(), the buffer is empty.
+ // If the stream doesn't end now,
+ // then we need to notify the reader on future changes.
+ assert.strictEqual(asyncReadable._readableState.needReadable, true);
+ }
+}, 2));
+
+process.nextTick(common.mustCall(() => {
+ asyncReadable.push('foooo');
+}));
+process.nextTick(common.mustCall(() => {
+ asyncReadable.push('bar');
+}));
+setImmediate(common.mustCall(() => {
+ asyncReadable.push(null);
+ assert.strictEqual(asyncReadable._readableState.needReadable, false);
+}));
+
+const flowing = new Readable({
+ read: () => {}
+});
+
+// Notice this must be above the on('data') call.
+flowing.push('foooo');
+flowing.push('bar');
+flowing.push('quo');
+process.nextTick(common.mustCall(() => {
+ flowing.push(null);
+}));
+
+// When the buffer already has enough data, and the stream is
+// in flowing mode, there is no need for the readable event.
+flowing.on('data', common.mustCall(function(data) {
+ assert.strictEqual(flowing._readableState.needReadable, false);
+}, 3));
+
+const slowProducer = new Readable({
+ read: () => {}
+});
+
+slowProducer.on('readable', common.mustCall(() => {
+ const chunk = slowProducer.read(8);
+ const state = slowProducer._readableState;
+ if (chunk === null) {
+ // The buffer doesn't have enough data, and the stream is not need,
+ // we need to notify the reader when data arrives.
+ assert.strictEqual(state.needReadable, true);
+ } else {
+ assert.strictEqual(state.needReadable, false);
+ }
+}, 4));
+
+process.nextTick(common.mustCall(() => {
+ slowProducer.push('foo');
+ process.nextTick(common.mustCall(() => {
+ slowProducer.push('foo');
+ process.nextTick(common.mustCall(() => {
+ slowProducer.push('foo');
+ process.nextTick(common.mustCall(() => {
+ slowProducer.push(null);
+ }));
+ }));
+ }));
+}));
diff --git a/tests/node_compat/test/parallel/test-stream-readable-next-no-null.js b/tests/node_compat/test/parallel/test-stream-readable-next-no-null.js
new file mode 100644
index 000000000..06f06f41d
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-readable-next-no-null.js
@@ -0,0 +1,26 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const { mustNotCall, expectsError } = require('../common');
+const { Readable } = require('stream');
+
+async function* generate() {
+ yield null;
+}
+
+const stream = Readable.from(generate());
+
+stream.on('error', expectsError({
+ code: 'ERR_STREAM_NULL_VALUES',
+ name: 'TypeError',
+ message: 'May not write null values to stream'
+}));
+
+stream.on('data', mustNotCall());
+
+stream.on('end', mustNotCall());
diff --git a/tests/node_compat/test/parallel/test-stream-readable-no-unneeded-readable.js b/tests/node_compat/test/parallel/test-stream-readable-no-unneeded-readable.js
new file mode 100644
index 000000000..9a96db87d
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-readable-no-unneeded-readable.js
@@ -0,0 +1,69 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const { Readable, PassThrough } = require('stream');
+
+function test(r) {
+ const wrapper = new Readable({
+ read: () => {
+ let data = r.read();
+
+ if (data) {
+ wrapper.push(data);
+ return;
+ }
+
+ r.once('readable', function() {
+ data = r.read();
+ if (data) {
+ wrapper.push(data);
+ }
+ // else: the end event should fire
+ });
+ },
+ });
+
+ r.once('end', function() {
+ wrapper.push(null);
+ });
+
+ wrapper.resume();
+ wrapper.once('end', common.mustCall());
+}
+
+{
+ const source = new Readable({
+ read: () => {}
+ });
+ source.push('foo');
+ source.push('bar');
+ source.push(null);
+
+ const pt = source.pipe(new PassThrough());
+ test(pt);
+}
+
+{
+ // This is the underlying cause of the above test case.
+ const pushChunks = ['foo', 'bar'];
+ const r = new Readable({
+ read: () => {
+ const chunk = pushChunks.shift();
+ if (chunk) {
+ // synchronous call
+ r.push(chunk);
+ } else {
+ // asynchronous call
+ process.nextTick(() => r.push(null));
+ }
+ },
+ });
+
+ test(r);
+}
diff --git a/tests/node_compat/test/parallel/test-stream-readable-object-multi-push-async.js b/tests/node_compat/test/parallel/test-stream-readable-object-multi-push-async.js
new file mode 100644
index 000000000..4ab7f3adb
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-readable-object-multi-push-async.js
@@ -0,0 +1,190 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const assert = require('assert');
+const { Readable } = require('stream');
+
+const MAX = 42;
+const BATCH = 10;
+
+{
+ const readable = new Readable({
+ objectMode: true,
+ read: common.mustCall(function() {
+ console.log('>> READ');
+ fetchData((err, data) => {
+ if (err) {
+ this.destroy(err);
+ return;
+ }
+
+ if (data.length === 0) {
+ console.log('pushing null');
+ this.push(null);
+ return;
+ }
+
+ console.log('pushing');
+ data.forEach((d) => this.push(d));
+ });
+ }, Math.floor(MAX / BATCH) + 2)
+ });
+
+ let i = 0;
+ function fetchData(cb) {
+ if (i > MAX) {
+ setTimeout(cb, 10, null, []);
+ } else {
+ const array = [];
+ const max = i + BATCH;
+ for (; i < max; i++) {
+ array.push(i);
+ }
+ setTimeout(cb, 10, null, array);
+ }
+ }
+
+ readable.on('readable', () => {
+ let data;
+ console.log('readable emitted');
+ while ((data = readable.read()) !== null) {
+ console.log(data);
+ }
+ });
+
+ readable.on('end', common.mustCall(() => {
+ assert.strictEqual(i, (Math.floor(MAX / BATCH) + 1) * BATCH);
+ }));
+}
+
+{
+ const readable = new Readable({
+ objectMode: true,
+ read: common.mustCall(function() {
+ console.log('>> READ');
+ fetchData((err, data) => {
+ if (err) {
+ this.destroy(err);
+ return;
+ }
+
+ if (data.length === 0) {
+ console.log('pushing null');
+ this.push(null);
+ return;
+ }
+
+ console.log('pushing');
+ data.forEach((d) => this.push(d));
+ });
+ }, Math.floor(MAX / BATCH) + 2)
+ });
+
+ let i = 0;
+ function fetchData(cb) {
+ if (i > MAX) {
+ setTimeout(cb, 10, null, []);
+ } else {
+ const array = [];
+ const max = i + BATCH;
+ for (; i < max; i++) {
+ array.push(i);
+ }
+ setTimeout(cb, 10, null, array);
+ }
+ }
+
+ readable.on('data', (data) => {
+ console.log('data emitted', data);
+ });
+
+ readable.on('end', common.mustCall(() => {
+ assert.strictEqual(i, (Math.floor(MAX / BATCH) + 1) * BATCH);
+ }));
+}
+
+{
+ const readable = new Readable({
+ objectMode: true,
+ read: common.mustCall(function() {
+ console.log('>> READ');
+ fetchData((err, data) => {
+ if (err) {
+ this.destroy(err);
+ return;
+ }
+
+ console.log('pushing');
+ data.forEach((d) => this.push(d));
+
+ if (data[BATCH - 1] >= MAX) {
+ console.log('pushing null');
+ this.push(null);
+ }
+ });
+ }, Math.floor(MAX / BATCH) + 1)
+ });
+
+ let i = 0;
+ function fetchData(cb) {
+ const array = [];
+ const max = i + BATCH;
+ for (; i < max; i++) {
+ array.push(i);
+ }
+ setTimeout(cb, 10, null, array);
+ }
+
+ readable.on('data', (data) => {
+ console.log('data emitted', data);
+ });
+
+ readable.on('end', common.mustCall(() => {
+ assert.strictEqual(i, (Math.floor(MAX / BATCH) + 1) * BATCH);
+ }));
+}
+
+{
+ const readable = new Readable({
+ objectMode: true,
+ read: common.mustNotCall()
+ });
+
+ readable.on('data', common.mustNotCall());
+
+ readable.push(null);
+
+ let nextTickPassed = false;
+ process.nextTick(() => {
+ nextTickPassed = true;
+ });
+
+ readable.on('end', common.mustCall(() => {
+ assert.strictEqual(nextTickPassed, true);
+ }));
+}
+
+{
+ const readable = new Readable({
+ objectMode: true,
+ read: common.mustCall()
+ });
+
+ readable.on('data', (data) => {
+ console.log('data emitted', data);
+ });
+
+ readable.on('end', common.mustCall());
+
+ setImmediate(() => {
+ readable.push('aaa');
+ readable.push(null);
+ });
+}
diff --git a/tests/node_compat/test/parallel/test-stream-readable-pause-and-resume.js b/tests/node_compat/test/parallel/test-stream-readable-pause-and-resume.js
new file mode 100644
index 000000000..923349ef4
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-readable-pause-and-resume.js
@@ -0,0 +1,81 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const assert = require('assert');
+const { Readable } = require('stream');
+
+let ticks = 18;
+let expectedData = 19;
+
+const rs = new Readable({
+ objectMode: true,
+ read: () => {
+ if (ticks-- > 0)
+ return process.nextTick(() => rs.push({}));
+ rs.push({});
+ rs.push(null);
+ }
+});
+
+rs.on('end', common.mustCall());
+readAndPause();
+
+function readAndPause() {
+ // Does a on(data) -> pause -> wait -> resume -> on(data) ... loop.
+ // Expects on(data) to never fire if the stream is paused.
+ const ondata = common.mustCall((data) => {
+ rs.pause();
+
+ expectedData--;
+ if (expectedData <= 0)
+ return;
+
+ setImmediate(function() {
+ rs.removeListener('data', ondata);
+ readAndPause();
+ rs.resume();
+ });
+ }, 1); // Only call ondata once
+
+ rs.on('data', ondata);
+}
+
+{
+ const readable = new Readable({
+ read() {}
+ });
+
+ function read() {}
+
+ readable.setEncoding('utf8');
+ readable.on('readable', read);
+ readable.removeListener('readable', read);
+ readable.pause();
+
+ process.nextTick(function() {
+ assert(readable.isPaused());
+ });
+}
+
+{
+ const { PassThrough } = require('stream');
+
+ const source3 = new PassThrough();
+ const target3 = new PassThrough();
+
+ const chunk = Buffer.allocUnsafe(1000);
+ while (target3.write(chunk));
+
+ source3.pipe(target3);
+ target3.on('drain', common.mustCall(() => {
+ assert(!source3.isPaused());
+ }));
+ target3.on('data', () => {});
+}
diff --git a/tests/node_compat/test/parallel/test-stream-readable-readable-then-resume.js b/tests/node_compat/test/parallel/test-stream-readable-readable-then-resume.js
new file mode 100644
index 000000000..3df0bcaaf
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-readable-readable-then-resume.js
@@ -0,0 +1,38 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const { Readable } = require('stream');
+const assert = require('assert');
+
+// This test verifies that a stream could be resumed after
+// removing the readable event in the same tick
+
+check(new Readable({
+ objectMode: true,
+ highWaterMark: 1,
+ read() {
+ if (!this.first) {
+ this.push('hello');
+ this.first = true;
+ return;
+ }
+
+ this.push(null);
+ }
+}));
+
+function check(s) {
+ const readableListener = common.mustNotCall();
+ s.on('readable', readableListener);
+ s.on('end', common.mustCall());
+ assert.strictEqual(s.removeListener, s.off);
+ s.removeListener('readable', readableListener);
+ s.resume();
+}
diff --git a/tests/node_compat/test/parallel/test-stream-readable-readable.js b/tests/node_compat/test/parallel/test-stream-readable-readable.js
new file mode 100644
index 000000000..6353ad8d4
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-readable-readable.js
@@ -0,0 +1,52 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+
+const { Readable } = require('stream');
+
+{
+ const r = new Readable({
+ read() {}
+ });
+ assert.strictEqual(r.readable, true);
+ r.destroy();
+ assert.strictEqual(r.readable, false);
+}
+
+{
+ const mustNotCall = common.mustNotCall();
+ const r = new Readable({
+ read() {}
+ });
+ assert.strictEqual(r.readable, true);
+ r.on('end', mustNotCall);
+ r.resume();
+ r.push(null);
+ assert.strictEqual(r.readable, true);
+ r.off('end', mustNotCall);
+ r.on('end', common.mustCall(() => {
+ assert.strictEqual(r.readable, false);
+ }));
+}
+
+{
+ const r = new Readable({
+ read: common.mustCall(() => {
+ process.nextTick(() => {
+ r.destroy(new Error());
+ assert.strictEqual(r.readable, false);
+ });
+ })
+ });
+ r.resume();
+ r.on('error', common.mustCall(() => {
+ assert.strictEqual(r.readable, false);
+ }));
+}
diff --git a/tests/node_compat/test/parallel/test-stream-readable-reading-readingMore.js b/tests/node_compat/test/parallel/test-stream-readable-reading-readingMore.js
new file mode 100644
index 000000000..26663b88b
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-readable-reading-readingMore.js
@@ -0,0 +1,178 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const Readable = require('stream').Readable;
+
+{
+ const readable = new Readable({
+ read(size) {}
+ });
+
+ const state = readable._readableState;
+
+ // Starting off with false initially.
+ assert.strictEqual(state.reading, false);
+ assert.strictEqual(state.readingMore, false);
+
+ readable.on('data', common.mustCall((data) => {
+ // While in a flowing state with a 'readable' listener
+ // we should not be reading more
+ if (readable.readableFlowing)
+ assert.strictEqual(state.readingMore, true);
+
+ // Reading as long as we've not ended
+ assert.strictEqual(state.reading, !state.ended);
+ }, 2));
+
+ function onStreamEnd() {
+ // End of stream; state.reading is false
+ // And so should be readingMore.
+ assert.strictEqual(state.readingMore, false);
+ assert.strictEqual(state.reading, false);
+ }
+
+ const expectedReadingMore = [true, true, false];
+ readable.on('readable', common.mustCall(() => {
+ // There is only one readingMore scheduled from on('data'),
+ // after which everything is governed by the .read() call
+ assert.strictEqual(state.readingMore, expectedReadingMore.shift());
+
+ // If the stream has ended, we shouldn't be reading
+ assert.strictEqual(state.ended, !state.reading);
+
+ // Consume all the data
+ while (readable.read() !== null);
+
+ if (expectedReadingMore.length === 0) // Reached end of stream
+ process.nextTick(common.mustCall(onStreamEnd, 1));
+ }, 3));
+
+ readable.on('end', common.mustCall(onStreamEnd));
+ readable.push('pushed');
+
+ readable.read(6);
+
+ // reading
+ assert.strictEqual(state.reading, true);
+ assert.strictEqual(state.readingMore, true);
+
+ // add chunk to front
+ readable.unshift('unshifted');
+
+ // end
+ readable.push(null);
+}
+
+{
+ const readable = new Readable({
+ read(size) {}
+ });
+
+ const state = readable._readableState;
+
+ // Starting off with false initially.
+ assert.strictEqual(state.reading, false);
+ assert.strictEqual(state.readingMore, false);
+
+ readable.on('data', common.mustCall((data) => {
+ // While in a flowing state without a 'readable' listener
+ // we should be reading more
+ if (readable.readableFlowing)
+ assert.strictEqual(state.readingMore, true);
+
+ // Reading as long as we've not ended
+ assert.strictEqual(state.reading, !state.ended);
+ }, 2));
+
+ function onStreamEnd() {
+ // End of stream; state.reading is false
+ // And so should be readingMore.
+ assert.strictEqual(state.readingMore, false);
+ assert.strictEqual(state.reading, false);
+ }
+
+ readable.on('end', common.mustCall(onStreamEnd));
+ readable.push('pushed');
+
+ // Stop emitting 'data' events
+ assert.strictEqual(state.flowing, true);
+ readable.pause();
+
+ // paused
+ assert.strictEqual(state.reading, false);
+ assert.strictEqual(state.flowing, false);
+
+ readable.resume();
+ assert.strictEqual(state.reading, false);
+ assert.strictEqual(state.flowing, true);
+
+ // add chunk to front
+ readable.unshift('unshifted');
+
+ // end
+ readable.push(null);
+}
+
+{
+ const readable = new Readable({
+ read(size) {}
+ });
+
+ const state = readable._readableState;
+
+ // Starting off with false initially.
+ assert.strictEqual(state.reading, false);
+ assert.strictEqual(state.readingMore, false);
+
+ const onReadable = common.mustNotCall();
+
+ readable.on('readable', onReadable);
+
+ readable.on('data', common.mustCall((data) => {
+ // Reading as long as we've not ended
+ assert.strictEqual(state.reading, !state.ended);
+ }, 2));
+
+ readable.removeListener('readable', onReadable);
+
+ function onStreamEnd() {
+ // End of stream; state.reading is false
+ // And so should be readingMore.
+ assert.strictEqual(state.readingMore, false);
+ assert.strictEqual(state.reading, false);
+ }
+
+ readable.on('end', common.mustCall(onStreamEnd));
+ readable.push('pushed');
+
+ // We are still not flowing, we will be resuming in the next tick
+ assert.strictEqual(state.flowing, false);
+
+ // Wait for nextTick, so the readableListener flag resets
+ process.nextTick(function() {
+ readable.resume();
+
+ // Stop emitting 'data' events
+ assert.strictEqual(state.flowing, true);
+ readable.pause();
+
+ // paused
+ assert.strictEqual(state.flowing, false);
+
+ readable.resume();
+ assert.strictEqual(state.flowing, true);
+
+ // add chunk to front
+ readable.unshift('unshifted');
+
+ // end
+ readable.push(null);
+ });
+}
diff --git a/tests/node_compat/test/parallel/test-stream-readable-resume-hwm.js b/tests/node_compat/test/parallel/test-stream-readable-resume-hwm.js
new file mode 100644
index 000000000..0e490529c
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-readable-resume-hwm.js
@@ -0,0 +1,28 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const { Readable } = require('stream');
+
+// readable.resume() should not lead to a ._read() call being scheduled
+// when we exceed the high water mark already.
+
+const readable = new Readable({
+ read: common.mustNotCall(),
+ highWaterMark: 100
+});
+
+// Fill up the internal buffer so that we definitely exceed the HWM:
+for (let i = 0; i < 10; i++)
+ readable.push('a'.repeat(200));
+
+// Call resume, and pause after one chunk.
+// The .pause() is just so that we don’t empty the buffer fully, which would
+// be a valid reason to call ._read().
+readable.resume();
+readable.once('data', common.mustCall(() => readable.pause()));
diff --git a/tests/node_compat/test/parallel/test-stream-readable-resumeScheduled.js b/tests/node_compat/test/parallel/test-stream-readable-resumeScheduled.js
new file mode 100644
index 000000000..474670264
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-readable-resumeScheduled.js
@@ -0,0 +1,72 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+
+// Testing Readable Stream resumeScheduled state
+
+const assert = require('assert');
+const { Readable, Writable } = require('stream');
+
+{
+ // pipe() test case
+ const r = new Readable({ read() {} });
+ const w = new Writable();
+
+ // resumeScheduled should start = `false`.
+ assert.strictEqual(r._readableState.resumeScheduled, false);
+
+ // Calling pipe() should change the state value = true.
+ r.pipe(w);
+ assert.strictEqual(r._readableState.resumeScheduled, true);
+
+ process.nextTick(common.mustCall(() => {
+ assert.strictEqual(r._readableState.resumeScheduled, false);
+ }));
+}
+
+{
+ // 'data' listener test case
+ const r = new Readable({ read() {} });
+
+ // resumeScheduled should start = `false`.
+ assert.strictEqual(r._readableState.resumeScheduled, false);
+
+ r.push(Buffer.from([1, 2, 3]));
+
+ // Adding 'data' listener should change the state value
+ r.on('data', common.mustCall(() => {
+ assert.strictEqual(r._readableState.resumeScheduled, false);
+ }));
+ assert.strictEqual(r._readableState.resumeScheduled, true);
+
+ process.nextTick(common.mustCall(() => {
+ assert.strictEqual(r._readableState.resumeScheduled, false);
+ }));
+}
+
+{
+ // resume() test case
+ const r = new Readable({ read() {} });
+
+ // resumeScheduled should start = `false`.
+ assert.strictEqual(r._readableState.resumeScheduled, false);
+
+ // Calling resume() should change the state value.
+ r.resume();
+ assert.strictEqual(r._readableState.resumeScheduled, true);
+
+ r.on('resume', common.mustCall(() => {
+ // The state value should be `false` again
+ assert.strictEqual(r._readableState.resumeScheduled, false);
+ }));
+
+ process.nextTick(common.mustCall(() => {
+ assert.strictEqual(r._readableState.resumeScheduled, false);
+ }));
+}
diff --git a/tests/node_compat/test/parallel/test-stream-readable-setEncoding-existing-buffers.js b/tests/node_compat/test/parallel/test-stream-readable-setEncoding-existing-buffers.js
new file mode 100644
index 000000000..c99a39819
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-readable-setEncoding-existing-buffers.js
@@ -0,0 +1,67 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+require('../common');
+const { Readable } = require('stream');
+const assert = require('assert');
+
+{
+ // Call .setEncoding() while there are bytes already in the buffer.
+ const r = new Readable({ read() {} });
+
+ r.push(Buffer.from('a'));
+ r.push(Buffer.from('b'));
+
+ r.setEncoding('utf8');
+ const chunks = [];
+ r.on('data', (chunk) => chunks.push(chunk));
+
+ process.nextTick(() => {
+ assert.deepStrictEqual(chunks, ['ab']);
+ });
+}
+
+{
+ // Call .setEncoding() while the buffer contains a complete,
+ // but chunked character.
+ const r = new Readable({ read() {} });
+
+ r.push(Buffer.from([0xf0]));
+ r.push(Buffer.from([0x9f]));
+ r.push(Buffer.from([0x8e]));
+ r.push(Buffer.from([0x89]));
+
+ r.setEncoding('utf8');
+ const chunks = [];
+ r.on('data', (chunk) => chunks.push(chunk));
+
+ process.nextTick(() => {
+ assert.deepStrictEqual(chunks, ['🎉']);
+ });
+}
+
+{
+ // Call .setEncoding() while the buffer contains an incomplete character,
+ // and finish the character later.
+ const r = new Readable({ read() {} });
+
+ r.push(Buffer.from([0xf0]));
+ r.push(Buffer.from([0x9f]));
+
+ r.setEncoding('utf8');
+
+ r.push(Buffer.from([0x8e]));
+ r.push(Buffer.from([0x89]));
+
+ const chunks = [];
+ r.on('data', (chunk) => chunks.push(chunk));
+
+ process.nextTick(() => {
+ assert.deepStrictEqual(chunks, ['🎉']);
+ });
+}
diff --git a/tests/node_compat/test/parallel/test-stream-readable-setEncoding-null.js b/tests/node_compat/test/parallel/test-stream-readable-setEncoding-null.js
new file mode 100644
index 000000000..e6823f7cd
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-readable-setEncoding-null.js
@@ -0,0 +1,22 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+require('../common');
+const assert = require('assert');
+const { Readable } = require('stream');
+
+
+{
+ const readable = new Readable({ encoding: 'hex' });
+ assert.strictEqual(readable._readableState.encoding, 'hex');
+
+ readable.setEncoding(null);
+
+ assert.strictEqual(readable._readableState.encoding, 'utf8');
+}
diff --git a/tests/node_compat/test/parallel/test-stream-readable-unshift.js b/tests/node_compat/test/parallel/test-stream-readable-unshift.js
new file mode 100644
index 000000000..1303befa9
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-readable-unshift.js
@@ -0,0 +1,177 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const assert = require('assert');
+const { Readable } = require('stream');
+
+{
+ // Check that strings are saved as Buffer
+ const readable = new Readable({ read() {} });
+
+ const string = 'abc';
+
+ readable.on('data', common.mustCall((chunk) => {
+ assert(Buffer.isBuffer(chunk));
+ assert.strictEqual(chunk.toString('utf8'), string);
+ }, 1));
+
+ readable.unshift(string);
+
+}
+
+{
+ // Check that data goes at the beginning
+ const readable = new Readable({ read() {} });
+ const unshift = 'front';
+ const push = 'back';
+
+ const expected = [unshift, push];
+ readable.on('data', common.mustCall((chunk) => {
+ assert.strictEqual(chunk.toString('utf8'), expected.shift());
+ }, 2));
+
+
+ readable.push(push);
+ readable.unshift(unshift);
+}
+
+{
+ // Check that buffer is saved with correct encoding
+ const readable = new Readable({ read() {} });
+
+ const encoding = 'base64';
+ const string = Buffer.from('abc').toString(encoding);
+
+ readable.on('data', common.mustCall((chunk) => {
+ assert.strictEqual(chunk.toString(encoding), string);
+ }, 1));
+
+ readable.unshift(string, encoding);
+
+}
+
+{
+
+ const streamEncoding = 'base64';
+
+ function checkEncoding(readable) {
+
+ // chunk encodings
+ const encodings = ['utf8', 'binary', 'hex', 'base64'];
+ const expected = [];
+
+ readable.on('data', common.mustCall((chunk) => {
+ const { encoding, string } = expected.pop();
+ assert.strictEqual(chunk.toString(encoding), string);
+ }, encodings.length));
+
+ for (const encoding of encodings) {
+ const string = 'abc';
+
+ // If encoding is the same as the state.encoding the string is
+ // saved as is
+ const expect = encoding !== streamEncoding ?
+ Buffer.from(string, encoding).toString(streamEncoding) : string;
+
+ expected.push({ encoding, string: expect });
+
+ readable.unshift(string, encoding);
+ }
+ }
+
+ const r1 = new Readable({ read() {} });
+ r1.setEncoding(streamEncoding);
+ checkEncoding(r1);
+
+ const r2 = new Readable({ read() {}, encoding: streamEncoding });
+ checkEncoding(r2);
+
+}
+
+{
+ // Both .push & .unshift should have the same behaviour
+ // When setting an encoding, each chunk should be emitted with that encoding
+ const encoding = 'base64';
+
+ function checkEncoding(readable) {
+ const string = 'abc';
+ readable.on('data', common.mustCall((chunk) => {
+ assert.strictEqual(chunk, Buffer.from(string).toString(encoding));
+ }, 2));
+
+ readable.push(string);
+ readable.unshift(string);
+ }
+
+ const r1 = new Readable({ read() {} });
+ r1.setEncoding(encoding);
+ checkEncoding(r1);
+
+ const r2 = new Readable({ read() {}, encoding });
+ checkEncoding(r2);
+
+}
+
+{
+ // Check that ObjectMode works
+ const readable = new Readable({ objectMode: true, read() {} });
+
+ const chunks = ['a', 1, {}, []];
+
+ readable.on('data', common.mustCall((chunk) => {
+ assert.strictEqual(chunk, chunks.pop());
+ }, chunks.length));
+
+ for (const chunk of chunks) {
+ readable.unshift(chunk);
+ }
+}
+
+{
+
+ // Should not throw: https://github.com/nodejs/node/issues/27192
+ const highWaterMark = 50;
+ class ArrayReader extends Readable {
+ constructor(opt) {
+ super({ highWaterMark });
+ // The error happened only when pushing above hwm
+ this.buffer = new Array(highWaterMark * 2).fill(0).map(String);
+ }
+ _read(size) {
+ while (this.buffer.length) {
+ const chunk = this.buffer.shift();
+ if (!this.buffer.length) {
+ this.push(chunk);
+ this.push(null);
+ return true;
+ }
+ if (!this.push(chunk))
+ return;
+ }
+ }
+ }
+
+ function onRead() {
+ while (null !== (stream.read())) {
+ // Remove the 'readable' listener before unshifting
+ stream.removeListener('readable', onRead);
+ stream.unshift('a');
+ stream.on('data', (chunk) => {
+ console.log(chunk.length);
+ });
+ break;
+ }
+ }
+
+ const stream = new ArrayReader();
+ stream.once('readable', common.mustCall(onRead));
+ stream.on('end', common.mustCall());
+
+}
diff --git a/tests/node_compat/test/parallel/test-stream-readable-with-unimplemented-_read.js b/tests/node_compat/test/parallel/test-stream-readable-with-unimplemented-_read.js
new file mode 100644
index 000000000..a2fe2ac01
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-readable-with-unimplemented-_read.js
@@ -0,0 +1,20 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const { Readable } = require('stream');
+
+const readable = new Readable();
+
+readable.read();
+readable.on('error', common.expectsError({
+ code: 'ERR_METHOD_NOT_IMPLEMENTED',
+ name: 'Error',
+ message: 'The _read() method is not implemented'
+}));
+readable.on('close', common.mustCall());
diff --git a/tests/node_compat/test/parallel/test-stream-readableListening-state.js b/tests/node_compat/test/parallel/test-stream-readableListening-state.js
new file mode 100644
index 000000000..69085ac86
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-readableListening-state.js
@@ -0,0 +1,41 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const assert = require('assert');
+const stream = require('stream');
+
+const r = new stream.Readable({
+ read: () => {}
+});
+
+// readableListening state should start in `false`.
+assert.strictEqual(r._readableState.readableListening, false);
+
+r.on('readable', common.mustCall(() => {
+ // Inside the readable event this state should be true.
+ assert.strictEqual(r._readableState.readableListening, true);
+}));
+
+r.push(Buffer.from('Testing readableListening state'));
+
+const r2 = new stream.Readable({
+ read: () => {}
+});
+
+// readableListening state should start in `false`.
+assert.strictEqual(r2._readableState.readableListening, false);
+
+r2.on('data', common.mustCall((chunk) => {
+ // readableListening should be false because we don't have
+ // a `readable` listener
+ assert.strictEqual(r2._readableState.readableListening, false);
+}));
+
+r2.push(Buffer.from('Testing readableListening state'));
diff --git a/tests/node_compat/test/parallel/test-stream-transform-callback-twice.js b/tests/node_compat/test/parallel/test-stream-transform-callback-twice.js
new file mode 100644
index 000000000..3ca0a4c68
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-transform-callback-twice.js
@@ -0,0 +1,21 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const { Transform } = require('stream');
+const stream = new Transform({
+ transform(chunk, enc, cb) { cb(); cb(); }
+});
+
+stream.on('error', common.expectsError({
+ name: 'Error',
+ message: 'Callback called multiple times',
+ code: 'ERR_MULTIPLE_CALLBACK'
+}));
+
+stream.write('foo');
diff --git a/tests/node_compat/test/parallel/test-stream-transform-constructor-set-methods.js b/tests/node_compat/test/parallel/test-stream-transform-constructor-set-methods.js
new file mode 100644
index 000000000..4daf199b0
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-transform-constructor-set-methods.js
@@ -0,0 +1,50 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+
+const assert = require('assert');
+const { Transform } = require('stream');
+
+const t = new Transform();
+
+assert.throws(
+ () => {
+ t.end(Buffer.from('blerg'));
+ },
+ {
+ name: 'Error',
+ code: 'ERR_METHOD_NOT_IMPLEMENTED',
+ message: 'The _transform() method is not implemented'
+ }
+);
+
+const _transform = common.mustCall((chunk, _, next) => {
+ next();
+});
+
+const _final = common.mustCall((next) => {
+ next();
+});
+
+const _flush = common.mustCall((next) => {
+ next();
+});
+
+const t2 = new Transform({
+ transform: _transform,
+ flush: _flush,
+ final: _final
+});
+
+assert.strictEqual(t2._transform, _transform);
+assert.strictEqual(t2._flush, _flush);
+assert.strictEqual(t2._final, _final);
+
+t2.end(Buffer.from('blerg'));
+t2.resume();
diff --git a/tests/node_compat/test/parallel/test-stream-transform-destroy.js b/tests/node_compat/test/parallel/test-stream-transform-destroy.js
new file mode 100644
index 000000000..e721f848f
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-transform-destroy.js
@@ -0,0 +1,150 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const { Transform } = require('stream');
+const assert = require('assert');
+
+{
+ const transform = new Transform({
+ transform(chunk, enc, cb) {}
+ });
+
+ transform.resume();
+
+ transform.on('end', common.mustNotCall());
+ transform.on('close', common.mustCall());
+ transform.on('finish', common.mustNotCall());
+
+ transform.destroy();
+}
+
+{
+ const transform = new Transform({
+ transform(chunk, enc, cb) {}
+ });
+ transform.resume();
+
+ const expected = new Error('kaboom');
+
+ transform.on('end', common.mustNotCall());
+ transform.on('finish', common.mustNotCall());
+ transform.on('close', common.mustCall());
+ transform.on('error', common.mustCall((err) => {
+ assert.strictEqual(err, expected);
+ }));
+
+ transform.destroy(expected);
+}
+
+{
+ const transform = new Transform({
+ transform(chunk, enc, cb) {}
+ });
+
+ transform._destroy = common.mustCall(function(err, cb) {
+ assert.strictEqual(err, expected);
+ cb(err);
+ }, 1);
+
+ const expected = new Error('kaboom');
+
+ transform.on('finish', common.mustNotCall('no finish event'));
+ transform.on('close', common.mustCall());
+ transform.on('error', common.mustCall((err) => {
+ assert.strictEqual(err, expected);
+ }));
+
+ transform.destroy(expected);
+}
+
+{
+ const expected = new Error('kaboom');
+ const transform = new Transform({
+ transform(chunk, enc, cb) {},
+ destroy: common.mustCall(function(err, cb) {
+ assert.strictEqual(err, expected);
+ cb();
+ }, 1)
+ });
+ transform.resume();
+
+ transform.on('end', common.mustNotCall('no end event'));
+ transform.on('close', common.mustCall());
+ transform.on('finish', common.mustNotCall('no finish event'));
+
+ // Error is swallowed by the custom _destroy
+ transform.on('error', common.mustNotCall('no error event'));
+
+ transform.destroy(expected);
+}
+
+{
+ const transform = new Transform({
+ transform(chunk, enc, cb) {}
+ });
+
+ transform._destroy = common.mustCall(function(err, cb) {
+ assert.strictEqual(err, null);
+ cb();
+ }, 1);
+
+ transform.destroy();
+}
+
+{
+ const transform = new Transform({
+ transform(chunk, enc, cb) {}
+ });
+ transform.resume();
+
+ transform._destroy = common.mustCall(function(err, cb) {
+ assert.strictEqual(err, null);
+ process.nextTick(() => {
+ this.push(null);
+ this.end();
+ cb();
+ });
+ }, 1);
+
+ const fail = common.mustNotCall('no event');
+
+ transform.on('finish', fail);
+ transform.on('end', fail);
+ transform.on('close', common.mustCall());
+
+ transform.destroy();
+
+ transform.removeListener('end', fail);
+ transform.removeListener('finish', fail);
+ transform.on('end', common.mustCall());
+ transform.on('finish', common.mustNotCall());
+}
+
+{
+ const transform = new Transform({
+ transform(chunk, enc, cb) {}
+ });
+
+ const expected = new Error('kaboom');
+
+ transform._destroy = common.mustCall(function(err, cb) {
+ assert.strictEqual(err, null);
+ cb(expected);
+ }, 1);
+
+ transform.on('close', common.mustCall());
+ transform.on('finish', common.mustNotCall('no finish event'));
+ transform.on('end', common.mustNotCall('no end event'));
+ transform.on('error', common.mustCall((err) => {
+ assert.strictEqual(err, expected);
+ }));
+
+ transform.destroy();
+}
diff --git a/tests/node_compat/test/parallel/test-stream-transform-final-sync.js b/tests/node_compat/test/parallel/test-stream-transform-final-sync.js
new file mode 100644
index 000000000..5d108097d
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-transform-final-sync.js
@@ -0,0 +1,117 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+
+const stream = require('stream');
+let state = 0;
+
+
+// What you do
+//
+// const stream = new stream.Transform({
+// transform: function transformCallback(chunk, _, next) {
+// // part 1
+// this.push(chunk);
+// //part 2
+// next();
+// },
+// final: function endCallback(done) {
+// // part 1
+// process.nextTick(function () {
+// // part 2
+// done();
+// });
+// },
+// flush: function flushCallback(done) {
+// // part 1
+// process.nextTick(function () {
+// // part 2
+// done();
+// });
+// }
+// });
+// t.on('data', dataListener);
+// t.on('end', endListener);
+// t.on('finish', finishListener);
+// t.write(1);
+// t.write(4);
+// t.end(7, endMethodCallback);
+//
+// The order things are called
+//
+// 1. transformCallback part 1
+// 2. dataListener
+// 3. transformCallback part 2
+// 4. transformCallback part 1
+// 5. dataListener
+// 6. transformCallback part 2
+// 7. transformCallback part 1
+// 8. dataListener
+// 9. transformCallback part 2
+// 10. finalCallback part 1
+// 11. finalCallback part 2
+// 12. flushCallback part 1
+// 13. finishListener
+// 14. endMethodCallback
+// 15. flushCallback part 2
+// 16. endListener
+
+const t = new stream.Transform({
+ objectMode: true,
+ transform: common.mustCall(function(chunk, _, next) {
+ // transformCallback part 1
+ assert.strictEqual(++state, chunk);
+ this.push(state);
+ // transformCallback part 2
+ assert.strictEqual(++state, chunk + 2);
+ process.nextTick(next);
+ }, 3),
+ final: common.mustCall(function(done) {
+ state++;
+ // finalCallback part 1
+ assert.strictEqual(state, 10);
+ state++;
+ // finalCallback part 2
+ assert.strictEqual(state, 11);
+ done();
+ }, 1),
+ flush: common.mustCall(function(done) {
+ state++;
+ // fluchCallback part 1
+ assert.strictEqual(state, 12);
+ process.nextTick(function() {
+ state++;
+ // fluchCallback part 2
+ assert.strictEqual(state, 13);
+ done();
+ });
+ }, 1)
+});
+t.on('finish', common.mustCall(function() {
+ state++;
+ // finishListener
+ assert.strictEqual(state, 15);
+}, 1));
+t.on('end', common.mustCall(function() {
+ state++;
+ // endEvent
+ assert.strictEqual(state, 16);
+}, 1));
+t.on('data', common.mustCall(function(d) {
+ // dataListener
+ assert.strictEqual(++state, d + 1);
+}, 3));
+t.write(1);
+t.write(4);
+t.end(7, common.mustCall(function() {
+ state++;
+ // endMethodCallback
+ assert.strictEqual(state, 14);
+}, 1));
diff --git a/tests/node_compat/test/parallel/test-stream-transform-final.js b/tests/node_compat/test/parallel/test-stream-transform-final.js
new file mode 100644
index 000000000..1d14adf6b
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-transform-final.js
@@ -0,0 +1,119 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+
+const stream = require('stream');
+let state = 0;
+
+
+// What you do:
+//
+// const stream = new stream.Transform({
+// transform: function transformCallback(chunk, _, next) {
+// // part 1
+// this.push(chunk);
+// //part 2
+// next();
+// },
+// final: function endCallback(done) {
+// // part 1
+// process.nextTick(function () {
+// // part 2
+// done();
+// });
+// },
+// flush: function flushCallback(done) {
+// // part 1
+// process.nextTick(function () {
+// // part 2
+// done();
+// });
+// }
+// });
+// t.on('data', dataListener);
+// t.on('end', endListener);
+// t.on('finish', finishListener);
+// t.write(1);
+// t.write(4);
+// t.end(7, endMethodCallback);
+//
+// The order things are called
+
+// 1. transformCallback part 1
+// 2. dataListener
+// 3. transformCallback part 2
+// 4. transformCallback part 1
+// 5. dataListener
+// 6. transformCallback part 2
+// 7. transformCallback part 1
+// 8. dataListener
+// 9. transformCallback part 2
+// 10. finalCallback part 1
+// 11. finalCallback part 2
+// 12. flushCallback part 1
+// 13. finishListener
+// 14. endMethodCallback
+// 15. flushCallback part 2
+// 16. endListener
+
+const t = new stream.Transform({
+ objectMode: true,
+ transform: common.mustCall(function(chunk, _, next) {
+ // transformCallback part 1
+ assert.strictEqual(++state, chunk);
+ this.push(state);
+ // transformCallback part 2
+ assert.strictEqual(++state, chunk + 2);
+ process.nextTick(next);
+ }, 3),
+ final: common.mustCall(function(done) {
+ state++;
+ // finalCallback part 1
+ assert.strictEqual(state, 10);
+ setTimeout(function() {
+ state++;
+ // finalCallback part 2
+ assert.strictEqual(state, 11);
+ done();
+ }, 100);
+ }, 1),
+ flush: common.mustCall(function(done) {
+ state++;
+ // flushCallback part 1
+ assert.strictEqual(state, 12);
+ process.nextTick(function() {
+ state++;
+ // flushCallback part 2
+ assert.strictEqual(state, 13);
+ done();
+ });
+ }, 1)
+});
+t.on('finish', common.mustCall(function() {
+ state++;
+ // finishListener
+ assert.strictEqual(state, 15);
+}, 1));
+t.on('end', common.mustCall(function() {
+ state++;
+ // end event
+ assert.strictEqual(state, 16);
+}, 1));
+t.on('data', common.mustCall(function(d) {
+ // dataListener
+ assert.strictEqual(++state, d + 1);
+}, 3));
+t.write(1);
+t.write(4);
+t.end(7, common.mustCall(function() {
+ state++;
+ // endMethodCallback
+ assert.strictEqual(state, 14);
+}, 1));
diff --git a/tests/node_compat/test/parallel/test-stream-transform-flush-data.js b/tests/node_compat/test/parallel/test-stream-transform-flush-data.js
new file mode 100644
index 000000000..6b8ba1adc
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-transform-flush-data.js
@@ -0,0 +1,35 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+require('../common');
+
+const assert = require('assert');
+const Transform = require('stream').Transform;
+
+
+const expected = 'asdf';
+
+
+function _transform(d, e, n) {
+ n();
+}
+
+function _flush(n) {
+ n(null, expected);
+}
+
+const t = new Transform({
+ transform: _transform,
+ flush: _flush
+});
+
+t.end(Buffer.from('blerg'));
+t.on('data', (data) => {
+ assert.strictEqual(data.toString(), expected);
+});
diff --git a/tests/node_compat/test/parallel/test-stream-transform-objectmode-falsey-value.js b/tests/node_compat/test/parallel/test-stream-transform-objectmode-falsey-value.js
new file mode 100644
index 000000000..12390fe36
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-transform-objectmode-falsey-value.js
@@ -0,0 +1,58 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+
+const stream = require('stream');
+const PassThrough = stream.PassThrough;
+
+const src = new PassThrough({ objectMode: true });
+const tx = new PassThrough({ objectMode: true });
+const dest = new PassThrough({ objectMode: true });
+
+const expect = [ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
+const results = [];
+
+dest.on('data', common.mustCall(function(x) {
+ results.push(x);
+}, expect.length));
+
+src.pipe(tx).pipe(dest);
+
+let i = -1;
+const int = setInterval(common.mustCall(function() {
+ if (results.length === expect.length) {
+ src.end();
+ clearInterval(int);
+ assert.deepStrictEqual(results, expect);
+ } else {
+ src.write(i++);
+ }
+}, expect.length + 1), 1);
diff --git a/tests/node_compat/test/parallel/test-stream-transform-split-highwatermark.js b/tests/node_compat/test/parallel/test-stream-transform-split-highwatermark.js
new file mode 100644
index 000000000..783ddfc91
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-transform-split-highwatermark.js
@@ -0,0 +1,80 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+
+const { Transform, Readable, Writable } = require('stream');
+
+const DEFAULT = 16 * 1024;
+
+function testTransform(expectedReadableHwm, expectedWritableHwm, options) {
+ const t = new Transform(options);
+ assert.strictEqual(t._readableState.highWaterMark, expectedReadableHwm);
+ assert.strictEqual(t._writableState.highWaterMark, expectedWritableHwm);
+}
+
+// Test overriding defaultHwm
+testTransform(666, DEFAULT, { readableHighWaterMark: 666 });
+testTransform(DEFAULT, 777, { writableHighWaterMark: 777 });
+testTransform(666, 777, {
+ readableHighWaterMark: 666,
+ writableHighWaterMark: 777,
+});
+
+// Test highWaterMark overriding
+testTransform(555, 555, {
+ highWaterMark: 555,
+ readableHighWaterMark: 666,
+});
+testTransform(555, 555, {
+ highWaterMark: 555,
+ writableHighWaterMark: 777,
+});
+testTransform(555, 555, {
+ highWaterMark: 555,
+ readableHighWaterMark: 666,
+ writableHighWaterMark: 777,
+});
+
+// Test undefined, null
+[undefined, null].forEach((v) => {
+ testTransform(DEFAULT, DEFAULT, { readableHighWaterMark: v });
+ testTransform(DEFAULT, DEFAULT, { writableHighWaterMark: v });
+ testTransform(666, DEFAULT, { highWaterMark: v, readableHighWaterMark: 666 });
+ testTransform(DEFAULT, 777, { highWaterMark: v, writableHighWaterMark: 777 });
+});
+
+// test NaN
+{
+ assert.throws(() => {
+ new Transform({ readableHighWaterMark: NaN });
+ }, {
+ name: 'TypeError',
+ code: 'ERR_INVALID_ARG_VALUE',
+ message: "The property 'options.readableHighWaterMark' is invalid. " +
+ 'Received NaN'
+ });
+
+ assert.throws(() => {
+ new Transform({ writableHighWaterMark: NaN });
+ }, {
+ name: 'TypeError',
+ code: 'ERR_INVALID_ARG_VALUE',
+ message: "The property 'options.writableHighWaterMark' is invalid. " +
+ 'Received NaN'
+ });
+}
+
+// Test non Duplex streams ignore the options
+{
+ const r = new Readable({ readableHighWaterMark: 666 });
+ assert.strictEqual(r._readableState.highWaterMark, DEFAULT);
+ const w = new Writable({ writableHighWaterMark: 777 });
+ assert.strictEqual(w._writableState.highWaterMark, DEFAULT);
+}
diff --git a/tests/node_compat/test/parallel/test-stream-transform-split-objectmode.js b/tests/node_compat/test/parallel/test-stream-transform-split-objectmode.js
new file mode 100644
index 000000000..22e2586df
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-transform-split-objectmode.js
@@ -0,0 +1,88 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+
+const Transform = require('stream').Transform;
+
+const parser = new Transform({ readableObjectMode: true });
+
+assert(parser._readableState.objectMode);
+assert(!parser._writableState.objectMode);
+assert.strictEqual(parser.readableHighWaterMark, 16);
+assert.strictEqual(parser.writableHighWaterMark, 16 * 1024);
+assert.strictEqual(parser.readableHighWaterMark,
+ parser._readableState.highWaterMark);
+assert.strictEqual(parser.writableHighWaterMark,
+ parser._writableState.highWaterMark);
+
+parser._transform = function(chunk, enc, callback) {
+ callback(null, { val: chunk[0] });
+};
+
+let parsed;
+
+parser.on('data', function(obj) {
+ parsed = obj;
+});
+
+parser.end(Buffer.from([42]));
+
+process.on('exit', function() {
+ assert.strictEqual(parsed.val, 42);
+});
+
+
+const serializer = new Transform({ writableObjectMode: true });
+
+assert(!serializer._readableState.objectMode);
+assert(serializer._writableState.objectMode);
+assert.strictEqual(serializer.readableHighWaterMark, 16 * 1024);
+assert.strictEqual(serializer.writableHighWaterMark, 16);
+assert.strictEqual(parser.readableHighWaterMark,
+ parser._readableState.highWaterMark);
+assert.strictEqual(parser.writableHighWaterMark,
+ parser._writableState.highWaterMark);
+
+serializer._transform = function(obj, _, callback) {
+ callback(null, Buffer.from([obj.val]));
+};
+
+let serialized;
+
+serializer.on('data', function(chunk) {
+ serialized = chunk;
+});
+
+serializer.write({ val: 42 });
+
+process.on('exit', function() {
+ assert.strictEqual(serialized[0], 42);
+});
diff --git a/tests/node_compat/test/parallel/test-stream-uint8array.js b/tests/node_compat/test/parallel/test-stream-uint8array.js
new file mode 100644
index 000000000..c8de2dfe6
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-uint8array.js
@@ -0,0 +1,108 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+
+const { Readable, Writable } = require('stream');
+
+const ABC = new Uint8Array([0x41, 0x42, 0x43]);
+const DEF = new Uint8Array([0x44, 0x45, 0x46]);
+const GHI = new Uint8Array([0x47, 0x48, 0x49]);
+
+{
+ // Simple Writable test.
+
+ let n = 0;
+ const writable = new Writable({
+ write: common.mustCall((chunk, encoding, cb) => {
+ assert(chunk instanceof Buffer);
+ if (n++ === 0) {
+ assert.strictEqual(String(chunk), 'ABC');
+ } else {
+ assert.strictEqual(String(chunk), 'DEF');
+ }
+
+ cb();
+ }, 2)
+ });
+
+ writable.write(ABC);
+ writable.end(DEF);
+}
+
+{
+ // Writable test, pass in Uint8Array in object mode.
+
+ const writable = new Writable({
+ objectMode: true,
+ write: common.mustCall((chunk, encoding, cb) => {
+ assert(!(chunk instanceof Buffer));
+ assert(chunk instanceof Uint8Array);
+ assert.strictEqual(chunk, ABC);
+ assert.strictEqual(encoding, 'utf8');
+ cb();
+ })
+ });
+
+ writable.end(ABC);
+}
+
+{
+ // Writable test, multiple writes carried out via writev.
+ let callback;
+
+ const writable = new Writable({
+ write: common.mustCall((chunk, encoding, cb) => {
+ assert(chunk instanceof Buffer);
+ assert.strictEqual(encoding, 'buffer');
+ assert.strictEqual(String(chunk), 'ABC');
+ callback = cb;
+ }),
+ writev: common.mustCall((chunks, cb) => {
+ assert.strictEqual(chunks.length, 2);
+ assert.strictEqual(chunks[0].encoding, 'buffer');
+ assert.strictEqual(chunks[1].encoding, 'buffer');
+ assert.strictEqual(chunks[0].chunk + chunks[1].chunk, 'DEFGHI');
+ })
+ });
+
+ writable.write(ABC);
+ writable.write(DEF);
+ writable.end(GHI);
+ callback();
+}
+
+{
+ // Simple Readable test.
+ const readable = new Readable({
+ read() {}
+ });
+
+ readable.push(DEF);
+ readable.unshift(ABC);
+
+ const buf = readable.read();
+ assert(buf instanceof Buffer);
+ assert.deepStrictEqual([...buf], [...ABC, ...DEF]);
+}
+
+{
+ // Readable test, setEncoding.
+ const readable = new Readable({
+ read() {}
+ });
+
+ readable.setEncoding('utf8');
+
+ readable.push(DEF);
+ readable.unshift(ABC);
+
+ const out = readable.read();
+ assert.strictEqual(out, 'ABCDEF');
+}
diff --git a/tests/node_compat/test/parallel/test-stream-unpipe-event.js b/tests/node_compat/test/parallel/test-stream-unpipe-event.js
new file mode 100644
index 000000000..d0b60f435
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-unpipe-event.js
@@ -0,0 +1,92 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const { Writable, Readable } = require('stream');
+class NullWriteable extends Writable {
+ _write(chunk, encoding, callback) {
+ return callback();
+ }
+}
+class QuickEndReadable extends Readable {
+ _read() {
+ this.push(null);
+ }
+}
+class NeverEndReadable extends Readable {
+ _read() {}
+}
+
+{
+ const dest = new NullWriteable();
+ const src = new QuickEndReadable();
+ dest.on('pipe', common.mustCall());
+ dest.on('unpipe', common.mustCall());
+ src.pipe(dest);
+ setImmediate(() => {
+ assert.strictEqual(src._readableState.pipes.length, 0);
+ });
+}
+
+{
+ const dest = new NullWriteable();
+ const src = new NeverEndReadable();
+ dest.on('pipe', common.mustCall());
+ dest.on('unpipe', common.mustNotCall('unpipe should not have been emitted'));
+ src.pipe(dest);
+ setImmediate(() => {
+ assert.strictEqual(src._readableState.pipes.length, 1);
+ });
+}
+
+{
+ const dest = new NullWriteable();
+ const src = new NeverEndReadable();
+ dest.on('pipe', common.mustCall());
+ dest.on('unpipe', common.mustCall());
+ src.pipe(dest);
+ src.unpipe(dest);
+ setImmediate(() => {
+ assert.strictEqual(src._readableState.pipes.length, 0);
+ });
+}
+
+{
+ const dest = new NullWriteable();
+ const src = new QuickEndReadable();
+ dest.on('pipe', common.mustCall());
+ dest.on('unpipe', common.mustCall());
+ src.pipe(dest, { end: false });
+ setImmediate(() => {
+ assert.strictEqual(src._readableState.pipes.length, 0);
+ });
+}
+
+{
+ const dest = new NullWriteable();
+ const src = new NeverEndReadable();
+ dest.on('pipe', common.mustCall());
+ dest.on('unpipe', common.mustNotCall('unpipe should not have been emitted'));
+ src.pipe(dest, { end: false });
+ setImmediate(() => {
+ assert.strictEqual(src._readableState.pipes.length, 1);
+ });
+}
+
+{
+ const dest = new NullWriteable();
+ const src = new NeverEndReadable();
+ dest.on('pipe', common.mustCall());
+ dest.on('unpipe', common.mustCall());
+ src.pipe(dest, { end: false });
+ src.unpipe(dest);
+ setImmediate(() => {
+ assert.strictEqual(src._readableState.pipes.length, 0);
+ });
+}
diff --git a/tests/node_compat/test/parallel/test-stream-unshift-empty-chunk.js b/tests/node_compat/test/parallel/test-stream-unshift-empty-chunk.js
new file mode 100644
index 000000000..f6c057fd6
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-unshift-empty-chunk.js
@@ -0,0 +1,87 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+
+// This test verifies that stream.unshift(Buffer.alloc(0)) or
+// stream.unshift('') does not set state.reading=false.
+const Readable = require('stream').Readable;
+
+const r = new Readable();
+let nChunks = 10;
+const chunk = Buffer.alloc(10, 'x');
+
+r._read = function(n) {
+ setImmediate(() => {
+ r.push(--nChunks === 0 ? null : chunk);
+ });
+};
+
+let readAll = false;
+const seen = [];
+r.on('readable', () => {
+ let chunk;
+ while ((chunk = r.read()) !== null) {
+ seen.push(chunk.toString());
+ // Simulate only reading a certain amount of the data,
+ // and then putting the rest of the chunk back into the
+ // stream, like a parser might do. We just fill it with
+ // 'y' so that it's easy to see which bits were touched,
+ // and which were not.
+ const putBack = Buffer.alloc(readAll ? 0 : 5, 'y');
+ readAll = !readAll;
+ r.unshift(putBack);
+ }
+});
+
+const expect =
+ [ 'xxxxxxxxxx',
+ 'yyyyy',
+ 'xxxxxxxxxx',
+ 'yyyyy',
+ 'xxxxxxxxxx',
+ 'yyyyy',
+ 'xxxxxxxxxx',
+ 'yyyyy',
+ 'xxxxxxxxxx',
+ 'yyyyy',
+ 'xxxxxxxxxx',
+ 'yyyyy',
+ 'xxxxxxxxxx',
+ 'yyyyy',
+ 'xxxxxxxxxx',
+ 'yyyyy',
+ 'xxxxxxxxxx',
+ 'yyyyy' ];
+
+r.on('end', () => {
+ assert.deepStrictEqual(seen, expect);
+ console.log('ok');
+});
diff --git a/tests/node_compat/test/parallel/test-stream-unshift-read-race.js b/tests/node_compat/test/parallel/test-stream-unshift-read-race.js
new file mode 100644
index 000000000..d88850519
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-unshift-read-race.js
@@ -0,0 +1,135 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+
+// This test verifies that:
+// 1. unshift() does not cause colliding _read() calls.
+// 2. unshift() after the 'end' event is an error, but after the EOF
+// signalling null, it is ok, and just creates a new readable chunk.
+// 3. push() after the EOF signaling null is an error.
+// 4. _read() is not called after pushing the EOF null chunk.
+
+const stream = require('stream');
+const hwm = 10;
+const r = stream.Readable({ highWaterMark: hwm, autoDestroy: false });
+const chunks = 10;
+
+const data = Buffer.allocUnsafe(chunks * hwm + Math.ceil(hwm / 2));
+for (let i = 0; i < data.length; i++) {
+ const c = 'asdf'.charCodeAt(i % 4);
+ data[i] = c;
+}
+
+let pos = 0;
+let pushedNull = false;
+r._read = function(n) {
+ assert(!pushedNull, '_read after null push');
+
+ // Every third chunk is fast
+ push(!(chunks % 3));
+
+ function push(fast) {
+ assert(!pushedNull, 'push() after null push');
+ const c = pos >= data.length ? null : data.slice(pos, pos + n);
+ pushedNull = c === null;
+ if (fast) {
+ pos += n;
+ r.push(c);
+ if (c === null) pushError();
+ } else {
+ setTimeout(function() {
+ pos += n;
+ r.push(c);
+ if (c === null) pushError();
+ }, 1);
+ }
+ }
+};
+
+function pushError() {
+ r.unshift(Buffer.allocUnsafe(1));
+ w.end();
+
+ assert.throws(() => {
+ r.push(Buffer.allocUnsafe(1));
+ }, {
+ code: 'ERR_STREAM_PUSH_AFTER_EOF',
+ name: 'Error',
+ message: 'stream.push() after EOF'
+ });
+}
+
+
+const w = stream.Writable();
+const written = [];
+w._write = function(chunk, encoding, cb) {
+ written.push(chunk.toString());
+ cb();
+};
+
+r.on('end', common.mustNotCall());
+
+r.on('readable', function() {
+ let chunk;
+ while (null !== (chunk = r.read(10))) {
+ w.write(chunk);
+ if (chunk.length > 4)
+ r.unshift(Buffer.from('1234'));
+ }
+});
+
+w.on('finish', common.mustCall(function() {
+ // Each chunk should start with 1234, and then be asfdasdfasdf...
+ // The first got pulled out before the first unshift('1234'), so it's
+ // lacking that piece.
+ assert.strictEqual(written[0], 'asdfasdfas');
+ let asdf = 'd';
+ console.error(`0: ${written[0]}`);
+ for (let i = 1; i < written.length; i++) {
+ console.error(`${i.toString(32)}: ${written[i]}`);
+ assert.strictEqual(written[i].slice(0, 4), '1234');
+ for (let j = 4; j < written[i].length; j++) {
+ const c = written[i].charAt(j);
+ assert.strictEqual(c, asdf);
+ switch (asdf) {
+ case 'a': asdf = 's'; break;
+ case 's': asdf = 'd'; break;
+ case 'd': asdf = 'f'; break;
+ case 'f': asdf = 'a'; break;
+ }
+ }
+ }
+}));
+
+process.on('exit', function() {
+ assert.strictEqual(written.length, 18);
+ console.log('ok');
+});
diff --git a/tests/node_compat/test/parallel/test-stream-writable-change-default-encoding.js b/tests/node_compat/test/parallel/test-stream-writable-change-default-encoding.js
new file mode 100644
index 000000000..547309d70
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-writable-change-default-encoding.js
@@ -0,0 +1,85 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+
+const stream = require('stream');
+
+class MyWritable extends stream.Writable {
+ constructor(fn, options) {
+ super(options);
+ this.fn = fn;
+ }
+
+ _write(chunk, encoding, callback) {
+ this.fn(Buffer.isBuffer(chunk), typeof chunk, encoding);
+ callback();
+ }
+}
+
+(function defaultCondingIsUtf8() {
+ const m = new MyWritable(function(isBuffer, type, enc) {
+ assert.strictEqual(enc, 'utf8');
+ }, { decodeStrings: false });
+ m.write('foo');
+ m.end();
+}());
+
+(function changeDefaultEncodingToAscii() {
+ const m = new MyWritable(function(isBuffer, type, enc) {
+ assert.strictEqual(enc, 'ascii');
+ }, { decodeStrings: false });
+ m.setDefaultEncoding('ascii');
+ m.write('bar');
+ m.end();
+}());
+
+// Change default encoding to invalid value.
+assert.throws(() => {
+ const m = new MyWritable(
+ (isBuffer, type, enc) => {},
+ { decodeStrings: false });
+ m.setDefaultEncoding({});
+ m.write('bar');
+ m.end();
+}, {
+ name: 'TypeError',
+ code: 'ERR_UNKNOWN_ENCODING',
+ message: 'Unknown encoding: {}'
+});
+
+(function checkVariableCaseEncoding() {
+ const m = new MyWritable(function(isBuffer, type, enc) {
+ assert.strictEqual(enc, 'ascii');
+ }, { decodeStrings: false });
+ m.setDefaultEncoding('AsCii');
+ m.write('bar');
+ m.end();
+}());
diff --git a/tests/node_compat/test/parallel/test-stream-writable-clear-buffer.js b/tests/node_compat/test/parallel/test-stream-writable-clear-buffer.js
new file mode 100644
index 000000000..ee24da756
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-writable-clear-buffer.js
@@ -0,0 +1,42 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+// This test ensures that the _writeableState.bufferedRequestCount and
+// the actual buffered request count are the same.
+
+const common = require('../common');
+const Stream = require('stream');
+const assert = require('assert');
+
+class StreamWritable extends Stream.Writable {
+ constructor() {
+ super({ objectMode: true });
+ }
+
+ // Refs: https://github.com/nodejs/node/issues/6758
+ // We need a timer like on the original issue thread.
+ // Otherwise the code will never reach our test case.
+ _write(chunk, encoding, cb) {
+ setImmediate(cb);
+ }
+}
+
+const testStream = new StreamWritable();
+testStream.cork();
+
+for (let i = 1; i <= 5; i++) {
+ testStream.write(i, common.mustCall(() => {
+ assert.strictEqual(
+ testStream._writableState.bufferedRequestCount,
+ testStream._writableState.getBuffer().length
+ );
+ }));
+}
+
+testStream.end();
diff --git a/tests/node_compat/test/parallel/test-stream-writable-constructor-set-methods.js b/tests/node_compat/test/parallel/test-stream-writable-constructor-set-methods.js
new file mode 100644
index 000000000..58e687edd
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-writable-constructor-set-methods.js
@@ -0,0 +1,48 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+
+const assert = require('assert');
+const { Writable } = require('stream');
+
+const bufferBlerg = Buffer.from('blerg');
+const w = new Writable();
+
+assert.throws(
+ () => {
+ w.end(bufferBlerg);
+ },
+ {
+ name: 'Error',
+ code: 'ERR_METHOD_NOT_IMPLEMENTED',
+ message: 'The _write() method is not implemented'
+ }
+);
+
+const _write = common.mustCall((chunk, _, next) => {
+ next();
+});
+
+const _writev = common.mustCall((chunks, next) => {
+ assert.strictEqual(chunks.length, 2);
+ next();
+});
+
+const w2 = new Writable({ write: _write, writev: _writev });
+
+assert.strictEqual(w2._write, _write);
+assert.strictEqual(w2._writev, _writev);
+
+w2.write(bufferBlerg);
+
+w2.cork();
+w2.write(bufferBlerg);
+w2.write(bufferBlerg);
+
+w2.end();
diff --git a/tests/node_compat/test/parallel/test-stream-writable-decoded-encoding.js b/tests/node_compat/test/parallel/test-stream-writable-decoded-encoding.js
new file mode 100644
index 000000000..9bf47bb1a
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-writable-decoded-encoding.js
@@ -0,0 +1,65 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+
+const stream = require('stream');
+
+class MyWritable extends stream.Writable {
+ constructor(fn, options) {
+ super(options);
+ this.fn = fn;
+ }
+
+ _write(chunk, encoding, callback) {
+ this.fn(Buffer.isBuffer(chunk), typeof chunk, encoding);
+ callback();
+ }
+}
+
+{
+ const m = new MyWritable(function(isBuffer, type, enc) {
+ assert(isBuffer);
+ assert.strictEqual(type, 'object');
+ assert.strictEqual(enc, 'buffer');
+ }, { decodeStrings: true });
+ m.write('some-text', 'utf8');
+ m.end();
+}
+
+{
+ const m = new MyWritable(function(isBuffer, type, enc) {
+ assert(!isBuffer);
+ assert.strictEqual(type, 'string');
+ assert.strictEqual(enc, 'utf8');
+ }, { decodeStrings: false });
+ m.write('some-text', 'utf8');
+ m.end();
+}
diff --git a/tests/node_compat/test/parallel/test-stream-writable-destroy.js b/tests/node_compat/test/parallel/test-stream-writable-destroy.js
new file mode 100644
index 000000000..bfe145854
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-writable-destroy.js
@@ -0,0 +1,496 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const { Writable, addAbortSignal } = require('stream');
+const assert = require('assert');
+
+{
+ const write = new Writable({
+ write(chunk, enc, cb) { cb(); }
+ });
+
+ write.on('finish', common.mustNotCall());
+ write.on('close', common.mustCall());
+
+ write.destroy();
+ assert.strictEqual(write.destroyed, true);
+}
+
+{
+ const write = new Writable({
+ write(chunk, enc, cb) {
+ this.destroy(new Error('asd'));
+ cb();
+ }
+ });
+
+ write.on('error', common.mustCall());
+ write.on('finish', common.mustNotCall());
+ write.end('asd');
+ assert.strictEqual(write.destroyed, true);
+}
+
+{
+ const write = new Writable({
+ write(chunk, enc, cb) { cb(); }
+ });
+
+ const expected = new Error('kaboom');
+
+ write.on('finish', common.mustNotCall());
+ write.on('close', common.mustCall());
+ write.on('error', common.mustCall((err) => {
+ assert.strictEqual(err, expected);
+ }));
+
+ write.destroy(expected);
+ assert.strictEqual(write.destroyed, true);
+}
+
+{
+ const write = new Writable({
+ write(chunk, enc, cb) { cb(); }
+ });
+
+ write._destroy = function(err, cb) {
+ assert.strictEqual(err, expected);
+ cb(err);
+ };
+
+ const expected = new Error('kaboom');
+
+ write.on('finish', common.mustNotCall('no finish event'));
+ write.on('close', common.mustCall());
+ write.on('error', common.mustCall((err) => {
+ assert.strictEqual(err, expected);
+ }));
+
+ write.destroy(expected);
+ assert.strictEqual(write.destroyed, true);
+}
+
+{
+ const write = new Writable({
+ write(chunk, enc, cb) { cb(); },
+ destroy: common.mustCall(function(err, cb) {
+ assert.strictEqual(err, expected);
+ cb();
+ })
+ });
+
+ const expected = new Error('kaboom');
+
+ write.on('finish', common.mustNotCall('no finish event'));
+ write.on('close', common.mustCall());
+
+ // Error is swallowed by the custom _destroy
+ write.on('error', common.mustNotCall('no error event'));
+
+ write.destroy(expected);
+ assert.strictEqual(write.destroyed, true);
+}
+
+{
+ const write = new Writable({
+ write(chunk, enc, cb) { cb(); }
+ });
+
+ write._destroy = common.mustCall(function(err, cb) {
+ assert.strictEqual(err, null);
+ cb();
+ });
+
+ write.destroy();
+ assert.strictEqual(write.destroyed, true);
+}
+
+{
+ const write = new Writable({
+ write(chunk, enc, cb) { cb(); }
+ });
+
+ write._destroy = common.mustCall(function(err, cb) {
+ assert.strictEqual(err, null);
+ process.nextTick(() => {
+ this.end();
+ cb();
+ });
+ });
+
+ const fail = common.mustNotCall('no finish event');
+
+ write.on('finish', fail);
+ write.on('close', common.mustCall());
+
+ write.destroy();
+
+ assert.strictEqual(write.destroyed, true);
+}
+
+{
+ const write = new Writable({
+ write(chunk, enc, cb) { cb(); }
+ });
+
+ const expected = new Error('kaboom');
+
+ write._destroy = common.mustCall(function(err, cb) {
+ assert.strictEqual(err, null);
+ cb(expected);
+ });
+
+ write.on('close', common.mustCall());
+ write.on('finish', common.mustNotCall('no finish event'));
+ write.on('error', common.mustCall((err) => {
+ assert.strictEqual(err, expected);
+ }));
+
+ write.destroy();
+ assert.strictEqual(write.destroyed, true);
+}
+
+{
+ // double error case
+ const write = new Writable({
+ write(chunk, enc, cb) { cb(); }
+ });
+
+ let ticked = false;
+ write.on('close', common.mustCall(() => {
+ assert.strictEqual(ticked, true);
+ }));
+ write.on('error', common.mustCall((err) => {
+ assert.strictEqual(ticked, true);
+ assert.strictEqual(err.message, 'kaboom 1');
+ assert.strictEqual(write._writableState.errorEmitted, true);
+ }));
+
+ const expected = new Error('kaboom 1');
+ write.destroy(expected);
+ write.destroy(new Error('kaboom 2'));
+ assert.strictEqual(write._writableState.errored, expected);
+ assert.strictEqual(write._writableState.errorEmitted, false);
+ assert.strictEqual(write.destroyed, true);
+ ticked = true;
+}
+
+{
+ const writable = new Writable({
+ destroy: common.mustCall(function(err, cb) {
+ process.nextTick(cb, new Error('kaboom 1'));
+ }),
+ write(chunk, enc, cb) {
+ cb();
+ }
+ });
+
+ let ticked = false;
+ writable.on('close', common.mustCall(() => {
+ writable.on('error', common.mustNotCall());
+ writable.destroy(new Error('hello'));
+ assert.strictEqual(ticked, true);
+ assert.strictEqual(writable._writableState.errorEmitted, true);
+ }));
+ writable.on('error', common.mustCall((err) => {
+ assert.strictEqual(ticked, true);
+ assert.strictEqual(err.message, 'kaboom 1');
+ assert.strictEqual(writable._writableState.errorEmitted, true);
+ }));
+
+ writable.destroy();
+ assert.strictEqual(writable.destroyed, true);
+ assert.strictEqual(writable._writableState.errored, null);
+ assert.strictEqual(writable._writableState.errorEmitted, false);
+
+ // Test case where `writable.destroy()` is called again with an error before
+ // the `_destroy()` callback is called.
+ writable.destroy(new Error('kaboom 2'));
+ assert.strictEqual(writable._writableState.errorEmitted, false);
+ assert.strictEqual(writable._writableState.errored, null);
+
+ ticked = true;
+}
+
+{
+ const write = new Writable({
+ write(chunk, enc, cb) { cb(); }
+ });
+
+ write.destroyed = true;
+ assert.strictEqual(write.destroyed, true);
+
+ // The internal destroy() mechanism should not be triggered
+ write.on('close', common.mustNotCall());
+ write.destroy();
+}
+
+{
+ function MyWritable() {
+ assert.strictEqual(this.destroyed, false);
+ this.destroyed = false;
+ Writable.call(this);
+ }
+
+ Object.setPrototypeOf(MyWritable.prototype, Writable.prototype);
+ Object.setPrototypeOf(MyWritable, Writable);
+
+ new MyWritable();
+}
+
+{
+ // Destroy and destroy callback
+ const write = new Writable({
+ write(chunk, enc, cb) { cb(); }
+ });
+
+ write.destroy();
+
+ const expected = new Error('kaboom');
+
+ write.destroy(expected, common.mustCall((err) => {
+ assert.strictEqual(err, undefined);
+ }));
+}
+
+{
+ // Checks that `._undestroy()` restores the state so that `final` will be
+ // called again.
+ const write = new Writable({
+ write: common.mustNotCall(),
+ final: common.mustCall((cb) => cb(), 2),
+ autoDestroy: true
+ });
+
+ write.end();
+ write.once('close', common.mustCall(() => {
+ write._undestroy();
+ write.end();
+ }));
+}
+
+{
+ const write = new Writable();
+
+ write.destroy();
+ write.on('error', common.mustNotCall());
+ write.write('asd', common.expectsError({
+ name: 'Error',
+ code: 'ERR_STREAM_DESTROYED',
+ message: 'Cannot call write after a stream was destroyed'
+ }));
+}
+
+{
+ const write = new Writable({
+ write(chunk, enc, cb) { cb(); }
+ });
+
+ write.on('error', common.mustNotCall());
+
+ write.cork();
+ write.write('asd', common.mustCall());
+ write.uncork();
+
+ write.cork();
+ write.write('asd', common.expectsError({
+ name: 'Error',
+ code: 'ERR_STREAM_DESTROYED',
+ message: 'Cannot call write after a stream was destroyed'
+ }));
+ write.destroy();
+ write.write('asd', common.expectsError({
+ name: 'Error',
+ code: 'ERR_STREAM_DESTROYED',
+ message: 'Cannot call write after a stream was destroyed'
+ }));
+ write.uncork();
+}
+
+{
+ // Call end(cb) after error & destroy
+
+ const write = new Writable({
+ write(chunk, enc, cb) { cb(new Error('asd')); }
+ });
+ write.on('error', common.mustCall(() => {
+ write.destroy();
+ let ticked = false;
+ write.end(common.mustCall((err) => {
+ assert.strictEqual(ticked, true);
+ assert.strictEqual(err.code, 'ERR_STREAM_DESTROYED');
+ }));
+ ticked = true;
+ }));
+ write.write('asd');
+}
+
+{
+ // Call end(cb) after finish & destroy
+
+ const write = new Writable({
+ write(chunk, enc, cb) { cb(); }
+ });
+ write.on('finish', common.mustCall(() => {
+ write.destroy();
+ let ticked = false;
+ write.end(common.mustCall((err) => {
+ assert.strictEqual(ticked, true);
+ assert.strictEqual(err.code, 'ERR_STREAM_ALREADY_FINISHED');
+ }));
+ ticked = true;
+ }));
+ write.end();
+}
+
+{
+ // Call end(cb) after error & destroy and don't trigger
+ // unhandled exception.
+
+ const write = new Writable({
+ write(chunk, enc, cb) { process.nextTick(cb); }
+ });
+ const _err = new Error('asd');
+ write.once('error', common.mustCall((err) => {
+ assert.strictEqual(err.message, 'asd');
+ }));
+ write.end('asd', common.mustCall((err) => {
+ assert.strictEqual(err, _err);
+ }));
+ write.destroy(_err);
+}
+
+{
+ // Call buffered write callback with error
+
+ const _err = new Error('asd');
+ const write = new Writable({
+ write(chunk, enc, cb) {
+ process.nextTick(cb, _err);
+ },
+ autoDestroy: false
+ });
+ write.cork();
+ write.write('asd', common.mustCall((err) => {
+ assert.strictEqual(err, _err);
+ }));
+ write.write('asd', common.mustCall((err) => {
+ assert.strictEqual(err, _err);
+ }));
+ write.on('error', common.mustCall((err) => {
+ assert.strictEqual(err, _err);
+ }));
+ write.uncork();
+}
+
+{
+ // Ensure callback order.
+
+ let state = 0;
+ const write = new Writable({
+ write(chunk, enc, cb) {
+ // `setImmediate()` is used on purpose to ensure the callback is called
+ // after `process.nextTick()` callbacks.
+ setImmediate(cb);
+ }
+ });
+ write.write('asd', common.mustCall(() => {
+ assert.strictEqual(state++, 0);
+ }));
+ write.write('asd', common.mustCall((err) => {
+ assert.strictEqual(err.code, 'ERR_STREAM_DESTROYED');
+ assert.strictEqual(state++, 1);
+ }));
+ write.destroy();
+}
+
+{
+ const write = new Writable({
+ autoDestroy: false,
+ write(chunk, enc, cb) {
+ cb();
+ cb();
+ }
+ });
+
+ write.on('error', common.mustCall(() => {
+ assert(write._writableState.errored);
+ }));
+ write.write('asd');
+}
+
+{
+ const ac = new AbortController();
+ const write = addAbortSignal(ac.signal, new Writable({
+ write(chunk, enc, cb) { cb(); }
+ }));
+
+ write.on('error', common.mustCall((e) => {
+ assert.strictEqual(e.name, 'AbortError');
+ assert.strictEqual(write.destroyed, true);
+ }));
+ write.write('asd');
+ ac.abort();
+}
+
+{
+ const ac = new AbortController();
+ const write = new Writable({
+ signal: ac.signal,
+ write(chunk, enc, cb) { cb(); }
+ });
+
+ write.on('error', common.mustCall((e) => {
+ assert.strictEqual(e.name, 'AbortError');
+ assert.strictEqual(write.destroyed, true);
+ }));
+ write.write('asd');
+ ac.abort();
+}
+
+{
+ const signal = AbortSignal.abort();
+
+ const write = new Writable({
+ signal,
+ write(chunk, enc, cb) { cb(); }
+ });
+
+ write.on('error', common.mustCall((e) => {
+ assert.strictEqual(e.name, 'AbortError');
+ assert.strictEqual(write.destroyed, true);
+ }));
+}
+
+{
+ // Destroy twice
+ const write = new Writable({
+ write(chunk, enc, cb) { cb(); }
+ });
+
+ write.end(common.mustCall());
+ write.destroy();
+ write.destroy();
+}
+
+{
+ // https://github.com/nodejs/node/issues/39356
+ const s = new Writable({
+ final() {}
+ });
+ const _err = new Error('oh no');
+ // Remove `callback` and it works
+ s.end(common.mustCall((err) => {
+ assert.strictEqual(err, _err);
+ }));
+ s.on('error', common.mustCall((err) => {
+ assert.strictEqual(err, _err);
+ }));
+ s.destroy(_err);
+}
diff --git a/tests/node_compat/test/parallel/test-stream-writable-end-cb-error.js b/tests/node_compat/test/parallel/test-stream-writable-end-cb-error.js
new file mode 100644
index 000000000..730146db3
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-writable-end-cb-error.js
@@ -0,0 +1,85 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const assert = require('assert');
+const stream = require('stream');
+
+{
+ // Invoke end callback on failure.
+ const writable = new stream.Writable();
+
+ const _err = new Error('kaboom');
+ writable._write = (chunk, encoding, cb) => {
+ process.nextTick(cb, _err);
+ };
+
+ writable.on('error', common.mustCall((err) => {
+ assert.strictEqual(err, _err);
+ }));
+ writable.write('asd');
+ writable.end(common.mustCall((err) => {
+ assert.strictEqual(err, _err);
+ }));
+ writable.end(common.mustCall((err) => {
+ assert.strictEqual(err, _err);
+ }));
+}
+
+{
+ // Don't invoke end callback twice
+ const writable = new stream.Writable();
+
+ writable._write = (chunk, encoding, cb) => {
+ process.nextTick(cb);
+ };
+
+ let called = false;
+ writable.end('asd', common.mustCall((err) => {
+ called = true;
+ assert.strictEqual(err, undefined);
+ }));
+
+ writable.on('error', common.mustCall((err) => {
+ assert.strictEqual(err.message, 'kaboom');
+ }));
+ writable.on('finish', common.mustCall(() => {
+ assert.strictEqual(called, true);
+ writable.emit('error', new Error('kaboom'));
+ }));
+}
+
+{
+ const w = new stream.Writable({
+ write(chunk, encoding, callback) {
+ setImmediate(callback);
+ },
+ finish(callback) {
+ setImmediate(callback);
+ }
+ });
+ w.end('testing ended state', common.mustCall((err) => {
+ assert.strictEqual(err.code, 'ERR_STREAM_WRITE_AFTER_END');
+ }));
+ assert.strictEqual(w.destroyed, false);
+ assert.strictEqual(w.writableEnded, true);
+ w.end(common.mustCall((err) => {
+ assert.strictEqual(err.code, 'ERR_STREAM_WRITE_AFTER_END');
+ }));
+ assert.strictEqual(w.destroyed, false);
+ assert.strictEqual(w.writableEnded, true);
+ w.end('end', common.mustCall((err) => {
+ assert.strictEqual(err.code, 'ERR_STREAM_WRITE_AFTER_END');
+ }));
+ assert.strictEqual(w.destroyed, true);
+ w.on('error', common.mustCall((err) => {
+ assert.strictEqual(err.code, 'ERR_STREAM_WRITE_AFTER_END');
+ }));
+ w.on('finish', common.mustNotCall());
+}
diff --git a/tests/node_compat/test/parallel/test-stream-writable-end-multiple.js b/tests/node_compat/test/parallel/test-stream-writable-end-multiple.js
new file mode 100644
index 000000000..ea1759303
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-writable-end-multiple.js
@@ -0,0 +1,29 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+
+const assert = require('assert');
+const stream = require('stream');
+
+const writable = new stream.Writable();
+writable._write = (chunk, encoding, cb) => {
+ setTimeout(() => cb(), 10);
+};
+
+writable.end('testing ended state', common.mustCall());
+writable.end(common.mustCall());
+writable.on('finish', common.mustCall(() => {
+ let ticked = false;
+ writable.end(common.mustCall((err) => {
+ assert.strictEqual(ticked, true);
+ assert.strictEqual(err.code, 'ERR_STREAM_ALREADY_FINISHED');
+ }));
+ ticked = true;
+}));
diff --git a/tests/node_compat/test/parallel/test-stream-writable-ended-state.js b/tests/node_compat/test/parallel/test-stream-writable-ended-state.js
new file mode 100644
index 000000000..f6f6971a2
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-writable-ended-state.js
@@ -0,0 +1,39 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+
+const assert = require('assert');
+const stream = require('stream');
+
+const writable = new stream.Writable();
+
+writable._write = (chunk, encoding, cb) => {
+ assert.strictEqual(writable._writableState.ended, false);
+ assert.strictEqual(writable._writableState.writable, undefined);
+ assert.strictEqual(writable.writableEnded, false);
+ cb();
+};
+
+assert.strictEqual(writable._writableState.ended, false);
+assert.strictEqual(writable._writableState.writable, undefined);
+assert.strictEqual(writable.writable, true);
+assert.strictEqual(writable.writableEnded, false);
+
+writable.end('testing ended state', common.mustCall(() => {
+ assert.strictEqual(writable._writableState.ended, true);
+ assert.strictEqual(writable._writableState.writable, undefined);
+ assert.strictEqual(writable.writable, false);
+ assert.strictEqual(writable.writableEnded, true);
+}));
+
+assert.strictEqual(writable._writableState.ended, true);
+assert.strictEqual(writable._writableState.writable, undefined);
+assert.strictEqual(writable.writable, false);
+assert.strictEqual(writable.writableEnded, true);
diff --git a/tests/node_compat/test/parallel/test-stream-writable-finish-destroyed.js b/tests/node_compat/test/parallel/test-stream-writable-finish-destroyed.js
new file mode 100644
index 000000000..9d8775dec
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-writable-finish-destroyed.js
@@ -0,0 +1,50 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const { Writable } = require('stream');
+
+{
+ const w = new Writable({
+ write: common.mustCall((chunk, encoding, cb) => {
+ w.on('close', common.mustCall(() => {
+ cb();
+ }));
+ })
+ });
+
+ w.on('finish', common.mustNotCall());
+ w.end('asd');
+ w.destroy();
+}
+
+{
+ const w = new Writable({
+ write: common.mustCall((chunk, encoding, cb) => {
+ w.on('close', common.mustCall(() => {
+ cb();
+ w.end();
+ }));
+ })
+ });
+
+ w.on('finish', common.mustNotCall());
+ w.write('asd');
+ w.destroy();
+}
+
+{
+ const w = new Writable({
+ write() {
+ }
+ });
+ w.on('finish', common.mustNotCall());
+ w.end();
+ w.destroy();
+}
diff --git a/tests/node_compat/test/parallel/test-stream-writable-finished-state.js b/tests/node_compat/test/parallel/test-stream-writable-finished-state.js
new file mode 100644
index 000000000..0b7333bf2
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-writable-finished-state.js
@@ -0,0 +1,29 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+
+const assert = require('assert');
+const stream = require('stream');
+
+const writable = new stream.Writable();
+
+writable._write = (chunk, encoding, cb) => {
+ // The state finished should start in false.
+ assert.strictEqual(writable._writableState.finished, false);
+ cb();
+};
+
+writable.on('finish', common.mustCall(() => {
+ assert.strictEqual(writable._writableState.finished, true);
+}));
+
+writable.end('testing finished state', common.mustCall(() => {
+ assert.strictEqual(writable._writableState.finished, true);
+}));
diff --git a/tests/node_compat/test/parallel/test-stream-writable-finished.js b/tests/node_compat/test/parallel/test-stream-writable-finished.js
new file mode 100644
index 000000000..30ae737f9
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-writable-finished.js
@@ -0,0 +1,106 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const { Writable } = require('stream');
+const assert = require('assert');
+
+// basic
+{
+ // Find it on Writable.prototype
+ assert(Object.hasOwn(Writable.prototype, 'writableFinished'));
+}
+
+// event
+{
+ const writable = new Writable();
+
+ writable._write = (chunk, encoding, cb) => {
+ // The state finished should start in false.
+ assert.strictEqual(writable.writableFinished, false);
+ cb();
+ };
+
+ writable.on('finish', common.mustCall(() => {
+ assert.strictEqual(writable.writableFinished, true);
+ }));
+
+ writable.end('testing finished state', common.mustCall(() => {
+ assert.strictEqual(writable.writableFinished, true);
+ }));
+}
+
+{
+ // Emit finish asynchronously.
+
+ const w = new Writable({
+ write(chunk, encoding, cb) {
+ cb();
+ }
+ });
+
+ w.end();
+ w.on('finish', common.mustCall());
+}
+
+{
+ // Emit prefinish synchronously.
+
+ const w = new Writable({
+ write(chunk, encoding, cb) {
+ cb();
+ }
+ });
+
+ let sync = true;
+ w.on('prefinish', common.mustCall(() => {
+ assert.strictEqual(sync, true);
+ }));
+ w.end();
+ sync = false;
+}
+
+{
+ // Emit prefinish synchronously w/ final.
+
+ const w = new Writable({
+ write(chunk, encoding, cb) {
+ cb();
+ },
+ final(cb) {
+ cb();
+ }
+ });
+
+ let sync = true;
+ w.on('prefinish', common.mustCall(() => {
+ assert.strictEqual(sync, true);
+ }));
+ w.end();
+ sync = false;
+}
+
+
+{
+ // Call _final synchronously.
+
+ let sync = true;
+ const w = new Writable({
+ write(chunk, encoding, cb) {
+ cb();
+ },
+ final: common.mustCall((cb) => {
+ assert.strictEqual(sync, true);
+ cb();
+ })
+ });
+
+ w.end();
+ sync = false;
+}
diff --git a/tests/node_compat/test/parallel/test-stream-writable-invalid-chunk.js b/tests/node_compat/test/parallel/test-stream-writable-invalid-chunk.js
new file mode 100644
index 000000000..82912adb8
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-writable-invalid-chunk.js
@@ -0,0 +1,43 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const stream = require('stream');
+const assert = require('assert');
+
+function testWriteType(val, objectMode, code) {
+ const writable = new stream.Writable({
+ objectMode,
+ write: () => {}
+ });
+ writable.on('error', common.mustNotCall());
+ if (code) {
+ assert.throws(() => {
+ writable.write(val);
+ }, { code });
+ } else {
+ writable.write(val);
+ }
+}
+
+testWriteType([], false, 'ERR_INVALID_ARG_TYPE');
+testWriteType({}, false, 'ERR_INVALID_ARG_TYPE');
+testWriteType(0, false, 'ERR_INVALID_ARG_TYPE');
+testWriteType(true, false, 'ERR_INVALID_ARG_TYPE');
+testWriteType(0.0, false, 'ERR_INVALID_ARG_TYPE');
+testWriteType(undefined, false, 'ERR_INVALID_ARG_TYPE');
+testWriteType(null, false, 'ERR_STREAM_NULL_VALUES');
+
+testWriteType([], true);
+testWriteType({}, true);
+testWriteType(0, true);
+testWriteType(true, true);
+testWriteType(0.0, true);
+testWriteType(undefined, true);
+testWriteType(null, true, 'ERR_STREAM_NULL_VALUES');
diff --git a/tests/node_compat/test/parallel/test-stream-writable-needdrain-state.js b/tests/node_compat/test/parallel/test-stream-writable-needdrain-state.js
new file mode 100644
index 000000000..fe8c28921
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-writable-needdrain-state.js
@@ -0,0 +1,32 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const stream = require('stream');
+const assert = require('assert');
+
+const transform = new stream.Transform({
+ transform: _transform,
+ highWaterMark: 1
+});
+
+function _transform(chunk, encoding, cb) {
+ process.nextTick(() => {
+ assert.strictEqual(transform._writableState.needDrain, true);
+ cb();
+ });
+}
+
+assert.strictEqual(transform._writableState.needDrain, false);
+
+transform.write('asdasd', common.mustCall(() => {
+ assert.strictEqual(transform._writableState.needDrain, false);
+}));
+
+assert.strictEqual(transform._writableState.needDrain, true);
diff --git a/tests/node_compat/test/parallel/test-stream-writable-null.js b/tests/node_compat/test/parallel/test-stream-writable-null.js
new file mode 100644
index 000000000..e2ddd7d0a
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-writable-null.js
@@ -0,0 +1,54 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+
+const stream = require('stream');
+
+class MyWritable extends stream.Writable {
+ constructor(options) {
+ super({ autoDestroy: false, ...options });
+ }
+ _write(chunk, encoding, callback) {
+ assert.notStrictEqual(chunk, null);
+ callback();
+ }
+}
+
+{
+ const m = new MyWritable({ objectMode: true });
+ m.on('error', common.mustNotCall());
+ assert.throws(() => {
+ m.write(null);
+ }, {
+ code: 'ERR_STREAM_NULL_VALUES'
+ });
+}
+
+{
+ const m = new MyWritable();
+ m.on('error', common.mustNotCall());
+ assert.throws(() => {
+ m.write(false);
+ }, {
+ code: 'ERR_INVALID_ARG_TYPE'
+ });
+}
+
+{ // Should not throw.
+ const m = new MyWritable({ objectMode: true });
+ m.write(false, assert.ifError);
+}
+
+{ // Should not throw.
+ const m = new MyWritable({ objectMode: true }).on('error', (e) => {
+ assert.ifError(e || new Error('should not get here'));
+ });
+ m.write(false, assert.ifError);
+}
diff --git a/tests/node_compat/test/parallel/test-stream-writable-properties.js b/tests/node_compat/test/parallel/test-stream-writable-properties.js
new file mode 100644
index 000000000..ef19b3a01
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-writable-properties.js
@@ -0,0 +1,29 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+
+const { Writable } = require('stream');
+
+{
+ const w = new Writable();
+ assert.strictEqual(w.writableCorked, 0);
+ w.uncork();
+ assert.strictEqual(w.writableCorked, 0);
+ w.cork();
+ assert.strictEqual(w.writableCorked, 1);
+ w.cork();
+ assert.strictEqual(w.writableCorked, 2);
+ w.uncork();
+ assert.strictEqual(w.writableCorked, 1);
+ w.uncork();
+ assert.strictEqual(w.writableCorked, 0);
+ w.uncork();
+ assert.strictEqual(w.writableCorked, 0);
+}
diff --git a/tests/node_compat/test/parallel/test-stream-writable-writable.js b/tests/node_compat/test/parallel/test-stream-writable-writable.js
new file mode 100644
index 000000000..63be4b3ca
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-writable-writable.js
@@ -0,0 +1,55 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+
+const { Writable } = require('stream');
+
+{
+ const w = new Writable({
+ write() {}
+ });
+ assert.strictEqual(w.writable, true);
+ w.destroy();
+ assert.strictEqual(w.writable, false);
+}
+
+{
+ const w = new Writable({
+ write: common.mustCall((chunk, encoding, callback) => {
+ callback(new Error());
+ })
+ });
+ assert.strictEqual(w.writable, true);
+ w.write('asd');
+ assert.strictEqual(w.writable, false);
+ w.on('error', common.mustCall());
+}
+
+{
+ const w = new Writable({
+ write: common.mustCall((chunk, encoding, callback) => {
+ process.nextTick(() => {
+ callback(new Error());
+ assert.strictEqual(w.writable, false);
+ });
+ })
+ });
+ w.write('asd');
+ w.on('error', common.mustCall());
+}
+
+{
+ const w = new Writable({
+ write: common.mustNotCall()
+ });
+ assert.strictEqual(w.writable, true);
+ w.end();
+ assert.strictEqual(w.writable, false);
+}
diff --git a/tests/node_compat/test/parallel/test-stream-writable-write-cb-error.js b/tests/node_compat/test/parallel/test-stream-writable-write-cb-error.js
new file mode 100644
index 000000000..c4df3233a
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-writable-write-cb-error.js
@@ -0,0 +1,65 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const { Writable } = require('stream');
+const assert = require('assert');
+
+// Ensure callback is always invoked before
+// error is emitted. Regardless if error was
+// sync or async.
+
+{
+ let callbackCalled = false;
+ // Sync Error
+ const writable = new Writable({
+ write: common.mustCall((buf, enc, cb) => {
+ cb(new Error());
+ })
+ });
+ writable.on('error', common.mustCall(() => {
+ assert.strictEqual(callbackCalled, true);
+ }));
+ writable.write('hi', common.mustCall(() => {
+ callbackCalled = true;
+ }));
+}
+
+{
+ let callbackCalled = false;
+ // Async Error
+ const writable = new Writable({
+ write: common.mustCall((buf, enc, cb) => {
+ process.nextTick(cb, new Error());
+ })
+ });
+ writable.on('error', common.mustCall(() => {
+ assert.strictEqual(callbackCalled, true);
+ }));
+ writable.write('hi', common.mustCall(() => {
+ callbackCalled = true;
+ }));
+}
+
+{
+ // Sync Error
+ const writable = new Writable({
+ write: common.mustCall((buf, enc, cb) => {
+ cb(new Error());
+ })
+ });
+
+ writable.on('error', common.mustCall());
+
+ let cnt = 0;
+ // Ensure we don't live lock on sync error
+ while (writable.write('a'))
+ cnt++;
+
+ assert.strictEqual(cnt, 0);
+}
diff --git a/tests/node_compat/test/parallel/test-stream-writable-write-cb-twice.js b/tests/node_compat/test/parallel/test-stream-writable-write-cb-twice.js
new file mode 100644
index 000000000..ab2408fd9
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-writable-write-cb-twice.js
@@ -0,0 +1,59 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const { Writable } = require('stream');
+
+{
+ // Sync + Sync
+ const writable = new Writable({
+ write: common.mustCall((buf, enc, cb) => {
+ cb();
+ cb();
+ })
+ });
+ writable.write('hi');
+ writable.on('error', common.expectsError({
+ code: 'ERR_MULTIPLE_CALLBACK',
+ name: 'Error'
+ }));
+}
+
+{
+ // Sync + Async
+ const writable = new Writable({
+ write: common.mustCall((buf, enc, cb) => {
+ cb();
+ process.nextTick(() => {
+ cb();
+ });
+ })
+ });
+ writable.write('hi');
+ writable.on('error', common.expectsError({
+ code: 'ERR_MULTIPLE_CALLBACK',
+ name: 'Error'
+ }));
+}
+
+{
+ // Async + Async
+ const writable = new Writable({
+ write: common.mustCall((buf, enc, cb) => {
+ process.nextTick(cb);
+ process.nextTick(() => {
+ cb();
+ });
+ })
+ });
+ writable.write('hi');
+ writable.on('error', common.expectsError({
+ code: 'ERR_MULTIPLE_CALLBACK',
+ name: 'Error'
+ }));
+}
diff --git a/tests/node_compat/test/parallel/test-stream-writable-write-error.js b/tests/node_compat/test/parallel/test-stream-writable-write-error.js
new file mode 100644
index 000000000..2bb91f821
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-writable-write-error.js
@@ -0,0 +1,82 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+
+const { Writable } = require('stream');
+
+function expectError(w, args, code, sync) {
+ if (sync) {
+ if (code) {
+ assert.throws(() => w.write(...args), { code });
+ } else {
+ w.write(...args);
+ }
+ } else {
+ let errorCalled = false;
+ let ticked = false;
+ w.write(...args, common.mustCall((err) => {
+ assert.strictEqual(ticked, true);
+ assert.strictEqual(errorCalled, false);
+ assert.strictEqual(err.code, code);
+ }));
+ ticked = true;
+ w.on('error', common.mustCall((err) => {
+ errorCalled = true;
+ assert.strictEqual(err.code, code);
+ }));
+ }
+}
+
+function test(autoDestroy) {
+ {
+ const w = new Writable({
+ autoDestroy,
+ _write() {}
+ });
+ w.end();
+ expectError(w, ['asd'], 'ERR_STREAM_WRITE_AFTER_END');
+ }
+
+ {
+ const w = new Writable({
+ autoDestroy,
+ _write() {}
+ });
+ w.destroy();
+ }
+
+ {
+ const w = new Writable({
+ autoDestroy,
+ _write() {}
+ });
+ expectError(w, [null], 'ERR_STREAM_NULL_VALUES', true);
+ }
+
+ {
+ const w = new Writable({
+ autoDestroy,
+ _write() {}
+ });
+ expectError(w, [{}], 'ERR_INVALID_ARG_TYPE', true);
+ }
+
+ {
+ const w = new Writable({
+ decodeStrings: false,
+ autoDestroy,
+ _write() {}
+ });
+ expectError(w, ['asd', 'noencoding'], 'ERR_UNKNOWN_ENCODING', true);
+ }
+}
+
+test(false);
+test(true);
diff --git a/tests/node_compat/test/parallel/test-stream-writable-write-writev-finish.js b/tests/node_compat/test/parallel/test-stream-writable-write-writev-finish.js
new file mode 100644
index 000000000..ff34a83c1
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-writable-write-writev-finish.js
@@ -0,0 +1,159 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const assert = require('assert');
+const stream = require('stream');
+
+// Ensure consistency between the finish event when using cork()
+// and writev and when not using them
+
+{
+ const writable = new stream.Writable();
+
+ writable._write = (chunks, encoding, cb) => {
+ cb(new Error('write test error'));
+ };
+
+ writable.on('finish', common.mustNotCall());
+ writable.on('prefinish', common.mustNotCall());
+ writable.on('error', common.mustCall((er) => {
+ assert.strictEqual(er.message, 'write test error');
+ }));
+
+ writable.end('test');
+}
+
+{
+ const writable = new stream.Writable();
+
+ writable._write = (chunks, encoding, cb) => {
+ setImmediate(cb, new Error('write test error'));
+ };
+
+ writable.on('finish', common.mustNotCall());
+ writable.on('prefinish', common.mustNotCall());
+ writable.on('error', common.mustCall((er) => {
+ assert.strictEqual(er.message, 'write test error');
+ }));
+
+ writable.end('test');
+}
+
+{
+ const writable = new stream.Writable();
+
+ writable._write = (chunks, encoding, cb) => {
+ cb(new Error('write test error'));
+ };
+
+ writable._writev = (chunks, cb) => {
+ cb(new Error('writev test error'));
+ };
+
+ writable.on('finish', common.mustNotCall());
+ writable.on('prefinish', common.mustNotCall());
+ writable.on('error', common.mustCall((er) => {
+ assert.strictEqual(er.message, 'writev test error');
+ }));
+
+ writable.cork();
+ writable.write('test');
+
+ setImmediate(function() {
+ writable.end('test');
+ });
+}
+
+{
+ const writable = new stream.Writable();
+
+ writable._write = (chunks, encoding, cb) => {
+ setImmediate(cb, new Error('write test error'));
+ };
+
+ writable._writev = (chunks, cb) => {
+ setImmediate(cb, new Error('writev test error'));
+ };
+
+ writable.on('finish', common.mustNotCall());
+ writable.on('prefinish', common.mustNotCall());
+ writable.on('error', common.mustCall((er) => {
+ assert.strictEqual(er.message, 'writev test error');
+ }));
+
+ writable.cork();
+ writable.write('test');
+
+ setImmediate(function() {
+ writable.end('test');
+ });
+}
+
+// Regression test for
+// https://github.com/nodejs/node/issues/13812
+
+{
+ const rs = new stream.Readable();
+ rs.push('ok');
+ rs.push(null);
+ rs._read = () => {};
+
+ const ws = new stream.Writable();
+
+ ws.on('finish', common.mustNotCall());
+ ws.on('error', common.mustCall());
+
+ ws._write = (chunk, encoding, done) => {
+ setImmediate(done, new Error());
+ };
+ rs.pipe(ws);
+}
+
+{
+ const rs = new stream.Readable();
+ rs.push('ok');
+ rs.push(null);
+ rs._read = () => {};
+
+ const ws = new stream.Writable();
+
+ ws.on('finish', common.mustNotCall());
+ ws.on('error', common.mustCall());
+
+ ws._write = (chunk, encoding, done) => {
+ done(new Error());
+ };
+ rs.pipe(ws);
+}
+
+{
+ const w = new stream.Writable();
+ w._write = (chunk, encoding, cb) => {
+ process.nextTick(cb);
+ };
+ w.on('error', common.mustCall());
+ w.on('finish', common.mustNotCall());
+ w.on('prefinish', () => {
+ w.write("shouldn't write in prefinish listener");
+ });
+ w.end();
+}
+
+{
+ const w = new stream.Writable();
+ w._write = (chunk, encoding, cb) => {
+ process.nextTick(cb);
+ };
+ w.on('error', common.mustCall());
+ w.on('finish', () => {
+ w.write("shouldn't write in finish listener");
+ });
+ w.end();
+}
diff --git a/tests/node_compat/test/parallel/test-stream-writableState-ending.js b/tests/node_compat/test/parallel/test-stream-writableState-ending.js
new file mode 100644
index 000000000..a477e63b6
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-writableState-ending.js
@@ -0,0 +1,44 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+require('../common');
+
+const assert = require('assert');
+const stream = require('stream');
+
+const writable = new stream.Writable();
+
+function testStates(ending, finished, ended) {
+ assert.strictEqual(writable._writableState.ending, ending);
+ assert.strictEqual(writable._writableState.finished, finished);
+ assert.strictEqual(writable._writableState.ended, ended);
+}
+
+writable._write = (chunk, encoding, cb) => {
+ // Ending, finished, ended start in false.
+ testStates(false, false, false);
+ cb();
+};
+
+writable.on('finish', () => {
+ // Ending, finished, ended = true.
+ testStates(true, true, true);
+});
+
+const result = writable.end('testing function end()', () => {
+ // Ending, finished, ended = true.
+ testStates(true, true, true);
+});
+
+// End returns the writable instance
+assert.strictEqual(result, writable);
+
+// Ending, ended = true.
+// finished = false.
+testStates(true, false, true);
diff --git a/tests/node_compat/test/parallel/test-stream-writableState-uncorked-bufferedRequestCount.js b/tests/node_compat/test/parallel/test-stream-writableState-uncorked-bufferedRequestCount.js
new file mode 100644
index 000000000..0320d1a5d
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-writableState-uncorked-bufferedRequestCount.js
@@ -0,0 +1,64 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const assert = require('assert');
+const stream = require('stream');
+
+const writable = new stream.Writable();
+
+writable._writev = common.mustCall((chunks, cb) => {
+ assert.strictEqual(chunks.length, 2);
+ cb();
+}, 1);
+
+writable._write = common.mustCall((chunk, encoding, cb) => {
+ cb();
+}, 1);
+
+// first cork
+writable.cork();
+assert.strictEqual(writable._writableState.corked, 1);
+assert.strictEqual(writable._writableState.bufferedRequestCount, 0);
+
+// cork again
+writable.cork();
+assert.strictEqual(writable._writableState.corked, 2);
+
+// The first chunk is buffered
+writable.write('first chunk');
+assert.strictEqual(writable._writableState.bufferedRequestCount, 1);
+
+// First uncork does nothing
+writable.uncork();
+assert.strictEqual(writable._writableState.corked, 1);
+assert.strictEqual(writable._writableState.bufferedRequestCount, 1);
+
+process.nextTick(uncork);
+
+// The second chunk is buffered, because we uncork at the end of tick
+writable.write('second chunk');
+assert.strictEqual(writable._writableState.corked, 1);
+assert.strictEqual(writable._writableState.bufferedRequestCount, 2);
+
+function uncork() {
+ // Second uncork flushes the buffer
+ writable.uncork();
+ assert.strictEqual(writable._writableState.corked, 0);
+ assert.strictEqual(writable._writableState.bufferedRequestCount, 0);
+
+ // Verify that end() uncorks correctly
+ writable.cork();
+ writable.write('third chunk');
+ writable.end();
+
+ // End causes an uncork() as well
+ assert.strictEqual(writable._writableState.corked, 0);
+ assert.strictEqual(writable._writableState.bufferedRequestCount, 0);
+}
diff --git a/tests/node_compat/test/parallel/test-stream-write-destroy.js b/tests/node_compat/test/parallel/test-stream-write-destroy.js
new file mode 100644
index 000000000..a4f103547
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-write-destroy.js
@@ -0,0 +1,69 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+const { Writable } = require('stream');
+
+// Test interaction between calling .destroy() on a writable and pending
+// writes.
+
+for (const withPendingData of [ false, true ]) {
+ for (const useEnd of [ false, true ]) {
+ const callbacks = [];
+
+ const w = new Writable({
+ write(data, enc, cb) {
+ callbacks.push(cb);
+ },
+ // Effectively disable the HWM to observe 'drain' events more easily.
+ highWaterMark: 1
+ });
+
+ let chunksWritten = 0;
+ let drains = 0;
+ w.on('drain', () => drains++);
+
+ function onWrite(err) {
+ if (err) {
+ assert.strictEqual(w.destroyed, true);
+ assert.strictEqual(err.code, 'ERR_STREAM_DESTROYED');
+ } else {
+ chunksWritten++;
+ }
+ }
+
+ w.write('abc', onWrite);
+ assert.strictEqual(chunksWritten, 0);
+ assert.strictEqual(drains, 0);
+ callbacks.shift()();
+ assert.strictEqual(chunksWritten, 1);
+ assert.strictEqual(drains, 1);
+
+ if (withPendingData) {
+ // Test 2 cases: There either is or is not data still in the write queue.
+ // (The second write will never actually get executed either way.)
+ w.write('def', onWrite);
+ }
+ if (useEnd) {
+ // Again, test 2 cases: Either we indicate that we want to end the
+ // writable or not.
+ w.end('ghi', onWrite);
+ } else {
+ w.write('ghi', onWrite);
+ }
+
+ assert.strictEqual(chunksWritten, 1);
+ w.destroy();
+ assert.strictEqual(chunksWritten, 1);
+ callbacks.shift()();
+ assert.strictEqual(chunksWritten, useEnd && !withPendingData ? 1 : 2);
+ assert.strictEqual(callbacks.length, 0);
+ assert.strictEqual(drains, 1);
+ }
+}
diff --git a/tests/node_compat/test/parallel/test-stream-write-drain.js b/tests/node_compat/test/parallel/test-stream-write-drain.js
new file mode 100644
index 000000000..008b2b34b
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-write-drain.js
@@ -0,0 +1,23 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const { Writable } = require('stream');
+
+// Don't emit 'drain' if ended
+
+const w = new Writable({
+ write(data, enc, cb) {
+ process.nextTick(cb);
+ },
+ highWaterMark: 1
+});
+
+w.on('drain', common.mustNotCall());
+w.write('asd');
+w.end();
diff --git a/tests/node_compat/test/parallel/test-stream-write-final.js b/tests/node_compat/test/parallel/test-stream-write-final.js
new file mode 100644
index 000000000..527f515eb
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-write-final.js
@@ -0,0 +1,31 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+
+const stream = require('stream');
+let shutdown = false;
+
+const w = new stream.Writable({
+ final: common.mustCall(function(cb) {
+ assert.strictEqual(this, w);
+ setTimeout(function() {
+ shutdown = true;
+ cb();
+ }, 100);
+ }),
+ write: function(chunk, e, cb) {
+ process.nextTick(cb);
+ }
+});
+w.on('finish', common.mustCall(function() {
+ assert(shutdown);
+}));
+w.write(Buffer.allocUnsafe(1));
+w.end(Buffer.allocUnsafe(0));
diff --git a/tests/node_compat/test/parallel/test-stream-writev.js b/tests/node_compat/test/parallel/test-stream-writev.js
new file mode 100644
index 000000000..050546646
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream-writev.js
@@ -0,0 +1,137 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+
+const stream = require('stream');
+
+const queue = [];
+for (let decode = 0; decode < 2; decode++) {
+ for (let uncork = 0; uncork < 2; uncork++) {
+ for (let multi = 0; multi < 2; multi++) {
+ queue.push([!!decode, !!uncork, !!multi]);
+ }
+ }
+}
+
+run();
+
+function run() {
+ const t = queue.pop();
+ if (t)
+ test(t[0], t[1], t[2], run);
+ else
+ console.log('ok');
+}
+
+function test(decode, uncork, multi, next) {
+ console.log(`# decode=${decode} uncork=${uncork} multi=${multi}`);
+ let counter = 0;
+ let expectCount = 0;
+ function cnt(msg) {
+ expectCount++;
+ const expect = expectCount;
+ return function(er) {
+ assert.ifError(er);
+ counter++;
+ assert.strictEqual(counter, expect);
+ };
+ }
+
+ const w = new stream.Writable({ decodeStrings: decode });
+ w._write = common.mustNotCall('Should not call _write');
+
+ const expectChunks = decode ? [
+ { encoding: 'buffer',
+ chunk: [104, 101, 108, 108, 111, 44, 32] },
+ { encoding: 'buffer',
+ chunk: [119, 111, 114, 108, 100] },
+ { encoding: 'buffer',
+ chunk: [33] },
+ { encoding: 'buffer',
+ chunk: [10, 97, 110, 100, 32, 116, 104, 101, 110, 46, 46, 46] },
+ { encoding: 'buffer',
+ chunk: [250, 206, 190, 167, 222, 173, 190, 239, 222, 202, 251, 173] },
+ ] : [
+ { encoding: 'ascii', chunk: 'hello, ' },
+ { encoding: 'utf8', chunk: 'world' },
+ { encoding: 'buffer', chunk: [33] },
+ { encoding: 'latin1', chunk: '\nand then...' },
+ { encoding: 'hex', chunk: 'facebea7deadbeefdecafbad' },
+ ];
+
+ let actualChunks;
+ w._writev = function(chunks, cb) {
+ actualChunks = chunks.map(function(chunk) {
+ return {
+ encoding: chunk.encoding,
+ chunk: Buffer.isBuffer(chunk.chunk) ?
+ Array.prototype.slice.call(chunk.chunk) : chunk.chunk
+ };
+ });
+ cb();
+ };
+
+ w.cork();
+ w.write('hello, ', 'ascii', cnt('hello'));
+ w.write('world', 'utf8', cnt('world'));
+
+ if (multi)
+ w.cork();
+
+ w.write(Buffer.from('!'), 'buffer', cnt('!'));
+ w.write('\nand then...', 'latin1', cnt('and then'));
+
+ if (multi)
+ w.uncork();
+
+ w.write('facebea7deadbeefdecafbad', 'hex', cnt('hex'));
+
+ if (uncork)
+ w.uncork();
+
+ w.end(cnt('end'));
+
+ w.on('finish', function() {
+ // Make sure finish comes after all the write cb
+ cnt('finish')();
+ assert.deepStrictEqual(actualChunks, expectChunks);
+ next();
+ });
+}
+
+{
+ const w = new stream.Writable({
+ writev: common.mustCall(function(chunks, cb) {
+ cb();
+ })
+ });
+ w.write('asd', common.mustCall());
+}
diff --git a/tests/node_compat/test/parallel/test-stream2-base64-single-char-read-end.js b/tests/node_compat/test/parallel/test-stream2-base64-single-char-read-end.js
new file mode 100644
index 000000000..34a1f7240
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream2-base64-single-char-read-end.js
@@ -0,0 +1,63 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+require('../common');
+const { Readable: R, Writable: W } = require('stream');
+const assert = require('assert');
+
+const src = new R({ encoding: 'base64' });
+const dst = new W();
+let hasRead = false;
+const accum = [];
+
+src._read = function(n) {
+ if (!hasRead) {
+ hasRead = true;
+ process.nextTick(function() {
+ src.push(Buffer.from('1'));
+ src.push(null);
+ });
+ }
+};
+
+dst._write = function(chunk, enc, cb) {
+ accum.push(chunk);
+ cb();
+};
+
+src.on('end', function() {
+ assert.strictEqual(String(Buffer.concat(accum)), 'MQ==');
+ clearTimeout(timeout);
+});
+
+src.pipe(dst);
+
+const timeout = setTimeout(function() {
+ assert.fail('timed out waiting for _write');
+}, 100);
diff --git a/tests/node_compat/test/parallel/test-stream2-basic.js b/tests/node_compat/test/parallel/test-stream2-basic.js
new file mode 100644
index 000000000..b820d5287
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream2-basic.js
@@ -0,0 +1,452 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+
+const common = require('../common');
+const { Readable: R, Writable: W } = require('stream');
+const assert = require('assert');
+
+const EE = require('events').EventEmitter;
+
+class TestReader extends R {
+ constructor(n) {
+ super();
+ this._buffer = Buffer.alloc(n || 100, 'x');
+ this._pos = 0;
+ this._bufs = 10;
+ }
+
+ _read(n) {
+ const max = this._buffer.length - this._pos;
+ n = Math.max(n, 0);
+ const toRead = Math.min(n, max);
+ if (toRead === 0) {
+ // Simulate the read buffer filling up with some more bytes some time
+ // in the future.
+ setTimeout(() => {
+ this._pos = 0;
+ this._bufs -= 1;
+ if (this._bufs <= 0) {
+ // read them all!
+ if (!this.ended)
+ this.push(null);
+ } else {
+ // now we have more.
+ // kinda cheating by calling _read, but whatever,
+ // it's just fake anyway.
+ this._read(n);
+ }
+ }, 10);
+ return;
+ }
+
+ const ret = this._buffer.slice(this._pos, this._pos + toRead);
+ this._pos += toRead;
+ this.push(ret);
+ }
+}
+
+class TestWriter extends EE {
+ constructor() {
+ super();
+ this.received = [];
+ this.flush = false;
+ }
+
+ write(c) {
+ this.received.push(c.toString());
+ this.emit('write', c);
+ return true;
+ }
+
+ end(c) {
+ if (c) this.write(c);
+ this.emit('end', this.received);
+ }
+}
+
+{
+ // Test basic functionality
+ const r = new TestReader(20);
+
+ const reads = [];
+ const expect = [ 'x',
+ 'xx',
+ 'xxx',
+ 'xxxx',
+ 'xxxxx',
+ 'xxxxxxxxx',
+ 'xxxxxxxxxx',
+ 'xxxxxxxxxxxx',
+ 'xxxxxxxxxxxxx',
+ 'xxxxxxxxxxxxxxx',
+ 'xxxxxxxxxxxxxxxxx',
+ 'xxxxxxxxxxxxxxxxxxx',
+ 'xxxxxxxxxxxxxxxxxxxxx',
+ 'xxxxxxxxxxxxxxxxxxxxxxx',
+ 'xxxxxxxxxxxxxxxxxxxxxxxxx',
+ 'xxxxxxxxxxxxxxxxxxxxx' ];
+
+ r.on('end', common.mustCall(function() {
+ assert.deepStrictEqual(reads, expect);
+ }));
+
+ let readSize = 1;
+ function flow() {
+ let res;
+ while (null !== (res = r.read(readSize++))) {
+ reads.push(res.toString());
+ }
+ r.once('readable', flow);
+ }
+
+ flow();
+}
+
+{
+ // Verify pipe
+ const r = new TestReader(5);
+
+ const expect = [ 'xxxxx',
+ 'xxxxx',
+ 'xxxxx',
+ 'xxxxx',
+ 'xxxxx',
+ 'xxxxx',
+ 'xxxxx',
+ 'xxxxx',
+ 'xxxxx',
+ 'xxxxx' ];
+
+ const w = new TestWriter();
+
+ w.on('end', common.mustCall(function(received) {
+ assert.deepStrictEqual(received, expect);
+ }));
+
+ r.pipe(w);
+}
+
+
+[1, 2, 3, 4, 5, 6, 7, 8, 9].forEach(function(SPLIT) {
+ // Verify unpipe
+ const r = new TestReader(5);
+
+ // Unpipe after 3 writes, then write to another stream instead.
+ let expect = [ 'xxxxx',
+ 'xxxxx',
+ 'xxxxx',
+ 'xxxxx',
+ 'xxxxx',
+ 'xxxxx',
+ 'xxxxx',
+ 'xxxxx',
+ 'xxxxx',
+ 'xxxxx' ];
+ expect = [ expect.slice(0, SPLIT), expect.slice(SPLIT) ];
+
+ const w = [ new TestWriter(), new TestWriter() ];
+
+ let writes = SPLIT;
+ w[0].on('write', function() {
+ if (--writes === 0) {
+ r.unpipe();
+ assert.deepStrictEqual(r._readableState.pipes, []);
+ w[0].end();
+ r.pipe(w[1]);
+ assert.deepStrictEqual(r._readableState.pipes, [w[1]]);
+ }
+ });
+
+ let ended = 0;
+
+ w[0].on('end', common.mustCall(function(results) {
+ ended++;
+ assert.strictEqual(ended, 1);
+ assert.deepStrictEqual(results, expect[0]);
+ }));
+
+ w[1].on('end', common.mustCall(function(results) {
+ ended++;
+ assert.strictEqual(ended, 2);
+ assert.deepStrictEqual(results, expect[1]);
+ }));
+
+ r.pipe(w[0]);
+});
+
+
+{
+ // Verify both writers get the same data when piping to destinations
+ const r = new TestReader(5);
+ const w = [ new TestWriter(), new TestWriter() ];
+
+ const expect = [ 'xxxxx',
+ 'xxxxx',
+ 'xxxxx',
+ 'xxxxx',
+ 'xxxxx',
+ 'xxxxx',
+ 'xxxxx',
+ 'xxxxx',
+ 'xxxxx',
+ 'xxxxx' ];
+
+ w[0].on('end', common.mustCall(function(received) {
+ assert.deepStrictEqual(received, expect);
+ }));
+ w[1].on('end', common.mustCall(function(received) {
+ assert.deepStrictEqual(received, expect);
+ }));
+
+ r.pipe(w[0]);
+ r.pipe(w[1]);
+}
+
+
+[1, 2, 3, 4, 5, 6, 7, 8, 9].forEach(function(SPLIT) {
+ // Verify multi-unpipe
+ const r = new TestReader(5);
+
+ // Unpipe after 3 writes, then write to another stream instead.
+ let expect = [ 'xxxxx',
+ 'xxxxx',
+ 'xxxxx',
+ 'xxxxx',
+ 'xxxxx',
+ 'xxxxx',
+ 'xxxxx',
+ 'xxxxx',
+ 'xxxxx',
+ 'xxxxx' ];
+ expect = [ expect.slice(0, SPLIT), expect.slice(SPLIT) ];
+
+ const w = [ new TestWriter(), new TestWriter(), new TestWriter() ];
+
+ let writes = SPLIT;
+ w[0].on('write', function() {
+ if (--writes === 0) {
+ r.unpipe();
+ w[0].end();
+ r.pipe(w[1]);
+ }
+ });
+
+ let ended = 0;
+
+ w[0].on('end', common.mustCall(function(results) {
+ ended++;
+ assert.strictEqual(ended, 1);
+ assert.deepStrictEqual(results, expect[0]);
+ }));
+
+ w[1].on('end', common.mustCall(function(results) {
+ ended++;
+ assert.strictEqual(ended, 2);
+ assert.deepStrictEqual(results, expect[1]);
+ }));
+
+ r.pipe(w[0]);
+ r.pipe(w[2]);
+});
+
+{
+ // Verify that back pressure is respected
+ const r = new R({ objectMode: true });
+ r._read = common.mustNotCall();
+ let counter = 0;
+ r.push(['one']);
+ r.push(['two']);
+ r.push(['three']);
+ r.push(['four']);
+ r.push(null);
+
+ const w1 = new R();
+ w1.write = function(chunk) {
+ assert.strictEqual(chunk[0], 'one');
+ w1.emit('close');
+ process.nextTick(function() {
+ r.pipe(w2);
+ r.pipe(w3);
+ });
+ };
+ w1.end = common.mustNotCall();
+
+ r.pipe(w1);
+
+ const expected = ['two', 'two', 'three', 'three', 'four', 'four'];
+
+ const w2 = new R();
+ w2.write = function(chunk) {
+ assert.strictEqual(chunk[0], expected.shift());
+ assert.strictEqual(counter, 0);
+
+ counter++;
+
+ if (chunk[0] === 'four') {
+ return true;
+ }
+
+ setTimeout(function() {
+ counter--;
+ w2.emit('drain');
+ }, 10);
+
+ return false;
+ };
+ w2.end = common.mustCall();
+
+ const w3 = new R();
+ w3.write = function(chunk) {
+ assert.strictEqual(chunk[0], expected.shift());
+ assert.strictEqual(counter, 1);
+
+ counter++;
+
+ if (chunk[0] === 'four') {
+ return true;
+ }
+
+ setTimeout(function() {
+ counter--;
+ w3.emit('drain');
+ }, 50);
+
+ return false;
+ };
+ w3.end = common.mustCall(function() {
+ assert.strictEqual(counter, 2);
+ assert.strictEqual(expected.length, 0);
+ });
+}
+
+{
+ // Verify read(0) behavior for ended streams
+ const r = new R();
+ let written = false;
+ let ended = false;
+ r._read = common.mustNotCall();
+
+ r.push(Buffer.from('foo'));
+ r.push(null);
+
+ const v = r.read(0);
+
+ assert.strictEqual(v, null);
+
+ const w = new R();
+ w.write = function(buffer) {
+ written = true;
+ assert.strictEqual(ended, false);
+ assert.strictEqual(buffer.toString(), 'foo');
+ };
+
+ w.end = common.mustCall(function() {
+ ended = true;
+ assert.strictEqual(written, true);
+ });
+
+ r.pipe(w);
+}
+
+{
+ // Verify synchronous _read ending
+ const r = new R();
+ let called = false;
+ r._read = function(n) {
+ r.push(null);
+ };
+
+ r.once('end', function() {
+ // Verify that this is called before the next tick
+ called = true;
+ });
+
+ r.read();
+
+ process.nextTick(function() {
+ assert.strictEqual(called, true);
+ });
+}
+
+{
+ // Verify that adding readable listeners trigger data flow
+ const r = new R({ highWaterMark: 5 });
+ let onReadable = false;
+ let readCalled = 0;
+
+ r._read = function(n) {
+ if (readCalled++ === 2)
+ r.push(null);
+ else
+ r.push(Buffer.from('asdf'));
+ };
+
+ r.on('readable', function() {
+ onReadable = true;
+ r.read();
+ });
+
+ r.on('end', common.mustCall(function() {
+ assert.strictEqual(readCalled, 3);
+ assert.ok(onReadable);
+ }));
+}
+
+{
+ // Verify that streams are chainable
+ const r = new R();
+ r._read = common.mustCall();
+ const r2 = r.setEncoding('utf8').pause().resume().pause();
+ assert.strictEqual(r, r2);
+}
+
+{
+ // Verify readableEncoding property
+ assert(Object.hasOwn(R.prototype, 'readableEncoding'));
+
+ const r = new R({ encoding: 'utf8' });
+ assert.strictEqual(r.readableEncoding, 'utf8');
+}
+
+{
+ // Verify readableObjectMode property
+ assert(Object.hasOwn(R.prototype, 'readableObjectMode'));
+
+ const r = new R({ objectMode: true });
+ assert.strictEqual(r.readableObjectMode, true);
+}
+
+{
+ // Verify writableObjectMode property
+ assert(Object.hasOwn(W.prototype, 'writableObjectMode'));
+
+ const w = new W({ objectMode: true });
+ assert.strictEqual(w.writableObjectMode, true);
+}
diff --git a/tests/node_compat/test/parallel/test-stream2-compatibility.js b/tests/node_compat/test/parallel/test-stream2-compatibility.js
new file mode 100644
index 000000000..c228366c3
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream2-compatibility.js
@@ -0,0 +1,77 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+require('../common');
+const { Readable: R, Writable: W } = require('stream');
+const assert = require('assert');
+
+let ondataCalled = 0;
+
+class TestReader extends R {
+ constructor() {
+ super();
+ this._buffer = Buffer.alloc(100, 'x');
+
+ this.on('data', () => {
+ ondataCalled++;
+ });
+ }
+
+ _read(n) {
+ this.push(this._buffer);
+ this._buffer = Buffer.alloc(0);
+ }
+}
+
+const reader = new TestReader();
+setImmediate(function() {
+ assert.strictEqual(ondataCalled, 1);
+ console.log('ok');
+ reader.push(null);
+});
+
+class TestWriter extends W {
+ constructor() {
+ super();
+ this.write('foo');
+ this.end();
+ }
+
+ _write(chunk, enc, cb) {
+ cb();
+ }
+}
+
+const writer = new TestWriter();
+
+process.on('exit', function() {
+ assert.strictEqual(reader.readable, false);
+ assert.strictEqual(writer.writable, false);
+ console.log('ok');
+});
diff --git a/tests/node_compat/test/parallel/test-stream2-decode-partial.js b/tests/node_compat/test/parallel/test-stream2-decode-partial.js
new file mode 100644
index 000000000..f3a9ec15d
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream2-decode-partial.js
@@ -0,0 +1,30 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+require('../common');
+const { Readable } = require('stream');
+const assert = require('assert');
+
+let buf = '';
+const euro = Buffer.from([0xE2, 0x82, 0xAC]);
+const cent = Buffer.from([0xC2, 0xA2]);
+const source = Buffer.concat([euro, cent]);
+
+const readable = Readable({ encoding: 'utf8' });
+readable.push(source.slice(0, 2));
+readable.push(source.slice(2, 4));
+readable.push(source.slice(4, 6));
+readable.push(null);
+
+readable.on('data', function(data) {
+ buf += data;
+});
+
+process.on('exit', function() {
+ assert.strictEqual(buf, '€¢');
+});
diff --git a/tests/node_compat/test/parallel/test-stream2-finish-pipe.js b/tests/node_compat/test/parallel/test-stream2-finish-pipe.js
new file mode 100644
index 000000000..c98812ff8
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream2-finish-pipe.js
@@ -0,0 +1,51 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+require('../common');
+const stream = require('stream');
+
+const r = new stream.Readable();
+r._read = function(size) {
+ r.push(Buffer.allocUnsafe(size));
+};
+
+const w = new stream.Writable();
+w._write = function(data, encoding, cb) {
+ process.nextTick(cb, null);
+};
+
+r.pipe(w);
+
+// end() must be called in nextTick or a WRITE_AFTER_END error occurs.
+process.nextTick(() => {
+ // This might sound unrealistic, but it happens in net.js. When
+ // socket.allowHalfOpen === false, EOF will cause .destroySoon() call which
+ // ends the writable side of net.Socket.
+ w.end();
+});
diff --git a/tests/node_compat/test/parallel/test-stream2-large-read-stall.js b/tests/node_compat/test/parallel/test-stream2-large-read-stall.js
new file mode 100644
index 000000000..e13b53711
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream2-large-read-stall.js
@@ -0,0 +1,81 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+
+// If everything aligns so that you do a read(n) of exactly the
+// remaining buffer, then make sure that 'end' still emits.
+
+const READSIZE = 100;
+const PUSHSIZE = 20;
+const PUSHCOUNT = 1000;
+const HWM = 50;
+
+const Readable = require('stream').Readable;
+const r = new Readable({
+ highWaterMark: HWM
+});
+const rs = r._readableState;
+
+r._read = push;
+
+r.on('readable', function() {
+ console.error('>> readable');
+ let ret;
+ do {
+ console.error(` > read(${READSIZE})`);
+ ret = r.read(READSIZE);
+ console.error(` < ${ret && ret.length} (${rs.length} remain)`);
+ } while (ret && ret.length === READSIZE);
+
+ console.error('<< after read()',
+ ret && ret.length,
+ rs.needReadable,
+ rs.length);
+});
+
+r.on('end', common.mustCall(function() {
+ assert.strictEqual(pushes, PUSHCOUNT + 1);
+}));
+
+let pushes = 0;
+function push() {
+ if (pushes > PUSHCOUNT)
+ return;
+
+ if (pushes++ === PUSHCOUNT) {
+ console.error(' push(EOF)');
+ return r.push(null);
+ }
+
+ console.error(` push #${pushes}`);
+ if (r.push(Buffer.allocUnsafe(PUSHSIZE)))
+ setTimeout(push, 1);
+}
diff --git a/tests/node_compat/test/parallel/test-stream2-objects.js b/tests/node_compat/test/parallel/test-stream2-objects.js
new file mode 100644
index 000000000..c5b2c981e
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream2-objects.js
@@ -0,0 +1,304 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+
+const common = require('../common');
+const { Readable, Writable } = require('stream');
+const assert = require('assert');
+
+function toArray(callback) {
+ const stream = new Writable({ objectMode: true });
+ const list = [];
+ stream.write = function(chunk) {
+ list.push(chunk);
+ };
+
+ stream.end = common.mustCall(function() {
+ callback(list);
+ });
+
+ return stream;
+}
+
+function fromArray(list) {
+ const r = new Readable({ objectMode: true });
+ r._read = common.mustNotCall();
+ list.forEach(function(chunk) {
+ r.push(chunk);
+ });
+ r.push(null);
+
+ return r;
+}
+
+{
+ // Verify that objects can be read from the stream
+ const r = fromArray([{ one: '1' }, { two: '2' }]);
+
+ const v1 = r.read();
+ const v2 = r.read();
+ const v3 = r.read();
+
+ assert.deepStrictEqual(v1, { one: '1' });
+ assert.deepStrictEqual(v2, { two: '2' });
+ assert.strictEqual(v3, null);
+}
+
+{
+ // Verify that objects can be piped into the stream
+ const r = fromArray([{ one: '1' }, { two: '2' }]);
+
+ r.pipe(toArray(common.mustCall(function(list) {
+ assert.deepStrictEqual(list, [
+ { one: '1' },
+ { two: '2' },
+ ]);
+ })));
+}
+
+{
+ // Verify that read(n) is ignored
+ const r = fromArray([{ one: '1' }, { two: '2' }]);
+ const value = r.read(2);
+
+ assert.deepStrictEqual(value, { one: '1' });
+}
+
+{
+ // Verify that objects can be synchronously read
+ const r = new Readable({ objectMode: true });
+ const list = [{ one: '1' }, { two: '2' }];
+ r._read = function(n) {
+ const item = list.shift();
+ r.push(item || null);
+ };
+
+ r.pipe(toArray(common.mustCall(function(list) {
+ assert.deepStrictEqual(list, [
+ { one: '1' },
+ { two: '2' },
+ ]);
+ })));
+}
+
+{
+ // Verify that objects can be asynchronously read
+ const r = new Readable({ objectMode: true });
+ const list = [{ one: '1' }, { two: '2' }];
+ r._read = function(n) {
+ const item = list.shift();
+ process.nextTick(function() {
+ r.push(item || null);
+ });
+ };
+
+ r.pipe(toArray(common.mustCall(function(list) {
+ assert.deepStrictEqual(list, [
+ { one: '1' },
+ { two: '2' },
+ ]);
+ })));
+}
+
+{
+ // Verify that strings can be read as objects
+ const r = new Readable({
+ objectMode: true
+ });
+ r._read = common.mustNotCall();
+ const list = ['one', 'two', 'three'];
+ list.forEach(function(str) {
+ r.push(str);
+ });
+ r.push(null);
+
+ r.pipe(toArray(common.mustCall(function(array) {
+ assert.deepStrictEqual(array, list);
+ })));
+}
+
+{
+ // Verify read(0) behavior for object streams
+ const r = new Readable({
+ objectMode: true
+ });
+ r._read = common.mustNotCall();
+
+ r.push('foobar');
+ r.push(null);
+
+ r.pipe(toArray(common.mustCall(function(array) {
+ assert.deepStrictEqual(array, ['foobar']);
+ })));
+}
+
+{
+ // Verify the behavior of pushing falsey values
+ const r = new Readable({
+ objectMode: true
+ });
+ r._read = common.mustNotCall();
+
+ r.push(false);
+ r.push(0);
+ r.push('');
+ r.push(null);
+
+ r.pipe(toArray(common.mustCall(function(array) {
+ assert.deepStrictEqual(array, [false, 0, '']);
+ })));
+}
+
+{
+ // Verify high watermark _read() behavior
+ const r = new Readable({
+ highWaterMark: 6,
+ objectMode: true
+ });
+ let calls = 0;
+ const list = ['1', '2', '3', '4', '5', '6', '7', '8'];
+
+ r._read = function(n) {
+ calls++;
+ };
+
+ list.forEach(function(c) {
+ r.push(c);
+ });
+
+ const v = r.read();
+
+ assert.strictEqual(calls, 0);
+ assert.strictEqual(v, '1');
+
+ const v2 = r.read();
+ assert.strictEqual(v2, '2');
+
+ const v3 = r.read();
+ assert.strictEqual(v3, '3');
+
+ assert.strictEqual(calls, 1);
+}
+
+{
+ // Verify high watermark push behavior
+ const r = new Readable({
+ highWaterMark: 6,
+ objectMode: true
+ });
+ r._read = common.mustNotCall();
+ for (let i = 0; i < 6; i++) {
+ const bool = r.push(i);
+ assert.strictEqual(bool, i !== 5);
+ }
+}
+
+{
+ // Verify that objects can be written to stream
+ const w = new Writable({ objectMode: true });
+
+ w._write = function(chunk, encoding, cb) {
+ assert.deepStrictEqual(chunk, { foo: 'bar' });
+ cb();
+ };
+
+ w.on('finish', common.mustCall());
+ w.write({ foo: 'bar' });
+ w.end();
+}
+
+{
+ // Verify that multiple objects can be written to stream
+ const w = new Writable({ objectMode: true });
+ const list = [];
+
+ w._write = function(chunk, encoding, cb) {
+ list.push(chunk);
+ cb();
+ };
+
+ w.on('finish', common.mustCall(function() {
+ assert.deepStrictEqual(list, [0, 1, 2, 3, 4]);
+ }));
+
+ w.write(0);
+ w.write(1);
+ w.write(2);
+ w.write(3);
+ w.write(4);
+ w.end();
+}
+
+{
+ // Verify that strings can be written as objects
+ const w = new Writable({
+ objectMode: true
+ });
+ const list = [];
+
+ w._write = function(chunk, encoding, cb) {
+ list.push(chunk);
+ process.nextTick(cb);
+ };
+
+ w.on('finish', common.mustCall(function() {
+ assert.deepStrictEqual(list, ['0', '1', '2', '3', '4']);
+ }));
+
+ w.write('0');
+ w.write('1');
+ w.write('2');
+ w.write('3');
+ w.write('4');
+ w.end();
+}
+
+{
+ // Verify that stream buffers finish until callback is called
+ const w = new Writable({
+ objectMode: true
+ });
+ let called = false;
+
+ w._write = function(chunk, encoding, cb) {
+ assert.strictEqual(chunk, 'foo');
+
+ process.nextTick(function() {
+ called = true;
+ cb();
+ });
+ };
+
+ w.on('finish', common.mustCall(function() {
+ assert.strictEqual(called, true);
+ }));
+
+ w.write('foo');
+ w.end();
+}
diff --git a/tests/node_compat/test/parallel/test-stream2-pipe-error-handling.js b/tests/node_compat/test/parallel/test-stream2-pipe-error-handling.js
new file mode 100644
index 000000000..ee8b0d656
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream2-pipe-error-handling.js
@@ -0,0 +1,113 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+const stream = require('stream');
+
+{
+ let count = 1000;
+
+ const source = new stream.Readable();
+ source._read = function(n) {
+ n = Math.min(count, n);
+ count -= n;
+ source.push(Buffer.allocUnsafe(n));
+ };
+
+ let unpipedDest;
+ source.unpipe = function(dest) {
+ unpipedDest = dest;
+ stream.Readable.prototype.unpipe.call(this, dest);
+ };
+
+ const dest = new stream.Writable();
+ dest._write = function(chunk, encoding, cb) {
+ cb();
+ };
+
+ source.pipe(dest);
+
+ let gotErr = null;
+ dest.on('error', function(err) {
+ gotErr = err;
+ });
+
+ let unpipedSource;
+ dest.on('unpipe', function(src) {
+ unpipedSource = src;
+ });
+
+ const err = new Error('This stream turned into bacon.');
+ dest.emit('error', err);
+ assert.strictEqual(gotErr, err);
+ assert.strictEqual(unpipedSource, source);
+ assert.strictEqual(unpipedDest, dest);
+}
+
+{
+ let count = 1000;
+
+ const source = new stream.Readable();
+ source._read = function(n) {
+ n = Math.min(count, n);
+ count -= n;
+ source.push(Buffer.allocUnsafe(n));
+ };
+
+ let unpipedDest;
+ source.unpipe = function(dest) {
+ unpipedDest = dest;
+ stream.Readable.prototype.unpipe.call(this, dest);
+ };
+
+ const dest = new stream.Writable({ autoDestroy: false });
+ dest._write = function(chunk, encoding, cb) {
+ cb();
+ };
+
+ source.pipe(dest);
+
+ let unpipedSource;
+ dest.on('unpipe', function(src) {
+ unpipedSource = src;
+ });
+
+ const err = new Error('This stream turned into bacon.');
+
+ let gotErr = null;
+ try {
+ dest.emit('error', err);
+ } catch (e) {
+ gotErr = e;
+ }
+ assert.strictEqual(gotErr, err);
+ assert.strictEqual(unpipedSource, source);
+ assert.strictEqual(unpipedDest, dest);
+}
diff --git a/tests/node_compat/test/parallel/test-stream2-pipe-error-once-listener.js b/tests/node_compat/test/parallel/test-stream2-pipe-error-once-listener.js
new file mode 100644
index 000000000..990dfc67d
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream2-pipe-error-once-listener.js
@@ -0,0 +1,60 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+
+require('../common');
+const stream = require('stream');
+
+class Read extends stream.Readable {
+ _read(size) {
+ this.push('x');
+ this.push(null);
+ }
+}
+
+class Write extends stream.Writable {
+ _write(buffer, encoding, cb) {
+ this.emit('error', new Error('boom'));
+ this.emit('alldone');
+ }
+}
+
+const read = new Read();
+const write = new Write();
+
+write.once('error', () => {});
+write.once('alldone', function(err) {
+ console.log('ok');
+});
+
+process.on('exit', function(c) {
+ console.error('error thrown even with listener');
+});
+
+read.pipe(write);
diff --git a/tests/node_compat/test/parallel/test-stream2-push.js b/tests/node_compat/test/parallel/test-stream2-push.js
new file mode 100644
index 000000000..e1dcdec95
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream2-push.js
@@ -0,0 +1,143 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+const { Readable, Writable } = require('stream');
+
+const EE = require('events').EventEmitter;
+
+
+// A mock thing a bit like the net.Socket/tcp_wrap.handle interaction
+
+const stream = new Readable({
+ highWaterMark: 16,
+ encoding: 'utf8'
+});
+
+const source = new EE();
+
+stream._read = function() {
+ console.error('stream._read');
+ readStart();
+};
+
+let ended = false;
+stream.on('end', function() {
+ ended = true;
+});
+
+source.on('data', function(chunk) {
+ const ret = stream.push(chunk);
+ console.error('data', stream.readableLength);
+ if (!ret)
+ readStop();
+});
+
+source.on('end', function() {
+ stream.push(null);
+});
+
+let reading = false;
+
+function readStart() {
+ console.error('readStart');
+ reading = true;
+}
+
+function readStop() {
+ console.error('readStop');
+ reading = false;
+ process.nextTick(function() {
+ const r = stream.read();
+ if (r !== null)
+ writer.write(r);
+ });
+}
+
+const writer = new Writable({
+ decodeStrings: false
+});
+
+const written = [];
+
+const expectWritten =
+ [ 'asdfgasdfgasdfgasdfg',
+ 'asdfgasdfgasdfgasdfg',
+ 'asdfgasdfgasdfgasdfg',
+ 'asdfgasdfgasdfgasdfg',
+ 'asdfgasdfgasdfgasdfg',
+ 'asdfgasdfgasdfgasdfg' ];
+
+writer._write = function(chunk, encoding, cb) {
+ console.error(`WRITE ${chunk}`);
+ written.push(chunk);
+ process.nextTick(cb);
+};
+
+writer.on('finish', finish);
+
+
+// Now emit some chunks.
+
+const chunk = 'asdfg';
+
+let set = 0;
+readStart();
+data();
+function data() {
+ assert(reading);
+ source.emit('data', chunk);
+ assert(reading);
+ source.emit('data', chunk);
+ assert(reading);
+ source.emit('data', chunk);
+ assert(reading);
+ source.emit('data', chunk);
+ assert(!reading);
+ if (set++ < 5)
+ setTimeout(data, 10);
+ else
+ end();
+}
+
+function finish() {
+ console.error('finish');
+ assert.deepStrictEqual(written, expectWritten);
+ console.log('ok');
+}
+
+function end() {
+ source.emit('end');
+ assert(!reading);
+ writer.end(stream.read());
+ setImmediate(function() {
+ assert(ended);
+ });
+}
diff --git a/tests/node_compat/test/parallel/test-stream2-read-sync-stack.js b/tests/node_compat/test/parallel/test-stream2-read-sync-stack.js
new file mode 100644
index 000000000..0d291ac08
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream2-read-sync-stack.js
@@ -0,0 +1,53 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const Readable = require('stream').Readable;
+
+// This tests synchronous read callbacks and verifies that even if they nest
+// heavily the process handles it without an error
+
+const r = new Readable();
+const N = 256 * 1024;
+
+let reads = 0;
+r._read = function(n) {
+ const chunk = reads++ === N ? null : Buffer.allocUnsafe(1);
+ r.push(chunk);
+};
+
+r.on('readable', function onReadable() {
+ if (!(r.readableLength % 256))
+ console.error('readable', r.readableLength);
+ r.read(N * 2);
+});
+
+r.on('end', common.mustCall());
+
+r.read(0);
diff --git a/tests/node_compat/test/parallel/test-stream2-readable-empty-buffer-no-eof.js b/tests/node_compat/test/parallel/test-stream2-readable-empty-buffer-no-eof.js
new file mode 100644
index 000000000..fca3b11f2
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream2-readable-empty-buffer-no-eof.js
@@ -0,0 +1,124 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+
+const Readable = require('stream').Readable;
+
+test1();
+test2();
+
+function test1() {
+ const r = new Readable();
+
+ // Should not end when we get a Buffer.alloc(0) or '' as the _read
+ // result that just means that there is *temporarily* no data, but to
+ // go ahead and try again later.
+ //
+ // note that this is very unusual. it only works for crypto streams
+ // because the other side of the stream will call read(0) to cycle
+ // data through openssl. that's why setImmediate() is used to call
+ // r.read(0) again later, otherwise there is no more work being done
+ // and the process just exits.
+
+ const buf = Buffer.alloc(5, 'x');
+ let reads = 5;
+ r._read = function(n) {
+ switch (reads--) {
+ case 5:
+ return setImmediate(() => {
+ return r.push(buf);
+ });
+ case 4:
+ setImmediate(() => {
+ return r.push(Buffer.alloc(0));
+ });
+ return setImmediate(r.read.bind(r, 0));
+ case 3:
+ setImmediate(r.read.bind(r, 0));
+ return process.nextTick(() => {
+ return r.push(Buffer.alloc(0));
+ });
+ case 2:
+ setImmediate(r.read.bind(r, 0));
+ return r.push(Buffer.alloc(0)); // Not-EOF!
+ case 1:
+ return r.push(buf);
+ case 0:
+ return r.push(null); // EOF
+ default:
+ throw new Error('unreachable');
+ }
+ };
+
+ const results = [];
+ function flow() {
+ let chunk;
+ while (null !== (chunk = r.read()))
+ results.push(String(chunk));
+ }
+ r.on('readable', flow);
+ r.on('end', () => {
+ results.push('EOF');
+ });
+ flow();
+
+ process.on('exit', () => {
+ assert.deepStrictEqual(results, [ 'xxxxx', 'xxxxx', 'EOF' ]);
+ console.log('ok');
+ });
+}
+
+function test2() {
+ const r = new Readable({ encoding: 'base64' });
+ let reads = 5;
+ r._read = function(n) {
+ if (!reads--)
+ return r.push(null); // EOF
+ return r.push(Buffer.from('x'));
+ };
+
+ const results = [];
+ function flow() {
+ let chunk;
+ while (null !== (chunk = r.read()))
+ results.push(String(chunk));
+ }
+ r.on('readable', flow);
+ r.on('end', () => {
+ results.push('EOF');
+ });
+ flow();
+
+ process.on('exit', () => {
+ assert.deepStrictEqual(results, [ 'eHh4', 'eHg=', 'EOF' ]);
+ console.log('ok');
+ });
+}
diff --git a/tests/node_compat/test/parallel/test-stream2-readable-from-list.js b/tests/node_compat/test/parallel/test-stream2-readable-from-list.js
new file mode 100644
index 000000000..90f93d040
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream2-readable-from-list.js
@@ -0,0 +1,108 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// Flags: --expose-internals
+'use strict';
+require('../common');
+const assert = require('assert');
+const fromList = require('stream').Readable._fromList;
+const BufferList = require('internal/streams/buffer_list');
+const util = require('util');
+
+function bufferListFromArray(arr) {
+ const bl = new BufferList();
+ for (let i = 0; i < arr.length; ++i)
+ bl.push(arr[i]);
+ return bl;
+}
+
+{
+ // Verify behavior with buffers
+ let list = [ Buffer.from('foog'),
+ Buffer.from('bark'),
+ Buffer.from('bazy'),
+ Buffer.from('kuel') ];
+ list = bufferListFromArray(list);
+
+ assert.strictEqual(
+ util.inspect([ list ], { compact: false }),
+ `[
+ BufferList {
+ head: [Object],
+ tail: [Object],
+ length: 4
+ }
+]`);
+
+ // Read more than the first element.
+ let ret = fromList(6, { buffer: list, length: 16 });
+ assert.strictEqual(ret.toString(), 'foogba');
+
+ // Read exactly the first element.
+ ret = fromList(2, { buffer: list, length: 10 });
+ assert.strictEqual(ret.toString(), 'rk');
+
+ // Read less than the first element.
+ ret = fromList(2, { buffer: list, length: 8 });
+ assert.strictEqual(ret.toString(), 'ba');
+
+ // Read more than we have.
+ ret = fromList(100, { buffer: list, length: 6 });
+ assert.strictEqual(ret.toString(), 'zykuel');
+
+ // all consumed.
+ assert.deepStrictEqual(list, new BufferList());
+}
+
+{
+ // Verify behavior with strings
+ let list = [ 'foog',
+ 'bark',
+ 'bazy',
+ 'kuel' ];
+ list = bufferListFromArray(list);
+
+ // Read more than the first element.
+ let ret = fromList(6, { buffer: list, length: 16, decoder: true });
+ assert.strictEqual(ret, 'foogba');
+
+ // Read exactly the first element.
+ ret = fromList(2, { buffer: list, length: 10, decoder: true });
+ assert.strictEqual(ret, 'rk');
+
+ // Read less than the first element.
+ ret = fromList(2, { buffer: list, length: 8, decoder: true });
+ assert.strictEqual(ret, 'ba');
+
+ // Read more than we have.
+ ret = fromList(100, { buffer: list, length: 6, decoder: true });
+ assert.strictEqual(ret, 'zykuel');
+
+ // all consumed.
+ assert.deepStrictEqual(list, new BufferList());
+}
diff --git a/tests/node_compat/test/parallel/test-stream2-readable-legacy-drain.js b/tests/node_compat/test/parallel/test-stream2-readable-legacy-drain.js
new file mode 100644
index 000000000..bf65fda0a
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream2-readable-legacy-drain.js
@@ -0,0 +1,62 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+
+const Stream = require('stream');
+const Readable = Stream.Readable;
+
+const r = new Readable();
+const N = 256;
+let reads = 0;
+r._read = function(n) {
+ return r.push(++reads === N ? null : Buffer.allocUnsafe(1));
+};
+
+r.on('end', common.mustCall());
+
+const w = new Stream();
+w.writable = true;
+let buffered = 0;
+w.write = function(c) {
+ buffered += c.length;
+ process.nextTick(drain);
+ return false;
+};
+
+function drain() {
+ assert(buffered <= 3);
+ buffered = 0;
+ w.emit('drain');
+}
+
+w.end = common.mustCall();
+
+r.pipe(w);
diff --git a/tests/node_compat/test/parallel/test-stream2-readable-non-empty-end.js b/tests/node_compat/test/parallel/test-stream2-readable-non-empty-end.js
new file mode 100644
index 000000000..c1e3a2f46
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream2-readable-non-empty-end.js
@@ -0,0 +1,79 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const { Readable } = require('stream');
+
+let len = 0;
+const chunks = new Array(10);
+for (let i = 1; i <= 10; i++) {
+ chunks[i - 1] = Buffer.allocUnsafe(i);
+ len += i;
+}
+
+const test = new Readable();
+let n = 0;
+test._read = function(size) {
+ const chunk = chunks[n++];
+ setTimeout(function() {
+ test.push(chunk === undefined ? null : chunk);
+ }, 1);
+};
+
+test.on('end', thrower);
+function thrower() {
+ throw new Error('this should not happen!');
+}
+
+let bytesread = 0;
+test.on('readable', function() {
+ const b = len - bytesread - 1;
+ const res = test.read(b);
+ if (res) {
+ bytesread += res.length;
+ console.error(`br=${bytesread} len=${len}`);
+ setTimeout(next, 1);
+ }
+ test.read(0);
+});
+test.read(0);
+
+function next() {
+ // Now let's make 'end' happen
+ test.removeListener('end', thrower);
+ test.on('end', common.mustCall());
+
+ // One to get the last byte
+ let r = test.read();
+ assert(r);
+ assert.strictEqual(r.length, 1);
+ r = test.read();
+ assert.strictEqual(r, null);
+}
diff --git a/tests/node_compat/test/parallel/test-stream2-readable-wrap-destroy.js b/tests/node_compat/test/parallel/test-stream2-readable-wrap-destroy.js
new file mode 100644
index 000000000..8971536e7
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream2-readable-wrap-destroy.js
@@ -0,0 +1,34 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+
+const { Readable } = require('stream');
+const EE = require('events').EventEmitter;
+
+const oldStream = new EE();
+oldStream.pause = () => {};
+oldStream.resume = () => {};
+
+{
+ new Readable({
+ autoDestroy: false,
+ destroy: common.mustCall()
+ })
+ .wrap(oldStream);
+ oldStream.emit('destroy');
+}
+
+{
+ new Readable({
+ autoDestroy: false,
+ destroy: common.mustCall()
+ })
+ .wrap(oldStream);
+ oldStream.emit('close');
+}
diff --git a/tests/node_compat/test/parallel/test-stream2-readable-wrap-empty.js b/tests/node_compat/test/parallel/test-stream2-readable-wrap-empty.js
new file mode 100644
index 000000000..5716d0bf9
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream2-readable-wrap-empty.js
@@ -0,0 +1,45 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+
+const { Readable } = require('stream');
+const EE = require('events').EventEmitter;
+
+const oldStream = new EE();
+oldStream.pause = () => {};
+oldStream.resume = () => {};
+
+const newStream = new Readable().wrap(oldStream);
+
+newStream
+ .on('readable', () => {})
+ .on('end', common.mustCall());
+
+oldStream.emit('end');
diff --git a/tests/node_compat/test/parallel/test-stream2-readable-wrap-error.js b/tests/node_compat/test/parallel/test-stream2-readable-wrap-error.js
new file mode 100644
index 000000000..77cb757c4
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream2-readable-wrap-error.js
@@ -0,0 +1,44 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+
+const { Readable } = require('stream');
+const EE = require('events').EventEmitter;
+
+class LegacyStream extends EE {
+ pause() {}
+ resume() {}
+}
+
+{
+ const err = new Error();
+ const oldStream = new LegacyStream();
+ const r = new Readable({ autoDestroy: true })
+ .wrap(oldStream)
+ .on('error', common.mustCall(() => {
+ assert.strictEqual(r._readableState.errorEmitted, true);
+ assert.strictEqual(r._readableState.errored, err);
+ assert.strictEqual(r.destroyed, true);
+ }));
+ oldStream.emit('error', err);
+}
+
+{
+ const err = new Error();
+ const oldStream = new LegacyStream();
+ const r = new Readable({ autoDestroy: false })
+ .wrap(oldStream)
+ .on('error', common.mustCall(() => {
+ assert.strictEqual(r._readableState.errorEmitted, true);
+ assert.strictEqual(r._readableState.errored, err);
+ assert.strictEqual(r.destroyed, false);
+ }));
+ oldStream.emit('error', err);
+}
diff --git a/tests/node_compat/test/parallel/test-stream2-readable-wrap.js b/tests/node_compat/test/parallel/test-stream2-readable-wrap.js
new file mode 100644
index 000000000..2bf8e99b0
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream2-readable-wrap.js
@@ -0,0 +1,107 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const { Readable, Writable } = require('stream');
+const EE = require('events').EventEmitter;
+
+function runTest(highWaterMark, objectMode, produce) {
+
+ const old = new EE();
+ const r = new Readable({ highWaterMark, objectMode });
+ assert.strictEqual(r, r.wrap(old));
+
+ r.on('end', common.mustCall());
+
+ old.pause = function() {
+ old.emit('pause');
+ flowing = false;
+ };
+
+ old.resume = function() {
+ old.emit('resume');
+ flow();
+ };
+
+ // Make sure pause is only emitted once.
+ let pausing = false;
+ r.on('pause', () => {
+ assert.strictEqual(pausing, false);
+ pausing = true;
+ process.nextTick(() => {
+ pausing = false;
+ });
+ });
+
+ let flowing;
+ let chunks = 10;
+ let oldEnded = false;
+ const expected = [];
+ function flow() {
+ flowing = true;
+ while (flowing && chunks-- > 0) {
+ const item = produce();
+ expected.push(item);
+ old.emit('data', item);
+ }
+ if (chunks <= 0) {
+ oldEnded = true;
+ old.emit('end');
+ }
+ }
+
+ const w = new Writable({ highWaterMark: highWaterMark * 2,
+ objectMode });
+ const written = [];
+ w._write = function(chunk, encoding, cb) {
+ written.push(chunk);
+ setTimeout(cb, 1);
+ };
+
+ w.on('finish', common.mustCall(function() {
+ performAsserts();
+ }));
+
+ r.pipe(w);
+
+ flow();
+
+ function performAsserts() {
+ assert(oldEnded);
+ assert.deepStrictEqual(written, expected);
+ }
+}
+
+runTest(100, false, function() { return Buffer.allocUnsafe(100); });
+runTest(10, false, function() { return Buffer.from('xxxxxxxxxx'); });
+runTest(1, true, function() { return { foo: 'bar' }; });
+
+const objectChunks = [ 5, 'a', false, 0, '', 'xyz', { x: 4 }, 7, [], 555 ];
+runTest(1, true, function() { return objectChunks.shift(); });
diff --git a/tests/node_compat/test/parallel/test-stream2-set-encoding.js b/tests/node_compat/test/parallel/test-stream2-set-encoding.js
new file mode 100644
index 000000000..ed7023b29
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream2-set-encoding.js
@@ -0,0 +1,330 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const { Readable: R } = require('stream');
+
+class TestReader extends R {
+ constructor(n, opts) {
+ super(opts);
+ this.pos = 0;
+ this.len = n || 100;
+ }
+
+ _read(n) {
+ setTimeout(() => {
+ if (this.pos >= this.len) {
+ // Double push(null) to test eos handling
+ this.push(null);
+ return this.push(null);
+ }
+
+ n = Math.min(n, this.len - this.pos);
+ if (n <= 0) {
+ // Double push(null) to test eos handling
+ this.push(null);
+ return this.push(null);
+ }
+
+ this.pos += n;
+ const ret = Buffer.alloc(n, 'a');
+
+ return this.push(ret);
+ }, 1);
+ }
+}
+
+{
+ // Verify utf8 encoding
+ const tr = new TestReader(100);
+ tr.setEncoding('utf8');
+ const out = [];
+ const expect =
+ [ 'aaaaaaaaaa',
+ 'aaaaaaaaaa',
+ 'aaaaaaaaaa',
+ 'aaaaaaaaaa',
+ 'aaaaaaaaaa',
+ 'aaaaaaaaaa',
+ 'aaaaaaaaaa',
+ 'aaaaaaaaaa',
+ 'aaaaaaaaaa',
+ 'aaaaaaaaaa' ];
+
+ tr.on('readable', function flow() {
+ let chunk;
+ while (null !== (chunk = tr.read(10)))
+ out.push(chunk);
+ });
+
+ tr.on('end', common.mustCall(function() {
+ assert.deepStrictEqual(out, expect);
+ }));
+}
+
+
+{
+ // Verify hex encoding
+ const tr = new TestReader(100);
+ tr.setEncoding('hex');
+ const out = [];
+ const expect =
+ [ '6161616161',
+ '6161616161',
+ '6161616161',
+ '6161616161',
+ '6161616161',
+ '6161616161',
+ '6161616161',
+ '6161616161',
+ '6161616161',
+ '6161616161',
+ '6161616161',
+ '6161616161',
+ '6161616161',
+ '6161616161',
+ '6161616161',
+ '6161616161',
+ '6161616161',
+ '6161616161',
+ '6161616161',
+ '6161616161' ];
+
+ tr.on('readable', function flow() {
+ let chunk;
+ while (null !== (chunk = tr.read(10)))
+ out.push(chunk);
+ });
+
+ tr.on('end', common.mustCall(function() {
+ assert.deepStrictEqual(out, expect);
+ }));
+}
+
+{
+ // Verify hex encoding with read(13)
+ const tr = new TestReader(100);
+ tr.setEncoding('hex');
+ const out = [];
+ const expect =
+ [ '6161616161616',
+ '1616161616161',
+ '6161616161616',
+ '1616161616161',
+ '6161616161616',
+ '1616161616161',
+ '6161616161616',
+ '1616161616161',
+ '6161616161616',
+ '1616161616161',
+ '6161616161616',
+ '1616161616161',
+ '6161616161616',
+ '1616161616161',
+ '6161616161616',
+ '16161' ];
+
+ tr.on('readable', function flow() {
+ let chunk;
+ while (null !== (chunk = tr.read(13)))
+ out.push(chunk);
+ });
+
+ tr.on('end', common.mustCall(function() {
+ assert.deepStrictEqual(out, expect);
+ }));
+}
+
+{
+ // Verify base64 encoding
+ const tr = new TestReader(100);
+ tr.setEncoding('base64');
+ const out = [];
+ const expect =
+ [ 'YWFhYWFhYW',
+ 'FhYWFhYWFh',
+ 'YWFhYWFhYW',
+ 'FhYWFhYWFh',
+ 'YWFhYWFhYW',
+ 'FhYWFhYWFh',
+ 'YWFhYWFhYW',
+ 'FhYWFhYWFh',
+ 'YWFhYWFhYW',
+ 'FhYWFhYWFh',
+ 'YWFhYWFhYW',
+ 'FhYWFhYWFh',
+ 'YWFhYWFhYW',
+ 'FhYQ==' ];
+
+ tr.on('readable', function flow() {
+ let chunk;
+ while (null !== (chunk = tr.read(10)))
+ out.push(chunk);
+ });
+
+ tr.on('end', common.mustCall(function() {
+ assert.deepStrictEqual(out, expect);
+ }));
+}
+
+{
+ // Verify utf8 encoding
+ const tr = new TestReader(100, { encoding: 'utf8' });
+ const out = [];
+ const expect =
+ [ 'aaaaaaaaaa',
+ 'aaaaaaaaaa',
+ 'aaaaaaaaaa',
+ 'aaaaaaaaaa',
+ 'aaaaaaaaaa',
+ 'aaaaaaaaaa',
+ 'aaaaaaaaaa',
+ 'aaaaaaaaaa',
+ 'aaaaaaaaaa',
+ 'aaaaaaaaaa' ];
+
+ tr.on('readable', function flow() {
+ let chunk;
+ while (null !== (chunk = tr.read(10)))
+ out.push(chunk);
+ });
+
+ tr.on('end', common.mustCall(function() {
+ assert.deepStrictEqual(out, expect);
+ }));
+}
+
+
+{
+ // Verify hex encoding
+ const tr = new TestReader(100, { encoding: 'hex' });
+ const out = [];
+ const expect =
+ [ '6161616161',
+ '6161616161',
+ '6161616161',
+ '6161616161',
+ '6161616161',
+ '6161616161',
+ '6161616161',
+ '6161616161',
+ '6161616161',
+ '6161616161',
+ '6161616161',
+ '6161616161',
+ '6161616161',
+ '6161616161',
+ '6161616161',
+ '6161616161',
+ '6161616161',
+ '6161616161',
+ '6161616161',
+ '6161616161' ];
+
+ tr.on('readable', function flow() {
+ let chunk;
+ while (null !== (chunk = tr.read(10)))
+ out.push(chunk);
+ });
+
+ tr.on('end', common.mustCall(function() {
+ assert.deepStrictEqual(out, expect);
+ }));
+}
+
+{
+ // Verify hex encoding with read(13)
+ const tr = new TestReader(100, { encoding: 'hex' });
+ const out = [];
+ const expect =
+ [ '6161616161616',
+ '1616161616161',
+ '6161616161616',
+ '1616161616161',
+ '6161616161616',
+ '1616161616161',
+ '6161616161616',
+ '1616161616161',
+ '6161616161616',
+ '1616161616161',
+ '6161616161616',
+ '1616161616161',
+ '6161616161616',
+ '1616161616161',
+ '6161616161616',
+ '16161' ];
+
+ tr.on('readable', function flow() {
+ let chunk;
+ while (null !== (chunk = tr.read(13)))
+ out.push(chunk);
+ });
+
+ tr.on('end', common.mustCall(function() {
+ assert.deepStrictEqual(out, expect);
+ }));
+}
+
+{
+ // Verify base64 encoding
+ const tr = new TestReader(100, { encoding: 'base64' });
+ const out = [];
+ const expect =
+ [ 'YWFhYWFhYW',
+ 'FhYWFhYWFh',
+ 'YWFhYWFhYW',
+ 'FhYWFhYWFh',
+ 'YWFhYWFhYW',
+ 'FhYWFhYWFh',
+ 'YWFhYWFhYW',
+ 'FhYWFhYWFh',
+ 'YWFhYWFhYW',
+ 'FhYWFhYWFh',
+ 'YWFhYWFhYW',
+ 'FhYWFhYWFh',
+ 'YWFhYWFhYW',
+ 'FhYQ==' ];
+
+ tr.on('readable', function flow() {
+ let chunk;
+ while (null !== (chunk = tr.read(10)))
+ out.push(chunk);
+ });
+
+ tr.on('end', common.mustCall(function() {
+ assert.deepStrictEqual(out, expect);
+ }));
+}
+
+{
+ // Verify chaining behavior
+ const tr = new TestReader(100);
+ assert.deepStrictEqual(tr.setEncoding('utf8'), tr);
+}
diff --git a/tests/node_compat/test/parallel/test-stream2-transform.js b/tests/node_compat/test/parallel/test-stream2-transform.js
new file mode 100644
index 000000000..2bd376b1f
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream2-transform.js
@@ -0,0 +1,501 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const { PassThrough, Transform } = require('stream');
+
+{
+ // Verify writable side consumption
+ const tx = new Transform({
+ highWaterMark: 10
+ });
+
+ let transformed = 0;
+ tx._transform = function(chunk, encoding, cb) {
+ transformed += chunk.length;
+ tx.push(chunk);
+ cb();
+ };
+
+ for (let i = 1; i <= 10; i++) {
+ tx.write(Buffer.allocUnsafe(i));
+ }
+ tx.end();
+
+ assert.strictEqual(tx.readableLength, 10);
+ assert.strictEqual(transformed, 10);
+ assert.deepStrictEqual(tx.writableBuffer.map(function(c) {
+ return c.chunk.length;
+ }), [5, 6, 7, 8, 9, 10]);
+}
+
+{
+ // Verify passthrough behavior
+ const pt = new PassThrough();
+
+ pt.write(Buffer.from('foog'));
+ pt.write(Buffer.from('bark'));
+ pt.write(Buffer.from('bazy'));
+ pt.write(Buffer.from('kuel'));
+ pt.end();
+
+ assert.strictEqual(pt.read(5).toString(), 'foogb');
+ assert.strictEqual(pt.read(5).toString(), 'arkba');
+ assert.strictEqual(pt.read(5).toString(), 'zykue');
+ assert.strictEqual(pt.read(5).toString(), 'l');
+}
+
+{
+ // Verify object passthrough behavior
+ const pt = new PassThrough({ objectMode: true });
+
+ pt.write(1);
+ pt.write(true);
+ pt.write(false);
+ pt.write(0);
+ pt.write('foo');
+ pt.write('');
+ pt.write({ a: 'b' });
+ pt.end();
+
+ assert.strictEqual(pt.read(), 1);
+ assert.strictEqual(pt.read(), true);
+ assert.strictEqual(pt.read(), false);
+ assert.strictEqual(pt.read(), 0);
+ assert.strictEqual(pt.read(), 'foo');
+ assert.strictEqual(pt.read(), '');
+ assert.deepStrictEqual(pt.read(), { a: 'b' });
+}
+
+{
+ // Verify passthrough constructor behavior
+ const pt = PassThrough();
+
+ assert(pt instanceof PassThrough);
+}
+
+{
+ // Verify transform constructor behavior
+ const pt = Transform();
+
+ assert(pt instanceof Transform);
+}
+
+{
+ // Perform a simple transform
+ const pt = new Transform();
+ pt._transform = function(c, e, cb) {
+ const ret = Buffer.alloc(c.length, 'x');
+ pt.push(ret);
+ cb();
+ };
+
+ pt.write(Buffer.from('foog'));
+ pt.write(Buffer.from('bark'));
+ pt.write(Buffer.from('bazy'));
+ pt.write(Buffer.from('kuel'));
+ pt.end();
+
+ assert.strictEqual(pt.read(5).toString(), 'xxxxx');
+ assert.strictEqual(pt.read(5).toString(), 'xxxxx');
+ assert.strictEqual(pt.read(5).toString(), 'xxxxx');
+ assert.strictEqual(pt.read(5).toString(), 'x');
+}
+
+{
+ // Verify simple object transform
+ const pt = new Transform({ objectMode: true });
+ pt._transform = function(c, e, cb) {
+ pt.push(JSON.stringify(c));
+ cb();
+ };
+
+ pt.write(1);
+ pt.write(true);
+ pt.write(false);
+ pt.write(0);
+ pt.write('foo');
+ pt.write('');
+ pt.write({ a: 'b' });
+ pt.end();
+
+ assert.strictEqual(pt.read(), '1');
+ assert.strictEqual(pt.read(), 'true');
+ assert.strictEqual(pt.read(), 'false');
+ assert.strictEqual(pt.read(), '0');
+ assert.strictEqual(pt.read(), '"foo"');
+ assert.strictEqual(pt.read(), '""');
+ assert.strictEqual(pt.read(), '{"a":"b"}');
+}
+
+{
+ // Verify async passthrough
+ const pt = new Transform();
+ pt._transform = function(chunk, encoding, cb) {
+ setTimeout(function() {
+ pt.push(chunk);
+ cb();
+ }, 10);
+ };
+
+ pt.write(Buffer.from('foog'));
+ pt.write(Buffer.from('bark'));
+ pt.write(Buffer.from('bazy'));
+ pt.write(Buffer.from('kuel'));
+ pt.end();
+
+ pt.on('finish', common.mustCall(function() {
+ assert.strictEqual(pt.read(5).toString(), 'foogb');
+ assert.strictEqual(pt.read(5).toString(), 'arkba');
+ assert.strictEqual(pt.read(5).toString(), 'zykue');
+ assert.strictEqual(pt.read(5).toString(), 'l');
+ }));
+}
+
+{
+ // Verify asymmetric transform (expand)
+ const pt = new Transform();
+
+ // Emit each chunk 2 times.
+ pt._transform = function(chunk, encoding, cb) {
+ setTimeout(function() {
+ pt.push(chunk);
+ setTimeout(function() {
+ pt.push(chunk);
+ cb();
+ }, 10);
+ }, 10);
+ };
+
+ pt.write(Buffer.from('foog'));
+ pt.write(Buffer.from('bark'));
+ pt.write(Buffer.from('bazy'));
+ pt.write(Buffer.from('kuel'));
+ pt.end();
+
+ pt.on('finish', common.mustCall(function() {
+ assert.strictEqual(pt.read(5).toString(), 'foogf');
+ assert.strictEqual(pt.read(5).toString(), 'oogba');
+ assert.strictEqual(pt.read(5).toString(), 'rkbar');
+ assert.strictEqual(pt.read(5).toString(), 'kbazy');
+ assert.strictEqual(pt.read(5).toString(), 'bazyk');
+ assert.strictEqual(pt.read(5).toString(), 'uelku');
+ assert.strictEqual(pt.read(5).toString(), 'el');
+ }));
+}
+
+{
+ // Verify asymmetric transform (compress)
+ const pt = new Transform();
+
+ // Each output is the first char of 3 consecutive chunks,
+ // or whatever's left.
+ pt.state = '';
+
+ pt._transform = function(chunk, encoding, cb) {
+ if (!chunk)
+ chunk = '';
+ const s = chunk.toString();
+ setTimeout(() => {
+ this.state += s.charAt(0);
+ if (this.state.length === 3) {
+ pt.push(Buffer.from(this.state));
+ this.state = '';
+ }
+ cb();
+ }, 10);
+ };
+
+ pt._flush = function(cb) {
+ // Just output whatever we have.
+ pt.push(Buffer.from(this.state));
+ this.state = '';
+ cb();
+ };
+
+ pt.write(Buffer.from('aaaa'));
+ pt.write(Buffer.from('bbbb'));
+ pt.write(Buffer.from('cccc'));
+ pt.write(Buffer.from('dddd'));
+ pt.write(Buffer.from('eeee'));
+ pt.write(Buffer.from('aaaa'));
+ pt.write(Buffer.from('bbbb'));
+ pt.write(Buffer.from('cccc'));
+ pt.write(Buffer.from('dddd'));
+ pt.write(Buffer.from('eeee'));
+ pt.write(Buffer.from('aaaa'));
+ pt.write(Buffer.from('bbbb'));
+ pt.write(Buffer.from('cccc'));
+ pt.write(Buffer.from('dddd'));
+ pt.end();
+
+ // 'abcdeabcdeabcd'
+ pt.on('finish', common.mustCall(function() {
+ assert.strictEqual(pt.read(5).toString(), 'abcde');
+ assert.strictEqual(pt.read(5).toString(), 'abcde');
+ assert.strictEqual(pt.read(5).toString(), 'abcd');
+ }));
+}
+
+// This tests for a stall when data is written to a full stream
+// that has empty transforms.
+{
+ // Verify complex transform behavior
+ let count = 0;
+ let saved = null;
+ const pt = new Transform({ highWaterMark: 3 });
+ pt._transform = function(c, e, cb) {
+ if (count++ === 1)
+ saved = c;
+ else {
+ if (saved) {
+ pt.push(saved);
+ saved = null;
+ }
+ pt.push(c);
+ }
+
+ cb();
+ };
+
+ pt.once('readable', function() {
+ process.nextTick(function() {
+ pt.write(Buffer.from('d'));
+ pt.write(Buffer.from('ef'), common.mustCall(function() {
+ pt.end();
+ }));
+ assert.strictEqual(pt.read().toString(), 'abcdef');
+ assert.strictEqual(pt.read(), null);
+ });
+ });
+
+ pt.write(Buffer.from('abc'));
+}
+
+
+{
+ // Verify passthrough event emission
+ const pt = new PassThrough();
+ let emits = 0;
+ pt.on('readable', function() {
+ emits++;
+ });
+
+ pt.write(Buffer.from('foog'));
+ pt.write(Buffer.from('bark'));
+
+ assert.strictEqual(emits, 0);
+ assert.strictEqual(pt.read(5).toString(), 'foogb');
+ assert.strictEqual(String(pt.read(5)), 'null');
+ assert.strictEqual(emits, 0);
+
+ pt.write(Buffer.from('bazy'));
+ pt.write(Buffer.from('kuel'));
+
+ assert.strictEqual(emits, 0);
+ assert.strictEqual(pt.read(5).toString(), 'arkba');
+ assert.strictEqual(pt.read(5).toString(), 'zykue');
+ assert.strictEqual(pt.read(5), null);
+
+ pt.end();
+
+ assert.strictEqual(emits, 1);
+ assert.strictEqual(pt.read(5).toString(), 'l');
+ assert.strictEqual(pt.read(5), null);
+ assert.strictEqual(emits, 1);
+}
+
+{
+ // Verify passthrough event emission reordering
+ const pt = new PassThrough();
+ let emits = 0;
+ pt.on('readable', function() {
+ emits++;
+ });
+
+ pt.write(Buffer.from('foog'));
+ pt.write(Buffer.from('bark'));
+
+ assert.strictEqual(emits, 0);
+ assert.strictEqual(pt.read(5).toString(), 'foogb');
+ assert.strictEqual(pt.read(5), null);
+
+ pt.once('readable', common.mustCall(function() {
+ assert.strictEqual(pt.read(5).toString(), 'arkba');
+ assert.strictEqual(pt.read(5), null);
+
+ pt.once('readable', common.mustCall(function() {
+ assert.strictEqual(pt.read(5).toString(), 'zykue');
+ assert.strictEqual(pt.read(5), null);
+ pt.once('readable', common.mustCall(function() {
+ assert.strictEqual(pt.read(5).toString(), 'l');
+ assert.strictEqual(pt.read(5), null);
+ assert.strictEqual(emits, 3);
+ }));
+ pt.end();
+ }));
+ pt.write(Buffer.from('kuel'));
+ }));
+
+ pt.write(Buffer.from('bazy'));
+}
+
+{
+ // Verify passthrough facade
+ const pt = new PassThrough();
+ const datas = [];
+ pt.on('data', function(chunk) {
+ datas.push(chunk.toString());
+ });
+
+ pt.on('end', common.mustCall(function() {
+ assert.deepStrictEqual(datas, ['foog', 'bark', 'bazy', 'kuel']);
+ }));
+
+ pt.write(Buffer.from('foog'));
+ setTimeout(function() {
+ pt.write(Buffer.from('bark'));
+ setTimeout(function() {
+ pt.write(Buffer.from('bazy'));
+ setTimeout(function() {
+ pt.write(Buffer.from('kuel'));
+ setTimeout(function() {
+ pt.end();
+ }, 10);
+ }, 10);
+ }, 10);
+ }, 10);
+}
+
+{
+ // Verify object transform (JSON parse)
+ const jp = new Transform({ objectMode: true });
+ jp._transform = function(data, encoding, cb) {
+ try {
+ jp.push(JSON.parse(data));
+ cb();
+ } catch (er) {
+ cb(er);
+ }
+ };
+
+ // Anything except null/undefined is fine.
+ // those are "magic" in the stream API, because they signal EOF.
+ const objects = [
+ { foo: 'bar' },
+ 100,
+ 'string',
+ { nested: { things: [ { foo: 'bar' }, 100, 'string' ] } },
+ ];
+
+ let ended = false;
+ jp.on('end', function() {
+ ended = true;
+ });
+
+ objects.forEach(function(obj) {
+ jp.write(JSON.stringify(obj));
+ const res = jp.read();
+ assert.deepStrictEqual(res, obj);
+ });
+
+ jp.end();
+ // Read one more time to get the 'end' event
+ jp.read();
+
+ process.nextTick(common.mustCall(function() {
+ assert.strictEqual(ended, true);
+ }));
+}
+
+{
+ // Verify object transform (JSON stringify)
+ const js = new Transform({ objectMode: true });
+ js._transform = function(data, encoding, cb) {
+ try {
+ js.push(JSON.stringify(data));
+ cb();
+ } catch (er) {
+ cb(er);
+ }
+ };
+
+ // Anything except null/undefined is fine.
+ // those are "magic" in the stream API, because they signal EOF.
+ const objects = [
+ { foo: 'bar' },
+ 100,
+ 'string',
+ { nested: { things: [ { foo: 'bar' }, 100, 'string' ] } },
+ ];
+
+ let ended = false;
+ js.on('end', function() {
+ ended = true;
+ });
+
+ objects.forEach(function(obj) {
+ js.write(obj);
+ const res = js.read();
+ assert.strictEqual(res, JSON.stringify(obj));
+ });
+
+ js.end();
+ // Read one more time to get the 'end' event
+ js.read();
+
+ process.nextTick(common.mustCall(function() {
+ assert.strictEqual(ended, true);
+ }));
+}
+
+{
+ const s = new Transform({
+ objectMode: true,
+ construct(callback) {
+ this.push('header from constructor');
+ callback();
+ },
+ transform: (row, encoding, callback) => {
+ callback(null, row);
+ },
+ });
+
+ const expected = [
+ 'header from constructor',
+ 'firstLine',
+ 'secondLine',
+ ];
+ s.on('data', common.mustCall((data) => {
+ assert.strictEqual(data.toString(), expected.shift());
+ }, 3));
+ s.write('firstLine');
+ process.nextTick(() => s.write('secondLine'));
+}
diff --git a/tests/node_compat/test/parallel/test-stream2-unpipe-drain.js b/tests/node_compat/test/parallel/test-stream2-unpipe-drain.js
new file mode 100644
index 000000000..9c1a6844d
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream2-unpipe-drain.js
@@ -0,0 +1,79 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+
+const stream = require('stream');
+
+class TestWriter extends stream.Writable {
+ _write(buffer, encoding, callback) {
+ console.log('write called');
+ // Super slow write stream (callback never called)
+ }
+}
+
+const dest = new TestWriter();
+
+class TestReader extends stream.Readable {
+ constructor() {
+ super();
+ this.reads = 0;
+ }
+
+ _read(size) {
+ this.reads += 1;
+ this.push(Buffer.alloc(size));
+ }
+}
+
+const src1 = new TestReader();
+const src2 = new TestReader();
+
+src1.pipe(dest);
+
+src1.once('readable', () => {
+ process.nextTick(() => {
+
+ src2.pipe(dest);
+
+ src2.once('readable', () => {
+ process.nextTick(() => {
+
+ src1.unpipe(dest);
+ });
+ });
+ });
+});
+
+
+process.on('exit', () => {
+ assert.strictEqual(src1.reads, 2);
+ assert.strictEqual(src2.reads, 2);
+});
diff --git a/tests/node_compat/test/parallel/test-stream2-unpipe-leak.js b/tests/node_compat/test/parallel/test-stream2-unpipe-leak.js
new file mode 100644
index 000000000..8958bc06b
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream2-unpipe-leak.js
@@ -0,0 +1,80 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+const stream = require('stream');
+
+const chunk = Buffer.from('hallo');
+
+class TestWriter extends stream.Writable {
+ _write(buffer, encoding, callback) {
+ callback(null);
+ }
+}
+
+const dest = new TestWriter();
+
+// Set this high so that we'd trigger a nextTick warning
+// and/or RangeError if we do maybeReadMore wrong.
+class TestReader extends stream.Readable {
+ constructor() {
+ super({
+ highWaterMark: 0x10000
+ });
+ }
+
+ _read(size) {
+ this.push(chunk);
+ }
+}
+
+const src = new TestReader();
+
+for (let i = 0; i < 10; i++) {
+ src.pipe(dest);
+ src.unpipe(dest);
+}
+
+assert.strictEqual(src.listeners('end').length, 0);
+assert.strictEqual(src.listeners('readable').length, 0);
+
+assert.strictEqual(dest.listeners('unpipe').length, 0);
+assert.strictEqual(dest.listeners('drain').length, 0);
+assert.strictEqual(dest.listeners('error').length, 0);
+assert.strictEqual(dest.listeners('close').length, 0);
+assert.strictEqual(dest.listeners('finish').length, 0);
+
+console.error(src._readableState);
+process.on('exit', function() {
+ src.readableBuffer.length = 0;
+ console.error(src._readableState);
+ assert(src.readableLength >= src.readableHighWaterMark);
+ console.log('ok');
+});
diff --git a/tests/node_compat/test/parallel/test-stream2-writable.js b/tests/node_compat/test/parallel/test-stream2-writable.js
new file mode 100644
index 000000000..8b7197b9b
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream2-writable.js
@@ -0,0 +1,466 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+
+const common = require('../common');
+const { Writable: W, Duplex: D } = require('stream');
+const assert = require('assert');
+
+class TestWriter extends W {
+ constructor(opts) {
+ super(opts);
+ this.buffer = [];
+ this.written = 0;
+ }
+
+ _write(chunk, encoding, cb) {
+ // Simulate a small unpredictable latency
+ setTimeout(() => {
+ this.buffer.push(chunk.toString());
+ this.written += chunk.length;
+ cb();
+ }, Math.floor(Math.random() * 10));
+ }
+}
+
+const chunks = new Array(50);
+for (let i = 0; i < chunks.length; i++) {
+ chunks[i] = 'x'.repeat(i);
+}
+
+{
+ // Verify fast writing
+ const tw = new TestWriter({
+ highWaterMark: 100
+ });
+
+ tw.on('finish', common.mustCall(function() {
+ // Got chunks in the right order
+ assert.deepStrictEqual(tw.buffer, chunks);
+ }));
+
+ chunks.forEach(function(chunk) {
+ // Ignore backpressure. Just buffer it all up.
+ tw.write(chunk);
+ });
+ tw.end();
+}
+
+{
+ // Verify slow writing
+ const tw = new TestWriter({
+ highWaterMark: 100
+ });
+
+ tw.on('finish', common.mustCall(function() {
+ // Got chunks in the right order
+ assert.deepStrictEqual(tw.buffer, chunks);
+ }));
+
+ let i = 0;
+ (function W() {
+ tw.write(chunks[i++]);
+ if (i < chunks.length)
+ setTimeout(W, 10);
+ else
+ tw.end();
+ })();
+}
+
+{
+ // Verify write backpressure
+ const tw = new TestWriter({
+ highWaterMark: 50
+ });
+
+ let drains = 0;
+
+ tw.on('finish', common.mustCall(function() {
+ // Got chunks in the right order
+ assert.deepStrictEqual(tw.buffer, chunks);
+ assert.strictEqual(drains, 17);
+ }));
+
+ tw.on('drain', function() {
+ drains++;
+ });
+
+ let i = 0;
+ (function W() {
+ let ret;
+ do {
+ ret = tw.write(chunks[i++]);
+ } while (ret !== false && i < chunks.length);
+
+ if (i < chunks.length) {
+ assert(tw.writableLength >= 50);
+ tw.once('drain', W);
+ } else {
+ tw.end();
+ }
+ })();
+}
+
+{
+ // Verify write buffersize
+ const tw = new TestWriter({
+ highWaterMark: 100
+ });
+
+ const encodings =
+ [ 'hex',
+ 'utf8',
+ 'utf-8',
+ 'ascii',
+ 'latin1',
+ 'binary',
+ 'base64',
+ 'ucs2',
+ 'ucs-2',
+ 'utf16le',
+ 'utf-16le',
+ undefined ];
+
+ tw.on('finish', function() {
+ // Got the expected chunks
+ assert.deepStrictEqual(tw.buffer, chunks);
+ });
+
+ chunks.forEach(function(chunk, i) {
+ const enc = encodings[i % encodings.length];
+ chunk = Buffer.from(chunk);
+ tw.write(chunk.toString(enc), enc);
+ });
+}
+
+{
+ // Verify write with no buffersize
+ const tw = new TestWriter({
+ highWaterMark: 100,
+ decodeStrings: false
+ });
+
+ tw._write = function(chunk, encoding, cb) {
+ assert.strictEqual(typeof chunk, 'string');
+ chunk = Buffer.from(chunk, encoding);
+ return TestWriter.prototype._write.call(this, chunk, encoding, cb);
+ };
+
+ const encodings =
+ [ 'hex',
+ 'utf8',
+ 'utf-8',
+ 'ascii',
+ 'latin1',
+ 'binary',
+ 'base64',
+ 'ucs2',
+ 'ucs-2',
+ 'utf16le',
+ 'utf-16le',
+ undefined ];
+
+ tw.on('finish', function() {
+ // Got the expected chunks
+ assert.deepStrictEqual(tw.buffer, chunks);
+ });
+
+ chunks.forEach(function(chunk, i) {
+ const enc = encodings[i % encodings.length];
+ chunk = Buffer.from(chunk);
+ tw.write(chunk.toString(enc), enc);
+ });
+}
+
+{
+ // Verify write callbacks
+ const callbacks = chunks.map(function(chunk, i) {
+ return [i, function() {
+ callbacks._called[i] = chunk;
+ }];
+ }).reduce(function(set, x) {
+ set[`callback-${x[0]}`] = x[1];
+ return set;
+ }, {});
+ callbacks._called = [];
+
+ const tw = new TestWriter({
+ highWaterMark: 100
+ });
+
+ tw.on('finish', common.mustCall(function() {
+ process.nextTick(common.mustCall(function() {
+ // Got chunks in the right order
+ assert.deepStrictEqual(tw.buffer, chunks);
+ // Called all callbacks
+ assert.deepStrictEqual(callbacks._called, chunks);
+ }));
+ }));
+
+ chunks.forEach(function(chunk, i) {
+ tw.write(chunk, callbacks[`callback-${i}`]);
+ });
+ tw.end();
+}
+
+{
+ // Verify end() callback
+ const tw = new TestWriter();
+ tw.end(common.mustCall());
+}
+
+const helloWorldBuffer = Buffer.from('hello world');
+
+{
+ // Verify end() callback with chunk
+ const tw = new TestWriter();
+ tw.end(helloWorldBuffer, common.mustCall());
+}
+
+{
+ // Verify end() callback with chunk and encoding
+ const tw = new TestWriter();
+ tw.end('hello world', 'ascii', common.mustCall());
+}
+
+{
+ // Verify end() callback after write() call
+ const tw = new TestWriter();
+ tw.write(helloWorldBuffer);
+ tw.end(common.mustCall());
+}
+
+{
+ // Verify end() callback after write() callback
+ const tw = new TestWriter();
+ let writeCalledback = false;
+ tw.write(helloWorldBuffer, function() {
+ writeCalledback = true;
+ });
+ tw.end(common.mustCall(function() {
+ assert.strictEqual(writeCalledback, true);
+ }));
+}
+
+{
+ // Verify encoding is ignored for buffers
+ const tw = new W();
+ const hex = '018b5e9a8f6236ffe30e31baf80d2cf6eb';
+ tw._write = common.mustCall(function(chunk) {
+ assert.strictEqual(chunk.toString('hex'), hex);
+ });
+ const buf = Buffer.from(hex, 'hex');
+ tw.write(buf, 'latin1');
+}
+
+{
+ // Verify writables cannot be piped
+ const w = new W({ autoDestroy: false });
+ w._write = common.mustNotCall();
+ let gotError = false;
+ w.on('error', function() {
+ gotError = true;
+ });
+ w.pipe(process.stdout);
+ assert.strictEqual(gotError, true);
+}
+
+{
+ // Verify that duplex streams cannot be piped
+ const d = new D();
+ d._read = common.mustCall();
+ d._write = common.mustNotCall();
+ let gotError = false;
+ d.on('error', function() {
+ gotError = true;
+ });
+ d.pipe(process.stdout);
+ assert.strictEqual(gotError, false);
+}
+
+{
+ // Verify that end(chunk) twice is an error
+ const w = new W();
+ w._write = common.mustCall((msg) => {
+ assert.strictEqual(msg.toString(), 'this is the end');
+ });
+ let gotError = false;
+ w.on('error', function(er) {
+ gotError = true;
+ assert.strictEqual(er.message, 'write after end');
+ });
+ w.end('this is the end');
+ w.end('and so is this');
+ process.nextTick(common.mustCall(function() {
+ assert.strictEqual(gotError, true);
+ }));
+}
+
+{
+ // Verify stream doesn't end while writing
+ const w = new W();
+ let wrote = false;
+ w._write = function(chunk, e, cb) {
+ assert.strictEqual(this.writing, undefined);
+ wrote = true;
+ this.writing = true;
+ setTimeout(() => {
+ this.writing = false;
+ cb();
+ }, 1);
+ };
+ w.on('finish', common.mustCall(function() {
+ assert.strictEqual(wrote, true);
+ assert.strictEqual(this.writing, false);
+ }));
+ w.write(Buffer.alloc(0));
+ w.end();
+}
+
+{
+ // Verify finish does not come before write() callback
+ const w = new W();
+ let writeCb = false;
+ w._write = function(chunk, e, cb) {
+ setTimeout(function() {
+ writeCb = true;
+ cb();
+ }, 10);
+ };
+ w.on('finish', common.mustCall(function() {
+ assert.strictEqual(writeCb, true);
+ }));
+ w.write(Buffer.alloc(0));
+ w.end();
+}
+
+{
+ // Verify finish does not come before synchronous _write() callback
+ const w = new W();
+ let writeCb = false;
+ w._write = function(chunk, e, cb) {
+ cb();
+ };
+ w.on('finish', common.mustCall(function() {
+ assert.strictEqual(writeCb, true);
+ }));
+ w.write(Buffer.alloc(0), function() {
+ writeCb = true;
+ });
+ w.end();
+}
+
+{
+ // Verify finish is emitted if the last chunk is empty
+ const w = new W();
+ w._write = function(chunk, e, cb) {
+ process.nextTick(cb);
+ };
+ w.on('finish', common.mustCall());
+ w.write(Buffer.allocUnsafe(1));
+ w.end(Buffer.alloc(0));
+}
+
+{
+ // Verify that finish is emitted after shutdown
+ const w = new W();
+ let shutdown = false;
+
+ w._final = common.mustCall(function(cb) {
+ assert.strictEqual(this, w);
+ setTimeout(function() {
+ shutdown = true;
+ cb();
+ }, 100);
+ });
+ w._write = function(chunk, e, cb) {
+ process.nextTick(cb);
+ };
+ w.on('finish', common.mustCall(function() {
+ assert.strictEqual(shutdown, true);
+ }));
+ w.write(Buffer.allocUnsafe(1));
+ w.end(Buffer.allocUnsafe(0));
+}
+
+{
+ // Verify that error is only emitted once when failing in _finish.
+ const w = new W();
+
+ w._final = common.mustCall(function(cb) {
+ cb(new Error('test'));
+ });
+ w.on('error', common.mustCall((err) => {
+ assert.strictEqual(w._writableState.errorEmitted, true);
+ assert.strictEqual(err.message, 'test');
+ w.on('error', common.mustNotCall());
+ w.destroy(new Error());
+ }));
+ w.end();
+}
+
+{
+ // Verify that error is only emitted once when failing in write.
+ const w = new W();
+ w.on('error', common.mustNotCall());
+ assert.throws(() => {
+ w.write(null);
+ }, {
+ code: 'ERR_STREAM_NULL_VALUES'
+ });
+}
+
+{
+ // Verify that error is only emitted once when failing in write after end.
+ const w = new W();
+ w.on('error', common.mustCall((err) => {
+ assert.strictEqual(w._writableState.errorEmitted, true);
+ assert.strictEqual(err.code, 'ERR_STREAM_WRITE_AFTER_END');
+ }));
+ w.end();
+ w.write('hello');
+ w.destroy(new Error());
+}
+
+{
+ // Verify that finish is not emitted after error
+ const w = new W();
+
+ w._final = common.mustCall(function(cb) {
+ cb(new Error());
+ });
+ w._write = function(chunk, e, cb) {
+ process.nextTick(cb);
+ };
+ w.on('error', common.mustCall());
+ w.on('prefinish', common.mustNotCall());
+ w.on('finish', common.mustNotCall());
+ w.write(Buffer.allocUnsafe(1));
+ w.end(Buffer.allocUnsafe(0));
+}
diff --git a/tests/node_compat/test/parallel/test-stream3-cork-end.js b/tests/node_compat/test/parallel/test-stream3-cork-end.js
new file mode 100644
index 000000000..52f881121
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream3-cork-end.js
@@ -0,0 +1,98 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+const stream = require('stream');
+const Writable = stream.Writable;
+
+// Test the buffering behavior of Writable streams.
+//
+// The call to cork() triggers storing chunks which are flushed
+// on calling end() and the stream subsequently ended.
+//
+// node version target: 0.12
+
+const expectedChunks = ['please', 'buffer', 'me', 'kindly'];
+const inputChunks = expectedChunks.slice(0);
+let seenChunks = [];
+let seenEnd = false;
+
+const w = new Writable();
+// Let's arrange to store the chunks.
+w._write = function(chunk, encoding, cb) {
+ // Stream end event is not seen before the last write.
+ assert.ok(!seenEnd);
+ // Default encoding given none was specified.
+ assert.strictEqual(encoding, 'buffer');
+
+ seenChunks.push(chunk);
+ cb();
+};
+// Let's record the stream end event.
+w.on('finish', () => {
+ seenEnd = true;
+});
+
+function writeChunks(remainingChunks, callback) {
+ const writeChunk = remainingChunks.shift();
+ let writeState;
+
+ if (writeChunk) {
+ setImmediate(() => {
+ writeState = w.write(writeChunk);
+ // We were not told to stop writing.
+ assert.ok(writeState);
+
+ writeChunks(remainingChunks, callback);
+ });
+ } else {
+ callback();
+ }
+}
+
+// Do an initial write.
+w.write('stuff');
+// The write was immediate.
+assert.strictEqual(seenChunks.length, 1);
+// Reset the seen chunks.
+seenChunks = [];
+
+// Trigger stream buffering.
+w.cork();
+
+// Write the bufferedChunks.
+writeChunks(inputChunks, () => {
+ // Should not have seen anything yet.
+ assert.strictEqual(seenChunks.length, 0);
+
+ // Trigger flush and ending the stream.
+ w.end();
+
+ // Stream should not ended in current tick.
+ assert.ok(!seenEnd);
+
+ // Buffered bytes should be seen in current tick.
+ assert.strictEqual(seenChunks.length, 4);
+
+ // Did the chunks match.
+ for (let i = 0, l = expectedChunks.length; i < l; i++) {
+ const seen = seenChunks[i];
+ // There was a chunk.
+ assert.ok(seen);
+
+ const expected = Buffer.from(expectedChunks[i]);
+ // It was what we expected.
+ assert.ok(seen.equals(expected));
+ }
+
+ setImmediate(() => {
+ // Stream should have ended in next tick.
+ assert.ok(seenEnd);
+ });
+});
diff --git a/tests/node_compat/test/parallel/test-stream3-cork-uncork.js b/tests/node_compat/test/parallel/test-stream3-cork-uncork.js
new file mode 100644
index 000000000..1fb993003
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream3-cork-uncork.js
@@ -0,0 +1,93 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+const stream = require('stream');
+const Writable = stream.Writable;
+
+// Test the buffering behavior of Writable streams.
+//
+// The call to cork() triggers storing chunks which are flushed
+// on calling uncork() in the same tick.
+//
+// node version target: 0.12
+
+const expectedChunks = ['please', 'buffer', 'me', 'kindly'];
+const inputChunks = expectedChunks.slice(0);
+let seenChunks = [];
+let seenEnd = false;
+
+const w = new Writable();
+// Let's arrange to store the chunks.
+w._write = function(chunk, encoding, cb) {
+ // Default encoding given none was specified.
+ assert.strictEqual(encoding, 'buffer');
+
+ seenChunks.push(chunk);
+ cb();
+};
+// Let's record the stream end event.
+w.on('finish', () => {
+ seenEnd = true;
+});
+
+function writeChunks(remainingChunks, callback) {
+ const writeChunk = remainingChunks.shift();
+ let writeState;
+
+ if (writeChunk) {
+ setImmediate(() => {
+ writeState = w.write(writeChunk);
+ // We were not told to stop writing.
+ assert.ok(writeState);
+
+ writeChunks(remainingChunks, callback);
+ });
+ } else {
+ callback();
+ }
+}
+
+// Do an initial write.
+w.write('stuff');
+// The write was immediate.
+assert.strictEqual(seenChunks.length, 1);
+// Reset the chunks seen so far.
+seenChunks = [];
+
+// Trigger stream buffering.
+w.cork();
+
+// Write the bufferedChunks.
+writeChunks(inputChunks, () => {
+ // Should not have seen anything yet.
+ assert.strictEqual(seenChunks.length, 0);
+
+ // Trigger writing out the buffer.
+ w.uncork();
+
+ // Buffered bytes should be seen in current tick.
+ assert.strictEqual(seenChunks.length, 4);
+
+ // Did the chunks match.
+ for (let i = 0, l = expectedChunks.length; i < l; i++) {
+ const seen = seenChunks[i];
+ // There was a chunk.
+ assert.ok(seen);
+
+ const expected = Buffer.from(expectedChunks[i]);
+ // It was what we expected.
+ assert.ok(seen.equals(expected));
+ }
+
+ setImmediate(() => {
+ // The stream should not have been ended.
+ assert.ok(!seenEnd);
+ });
+});
diff --git a/tests/node_compat/test/parallel/test-stream3-pause-then-read.js b/tests/node_compat/test/parallel/test-stream3-pause-then-read.js
new file mode 100644
index 000000000..f840672ce
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-stream3-pause-then-read.js
@@ -0,0 +1,177 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+
+const stream = require('stream');
+const Readable = stream.Readable;
+const Writable = stream.Writable;
+
+const totalChunks = 100;
+const chunkSize = 99;
+const expectTotalData = totalChunks * chunkSize;
+let expectEndingData = expectTotalData;
+
+const r = new Readable({ highWaterMark: 1000 });
+let chunks = totalChunks;
+r._read = function(n) {
+ console.log('_read called', chunks);
+ if (!(chunks % 2))
+ setImmediate(push);
+ else if (!(chunks % 3))
+ process.nextTick(push);
+ else
+ push();
+};
+
+let totalPushed = 0;
+function push() {
+ const chunk = chunks-- > 0 ? Buffer.alloc(chunkSize, 'x') : null;
+ if (chunk) {
+ totalPushed += chunk.length;
+ }
+ console.log('chunks', chunks);
+ r.push(chunk);
+}
+
+read100();
+
+// First we read 100 bytes.
+function read100() {
+ readn(100, onData);
+}
+
+function readn(n, then) {
+ console.error(`read ${n}`);
+ expectEndingData -= n;
+ (function read() {
+ const c = r.read(n);
+ console.error('c', c);
+ if (!c)
+ r.once('readable', read);
+ else {
+ assert.strictEqual(c.length, n);
+ assert(!r.readableFlowing);
+ then();
+ }
+ })();
+}
+
+// Then we listen to some data events.
+function onData() {
+ expectEndingData -= 100;
+ console.error('onData');
+ let seen = 0;
+ r.on('data', function od(c) {
+ seen += c.length;
+ if (seen >= 100) {
+ // Seen enough
+ r.removeListener('data', od);
+ r.pause();
+ if (seen > 100) {
+ // Oh no, seen too much!
+ // Put the extra back.
+ const diff = seen - 100;
+ r.unshift(c.slice(c.length - diff));
+ console.error('seen too much', seen, diff);
+ }
+
+ // Nothing should be lost in-between.
+ setImmediate(pipeLittle);
+ }
+ });
+}
+
+// Just pipe 200 bytes, then unshift the extra and unpipe.
+function pipeLittle() {
+ expectEndingData -= 200;
+ console.error('pipe a little');
+ const w = new Writable();
+ let written = 0;
+ w.on('finish', () => {
+ assert.strictEqual(written, 200);
+ setImmediate(read1234);
+ });
+ w._write = function(chunk, encoding, cb) {
+ written += chunk.length;
+ if (written >= 200) {
+ r.unpipe(w);
+ w.end();
+ cb();
+ if (written > 200) {
+ const diff = written - 200;
+ written -= diff;
+ r.unshift(chunk.slice(chunk.length - diff));
+ }
+ } else {
+ setImmediate(cb);
+ }
+ };
+ r.pipe(w);
+}
+
+// Now read 1234 more bytes.
+function read1234() {
+ readn(1234, resumePause);
+}
+
+function resumePause() {
+ console.error('resumePause');
+ // Don't read anything, just resume and re-pause a whole bunch.
+ r.resume();
+ r.pause();
+ r.resume();
+ r.pause();
+ r.resume();
+ r.pause();
+ r.resume();
+ r.pause();
+ r.resume();
+ r.pause();
+ setImmediate(pipe);
+}
+
+
+function pipe() {
+ console.error('pipe the rest');
+ const w = new Writable();
+ let written = 0;
+ w._write = function(chunk, encoding, cb) {
+ written += chunk.length;
+ cb();
+ };
+ w.on('finish', () => {
+ console.error('written', written, totalPushed);
+ assert.strictEqual(written, expectEndingData);
+ assert.strictEqual(totalPushed, expectTotalData);
+ console.log('ok');
+ });
+ r.pipe(w);
+}
diff --git a/tests/node_compat/test/parallel/test-streams-highwatermark.js b/tests/node_compat/test/parallel/test-streams-highwatermark.js
new file mode 100644
index 000000000..9245f7db0
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-streams-highwatermark.js
@@ -0,0 +1,94 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+
+const assert = require('assert');
+const stream = require('stream');
+const { inspect } = require('util');
+
+{
+ // This test ensures that the stream implementation correctly handles values
+ // for highWaterMark which exceed the range of signed 32 bit integers and
+ // rejects invalid values.
+
+ // This number exceeds the range of 32 bit integer arithmetic but should still
+ // be handled correctly.
+ const ovfl = Number.MAX_SAFE_INTEGER;
+
+ const readable = stream.Readable({ highWaterMark: ovfl });
+ assert.strictEqual(readable._readableState.highWaterMark, ovfl);
+
+ const writable = stream.Writable({ highWaterMark: ovfl });
+ assert.strictEqual(writable._writableState.highWaterMark, ovfl);
+
+ for (const invalidHwm of [true, false, '5', {}, -5, NaN]) {
+ for (const type of [stream.Readable, stream.Writable]) {
+ assert.throws(() => {
+ type({ highWaterMark: invalidHwm });
+ }, {
+ name: 'TypeError',
+ code: 'ERR_INVALID_ARG_VALUE',
+ message: "The property 'options.highWaterMark' is invalid. " +
+ `Received ${inspect(invalidHwm)}`
+ });
+ }
+ }
+}
+
+{
+ // This test ensures that the push method's implementation
+ // correctly handles the edge case where the highWaterMark and
+ // the state.length are both zero
+
+ const readable = stream.Readable({ highWaterMark: 0 });
+
+ for (let i = 0; i < 3; i++) {
+ const needMoreData = readable.push();
+ assert.strictEqual(needMoreData, true);
+ }
+}
+
+{
+ // This test ensures that the read(n) method's implementation
+ // correctly handles the edge case where the highWaterMark, state.length
+ // and n are all zero
+
+ const readable = stream.Readable({ highWaterMark: 0 });
+
+ readable._read = common.mustCall();
+ readable.read(0);
+}
+
+{
+ // Parse size as decimal integer
+ ['1', '1.0', 1].forEach((size) => {
+ const readable = new stream.Readable({
+ read: common.mustCall(),
+ highWaterMark: 0,
+ });
+ readable.read(size);
+
+ assert.strictEqual(readable._readableState.highWaterMark, Number(size));
+ });
+}
+
+{
+ // Test highwatermark limit
+ const hwm = 0x40000000 + 1;
+ const readable = stream.Readable({
+ read() {},
+ });
+
+ assert.throws(() => readable.read(hwm), common.expectsError({
+ code: 'ERR_OUT_OF_RANGE',
+ message: 'The value of "size" is out of range.' +
+ ' It must be <= 1GiB. Received ' +
+ hwm,
+ }));
+}
diff --git a/tests/node_compat/test/parallel/test-timers-api-refs.js b/tests/node_compat/test/parallel/test-timers-api-refs.js
new file mode 100644
index 000000000..62ce55fad
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-timers-api-refs.js
@@ -0,0 +1,28 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const timers = require('timers');
+
+// Delete global APIs to make sure they're not relied on by the internal timers
+// code
+delete global.setTimeout;
+delete global.clearTimeout;
+delete global.setInterval;
+delete global.clearInterval;
+delete global.setImmediate;
+delete global.clearImmediate;
+
+const timeoutCallback = () => { timers.clearTimeout(timeout); };
+const timeout = timers.setTimeout(common.mustCall(timeoutCallback), 1);
+
+const intervalCallback = () => { timers.clearInterval(interval); };
+const interval = timers.setInterval(common.mustCall(intervalCallback), 1);
+
+const immediateCallback = () => { timers.clearImmediate(immediate); };
+const immediate = timers.setImmediate(immediateCallback);
diff --git a/tests/node_compat/test/parallel/test-timers-args.js b/tests/node_compat/test/parallel/test-timers-args.js
new file mode 100644
index 000000000..b771bf591
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-timers-args.js
@@ -0,0 +1,38 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+
+function range(n) {
+ return 'x'.repeat(n + 1).split('').map(function(_, i) { return i; });
+}
+
+function timeout(nargs) {
+ const args = range(nargs);
+ setTimeout.apply(null, [callback, 1].concat(args));
+
+ function callback() {
+ assert.deepStrictEqual([].slice.call(arguments), args);
+ if (nargs < 128) timeout(nargs + 1);
+ }
+}
+
+function interval(nargs) {
+ const args = range(nargs);
+ const timer = setTimeout.apply(null, [callback, 1].concat(args));
+
+ function callback() {
+ clearInterval(timer);
+ assert.deepStrictEqual([].slice.call(arguments), args);
+ if (nargs < 128) interval(nargs + 1);
+ }
+}
+
+timeout(0);
+interval(0);
diff --git a/tests/node_compat/test/parallel/test-timers-clear-null-does-not-throw-error.js b/tests/node_compat/test/parallel/test-timers-clear-null-does-not-throw-error.js
new file mode 100644
index 000000000..7b7b59b27
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-timers-clear-null-does-not-throw-error.js
@@ -0,0 +1,18 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+require('../common');
+
+// This test makes sure clearing timers with
+// 'null' or no input does not throw error
+clearInterval(null);
+clearInterval();
+clearTimeout(null);
+clearTimeout();
+clearImmediate(null);
+clearImmediate();
diff --git a/tests/node_compat/test/parallel/test-timers-clear-object-does-not-throw-error.js b/tests/node_compat/test/parallel/test-timers-clear-object-does-not-throw-error.js
new file mode 100644
index 000000000..524389c6b
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-timers-clear-object-does-not-throw-error.js
@@ -0,0 +1,15 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+require('../common');
+
+// This test makes sure clearing timers with
+// objects doesn't throw
+clearImmediate({});
+clearTimeout({});
+clearInterval({});
diff --git a/tests/node_compat/test/parallel/test-timers-clear-timeout-interval-equivalent.js b/tests/node_compat/test/parallel/test-timers-clear-timeout-interval-equivalent.js
new file mode 100644
index 000000000..b6af3f943
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-timers-clear-timeout-interval-equivalent.js
@@ -0,0 +1,25 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+
+// This test makes sure that timers created with setTimeout can be disarmed by
+// clearInterval and that timers created with setInterval can be disarmed by
+// clearTimeout.
+//
+// This behavior is documented in the HTML Living Standard:
+//
+// * Refs: https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#dom-setinterval
+
+// Disarm interval with clearTimeout.
+const interval = setInterval(common.mustNotCall(), 1);
+clearTimeout(interval);
+
+// Disarm timeout with clearInterval.
+const timeout = setTimeout(common.mustNotCall(), 1);
+clearInterval(timeout);
diff --git a/tests/node_compat/test/parallel/test-timers-clearImmediate.js b/tests/node_compat/test/parallel/test-timers-clearImmediate.js
new file mode 100644
index 000000000..129e301f2
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-timers-clearImmediate.js
@@ -0,0 +1,20 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+
+const N = 3;
+
+function next() {
+ const fn = common.mustCall(() => clearImmediate(immediate));
+ const immediate = setImmediate(fn);
+}
+
+for (let i = 0; i < N; i++) {
+ next();
+}
diff --git a/tests/node_compat/test/parallel/test-timers-interval-throw.js b/tests/node_compat/test/parallel/test-timers-interval-throw.js
new file mode 100644
index 000000000..d408fc866
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-timers-interval-throw.js
@@ -0,0 +1,24 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const assert = require('assert');
+
+// To match browser behaviour, interval should continue
+// being rescheduled even if it throws.
+
+let count = 2;
+const interval = setInterval(() => { throw new Error('IntervalError'); }, 1);
+
+process.on('uncaughtException', common.mustCall((err) => {
+ assert.strictEqual(err.message, 'IntervalError');
+ if (--count === 0) {
+ clearInterval(interval);
+ }
+}, 2));
diff --git a/tests/node_compat/test/parallel/test-timers-non-integer-delay.js b/tests/node_compat/test/parallel/test-timers-non-integer-delay.js
new file mode 100644
index 000000000..1d3ca55c2
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-timers-non-integer-delay.js
@@ -0,0 +1,88 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+
+// This test makes sure that non-integer timer delays do not make the process
+// hang. See https://github.com/joyent/node/issues/8065 and
+// https://github.com/joyent/node/issues/8068 which have been fixed by
+// https://github.com/joyent/node/pull/8073.
+//
+// If the process hangs, this test will make the tests suite timeout,
+// otherwise it will exit very quickly (after 50 timers with a short delay
+// fire).
+//
+// We have to set at least several timers with a non-integer delay to
+// reproduce the issue. Sometimes, a timer with a non-integer delay will
+// expire correctly. 50 timers has always been more than enough to reproduce
+// it 100%.
+
+const TIMEOUT_DELAY = 1.1;
+let N = 50;
+
+const interval = setInterval(common.mustCall(() => {
+ if (--N === 0) {
+ clearInterval(interval);
+ }
+}, N), TIMEOUT_DELAY);
+
+// Test non-integer delay ordering
+{
+ const ordering = [];
+
+ setTimeout(common.mustCall(() => {
+ ordering.push(1);
+ }), 1);
+
+ setTimeout(common.mustCall(() => {
+ ordering.push(2);
+ }), 1.8);
+
+ setTimeout(common.mustCall(() => {
+ ordering.push(3);
+ }), 1.1);
+
+ setTimeout(common.mustCall(() => {
+ ordering.push(4);
+ }), 1);
+
+ setTimeout(common.mustCall(() => {
+ const expected = [1, 2, 3, 4];
+
+ assert.deepStrictEqual(
+ ordering,
+ expected,
+ `Non-integer delay ordering should be ${expected}, but got ${ordering}`
+ );
+
+ // 2 should always be last of these delays due to ordering guarantees by
+ // the implementation.
+ }), 2);
+}
diff --git a/tests/node_compat/test/parallel/test-timers-refresh.js b/tests/node_compat/test/parallel/test-timers-refresh.js
new file mode 100644
index 000000000..942cf5604
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-timers-refresh.js
@@ -0,0 +1,109 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Flags: --expose-internals
+
+'use strict';
+
+const common = require('../common');
+
+const { strictEqual, throws } = require('assert');
+const { setUnrefTimeout } = require('internal/timers');
+
+// Schedule the unrefed cases first so that the later case keeps the event loop
+// active.
+
+// Every case in this test relies on implicit sorting within either Node's or
+// libuv's timers storage data structures.
+
+// unref()'d timer
+{
+ let called = false;
+ const timer = setTimeout(common.mustCall(() => {
+ called = true;
+ }), 1);
+ timer.unref();
+
+ // This relies on implicit timers handle sorting within libuv.
+
+ setTimeout(common.mustCall(() => {
+ strictEqual(called, false, 'unref()\'d timer returned before check');
+ }), 1);
+
+ strictEqual(timer.refresh(), timer);
+}
+
+// Should throw with non-functions
+{
+ [null, true, false, 0, 1, NaN, '', 'foo', {}, Symbol()].forEach((cb) => {
+ throws(
+ () => setUnrefTimeout(cb),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ }
+ );
+ });
+}
+
+// unref pooled timer
+{
+ let called = false;
+ const timer = setUnrefTimeout(common.mustCall(() => {
+ called = true;
+ }), 1);
+
+ setUnrefTimeout(common.mustCall(() => {
+ strictEqual(called, false, 'unref pooled timer returned before check');
+ }), 1);
+
+ strictEqual(timer.refresh(), timer);
+}
+
+// regular timer
+{
+ let called = false;
+ const timer = setTimeout(common.mustCall(() => {
+ called = true;
+ }), 1);
+
+ setTimeout(common.mustCall(() => {
+ strictEqual(called, false, 'pooled timer returned before check');
+ }), 1);
+
+ strictEqual(timer.refresh(), timer);
+}
+
+// regular timer
+{
+ let called = false;
+ const timer = setTimeout(common.mustCall(() => {
+ if (!called) {
+ called = true;
+ process.nextTick(common.mustCall(() => {
+ timer.refresh();
+ strictEqual(timer.hasRef(), true);
+ }));
+ }
+ }, 2), 1);
+}
+
+// interval
+{
+ let called = 0;
+ const timer = setInterval(common.mustCall(() => {
+ called += 1;
+ if (called === 2) {
+ clearInterval(timer);
+ }
+ }, 2), 1);
+
+ setTimeout(common.mustCall(() => {
+ strictEqual(called, 0, 'pooled timer returned before check');
+ }), 1);
+
+ strictEqual(timer.refresh(), timer);
+}
diff --git a/tests/node_compat/test/parallel/test-timers-same-timeout-wrong-list-deleted.js b/tests/node_compat/test/parallel/test-timers-same-timeout-wrong-list-deleted.js
new file mode 100644
index 000000000..fa6348d75
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-timers-same-timeout-wrong-list-deleted.js
@@ -0,0 +1,41 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+// This is a regression test for https://github.com/nodejs/node/issues/7722.
+//
+// When nested timers have the same timeout, calling clearTimeout on the
+// older timer after it has fired causes the list the newer timer is in
+// to be deleted. Since the newer timer was not cleared, it still blocks
+// the event loop completing for the duration of its timeout, however, since
+// no reference exists to it in its list, it cannot be canceled and its
+// callback is not called when the timeout elapses.
+
+const common = require('../common');
+
+const TIMEOUT = common.platformTimeout(100);
+
+const handle1 = setTimeout(common.mustCall(function() {
+ // Cause the old TIMEOUT list to be deleted
+ clearTimeout(handle1);
+
+ // Cause a new list with the same key (TIMEOUT) to be created for this timer
+ const handle2 = setTimeout(common.mustNotCall(), TIMEOUT);
+
+ setTimeout(common.mustCall(function() {
+ // Attempt to cancel the second timer. Fix for this bug will keep the
+ // newer timer from being dereferenced by keeping its list from being
+ // erroneously deleted. If we are able to cancel the timer successfully,
+ // the bug is fixed.
+ clearTimeout(handle2);
+ }), 1);
+
+ // When this callback completes, `listOnTimeout` should now look at the
+ // correct list and refrain from removing the new TIMEOUT list which
+ // contains the reference to the newer timer.
+}), TIMEOUT);
diff --git a/tests/node_compat/test/parallel/test-timers-timeout-with-non-integer.js b/tests/node_compat/test/parallel/test-timers-timeout-with-non-integer.js
new file mode 100644
index 000000000..d93ef57fe
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-timers-timeout-with-non-integer.js
@@ -0,0 +1,22 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+
+/**
+ * This test is for https://github.com/nodejs/node/issues/24203
+ */
+let count = 50;
+const time = 1.00000000000001;
+const exec = common.mustCall(() => {
+ if (--count === 0) {
+ return;
+ }
+ setTimeout(exec, time);
+}, count);
+exec();
diff --git a/tests/node_compat/test/parallel/test-timers-uncaught-exception.js b/tests/node_compat/test/parallel/test-timers-uncaught-exception.js
new file mode 100644
index 000000000..e76c11afc
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-timers-uncaught-exception.js
@@ -0,0 +1,46 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const errorMsg = 'BAM!';
+
+// The first timer throws...
+setTimeout(common.mustCall(function() {
+ throw new Error(errorMsg);
+}), 1);
+
+// ...but the second one should still run
+setTimeout(common.mustCall(), 1);
+
+function uncaughtException(err) {
+ assert.strictEqual(err.message, errorMsg);
+}
+
+process.on('uncaughtException', common.mustCall(uncaughtException));
diff --git a/tests/node_compat/test/parallel/test-timers-unref-throw-then-ref.js b/tests/node_compat/test/parallel/test-timers-unref-throw-then-ref.js
new file mode 100644
index 000000000..03a0861e2
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-timers-unref-throw-then-ref.js
@@ -0,0 +1,26 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+
+process.once('uncaughtException', common.mustCall((err) => {
+ common.expectsError({
+ message: 'Timeout Error'
+ })(err);
+}));
+
+let called = false;
+const t = setTimeout(() => {
+ assert(!called);
+ called = true;
+ t.ref();
+ throw new Error('Timeout Error');
+}, 1).unref();
+
+setTimeout(common.mustCall(), 1);
diff --git a/tests/node_compat/test/parallel/test-timers-user-call.js b/tests/node_compat/test/parallel/test-timers-user-call.js
new file mode 100644
index 000000000..969051f80
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-timers-user-call.js
@@ -0,0 +1,47 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Make sure `setTimeout()` and friends don't throw if the user-supplied
+// function has .call() and .apply() monkey-patched to undesirable values.
+
+// Refs: https://github.com/nodejs/node/issues/12956
+
+'use strict';
+
+const common = require('../common');
+
+{
+ const fn = common.mustCall(10);
+ fn.call = 'not a function';
+ fn.apply = 'also not a function';
+ setTimeout(fn, 1);
+ setTimeout(fn, 1, 'oneArg');
+ setTimeout(fn, 1, 'two', 'args');
+ setTimeout(fn, 1, 'three', '(3)', 'args');
+ setTimeout(fn, 1, 'more', 'than', 'three', 'args');
+
+ setImmediate(fn, 1);
+ setImmediate(fn, 1, 'oneArg');
+ setImmediate(fn, 1, 'two', 'args');
+ setImmediate(fn, 1, 'three', '(3)', 'args');
+ setImmediate(fn, 1, 'more', 'than', 'three', 'args');
+}
+
+{
+ const testInterval = (...args) => {
+ const fn = common.mustCall(() => { clearInterval(interval); });
+ fn.call = 'not a function';
+ fn.apply = 'also not a function';
+ const interval = setInterval(fn, 1, ...args);
+ };
+
+ testInterval();
+ testInterval('oneArg');
+ testInterval('two', 'args');
+ testInterval('three', '(3)', 'args');
+ testInterval('more', 'than', 'three', 'args');
+}
diff --git a/tests/node_compat/test/parallel/test-timers-zero-timeout.js b/tests/node_compat/test/parallel/test-timers-zero-timeout.js
new file mode 100644
index 000000000..ef32f7381
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-timers-zero-timeout.js
@@ -0,0 +1,56 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+
+// https://github.com/joyent/node/issues/2079 - zero timeout drops extra args
+{
+ setTimeout(common.mustCall(f), 0, 'foo', 'bar', 'baz');
+ setTimeout(() => {}, 0);
+
+ function f(a, b, c) {
+ assert.strictEqual(a, 'foo');
+ assert.strictEqual(b, 'bar');
+ assert.strictEqual(c, 'baz');
+ }
+}
+
+{
+ let ncalled = 3;
+
+ const f = common.mustCall((a, b, c) => {
+ assert.strictEqual(a, 'foo');
+ assert.strictEqual(b, 'bar');
+ assert.strictEqual(c, 'baz');
+ if (--ncalled === 0) clearTimeout(iv);
+ }, ncalled);
+
+ const iv = setInterval(f, 0, 'foo', 'bar', 'baz');
+}
diff --git a/tests/node_compat/test/parallel/test-tty-stdin-end.js b/tests/node_compat/test/parallel/test-tty-stdin-end.js
new file mode 100644
index 000000000..ee38cbd2c
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-tty-stdin-end.js
@@ -0,0 +1,14 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+require('../common');
+
+// This test ensures that Node.js doesn't crash on `process.stdin.emit("end")`.
+// https://github.com/nodejs/node/issues/1068
+
+process.stdin.emit('end');
diff --git a/tests/node_compat/test/parallel/test-ttywrap-invalid-fd.js b/tests/node_compat/test/parallel/test-ttywrap-invalid-fd.js
new file mode 100644
index 000000000..95b9bffe6
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-ttywrap-invalid-fd.js
@@ -0,0 +1,74 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Flags: --expose-internals
+'use strict';
+
+// const common = require('../common');
+const tty = require('tty');
+// const { internalBinding } = require('internal/test/binding');
+// const {
+// UV_EBADF,
+// UV_EINVAL
+// } = internalBinding('uv');
+const assert = require('assert');
+
+assert.throws(
+ () => new tty.WriteStream(-1),
+ {
+ code: 'ERR_INVALID_FD',
+ name: 'RangeError',
+ message: '"fd" must be a positive integer: -1'
+ }
+);
+
+// {
+// const info = {
+// code: common.isWindows ? 'EBADF' : 'EINVAL',
+// message: common.isWindows ? 'bad file descriptor' : 'invalid argument',
+// errno: common.isWindows ? UV_EBADF : UV_EINVAL,
+// syscall: 'uv_tty_init'
+// };
+
+// const suffix = common.isWindows ?
+// 'EBADF (bad file descriptor)' : 'EINVAL (invalid argument)';
+// const message = `TTY initialization failed: uv_tty_init returned ${suffix}`;
+
+// assert.throws(
+// () => {
+// common.runWithInvalidFD((fd) => {
+// new tty.WriteStream(fd);
+// });
+// }, {
+// code: 'ERR_TTY_INIT_FAILED',
+// name: 'SystemError',
+// message,
+// info
+// }
+// );
+
+// assert.throws(
+// () => {
+// common.runWithInvalidFD((fd) => {
+// new tty.ReadStream(fd);
+// });
+// }, {
+// code: 'ERR_TTY_INIT_FAILED',
+// name: 'SystemError',
+// message,
+// info
+// });
+// }
+
+assert.throws(
+ () => new tty.ReadStream(-1),
+ {
+ code: 'ERR_INVALID_FD',
+ name: 'RangeError',
+ message: '"fd" must be a positive integer: -1'
+ }
+);
diff --git a/tests/node_compat/test/parallel/test-url-domain-ascii-unicode.js b/tests/node_compat/test/parallel/test-url-domain-ascii-unicode.js
new file mode 100644
index 000000000..9aeb23a54
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-url-domain-ascii-unicode.js
@@ -0,0 +1,38 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+if (!common.hasIntl)
+ common.skip('missing Intl');
+
+const strictEqual = require('assert').strictEqual;
+const url = require('url');
+
+const domainToASCII = url.domainToASCII;
+const domainToUnicode = url.domainToUnicode;
+
+const domainWithASCII = [
+ ['ıíd', 'xn--d-iga7r'],
+ ['يٴ', 'xn--mhb8f'],
+ ['www.ϧƽəʐ.com', 'www.xn--cja62apfr6c.com'],
+ ['новини.com', 'xn--b1amarcd.com'],
+ ['名がドメイン.com', 'xn--v8jxj3d1dzdz08w.com'],
+ ['افغانستا.icom.museum', 'xn--mgbaal8b0b9b2b.icom.museum'],
+ ['الجزائر.icom.fake', 'xn--lgbbat1ad8j.icom.fake'],
+ ['भारत.org', 'xn--h2brj9c.org'],
+];
+
+domainWithASCII.forEach((pair) => {
+ const domain = pair[0];
+ const ascii = pair[1];
+ const domainConvertedToASCII = domainToASCII(domain);
+ strictEqual(domainConvertedToASCII, ascii);
+ const asciiConvertedToUnicode = domainToUnicode(ascii);
+ strictEqual(asciiConvertedToUnicode, domain);
+});
diff --git a/tests/node_compat/test/parallel/test-url-fileurltopath.js b/tests/node_compat/test/parallel/test-url-fileurltopath.js
new file mode 100644
index 000000000..72ba73166
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-url-fileurltopath.js
@@ -0,0 +1,161 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const { isWindows } = require('../common');
+const assert = require('assert');
+const url = require('url');
+
+function testInvalidArgs(...args) {
+ for (const arg of args) {
+ assert.throws(() => url.fileURLToPath(arg), {
+ code: 'ERR_INVALID_ARG_TYPE'
+ });
+ }
+}
+
+// Input must be string or URL
+testInvalidArgs(null, undefined, 1, {}, true);
+
+// Input must be a file URL
+assert.throws(() => url.fileURLToPath('https://a/b/c'), {
+ code: 'ERR_INVALID_URL_SCHEME'
+});
+
+{
+ const withHost = new URL('file://host/a');
+
+ if (isWindows) {
+ assert.strictEqual(url.fileURLToPath(withHost), '\\\\host\\a');
+ } else {
+ assert.throws(() => url.fileURLToPath(withHost), {
+ code: 'ERR_INVALID_FILE_URL_HOST'
+ });
+ }
+}
+
+{
+ if (isWindows) {
+ assert.throws(() => url.fileURLToPath('file:///C:/a%2F/'), {
+ code: 'ERR_INVALID_FILE_URL_PATH'
+ });
+ assert.throws(() => url.fileURLToPath('file:///C:/a%5C/'), {
+ code: 'ERR_INVALID_FILE_URL_PATH'
+ });
+ assert.throws(() => url.fileURLToPath('file:///?:/'), {
+ code: 'ERR_INVALID_FILE_URL_PATH'
+ });
+ } else {
+ assert.throws(() => url.fileURLToPath('file:///a%2F/'), {
+ code: 'ERR_INVALID_FILE_URL_PATH'
+ });
+ }
+}
+
+{
+ let testCases;
+ if (isWindows) {
+ testCases = [
+ // Lowercase ascii alpha
+ { path: 'C:\\foo', fileURL: 'file:///C:/foo' },
+ // Uppercase ascii alpha
+ { path: 'C:\\FOO', fileURL: 'file:///C:/FOO' },
+ // dir
+ { path: 'C:\\dir\\foo', fileURL: 'file:///C:/dir/foo' },
+ // trailing separator
+ { path: 'C:\\dir\\', fileURL: 'file:///C:/dir/' },
+ // dot
+ { path: 'C:\\foo.mjs', fileURL: 'file:///C:/foo.mjs' },
+ // space
+ { path: 'C:\\foo bar', fileURL: 'file:///C:/foo%20bar' },
+ // question mark
+ { path: 'C:\\foo?bar', fileURL: 'file:///C:/foo%3Fbar' },
+ // number sign
+ { path: 'C:\\foo#bar', fileURL: 'file:///C:/foo%23bar' },
+ // ampersand
+ { path: 'C:\\foo&bar', fileURL: 'file:///C:/foo&bar' },
+ // equals
+ { path: 'C:\\foo=bar', fileURL: 'file:///C:/foo=bar' },
+ // colon
+ { path: 'C:\\foo:bar', fileURL: 'file:///C:/foo:bar' },
+ // semicolon
+ { path: 'C:\\foo;bar', fileURL: 'file:///C:/foo;bar' },
+ // percent
+ { path: 'C:\\foo%bar', fileURL: 'file:///C:/foo%25bar' },
+ // backslash
+ { path: 'C:\\foo\\bar', fileURL: 'file:///C:/foo/bar' },
+ // backspace
+ { path: 'C:\\foo\bbar', fileURL: 'file:///C:/foo%08bar' },
+ // tab
+ { path: 'C:\\foo\tbar', fileURL: 'file:///C:/foo%09bar' },
+ // newline
+ { path: 'C:\\foo\nbar', fileURL: 'file:///C:/foo%0Abar' },
+ // carriage return
+ { path: 'C:\\foo\rbar', fileURL: 'file:///C:/foo%0Dbar' },
+ // latin1
+ { path: 'C:\\fóóbàr', fileURL: 'file:///C:/f%C3%B3%C3%B3b%C3%A0r' },
+ // Euro sign (BMP code point)
+ { path: 'C:\\€', fileURL: 'file:///C:/%E2%82%AC' },
+ // Rocket emoji (non-BMP code point)
+ { path: 'C:\\🚀', fileURL: 'file:///C:/%F0%9F%9A%80' },
+ // UNC path (see https://docs.microsoft.com/en-us/archive/blogs/ie/file-uris-in-windows)
+ { path: '\\\\nas\\My Docs\\File.doc', fileURL: 'file://nas/My%20Docs/File.doc' },
+ ];
+ } else {
+ testCases = [
+ // Lowercase ascii alpha
+ { path: '/foo', fileURL: 'file:///foo' },
+ // Uppercase ascii alpha
+ { path: '/FOO', fileURL: 'file:///FOO' },
+ // dir
+ { path: '/dir/foo', fileURL: 'file:///dir/foo' },
+ // trailing separator
+ { path: '/dir/', fileURL: 'file:///dir/' },
+ // dot
+ { path: '/foo.mjs', fileURL: 'file:///foo.mjs' },
+ // space
+ { path: '/foo bar', fileURL: 'file:///foo%20bar' },
+ // question mark
+ { path: '/foo?bar', fileURL: 'file:///foo%3Fbar' },
+ // number sign
+ { path: '/foo#bar', fileURL: 'file:///foo%23bar' },
+ // ampersand
+ { path: '/foo&bar', fileURL: 'file:///foo&bar' },
+ // equals
+ { path: '/foo=bar', fileURL: 'file:///foo=bar' },
+ // colon
+ { path: '/foo:bar', fileURL: 'file:///foo:bar' },
+ // semicolon
+ { path: '/foo;bar', fileURL: 'file:///foo;bar' },
+ // percent
+ { path: '/foo%bar', fileURL: 'file:///foo%25bar' },
+ // backslash
+ { path: '/foo\\bar', fileURL: 'file:///foo%5Cbar' },
+ // backspace
+ { path: '/foo\bbar', fileURL: 'file:///foo%08bar' },
+ // tab
+ { path: '/foo\tbar', fileURL: 'file:///foo%09bar' },
+ // newline
+ { path: '/foo\nbar', fileURL: 'file:///foo%0Abar' },
+ // carriage return
+ { path: '/foo\rbar', fileURL: 'file:///foo%0Dbar' },
+ // latin1
+ { path: '/fóóbàr', fileURL: 'file:///f%C3%B3%C3%B3b%C3%A0r' },
+ // Euro sign (BMP code point)
+ { path: '/€', fileURL: 'file:///%E2%82%AC' },
+ // Rocket emoji (non-BMP code point)
+ { path: '/🚀', fileURL: 'file:///%F0%9F%9A%80' },
+ ];
+ }
+
+ for (const { path, fileURL } of testCases) {
+ const fromString = url.fileURLToPath(fileURL);
+ assert.strictEqual(fromString, path);
+ const fromURL = url.fileURLToPath(new URL(fileURL));
+ assert.strictEqual(fromURL, path);
+ }
+}
diff --git a/tests/node_compat/test/parallel/test-url-format-invalid-input.js b/tests/node_compat/test/parallel/test-url-format-invalid-input.js
new file mode 100644
index 000000000..d411b8d32
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-url-format-invalid-input.js
@@ -0,0 +1,34 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const url = require('url');
+
+const throwsObjsAndReportTypes = [
+ undefined,
+ null,
+ true,
+ false,
+ 0,
+ function() {},
+ Symbol('foo'),
+];
+
+for (const urlObject of throwsObjsAndReportTypes) {
+ assert.throws(() => {
+ url.format(urlObject);
+ }, {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: 'The "urlObject" argument must be one of type object or string.' +
+ common.invalidArgTypeHelper(urlObject)
+ });
+}
+assert.strictEqual(url.format(''), '');
+assert.strictEqual(url.format({}), '');
diff --git a/tests/node_compat/test/parallel/test-url-format-whatwg.js b/tests/node_compat/test/parallel/test-url-format-whatwg.js
new file mode 100644
index 000000000..1e9b36dcb
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-url-format-whatwg.js
@@ -0,0 +1,149 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+if (!common.hasIntl)
+ common.skip('missing Intl');
+
+const assert = require('assert');
+const url = require('url');
+
+const myURL = new URL('http://user:pass@xn--lck1c3crb1723bpq4a.com/a?a=b#c');
+
+assert.strictEqual(
+ url.format(myURL),
+ 'http://user:pass@xn--lck1c3crb1723bpq4a.com/a?a=b#c'
+);
+
+assert.strictEqual(
+ url.format(myURL, {}),
+ 'http://user:pass@xn--lck1c3crb1723bpq4a.com/a?a=b#c'
+);
+
+{
+ [true, 1, 'test', Infinity].forEach((value) => {
+ assert.throws(
+ () => url.format(myURL, value),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: 'The "options" argument must be of type object.' +
+ common.invalidArgTypeHelper(value)
+ }
+ );
+ });
+}
+
+// Any falsy value other than undefined will be treated as false.
+// Any truthy value will be treated as true.
+
+assert.strictEqual(
+ url.format(myURL, { auth: false }),
+ 'http://xn--lck1c3crb1723bpq4a.com/a?a=b#c'
+);
+
+assert.strictEqual(
+ url.format(myURL, { auth: '' }),
+ 'http://xn--lck1c3crb1723bpq4a.com/a?a=b#c'
+);
+
+assert.strictEqual(
+ url.format(myURL, { auth: 0 }),
+ 'http://xn--lck1c3crb1723bpq4a.com/a?a=b#c'
+);
+
+assert.strictEqual(
+ url.format(myURL, { auth: 1 }),
+ 'http://user:pass@xn--lck1c3crb1723bpq4a.com/a?a=b#c'
+);
+
+assert.strictEqual(
+ url.format(myURL, { auth: {} }),
+ 'http://user:pass@xn--lck1c3crb1723bpq4a.com/a?a=b#c'
+);
+
+assert.strictEqual(
+ url.format(myURL, { fragment: false }),
+ 'http://user:pass@xn--lck1c3crb1723bpq4a.com/a?a=b'
+);
+
+assert.strictEqual(
+ url.format(myURL, { fragment: '' }),
+ 'http://user:pass@xn--lck1c3crb1723bpq4a.com/a?a=b'
+);
+
+assert.strictEqual(
+ url.format(myURL, { fragment: 0 }),
+ 'http://user:pass@xn--lck1c3crb1723bpq4a.com/a?a=b'
+);
+
+assert.strictEqual(
+ url.format(myURL, { fragment: 1 }),
+ 'http://user:pass@xn--lck1c3crb1723bpq4a.com/a?a=b#c'
+);
+
+assert.strictEqual(
+ url.format(myURL, { fragment: {} }),
+ 'http://user:pass@xn--lck1c3crb1723bpq4a.com/a?a=b#c'
+);
+
+assert.strictEqual(
+ url.format(myURL, { search: false }),
+ 'http://user:pass@xn--lck1c3crb1723bpq4a.com/a#c'
+);
+
+assert.strictEqual(
+ url.format(myURL, { search: '' }),
+ 'http://user:pass@xn--lck1c3crb1723bpq4a.com/a#c'
+);
+
+assert.strictEqual(
+ url.format(myURL, { search: 0 }),
+ 'http://user:pass@xn--lck1c3crb1723bpq4a.com/a#c'
+);
+
+assert.strictEqual(
+ url.format(myURL, { search: 1 }),
+ 'http://user:pass@xn--lck1c3crb1723bpq4a.com/a?a=b#c'
+);
+
+assert.strictEqual(
+ url.format(myURL, { search: {} }),
+ 'http://user:pass@xn--lck1c3crb1723bpq4a.com/a?a=b#c'
+);
+
+assert.strictEqual(
+ url.format(myURL, { unicode: true }),
+ 'http://user:pass@理容ナカムラ.com/a?a=b#c'
+);
+
+assert.strictEqual(
+ url.format(myURL, { unicode: 1 }),
+ 'http://user:pass@理容ナカムラ.com/a?a=b#c'
+);
+
+assert.strictEqual(
+ url.format(myURL, { unicode: {} }),
+ 'http://user:pass@理容ナカムラ.com/a?a=b#c'
+);
+
+assert.strictEqual(
+ url.format(myURL, { unicode: false }),
+ 'http://user:pass@xn--lck1c3crb1723bpq4a.com/a?a=b#c'
+);
+
+assert.strictEqual(
+ url.format(myURL, { unicode: 0 }),
+ 'http://user:pass@xn--lck1c3crb1723bpq4a.com/a?a=b#c'
+);
+
+assert.strictEqual(
+ url.format(new URL('http://user:pass@xn--0zwm56d.com:8080/path'), { unicode: true }),
+ 'http://user:pass@测试.com:8080/path'
+);
diff --git a/tests/node_compat/test/parallel/test-url-format.js b/tests/node_compat/test/parallel/test-url-format.js
new file mode 100644
index 000000000..1208509c7
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-url-format.js
@@ -0,0 +1,284 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const url = require('url');
+
+if (!common.hasIntl)
+ common.skip('missing Intl');
+
+// Formatting tests to verify that it'll format slightly wonky content to a
+// valid URL.
+const formatTests = {
+ 'http://example.com?': {
+ href: 'http://example.com/?',
+ protocol: 'http:',
+ slashes: true,
+ host: 'example.com',
+ hostname: 'example.com',
+ search: '?',
+ query: {},
+ pathname: '/'
+ },
+ 'http://example.com?foo=bar#frag': {
+ href: 'http://example.com/?foo=bar#frag',
+ protocol: 'http:',
+ host: 'example.com',
+ hostname: 'example.com',
+ hash: '#frag',
+ search: '?foo=bar',
+ query: 'foo=bar',
+ pathname: '/'
+ },
+ 'http://example.com?foo=@bar#frag': {
+ href: 'http://example.com/?foo=@bar#frag',
+ protocol: 'http:',
+ host: 'example.com',
+ hostname: 'example.com',
+ hash: '#frag',
+ search: '?foo=@bar',
+ query: 'foo=@bar',
+ pathname: '/'
+ },
+ 'http://example.com?foo=/bar/#frag': {
+ href: 'http://example.com/?foo=/bar/#frag',
+ protocol: 'http:',
+ host: 'example.com',
+ hostname: 'example.com',
+ hash: '#frag',
+ search: '?foo=/bar/',
+ query: 'foo=/bar/',
+ pathname: '/'
+ },
+ 'http://example.com?foo=?bar/#frag': {
+ href: 'http://example.com/?foo=?bar/#frag',
+ protocol: 'http:',
+ host: 'example.com',
+ hostname: 'example.com',
+ hash: '#frag',
+ search: '?foo=?bar/',
+ query: 'foo=?bar/',
+ pathname: '/'
+ },
+ 'http://example.com#frag=?bar/#frag': {
+ href: 'http://example.com/#frag=?bar/#frag',
+ protocol: 'http:',
+ host: 'example.com',
+ hostname: 'example.com',
+ hash: '#frag=?bar/#frag',
+ pathname: '/'
+ },
+ 'http://google.com" onload="alert(42)/': {
+ href: 'http://google.com/%22%20onload=%22alert(42)/',
+ protocol: 'http:',
+ host: 'google.com',
+ pathname: '/%22%20onload=%22alert(42)/'
+ },
+ 'http://a.com/a/b/c?s#h': {
+ href: 'http://a.com/a/b/c?s#h',
+ protocol: 'http',
+ host: 'a.com',
+ pathname: 'a/b/c',
+ hash: 'h',
+ search: 's'
+ },
+ 'xmpp:isaacschlueter@jabber.org': {
+ href: 'xmpp:isaacschlueter@jabber.org',
+ protocol: 'xmpp:',
+ host: 'jabber.org',
+ auth: 'isaacschlueter',
+ hostname: 'jabber.org'
+ },
+ 'http://atpass:foo%40bar@127.0.0.1/': {
+ href: 'http://atpass:foo%40bar@127.0.0.1/',
+ auth: 'atpass:foo@bar',
+ hostname: '127.0.0.1',
+ protocol: 'http:',
+ pathname: '/'
+ },
+ 'http://atslash%2F%40:%2F%40@foo/': {
+ href: 'http://atslash%2F%40:%2F%40@foo/',
+ auth: 'atslash/@:/@',
+ hostname: 'foo',
+ protocol: 'http:',
+ pathname: '/'
+ },
+ 'svn+ssh://foo/bar': {
+ href: 'svn+ssh://foo/bar',
+ hostname: 'foo',
+ protocol: 'svn+ssh:',
+ pathname: '/bar',
+ slashes: true
+ },
+ 'dash-test://foo/bar': {
+ href: 'dash-test://foo/bar',
+ hostname: 'foo',
+ protocol: 'dash-test:',
+ pathname: '/bar',
+ slashes: true
+ },
+ 'dash-test:foo/bar': {
+ href: 'dash-test:foo/bar',
+ hostname: 'foo',
+ protocol: 'dash-test:',
+ pathname: '/bar'
+ },
+ 'dot.test://foo/bar': {
+ href: 'dot.test://foo/bar',
+ hostname: 'foo',
+ protocol: 'dot.test:',
+ pathname: '/bar',
+ slashes: true
+ },
+ 'dot.test:foo/bar': {
+ href: 'dot.test:foo/bar',
+ hostname: 'foo',
+ protocol: 'dot.test:',
+ pathname: '/bar'
+ },
+ // IPv6 support
+ 'coap:u:p@[::1]:61616/.well-known/r?n=Temperature': {
+ href: 'coap:u:p@[::1]:61616/.well-known/r?n=Temperature',
+ protocol: 'coap:',
+ auth: 'u:p',
+ hostname: '::1',
+ port: '61616',
+ pathname: '/.well-known/r',
+ search: 'n=Temperature'
+ },
+ 'coap:[fedc:ba98:7654:3210:fedc:ba98:7654:3210]:61616/s/stopButton': {
+ href: 'coap:[fedc:ba98:7654:3210:fedc:ba98:7654:3210]:61616/s/stopButton',
+ protocol: 'coap',
+ host: '[fedc:ba98:7654:3210:fedc:ba98:7654:3210]:61616',
+ pathname: '/s/stopButton'
+ },
+ 'http://[::]/': {
+ href: 'http://[::]/',
+ protocol: 'http:',
+ hostname: '[::]',
+ pathname: '/'
+ },
+
+ // Encode context-specific delimiters in path and query, but do not touch
+ // other non-delimiter chars like `%`.
+ // <https://github.com/nodejs/node-v0.x-archive/issues/4082>
+
+ // `#`,`?` in path
+ '/path/to/%%23%3F+=&.txt?foo=theA1#bar': {
+ href: '/path/to/%%23%3F+=&.txt?foo=theA1#bar',
+ pathname: '/path/to/%#?+=&.txt',
+ query: {
+ foo: 'theA1'
+ },
+ hash: '#bar'
+ },
+
+ // `#`,`?` in path + `#` in query
+ '/path/to/%%23%3F+=&.txt?foo=the%231#bar': {
+ href: '/path/to/%%23%3F+=&.txt?foo=the%231#bar',
+ pathname: '/path/to/%#?+=&.txt',
+ query: {
+ foo: 'the#1'
+ },
+ hash: '#bar'
+ },
+
+ // `#` in path end + `#` in query
+ '/path/to/%%23?foo=the%231#bar': {
+ href: '/path/to/%%23?foo=the%231#bar',
+ pathname: '/path/to/%#',
+ query: {
+ foo: 'the#1'
+ },
+ hash: '#bar'
+ },
+
+ // `?` and `#` in path and search
+ 'http://ex.com/foo%3F100%m%23r?abc=the%231?&foo=bar#frag': {
+ href: 'http://ex.com/foo%3F100%m%23r?abc=the%231?&foo=bar#frag',
+ protocol: 'http:',
+ hostname: 'ex.com',
+ hash: '#frag',
+ search: '?abc=the#1?&foo=bar',
+ pathname: '/foo?100%m#r',
+ },
+
+ // `?` and `#` in search only
+ 'http://ex.com/fooA100%mBr?abc=the%231?&foo=bar#frag': {
+ href: 'http://ex.com/fooA100%mBr?abc=the%231?&foo=bar#frag',
+ protocol: 'http:',
+ hostname: 'ex.com',
+ hash: '#frag',
+ search: '?abc=the#1?&foo=bar',
+ pathname: '/fooA100%mBr',
+ },
+
+ // Multiple `#` in search
+ 'http://example.com/?foo=bar%231%232%233&abc=%234%23%235#frag': {
+ href: 'http://example.com/?foo=bar%231%232%233&abc=%234%23%235#frag',
+ protocol: 'http:',
+ slashes: true,
+ host: 'example.com',
+ hostname: 'example.com',
+ hash: '#frag',
+ search: '?foo=bar#1#2#3&abc=#4##5',
+ query: {},
+ pathname: '/'
+ },
+
+ // More than 255 characters in hostname which exceeds the limit
+ [`http://${'a'.repeat(255)}.com/node`]: {
+ href: 'http:///node',
+ protocol: 'http:',
+ slashes: true,
+ host: '',
+ hostname: '',
+ pathname: '/node',
+ path: '/node'
+ },
+
+ // Greater than or equal to 63 characters after `.` in hostname
+ [`http://www.${'z'.repeat(63)}example.com/node`]: {
+ href: `http://www.${'z'.repeat(63)}example.com/node`,
+ protocol: 'http:',
+ slashes: true,
+ host: `www.${'z'.repeat(63)}example.com`,
+ hostname: `www.${'z'.repeat(63)}example.com`,
+ pathname: '/node',
+ path: '/node'
+ },
+
+ // https://github.com/nodejs/node/issues/3361
+ 'file:///home/user': {
+ href: 'file:///home/user',
+ protocol: 'file',
+ pathname: '/home/user',
+ path: '/home/user'
+ },
+
+ // surrogate in auth
+ 'http://%F0%9F%98%80@www.example.com/': {
+ href: 'http://%F0%9F%98%80@www.example.com/',
+ protocol: 'http:',
+ auth: '\uD83D\uDE00',
+ hostname: 'www.example.com',
+ pathname: '/'
+ }
+};
+for (const u in formatTests) {
+ const expect = formatTests[u].href;
+ delete formatTests[u].href;
+ const actual = url.format(u);
+ const actualObj = url.format(formatTests[u]);
+ assert.strictEqual(actual, expect,
+ `wonky format(${u}) == ${expect}\nactual:${actual}`);
+ assert.strictEqual(actualObj, expect,
+ `wonky format(${JSON.stringify(formatTests[u])}) == ${
+ expect}\nactual: ${actualObj}`);
+}
diff --git a/tests/node_compat/test/parallel/test-url-parse-invalid-input.js b/tests/node_compat/test/parallel/test-url-parse-invalid-input.js
new file mode 100644
index 000000000..345e8d338
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-url-parse-invalid-input.js
@@ -0,0 +1,83 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const url = require('url');
+
+// https://github.com/joyent/node/issues/568
+[
+ [undefined, 'undefined'],
+ [null, 'object'],
+ [true, 'boolean'],
+ [false, 'boolean'],
+ [0.0, 'number'],
+ [0, 'number'],
+ [[], 'object'],
+ [{}, 'object'],
+ [() => {}, 'function'],
+ [Symbol('foo'), 'symbol'],
+].forEach(([val, type]) => {
+ assert.throws(() => {
+ url.parse(val);
+ }, {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: 'The "url" argument must be of type string.' +
+ common.invalidArgTypeHelper(val)
+ });
+});
+
+assert.throws(() => { url.parse('http://%E0%A4%A@fail'); },
+ (e) => {
+ // The error should be a URIError.
+ if (!(e instanceof URIError))
+ return false;
+
+ // The error should be from the JS engine and not from Node.js.
+ // JS engine errors do not have the `code` property.
+ return e.code === undefined;
+ });
+
+assert.throws(() => { url.parse('http://[127.0.0.1\x00c8763]:8000/'); },
+ { code: 'ERR_INVALID_URL', input: 'http://[127.0.0.1\x00c8763]:8000/' }
+);
+
+if (common.hasIntl) {
+ // An array of Unicode code points whose Unicode NFKD contains a "bad
+ // character".
+ const badIDNA = (() => {
+ const BAD_CHARS = '#%/:?@[\\]^|';
+ const out = [];
+ for (let i = 0x80; i < 0x110000; i++) {
+ const cp = String.fromCodePoint(i);
+ for (const badChar of BAD_CHARS) {
+ if (cp.normalize('NFKD').includes(badChar)) {
+ out.push(cp);
+ }
+ }
+ }
+ return out;
+ })();
+
+ // The generation logic above should at a minimum produce these two
+ // characters.
+ assert(badIDNA.includes('℀'));
+ assert(badIDNA.includes('@'));
+
+ for (const badCodePoint of badIDNA) {
+ const badURL = `http://fail${badCodePoint}fail.com/`;
+ assert.throws(() => { url.parse(badURL); },
+ (e) => e.code === 'ERR_INVALID_URL',
+ `parsing ${badURL}`);
+ }
+
+ assert.throws(() => { url.parse('http://\u00AD/bad.com/'); },
+ (e) => e.code === 'ERR_INVALID_URL',
+ 'parsing http://\u00AD/bad.com/');
+}
diff --git a/tests/node_compat/test/parallel/test-url-parse-query.js b/tests/node_compat/test/parallel/test-url-parse-query.js
new file mode 100644
index 000000000..f6ccb1f46
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-url-parse-query.js
@@ -0,0 +1,97 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+const url = require('url');
+
+function createWithNoPrototype(properties = []) {
+ const noProto = Object.create(null);
+ properties.forEach((property) => {
+ noProto[property.key] = property.value;
+ });
+ return noProto;
+}
+
+function check(actual, expected) {
+ assert.notStrictEqual(Object.getPrototypeOf(actual), Object.prototype);
+ assert.deepStrictEqual(Object.keys(actual).sort(),
+ Object.keys(expected).sort());
+ Object.keys(expected).forEach(function(key) {
+ assert.deepStrictEqual(actual[key], expected[key]);
+ });
+}
+
+const parseTestsWithQueryString = {
+ '/foo/bar?baz=quux#frag': {
+ href: '/foo/bar?baz=quux#frag',
+ hash: '#frag',
+ search: '?baz=quux',
+ query: createWithNoPrototype([{ key: 'baz', value: 'quux' }]),
+ pathname: '/foo/bar',
+ path: '/foo/bar?baz=quux'
+ },
+ 'http://example.com': {
+ href: 'http://example.com/',
+ protocol: 'http:',
+ slashes: true,
+ host: 'example.com',
+ hostname: 'example.com',
+ query: createWithNoPrototype(),
+ search: null,
+ pathname: '/',
+ path: '/'
+ },
+ '/example': {
+ protocol: null,
+ slashes: null,
+ auth: undefined,
+ host: null,
+ port: null,
+ hostname: null,
+ hash: null,
+ search: null,
+ query: createWithNoPrototype(),
+ pathname: '/example',
+ path: '/example',
+ href: '/example'
+ },
+ '/example?query=value': {
+ protocol: null,
+ slashes: null,
+ auth: undefined,
+ host: null,
+ port: null,
+ hostname: null,
+ hash: null,
+ search: '?query=value',
+ query: createWithNoPrototype([{ key: 'query', value: 'value' }]),
+ pathname: '/example',
+ path: '/example?query=value',
+ href: '/example?query=value'
+ }
+};
+for (const u in parseTestsWithQueryString) {
+ const actual = url.parse(u, true);
+ const expected = Object.assign(new url.Url(), parseTestsWithQueryString[u]);
+ for (const i in actual) {
+ if (actual[i] === null && expected[i] === undefined) {
+ expected[i] = null;
+ }
+ }
+
+ const properties = Object.keys(actual).sort();
+ assert.deepStrictEqual(properties, Object.keys(expected).sort());
+ properties.forEach((property) => {
+ if (property === 'query') {
+ check(actual[property], expected[property]);
+ } else {
+ assert.deepStrictEqual(actual[property], expected[property]);
+ }
+ });
+}
diff --git a/tests/node_compat/test/parallel/test-url-pathtofileurl.js b/tests/node_compat/test/parallel/test-url-pathtofileurl.js
new file mode 100644
index 000000000..bafd870aa
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-url-pathtofileurl.js
@@ -0,0 +1,153 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const { isWindows } = require('../common');
+const assert = require('assert');
+const url = require('url');
+
+{
+ const fileURL = url.pathToFileURL('test/').href;
+ assert.ok(fileURL.startsWith('file:///'));
+ assert.ok(fileURL.endsWith('/'));
+}
+
+{
+ const fileURL = url.pathToFileURL('test\\').href;
+ assert.ok(fileURL.startsWith('file:///'));
+ if (isWindows)
+ assert.ok(fileURL.endsWith('/'));
+ else
+ assert.ok(fileURL.endsWith('%5C'));
+}
+
+{
+ const fileURL = url.pathToFileURL('test/%').href;
+ assert.ok(fileURL.includes('%25'));
+}
+
+{
+ if (isWindows) {
+ // UNC path: \\server\share\resource
+
+ // Missing server:
+ assert.throws(() => url.pathToFileURL('\\\\\\no-server'), {
+ code: 'ERR_INVALID_ARG_VALUE'
+ });
+
+ // Missing share or resource:
+ assert.throws(() => url.pathToFileURL('\\\\host'), {
+ code: 'ERR_INVALID_ARG_VALUE'
+ });
+ } else {
+ // UNC paths on posix are considered a single path that has backslashes:
+ const fileURL = url.pathToFileURL('\\\\nas\\share\\path.txt').href;
+ assert.match(fileURL, /file:\/\/.+%5C%5Cnas%5Cshare%5Cpath\.txt$/);
+ }
+}
+
+{
+ let testCases;
+ if (isWindows) {
+ testCases = [
+ // Lowercase ascii alpha
+ { path: 'C:\\foo', expected: 'file:///C:/foo' },
+ // Uppercase ascii alpha
+ { path: 'C:\\FOO', expected: 'file:///C:/FOO' },
+ // dir
+ { path: 'C:\\dir\\foo', expected: 'file:///C:/dir/foo' },
+ // trailing separator
+ { path: 'C:\\dir\\', expected: 'file:///C:/dir/' },
+ // dot
+ { path: 'C:\\foo.mjs', expected: 'file:///C:/foo.mjs' },
+ // space
+ { path: 'C:\\foo bar', expected: 'file:///C:/foo%20bar' },
+ // question mark
+ { path: 'C:\\foo?bar', expected: 'file:///C:/foo%3Fbar' },
+ // number sign
+ { path: 'C:\\foo#bar', expected: 'file:///C:/foo%23bar' },
+ // ampersand
+ { path: 'C:\\foo&bar', expected: 'file:///C:/foo&bar' },
+ // equals
+ { path: 'C:\\foo=bar', expected: 'file:///C:/foo=bar' },
+ // colon
+ { path: 'C:\\foo:bar', expected: 'file:///C:/foo:bar' },
+ // semicolon
+ { path: 'C:\\foo;bar', expected: 'file:///C:/foo;bar' },
+ // percent
+ { path: 'C:\\foo%bar', expected: 'file:///C:/foo%25bar' },
+ // backslash
+ { path: 'C:\\foo\\bar', expected: 'file:///C:/foo/bar' },
+ // backspace
+ { path: 'C:\\foo\bbar', expected: 'file:///C:/foo%08bar' },
+ // tab
+ { path: 'C:\\foo\tbar', expected: 'file:///C:/foo%09bar' },
+ // newline
+ { path: 'C:\\foo\nbar', expected: 'file:///C:/foo%0Abar' },
+ // carriage return
+ { path: 'C:\\foo\rbar', expected: 'file:///C:/foo%0Dbar' },
+ // latin1
+ { path: 'C:\\fóóbàr', expected: 'file:///C:/f%C3%B3%C3%B3b%C3%A0r' },
+ // Euro sign (BMP code point)
+ { path: 'C:\\€', expected: 'file:///C:/%E2%82%AC' },
+ // Rocket emoji (non-BMP code point)
+ { path: 'C:\\🚀', expected: 'file:///C:/%F0%9F%9A%80' },
+ // UNC path (see https://docs.microsoft.com/en-us/archive/blogs/ie/file-uris-in-windows)
+ { path: '\\\\nas\\My Docs\\File.doc', expected: 'file://nas/My%20Docs/File.doc' },
+ ];
+ } else {
+ testCases = [
+ // Lowercase ascii alpha
+ { path: '/foo', expected: 'file:///foo' },
+ // Uppercase ascii alpha
+ { path: '/FOO', expected: 'file:///FOO' },
+ // dir
+ { path: '/dir/foo', expected: 'file:///dir/foo' },
+ // trailing separator
+ { path: '/dir/', expected: 'file:///dir/' },
+ // dot
+ { path: '/foo.mjs', expected: 'file:///foo.mjs' },
+ // space
+ { path: '/foo bar', expected: 'file:///foo%20bar' },
+ // question mark
+ { path: '/foo?bar', expected: 'file:///foo%3Fbar' },
+ // number sign
+ { path: '/foo#bar', expected: 'file:///foo%23bar' },
+ // ampersand
+ { path: '/foo&bar', expected: 'file:///foo&bar' },
+ // equals
+ { path: '/foo=bar', expected: 'file:///foo=bar' },
+ // colon
+ { path: '/foo:bar', expected: 'file:///foo:bar' },
+ // semicolon
+ { path: '/foo;bar', expected: 'file:///foo;bar' },
+ // percent
+ { path: '/foo%bar', expected: 'file:///foo%25bar' },
+ // backslash
+ { path: '/foo\\bar', expected: 'file:///foo%5Cbar' },
+ // backspace
+ { path: '/foo\bbar', expected: 'file:///foo%08bar' },
+ // tab
+ { path: '/foo\tbar', expected: 'file:///foo%09bar' },
+ // newline
+ { path: '/foo\nbar', expected: 'file:///foo%0Abar' },
+ // carriage return
+ { path: '/foo\rbar', expected: 'file:///foo%0Dbar' },
+ // latin1
+ { path: '/fóóbàr', expected: 'file:///f%C3%B3%C3%B3b%C3%A0r' },
+ // Euro sign (BMP code point)
+ { path: '/€', expected: 'file:///%E2%82%AC' },
+ // Rocket emoji (non-BMP code point)
+ { path: '/🚀', expected: 'file:///%F0%9F%9A%80' },
+ ];
+ }
+
+ for (const { path, expected } of testCases) {
+ const actual = url.pathToFileURL(path).href;
+ assert.strictEqual(actual, expected);
+ }
+}
diff --git a/tests/node_compat/test/parallel/test-url-relative.js b/tests/node_compat/test/parallel/test-url-relative.js
new file mode 100644
index 000000000..2bcddd96f
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-url-relative.js
@@ -0,0 +1,441 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+const inspect = require('util').inspect;
+const url = require('url');
+
+// When source is false
+assert.strictEqual(url.resolveObject('', 'foo'), 'foo');
+
+// [from, path, expected]
+const relativeTests = [
+ ['/foo/bar/baz', 'quux', '/foo/bar/quux'],
+ ['/foo/bar/baz', 'quux/asdf', '/foo/bar/quux/asdf'],
+ ['/foo/bar/baz', 'quux/baz', '/foo/bar/quux/baz'],
+ ['/foo/bar/baz', '../quux/baz', '/foo/quux/baz'],
+ ['/foo/bar/baz', '/bar', '/bar'],
+ ['/foo/bar/baz/', 'quux', '/foo/bar/baz/quux'],
+ ['/foo/bar/baz/', 'quux/baz', '/foo/bar/baz/quux/baz'],
+ ['/foo/bar/baz', '../../../../../../../../quux/baz', '/quux/baz'],
+ ['/foo/bar/baz', '../../../../../../../quux/baz', '/quux/baz'],
+ ['/foo', '.', '/'],
+ ['/foo', '..', '/'],
+ ['/foo/', '.', '/foo/'],
+ ['/foo/', '..', '/'],
+ ['/foo/bar', '.', '/foo/'],
+ ['/foo/bar', '..', '/'],
+ ['/foo/bar/', '.', '/foo/bar/'],
+ ['/foo/bar/', '..', '/foo/'],
+ ['foo/bar', '../../../baz', '../../baz'],
+ ['foo/bar/', '../../../baz', '../baz'],
+ ['http://example.com/b//c//d;p?q#blarg', 'https:#hash2', 'https:///#hash2'],
+ ['http://example.com/b//c//d;p?q#blarg',
+ 'https:/p/a/t/h?s#hash2',
+ 'https://p/a/t/h?s#hash2'],
+ ['http://example.com/b//c//d;p?q#blarg',
+ 'https://u:p@h.com/p/a/t/h?s#hash2',
+ 'https://u:p@h.com/p/a/t/h?s#hash2'],
+ ['http://example.com/b//c//d;p?q#blarg',
+ 'https:/a/b/c/d',
+ 'https://a/b/c/d'],
+ ['http://example.com/b//c//d;p?q#blarg',
+ 'http:#hash2',
+ 'http://example.com/b//c//d;p?q#hash2'],
+ ['http://example.com/b//c//d;p?q#blarg',
+ 'http:/p/a/t/h?s#hash2',
+ 'http://example.com/p/a/t/h?s#hash2'],
+ ['http://example.com/b//c//d;p?q#blarg',
+ 'http://u:p@h.com/p/a/t/h?s#hash2',
+ 'http://u:p@h.com/p/a/t/h?s#hash2'],
+ ['http://example.com/b//c//d;p?q#blarg',
+ 'http:/a/b/c/d',
+ 'http://example.com/a/b/c/d'],
+ ['/foo/bar/baz', '/../etc/passwd', '/etc/passwd'],
+ ['http://localhost', 'file:///Users/foo', 'file:///Users/foo'],
+ ['http://localhost', 'file://foo/Users', 'file://foo/Users'],
+ ['https://registry.npmjs.org', '@foo/bar', 'https://registry.npmjs.org/@foo/bar'],
+];
+relativeTests.forEach(function(relativeTest) {
+ const a = url.resolve(relativeTest[0], relativeTest[1]);
+ const e = relativeTest[2];
+ assert.strictEqual(a, e,
+ `resolve(${relativeTest[0]}, ${relativeTest[1]})` +
+ ` == ${e}\n actual=${a}`);
+});
+
+//
+// Tests below taken from Chiron
+// http://code.google.com/p/chironjs/source/browse/trunk/src/test/http/url.js
+//
+// Copyright (c) 2002-2008 Kris Kowal <http://cixar.com/~kris.kowal>
+// used with permission under MIT License
+//
+// Changes marked with @isaacs
+
+const bases = [
+ 'http://a/b/c/d;p?q',
+ 'http://a/b/c/d;p?q=1/2',
+ 'http://a/b/c/d;p=1/2?q',
+ 'fred:///s//a/b/c',
+ 'http:///s//a/b/c',
+];
+
+// [to, from, result]
+const relativeTests2 = [
+ // http://lists.w3.org/Archives/Public/uri/2004Feb/0114.html
+ ['../c', 'foo:a/b', 'foo:c'],
+ ['foo:.', 'foo:a', 'foo:'],
+ ['/foo/../../../bar', 'zz:abc', 'zz:/bar'],
+ ['/foo/../bar', 'zz:abc', 'zz:/bar'],
+ // @isaacs Disagree. Not how web browsers resolve this.
+ ['foo/../../../bar', 'zz:abc', 'zz:bar'],
+ // ['foo/../../../bar', 'zz:abc', 'zz:../../bar'], // @isaacs Added
+ ['foo/../bar', 'zz:abc', 'zz:bar'],
+ ['zz:.', 'zz:abc', 'zz:'],
+ ['/.', bases[0], 'http://a/'],
+ ['/.foo', bases[0], 'http://a/.foo'],
+ ['.foo', bases[0], 'http://a/b/c/.foo'],
+
+ // http://gbiv.com/protocols/uri/test/rel_examples1.html
+ // examples from RFC 2396
+ ['g:h', bases[0], 'g:h'],
+ ['g', bases[0], 'http://a/b/c/g'],
+ ['./g', bases[0], 'http://a/b/c/g'],
+ ['g/', bases[0], 'http://a/b/c/g/'],
+ ['/g', bases[0], 'http://a/g'],
+ ['//g', bases[0], 'http://g/'],
+ // Changed with RFC 2396bis
+ // ('?y', bases[0], 'http://a/b/c/d;p?y'],
+ ['?y', bases[0], 'http://a/b/c/d;p?y'],
+ ['g?y', bases[0], 'http://a/b/c/g?y'],
+ // Changed with RFC 2396bis
+ // ('#s', bases[0], CURRENT_DOC_URI + '#s'],
+ ['#s', bases[0], 'http://a/b/c/d;p?q#s'],
+ ['g#s', bases[0], 'http://a/b/c/g#s'],
+ ['g?y#s', bases[0], 'http://a/b/c/g?y#s'],
+ [';x', bases[0], 'http://a/b/c/;x'],
+ ['g;x', bases[0], 'http://a/b/c/g;x'],
+ ['g;x?y#s', bases[0], 'http://a/b/c/g;x?y#s'],
+ // Changed with RFC 2396bis
+ // ('', bases[0], CURRENT_DOC_URI],
+ ['', bases[0], 'http://a/b/c/d;p?q'],
+ ['.', bases[0], 'http://a/b/c/'],
+ ['./', bases[0], 'http://a/b/c/'],
+ ['..', bases[0], 'http://a/b/'],
+ ['../', bases[0], 'http://a/b/'],
+ ['../g', bases[0], 'http://a/b/g'],
+ ['../..', bases[0], 'http://a/'],
+ ['../../', bases[0], 'http://a/'],
+ ['../../g', bases[0], 'http://a/g'],
+ ['../../../g', bases[0], ('http://a/../g', 'http://a/g')],
+ ['../../../../g', bases[0], ('http://a/../../g', 'http://a/g')],
+ // Changed with RFC 2396bis
+ // ('/./g', bases[0], 'http://a/./g'],
+ ['/./g', bases[0], 'http://a/g'],
+ // Changed with RFC 2396bis
+ // ('/../g', bases[0], 'http://a/../g'],
+ ['/../g', bases[0], 'http://a/g'],
+ ['g.', bases[0], 'http://a/b/c/g.'],
+ ['.g', bases[0], 'http://a/b/c/.g'],
+ ['g..', bases[0], 'http://a/b/c/g..'],
+ ['..g', bases[0], 'http://a/b/c/..g'],
+ ['./../g', bases[0], 'http://a/b/g'],
+ ['./g/.', bases[0], 'http://a/b/c/g/'],
+ ['g/./h', bases[0], 'http://a/b/c/g/h'],
+ ['g/../h', bases[0], 'http://a/b/c/h'],
+ ['g;x=1/./y', bases[0], 'http://a/b/c/g;x=1/y'],
+ ['g;x=1/../y', bases[0], 'http://a/b/c/y'],
+ ['g?y/./x', bases[0], 'http://a/b/c/g?y/./x'],
+ ['g?y/../x', bases[0], 'http://a/b/c/g?y/../x'],
+ ['g#s/./x', bases[0], 'http://a/b/c/g#s/./x'],
+ ['g#s/../x', bases[0], 'http://a/b/c/g#s/../x'],
+ ['http:g', bases[0], ('http:g', 'http://a/b/c/g')],
+ ['http:', bases[0], ('http:', bases[0])],
+ // Not sure where this one originated
+ ['/a/b/c/./../../g', bases[0], 'http://a/a/g'],
+
+ // http://gbiv.com/protocols/uri/test/rel_examples2.html
+ // slashes in base URI's query args
+ ['g', bases[1], 'http://a/b/c/g'],
+ ['./g', bases[1], 'http://a/b/c/g'],
+ ['g/', bases[1], 'http://a/b/c/g/'],
+ ['/g', bases[1], 'http://a/g'],
+ ['//g', bases[1], 'http://g/'],
+ // Changed in RFC 2396bis
+ // ('?y', bases[1], 'http://a/b/c/?y'],
+ ['?y', bases[1], 'http://a/b/c/d;p?y'],
+ ['g?y', bases[1], 'http://a/b/c/g?y'],
+ ['g?y/./x', bases[1], 'http://a/b/c/g?y/./x'],
+ ['g?y/../x', bases[1], 'http://a/b/c/g?y/../x'],
+ ['g#s', bases[1], 'http://a/b/c/g#s'],
+ ['g#s/./x', bases[1], 'http://a/b/c/g#s/./x'],
+ ['g#s/../x', bases[1], 'http://a/b/c/g#s/../x'],
+ ['./', bases[1], 'http://a/b/c/'],
+ ['../', bases[1], 'http://a/b/'],
+ ['../g', bases[1], 'http://a/b/g'],
+ ['../../', bases[1], 'http://a/'],
+ ['../../g', bases[1], 'http://a/g'],
+
+ // http://gbiv.com/protocols/uri/test/rel_examples3.html
+ // slashes in path params
+ // all of these changed in RFC 2396bis
+ ['g', bases[2], 'http://a/b/c/d;p=1/g'],
+ ['./g', bases[2], 'http://a/b/c/d;p=1/g'],
+ ['g/', bases[2], 'http://a/b/c/d;p=1/g/'],
+ ['g?y', bases[2], 'http://a/b/c/d;p=1/g?y'],
+ [';x', bases[2], 'http://a/b/c/d;p=1/;x'],
+ ['g;x', bases[2], 'http://a/b/c/d;p=1/g;x'],
+ ['g;x=1/./y', bases[2], 'http://a/b/c/d;p=1/g;x=1/y'],
+ ['g;x=1/../y', bases[2], 'http://a/b/c/d;p=1/y'],
+ ['./', bases[2], 'http://a/b/c/d;p=1/'],
+ ['../', bases[2], 'http://a/b/c/'],
+ ['../g', bases[2], 'http://a/b/c/g'],
+ ['../../', bases[2], 'http://a/b/'],
+ ['../../g', bases[2], 'http://a/b/g'],
+
+ // http://gbiv.com/protocols/uri/test/rel_examples4.html
+ // double and triple slash, unknown scheme
+ ['g:h', bases[3], 'g:h'],
+ ['g', bases[3], 'fred:///s//a/b/g'],
+ ['./g', bases[3], 'fred:///s//a/b/g'],
+ ['g/', bases[3], 'fred:///s//a/b/g/'],
+ ['/g', bases[3], 'fred:///g'], // May change to fred:///s//a/g
+ ['//g', bases[3], 'fred://g'], // May change to fred:///s//g
+ ['//g/x', bases[3], 'fred://g/x'], // May change to fred:///s//g/x
+ ['///g', bases[3], 'fred:///g'],
+ ['./', bases[3], 'fred:///s//a/b/'],
+ ['../', bases[3], 'fred:///s//a/'],
+ ['../g', bases[3], 'fred:///s//a/g'],
+
+ ['../../', bases[3], 'fred:///s//'],
+ ['../../g', bases[3], 'fred:///s//g'],
+ ['../../../g', bases[3], 'fred:///s/g'],
+ // May change to fred:///s//a/../../../g
+ ['../../../../g', bases[3], 'fred:///g'],
+
+ // http://gbiv.com/protocols/uri/test/rel_examples5.html
+ // double and triple slash, well-known scheme
+ ['g:h', bases[4], 'g:h'],
+ ['g', bases[4], 'http:///s//a/b/g'],
+ ['./g', bases[4], 'http:///s//a/b/g'],
+ ['g/', bases[4], 'http:///s//a/b/g/'],
+ ['/g', bases[4], 'http:///g'], // May change to http:///s//a/g
+ ['//g', bases[4], 'http://g/'], // May change to http:///s//g
+ ['//g/x', bases[4], 'http://g/x'], // May change to http:///s//g/x
+ ['///g', bases[4], 'http:///g'],
+ ['./', bases[4], 'http:///s//a/b/'],
+ ['../', bases[4], 'http:///s//a/'],
+ ['../g', bases[4], 'http:///s//a/g'],
+ ['../../', bases[4], 'http:///s//'],
+ ['../../g', bases[4], 'http:///s//g'],
+ // May change to http:///s//a/../../g
+ ['../../../g', bases[4], 'http:///s/g'],
+ // May change to http:///s//a/../../../g
+ ['../../../../g', bases[4], 'http:///g'],
+
+ // From Dan Connelly's tests in http://www.w3.org/2000/10/swap/uripath.py
+ ['bar:abc', 'foo:xyz', 'bar:abc'],
+ ['../abc', 'http://example/x/y/z', 'http://example/x/abc'],
+ ['http://example/x/abc', 'http://example2/x/y/z', 'http://example/x/abc'],
+ ['../r', 'http://ex/x/y/z', 'http://ex/x/r'],
+ ['q/r', 'http://ex/x/y', 'http://ex/x/q/r'],
+ ['q/r#s', 'http://ex/x/y', 'http://ex/x/q/r#s'],
+ ['q/r#s/t', 'http://ex/x/y', 'http://ex/x/q/r#s/t'],
+ ['ftp://ex/x/q/r', 'http://ex/x/y', 'ftp://ex/x/q/r'],
+ ['', 'http://ex/x/y', 'http://ex/x/y'],
+ ['', 'http://ex/x/y/', 'http://ex/x/y/'],
+ ['', 'http://ex/x/y/pdq', 'http://ex/x/y/pdq'],
+ ['z/', 'http://ex/x/y/', 'http://ex/x/y/z/'],
+ ['#Animal',
+ 'file:/swap/test/animal.rdf',
+ 'file:/swap/test/animal.rdf#Animal'],
+ ['../abc', 'file:/e/x/y/z', 'file:/e/x/abc'],
+ ['/example/x/abc', 'file:/example2/x/y/z', 'file:/example/x/abc'],
+ ['../r', 'file:/ex/x/y/z', 'file:/ex/x/r'],
+ ['/r', 'file:/ex/x/y/z', 'file:/r'],
+ ['q/r', 'file:/ex/x/y', 'file:/ex/x/q/r'],
+ ['q/r#s', 'file:/ex/x/y', 'file:/ex/x/q/r#s'],
+ ['q/r#', 'file:/ex/x/y', 'file:/ex/x/q/r#'],
+ ['q/r#s/t', 'file:/ex/x/y', 'file:/ex/x/q/r#s/t'],
+ ['ftp://ex/x/q/r', 'file:/ex/x/y', 'ftp://ex/x/q/r'],
+ ['', 'file:/ex/x/y', 'file:/ex/x/y'],
+ ['', 'file:/ex/x/y/', 'file:/ex/x/y/'],
+ ['', 'file:/ex/x/y/pdq', 'file:/ex/x/y/pdq'],
+ ['z/', 'file:/ex/x/y/', 'file:/ex/x/y/z/'],
+ ['file://meetings.example.com/cal#m1',
+ 'file:/devel/WWW/2000/10/swap/test/reluri-1.n3',
+ 'file://meetings.example.com/cal#m1'],
+ ['file://meetings.example.com/cal#m1',
+ 'file:/home/connolly/w3ccvs/WWW/2000/10/swap/test/reluri-1.n3',
+ 'file://meetings.example.com/cal#m1'],
+ ['./#blort', 'file:/some/dir/foo', 'file:/some/dir/#blort'],
+ ['./#', 'file:/some/dir/foo', 'file:/some/dir/#'],
+ // Ryan Lee
+ ['./', 'http://example/x/abc.efg', 'http://example/x/'],
+
+
+ // Graham Klyne's tests
+ // http://www.ninebynine.org/Software/HaskellUtils/Network/UriTest.xls
+ // 01-31 are from Connelly's cases
+
+ // 32-49
+ ['./q:r', 'http://ex/x/y', 'http://ex/x/q:r'],
+ ['./p=q:r', 'http://ex/x/y', 'http://ex/x/p=q:r'],
+ ['?pp/rr', 'http://ex/x/y?pp/qq', 'http://ex/x/y?pp/rr'],
+ ['y/z', 'http://ex/x/y?pp/qq', 'http://ex/x/y/z'],
+ ['local/qual@domain.org#frag',
+ 'mailto:local',
+ 'mailto:local/qual@domain.org#frag'],
+ ['more/qual2@domain2.org#frag',
+ 'mailto:local/qual1@domain1.org',
+ 'mailto:local/more/qual2@domain2.org#frag'],
+ ['y?q', 'http://ex/x/y?q', 'http://ex/x/y?q'],
+ ['/x/y?q', 'http://ex?p', 'http://ex/x/y?q'],
+ ['c/d', 'foo:a/b', 'foo:a/c/d'],
+ ['/c/d', 'foo:a/b', 'foo:/c/d'],
+ ['', 'foo:a/b?c#d', 'foo:a/b?c'],
+ ['b/c', 'foo:a', 'foo:b/c'],
+ ['../b/c', 'foo:/a/y/z', 'foo:/a/b/c'],
+ ['./b/c', 'foo:a', 'foo:b/c'],
+ ['/./b/c', 'foo:a', 'foo:/b/c'],
+ ['../../d', 'foo://a//b/c', 'foo://a/d'],
+ ['.', 'foo:a', 'foo:'],
+ ['..', 'foo:a', 'foo:'],
+
+ // 50-57[cf. TimBL comments --
+ // http://lists.w3.org/Archives/Public/uri/2003Feb/0028.html,
+ // http://lists.w3.org/Archives/Public/uri/2003Jan/0008.html)
+ ['abc', 'http://example/x/y%2Fz', 'http://example/x/abc'],
+ ['../../x%2Fabc', 'http://example/a/x/y/z', 'http://example/a/x%2Fabc'],
+ ['../x%2Fabc', 'http://example/a/x/y%2Fz', 'http://example/a/x%2Fabc'],
+ ['abc', 'http://example/x%2Fy/z', 'http://example/x%2Fy/abc'],
+ ['q%3Ar', 'http://ex/x/y', 'http://ex/x/q%3Ar'],
+ ['/x%2Fabc', 'http://example/x/y%2Fz', 'http://example/x%2Fabc'],
+ ['/x%2Fabc', 'http://example/x/y/z', 'http://example/x%2Fabc'],
+ ['/x%2Fabc', 'http://example/x/y%2Fz', 'http://example/x%2Fabc'],
+
+ // 70-77
+ ['local2@domain2', 'mailto:local1@domain1?query1', 'mailto:local2@domain2'],
+ ['local2@domain2?query2',
+ 'mailto:local1@domain1',
+ 'mailto:local2@domain2?query2'],
+ ['local2@domain2?query2',
+ 'mailto:local1@domain1?query1',
+ 'mailto:local2@domain2?query2'],
+ ['?query2', 'mailto:local@domain?query1', 'mailto:local@domain?query2'],
+ ['local@domain?query2', 'mailto:?query1', 'mailto:local@domain?query2'],
+ ['?query2', 'mailto:local@domain?query1', 'mailto:local@domain?query2'],
+ ['http://example/a/b?c/../d', 'foo:bar', 'http://example/a/b?c/../d'],
+ ['http://example/a/b#c/../d', 'foo:bar', 'http://example/a/b#c/../d'],
+
+ // 82-88
+ // @isaacs Disagree. Not how browsers do it.
+ // ['http:this', 'http://example.org/base/uri', 'http:this'],
+ // @isaacs Added
+ ['http:this', 'http://example.org/base/uri', 'http://example.org/base/this'],
+ ['http:this', 'http:base', 'http:this'],
+ ['.//g', 'f:/a', 'f://g'],
+ ['b/c//d/e', 'f://example.org/base/a', 'f://example.org/base/b/c//d/e'],
+ ['m2@example.ord/c2@example.org',
+ 'mid:m@example.ord/c@example.org',
+ 'mid:m@example.ord/m2@example.ord/c2@example.org'],
+ ['mini1.xml',
+ 'file:///C:/DEV/Haskell/lib/HXmlToolbox-3.01/examples/',
+ 'file:///C:/DEV/Haskell/lib/HXmlToolbox-3.01/examples/mini1.xml'],
+ ['../b/c', 'foo:a/y/z', 'foo:a/b/c'],
+
+ // changeing auth
+ ['http://diff:auth@www.example.com',
+ 'http://asdf:qwer@www.example.com',
+ 'http://diff:auth@www.example.com/'],
+
+ // changing port
+ ['https://example.com:81/',
+ 'https://example.com:82/',
+ 'https://example.com:81/'],
+
+ // https://github.com/nodejs/node/issues/1435
+ ['https://another.host.com/',
+ 'https://user:password@example.org/',
+ 'https://another.host.com/'],
+ ['//another.host.com/',
+ 'https://user:password@example.org/',
+ 'https://another.host.com/'],
+ ['http://another.host.com/',
+ 'https://user:password@example.org/',
+ 'http://another.host.com/'],
+ ['mailto:another.host.com',
+ 'mailto:user@example.org',
+ 'mailto:another.host.com'],
+ ['https://example.com/foo',
+ 'https://user:password@example.com',
+ 'https://user:password@example.com/foo'],
+
+ // No path at all
+ ['#hash1', '#hash2', '#hash1'],
+];
+relativeTests2.forEach(function(relativeTest) {
+ const a = url.resolve(relativeTest[1], relativeTest[0]);
+ const e = url.format(relativeTest[2]);
+ assert.strictEqual(a, e,
+ `resolve(${relativeTest[0]}, ${relativeTest[1]})` +
+ ` == ${e}\n actual=${a}`);
+});
+
+// If format and parse are inverse operations then
+// resolveObject(parse(x), y) == parse(resolve(x, y))
+
+// format: [from, path, expected]
+relativeTests.forEach(function(relativeTest) {
+ let actual = url.resolveObject(url.parse(relativeTest[0]), relativeTest[1]);
+ let expected = url.parse(relativeTest[2]);
+
+
+ assert.deepStrictEqual(actual, expected);
+
+ expected = relativeTest[2];
+ actual = url.format(actual);
+
+ assert.strictEqual(actual, expected,
+ `format(${actual}) == ${expected}\n` +
+ `actual: ${actual}`);
+});
+
+// format: [to, from, result]
+// the test: ['.//g', 'f:/a', 'f://g'] is a fundamental problem
+// url.parse('f:/a') does not have a host
+// url.resolve('f:/a', './/g') does not have a host because you have moved
+// down to the g directory. i.e. f: //g, however when this url is parsed
+// f:// will indicate that the host is g which is not the case.
+// it is unclear to me how to keep this information from being lost
+// it may be that a pathname of ////g should collapse to /g but this seems
+// to be a lot of work for an edge case. Right now I remove the test
+if (relativeTests2[181][0] === './/g' &&
+ relativeTests2[181][1] === 'f:/a' &&
+ relativeTests2[181][2] === 'f://g') {
+ relativeTests2.splice(181, 1);
+}
+relativeTests2.forEach(function(relativeTest) {
+ let actual = url.resolveObject(url.parse(relativeTest[1]), relativeTest[0]);
+ let expected = url.parse(relativeTest[2]);
+
+ assert.deepStrictEqual(
+ actual,
+ expected,
+ `expected ${inspect(expected)} but got ${inspect(actual)}`
+ );
+
+ expected = url.format(relativeTest[2]);
+ actual = url.format(actual);
+
+ assert.strictEqual(actual, expected,
+ `format(${relativeTest[1]}) == ${expected}\n` +
+ `actual: ${actual}`);
+});
diff --git a/tests/node_compat/test/parallel/test-url-urltooptions.js b/tests/node_compat/test/parallel/test-url-urltooptions.js
new file mode 100644
index 000000000..05813f0ae
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-url-urltooptions.js
@@ -0,0 +1,45 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 16.11.1
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+'use strict';
+require('../common');
+const assert = require('assert');
+const { urlToHttpOptions } = require('url');
+
+// Test urlToHttpOptions
+const urlObj = new URL('http://user:pass@foo.bar.com:21/aaa/zzz?l=24#test');
+const opts = urlToHttpOptions(urlObj);
+assert.strictEqual(opts instanceof URL, false);
+assert.strictEqual(opts.protocol, 'http:');
+assert.strictEqual(opts.auth, 'user:pass');
+assert.strictEqual(opts.hostname, 'foo.bar.com');
+assert.strictEqual(opts.port, 21);
+assert.strictEqual(opts.path, '/aaa/zzz?l=24');
+assert.strictEqual(opts.pathname, '/aaa/zzz');
+assert.strictEqual(opts.search, '?l=24');
+assert.strictEqual(opts.hash, '#test');
+
+const { hostname } = urlToHttpOptions(new URL('http://[::1]:21'));
+assert.strictEqual(hostname, '::1');
+
+// If a WHATWG URL object is copied, it is possible that the resulting copy
+// contains the Symbols that Node uses for brand checking, but not the data
+// properties, which are getters. Verify that urlToHttpOptions() can handle
+// such a case.
+const copiedUrlObj = { ...urlObj };
+const copiedOpts = urlToHttpOptions(copiedUrlObj);
+assert.strictEqual(copiedOpts instanceof URL, false);
+assert.strictEqual(copiedOpts.protocol, undefined);
+assert.strictEqual(copiedOpts.auth, undefined);
+assert.strictEqual(copiedOpts.hostname, undefined);
+// TODO(wafuwafu13): Fix `AssertionError: Values have the same structure but are not reference-equal`
+// assert.strictEqual(copiedOpts.port, NaN);
+assert.strictEqual(copiedOpts.path, '');
+assert.strictEqual(copiedOpts.pathname, undefined);
+assert.strictEqual(copiedOpts.search, undefined);
+assert.strictEqual(copiedOpts.hash, undefined);
+assert.strictEqual(copiedOpts.href, undefined);
diff --git a/tests/node_compat/test/parallel/test-util-deprecate-invalid-code.js b/tests/node_compat/test/parallel/test-util-deprecate-invalid-code.js
new file mode 100644
index 000000000..19093a3ae
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-util-deprecate-invalid-code.js
@@ -0,0 +1,21 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const assert = require('assert');
+const util = require('util');
+
+[1, true, false, null, {}].forEach((notString) => {
+ assert.throws(() => util.deprecate(() => {}, 'message', notString), {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: 'The "code" argument must be of type string.' +
+ common.invalidArgTypeHelper(notString)
+ });
+});
diff --git a/tests/node_compat/test/parallel/test-util-deprecate.js b/tests/node_compat/test/parallel/test-util-deprecate.js
new file mode 100644
index 000000000..2394caa22
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-util-deprecate.js
@@ -0,0 +1,64 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+require('../common');
+
+// Tests basic functionality of util.deprecate().
+
+const assert = require('assert');
+const util = require('util');
+
+const expectedWarnings = new Map();
+
+// Emits deprecation only once if same function is called.
+{
+ const msg = 'fhqwhgads';
+ const fn = util.deprecate(() => {}, msg);
+ expectedWarnings.set(msg, { code: undefined, count: 1 });
+ fn();
+ fn();
+}
+
+// Emits deprecation twice for different functions.
+{
+ const msg = 'sterrance';
+ const fn1 = util.deprecate(() => {}, msg);
+ const fn2 = util.deprecate(() => {}, msg);
+ expectedWarnings.set(msg, { code: undefined, count: 2 });
+ fn1();
+ fn2();
+}
+
+// Emits deprecation only once if optional code is the same, even for different
+// functions.
+{
+ const msg = 'cannonmouth';
+ const code = 'deprecatesque';
+ const fn1 = util.deprecate(() => {}, msg, code);
+ const fn2 = util.deprecate(() => {}, msg, code);
+ expectedWarnings.set(msg, { code, count: 1 });
+ fn1();
+ fn2();
+ fn1();
+ fn2();
+}
+
+process.on('warning', (warning) => {
+ assert.strictEqual(warning.name, 'DeprecationWarning');
+ assert.ok(expectedWarnings.has(warning.message));
+ const expected = expectedWarnings.get(warning.message);
+ assert.strictEqual(warning.code, expected.code);
+ expected.count = expected.count - 1;
+ if (expected.count === 0)
+ expectedWarnings.delete(warning.message);
+});
+
+process.on('exit', () => {
+ assert.deepStrictEqual(expectedWarnings, new Map());
+});
diff --git a/tests/node_compat/test/parallel/test-util-format.js b/tests/node_compat/test/parallel/test-util-format.js
new file mode 100644
index 000000000..9d474c481
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-util-format.js
@@ -0,0 +1,504 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 16.13.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+require('../common');
+const assert = require('assert');
+const util = require('util');
+const symbol = Symbol('foo');
+
+assert.strictEqual(util.format(), '');
+assert.strictEqual(util.format(''), '');
+assert.strictEqual(util.format([]), '[]');
+assert.strictEqual(util.format([0]), '[ 0 ]');
+assert.strictEqual(util.format({}), '{}');
+assert.strictEqual(util.format({ foo: 42 }), '{ foo: 42 }');
+assert.strictEqual(util.format(null), 'null');
+assert.strictEqual(util.format(true), 'true');
+assert.strictEqual(util.format(false), 'false');
+assert.strictEqual(util.format('test'), 'test');
+
+// CHECKME this is for console.log() compatibility - but is it *right*?
+assert.strictEqual(util.format('foo', 'bar', 'baz'), 'foo bar baz');
+
+// ES6 Symbol handling
+assert.strictEqual(util.format(symbol), 'Symbol(foo)');
+assert.strictEqual(util.format('foo', symbol), 'foo Symbol(foo)');
+assert.strictEqual(util.format('%s', symbol), 'Symbol(foo)');
+assert.strictEqual(util.format('%j', symbol), 'undefined');
+
+// Number format specifier
+assert.strictEqual(util.format('%d'), '%d');
+assert.strictEqual(util.format('%d', 42.0), '42');
+assert.strictEqual(util.format('%d', 42), '42');
+assert.strictEqual(util.format('%d', '42'), '42');
+assert.strictEqual(util.format('%d', '42.0'), '42');
+assert.strictEqual(util.format('%d', 1.5), '1.5');
+assert.strictEqual(util.format('%d', -0.5), '-0.5');
+assert.strictEqual(util.format('%d', -0.0), '-0');
+assert.strictEqual(util.format('%d', ''), '0');
+assert.strictEqual(util.format('%d', ' -0.000'), '-0');
+assert.strictEqual(util.format('%d', Symbol()), 'NaN');
+assert.strictEqual(util.format('%d', Infinity), 'Infinity');
+assert.strictEqual(util.format('%d', -Infinity), '-Infinity');
+assert.strictEqual(util.format('%d %d', 42, 43), '42 43');
+assert.strictEqual(util.format('%d %d', 42), '42 %d');
+assert.strictEqual(
+ util.format('%d', 1180591620717411303424),
+ '1.1805916207174113e+21'
+);
+assert.strictEqual(
+ util.format('%d', 1180591620717411303424n),
+ '1180591620717411303424n'
+);
+assert.strictEqual(
+ util.format('%d %d', 1180591620717411303424n, 12345678901234567890123n),
+ '1180591620717411303424n 12345678901234567890123n'
+);
+
+// Integer format specifier
+assert.strictEqual(util.format('%i'), '%i');
+assert.strictEqual(util.format('%i', 42.0), '42');
+assert.strictEqual(util.format('%i', 42), '42');
+assert.strictEqual(util.format('%i', '42'), '42');
+assert.strictEqual(util.format('%i', '42.0'), '42');
+assert.strictEqual(util.format('%i', 1.5), '1');
+assert.strictEqual(util.format('%i', -0.5), '-0');
+assert.strictEqual(util.format('%i', ''), 'NaN');
+assert.strictEqual(util.format('%i', Infinity), 'NaN');
+assert.strictEqual(util.format('%i', -Infinity), 'NaN');
+assert.strictEqual(util.format('%i', Symbol()), 'NaN');
+assert.strictEqual(util.format('%i %i', 42, 43), '42 43');
+assert.strictEqual(util.format('%i %i', 42), '42 %i');
+assert.strictEqual(
+ util.format('%i', 1180591620717411303424),
+ '1'
+);
+assert.strictEqual(
+ util.format('%i', 1180591620717411303424n),
+ '1180591620717411303424n'
+);
+assert.strictEqual(
+ util.format('%i %i', 1180591620717411303424n, 12345678901234567890123n),
+ '1180591620717411303424n 12345678901234567890123n'
+);
+
+assert.strictEqual(
+ util.format('%d %i', 1180591620717411303424n, 12345678901234567890123n),
+ '1180591620717411303424n 12345678901234567890123n'
+);
+
+assert.strictEqual(
+ util.format('%i %d', 1180591620717411303424n, 12345678901234567890123n),
+ '1180591620717411303424n 12345678901234567890123n'
+);
+
+// Float format specifier
+assert.strictEqual(util.format('%f'), '%f');
+assert.strictEqual(util.format('%f', 42.0), '42');
+assert.strictEqual(util.format('%f', 42), '42');
+assert.strictEqual(util.format('%f', '42'), '42');
+assert.strictEqual(util.format('%f', '-0.0'), '-0');
+assert.strictEqual(util.format('%f', '42.0'), '42');
+assert.strictEqual(util.format('%f', 1.5), '1.5');
+assert.strictEqual(util.format('%f', -0.5), '-0.5');
+assert.strictEqual(util.format('%f', Math.PI), '3.141592653589793');
+assert.strictEqual(util.format('%f', ''), 'NaN');
+assert.strictEqual(util.format('%f', Symbol('foo')), 'NaN');
+assert.strictEqual(util.format('%f', 5n), '5');
+assert.strictEqual(util.format('%f', Infinity), 'Infinity');
+assert.strictEqual(util.format('%f', -Infinity), '-Infinity');
+assert.strictEqual(util.format('%f %f', 42, 43), '42 43');
+assert.strictEqual(util.format('%f %f', 42), '42 %f');
+
+// String format specifier
+assert.strictEqual(util.format('%s'), '%s');
+assert.strictEqual(util.format('%s', undefined), 'undefined');
+assert.strictEqual(util.format('%s', null), 'null');
+assert.strictEqual(util.format('%s', 'foo'), 'foo');
+assert.strictEqual(util.format('%s', 42), '42');
+assert.strictEqual(util.format('%s', '42'), '42');
+assert.strictEqual(util.format('%s', -0), '-0');
+assert.strictEqual(util.format('%s', '-0.0'), '-0.0');
+assert.strictEqual(util.format('%s %s', 42, 43), '42 43');
+assert.strictEqual(util.format('%s %s', 42), '42 %s');
+assert.strictEqual(util.format('%s', 42n), '42n');
+assert.strictEqual(util.format('%s', Symbol('foo')), 'Symbol(foo)');
+assert.strictEqual(util.format('%s', true), 'true');
+assert.strictEqual(util.format('%s', { a: [1, 2, 3] }), '{ a: [Array] }');
+assert.strictEqual(util.format('%s', { toString() { return 'Foo'; } }), 'Foo');
+assert.strictEqual(util.format('%s', { toString: 5 }), '{ toString: 5 }');
+assert.strictEqual(util.format('%s', () => 5), '() => 5');
+assert.strictEqual(util.format('%s', Infinity), 'Infinity');
+assert.strictEqual(util.format('%s', -Infinity), '-Infinity');
+
+// TODO(wafuwafu13): Fix
+// // String format specifier including `toString` properties on the prototype.
+// {
+// class Foo { toString() { return 'Bar'; } }
+// assert.strictEqual(util.format('%s', new Foo()), 'Bar');
+// assert.strictEqual(
+// util.format('%s', Object.setPrototypeOf(new Foo(), null)),
+// '[Foo: null prototype] {}'
+// );
+// global.Foo = Foo;
+// assert.strictEqual(util.format('%s', new Foo()), 'Bar');
+// delete global.Foo;
+// class Bar { abc = true; }
+// assert.strictEqual(util.format('%s', new Bar()), 'Bar { abc: true }');
+// class Foobar extends Array { aaa = true; }
+// assert.strictEqual(
+// util.format('%s', new Foobar(5)),
+// 'Foobar(5) [ <5 empty items>, aaa: true ]'
+// );
+
+// // Subclassing:
+// class B extends Foo {}
+
+// function C() {}
+// C.prototype.toString = function() {
+// return 'Custom';
+// };
+
+// function D() {
+// C.call(this);
+// }
+// D.prototype = Object.create(C.prototype);
+
+// assert.strictEqual(
+// util.format('%s', new B()),
+// 'Bar'
+// );
+// assert.strictEqual(
+// util.format('%s', new C()),
+// 'Custom'
+// );
+// assert.strictEqual(
+// util.format('%s', new D()),
+// 'Custom'
+// );
+
+// D.prototype.constructor = D;
+// assert.strictEqual(
+// util.format('%s', new D()),
+// 'Custom'
+// );
+
+// D.prototype.constructor = null;
+// assert.strictEqual(
+// util.format('%s', new D()),
+// 'Custom'
+// );
+
+// D.prototype.constructor = { name: 'Foobar' };
+// assert.strictEqual(
+// util.format('%s', new D()),
+// 'Custom'
+// );
+
+// Object.defineProperty(D.prototype, 'constructor', {
+// get() {
+// throw new Error();
+// },
+// configurable: true
+// });
+// assert.strictEqual(
+// util.format('%s', new D()),
+// 'Custom'
+// );
+
+// assert.strictEqual(
+// util.format('%s', Object.create(null)),
+// '[Object: null prototype] {}'
+// );
+// }
+
+// JSON format specifier
+assert.strictEqual(util.format('%j'), '%j');
+assert.strictEqual(util.format('%j', 42), '42');
+assert.strictEqual(util.format('%j', '42'), '"42"');
+assert.strictEqual(util.format('%j %j', 42, 43), '42 43');
+assert.strictEqual(util.format('%j %j', 42), '42 %j');
+
+// Object format specifier
+const obj = {
+ foo: 'bar',
+ foobar: 1,
+ func: function() {}
+};
+const nestedObj = {
+ foo: 'bar',
+ foobar: {
+ foo: 'bar',
+ func: function() {}
+ }
+};
+const nestedObj2 = {
+ foo: 'bar',
+ foobar: 1,
+ func: [{ a: function() {} }]
+};
+assert.strictEqual(util.format('%o'), '%o');
+assert.strictEqual(util.format('%o', 42), '42');
+assert.strictEqual(util.format('%o', 'foo'), '\'foo\'');
+assert.strictEqual(
+ util.format('%o', obj),
+ '{\n' +
+ ' foo: \'bar\',\n' +
+ ' foobar: 1,\n' +
+ ' func: <ref *1> [Function: func] {\n' +
+ ' [length]: 0,\n' +
+ ' [name]: \'func\',\n' +
+ ' [prototype]: { [constructor]: [Circular *1] }\n' +
+ ' }\n' +
+ '}');
+assert.strictEqual(
+ util.format('%o', nestedObj2),
+ '{\n' +
+ ' foo: \'bar\',\n' +
+ ' foobar: 1,\n' +
+ ' func: [\n' +
+ ' {\n' +
+ ' a: <ref *1> [Function: a] {\n' +
+ ' [length]: 0,\n' +
+ ' [name]: \'a\',\n' +
+ ' [prototype]: { [constructor]: [Circular *1] }\n' +
+ ' }\n' +
+ ' },\n' +
+ ' [length]: 1\n' +
+ ' ]\n' +
+ '}');
+assert.strictEqual(
+ util.format('%o', nestedObj),
+ '{\n' +
+ ' foo: \'bar\',\n' +
+ ' foobar: {\n' +
+ ' foo: \'bar\',\n' +
+ ' func: <ref *1> [Function: func] {\n' +
+ ' [length]: 0,\n' +
+ ' [name]: \'func\',\n' +
+ ' [prototype]: { [constructor]: [Circular *1] }\n' +
+ ' }\n' +
+ ' }\n' +
+ '}');
+assert.strictEqual(
+ util.format('%o %o', obj, obj),
+ '{\n' +
+ ' foo: \'bar\',\n' +
+ ' foobar: 1,\n' +
+ ' func: <ref *1> [Function: func] {\n' +
+ ' [length]: 0,\n' +
+ ' [name]: \'func\',\n' +
+ ' [prototype]: { [constructor]: [Circular *1] }\n' +
+ ' }\n' +
+ '} {\n' +
+ ' foo: \'bar\',\n' +
+ ' foobar: 1,\n' +
+ ' func: <ref *1> [Function: func] {\n' +
+ ' [length]: 0,\n' +
+ ' [name]: \'func\',\n' +
+ ' [prototype]: { [constructor]: [Circular *1] }\n' +
+ ' }\n' +
+ '}');
+assert.strictEqual(
+ util.format('%o %o', obj),
+ '{\n' +
+ ' foo: \'bar\',\n' +
+ ' foobar: 1,\n' +
+ ' func: <ref *1> [Function: func] {\n' +
+ ' [length]: 0,\n' +
+ ' [name]: \'func\',\n' +
+ ' [prototype]: { [constructor]: [Circular *1] }\n' +
+ ' }\n' +
+ '} %o');
+
+assert.strictEqual(util.format('%O'), '%O');
+assert.strictEqual(util.format('%O', 42), '42');
+assert.strictEqual(util.format('%O', 'foo'), '\'foo\'');
+assert.strictEqual(
+ util.format('%O', obj),
+ '{ foo: \'bar\', foobar: 1, func: [Function: func] }');
+assert.strictEqual(
+ util.format('%O', nestedObj),
+ '{ foo: \'bar\', foobar: { foo: \'bar\', func: [Function: func] } }');
+assert.strictEqual(
+ util.format('%O %O', obj, obj),
+ '{ foo: \'bar\', foobar: 1, func: [Function: func] } ' +
+ '{ foo: \'bar\', foobar: 1, func: [Function: func] }');
+assert.strictEqual(
+ util.format('%O %O', obj),
+ '{ foo: \'bar\', foobar: 1, func: [Function: func] } %O');
+
+// Various format specifiers
+assert.strictEqual(util.format('%%s%s', 'foo'), '%sfoo');
+assert.strictEqual(util.format('%s:%s'), '%s:%s');
+assert.strictEqual(util.format('%s:%s', undefined), 'undefined:%s');
+assert.strictEqual(util.format('%s:%s', 'foo'), 'foo:%s');
+assert.strictEqual(util.format('%s:%i', 'foo'), 'foo:%i');
+assert.strictEqual(util.format('%s:%f', 'foo'), 'foo:%f');
+assert.strictEqual(util.format('%s:%s', 'foo', 'bar'), 'foo:bar');
+assert.strictEqual(util.format('%s:%s', 'foo', 'bar', 'baz'), 'foo:bar baz');
+assert.strictEqual(util.format('%%%s%%', 'hi'), '%hi%');
+assert.strictEqual(util.format('%%%s%%%%', 'hi'), '%hi%%');
+assert.strictEqual(util.format('%sbc%%def', 'a'), 'abc%def');
+assert.strictEqual(util.format('%d:%d', 12, 30), '12:30');
+assert.strictEqual(util.format('%d:%d', 12), '12:%d');
+assert.strictEqual(util.format('%d:%d'), '%d:%d');
+assert.strictEqual(util.format('%i:%i', 12, 30), '12:30');
+assert.strictEqual(util.format('%i:%i', 12), '12:%i');
+assert.strictEqual(util.format('%i:%i'), '%i:%i');
+assert.strictEqual(util.format('%f:%f', 12, 30), '12:30');
+assert.strictEqual(util.format('%f:%f', 12), '12:%f');
+assert.strictEqual(util.format('%f:%f'), '%f:%f');
+assert.strictEqual(util.format('o: %j, a: %j', {}, []), 'o: {}, a: []');
+assert.strictEqual(util.format('o: %j, a: %j', {}), 'o: {}, a: %j');
+assert.strictEqual(util.format('o: %j, a: %j'), 'o: %j, a: %j');
+assert.strictEqual(util.format('o: %o, a: %O', {}, []), 'o: {}, a: []');
+assert.strictEqual(util.format('o: %o, a: %o', {}), 'o: {}, a: %o');
+assert.strictEqual(util.format('o: %O, a: %O'), 'o: %O, a: %O');
+
+
+// Invalid format specifiers
+assert.strictEqual(util.format('a% b', 'x'), 'a% b x');
+assert.strictEqual(util.format('percent: %d%, fraction: %d', 10, 0.1),
+ 'percent: 10%, fraction: 0.1');
+assert.strictEqual(util.format('abc%', 1), 'abc% 1');
+
+// Additional arguments after format specifiers
+assert.strictEqual(util.format('%i', 1, 'number'), '1 number');
+assert.strictEqual(util.format('%i', 1, () => {}), '1 [Function (anonymous)]');
+
+// %c from https://console.spec.whatwg.org/
+assert.strictEqual(util.format('%c'), '%c');
+assert.strictEqual(util.format('%cab'), '%cab');
+assert.strictEqual(util.format('%cab', 'color: blue'), 'ab');
+assert.strictEqual(util.format('%cab', 'color: blue', 'c'), 'ab c');
+
+{
+ const o = {};
+ o.o = o;
+ assert.strictEqual(util.format('%j', o), '[Circular]');
+}
+
+{
+ const o = {
+ toJSON() {
+ throw new Error('Not a circular object but still not serializable');
+ }
+ };
+ assert.throws(() => util.format('%j', o),
+ /^Error: Not a circular object but still not serializable$/);
+}
+
+// Errors
+const err = new Error('foo');
+assert.strictEqual(util.format(err), err.stack);
+class CustomError extends Error {
+ constructor(msg) {
+ super();
+ Object.defineProperty(this, 'message',
+ { value: msg, enumerable: false });
+ Object.defineProperty(this, 'name',
+ { value: 'CustomError', enumerable: false });
+ Error.captureStackTrace(this, CustomError);
+ }
+}
+const customError = new CustomError('bar');
+assert.strictEqual(util.format(customError), customError.stack);
+// Doesn't capture stack trace
+function BadCustomError(msg) {
+ Error.call(this);
+ Object.defineProperty(this, 'message',
+ { value: msg, enumerable: false });
+ Object.defineProperty(this, 'name',
+ { value: 'BadCustomError', enumerable: false });
+}
+Object.setPrototypeOf(BadCustomError.prototype, Error.prototype);
+Object.setPrototypeOf(BadCustomError, Error);
+assert.strictEqual(util.format(new BadCustomError('foo')),
+ '[BadCustomError: foo]');
+
+// The format of arguments should not depend on type of the first argument
+assert.strictEqual(util.format('1', '1'), '1 1');
+assert.strictEqual(util.format(1, '1'), '1 1');
+assert.strictEqual(util.format('1', 1), '1 1');
+assert.strictEqual(util.format(1, -0), '1 -0');
+assert.strictEqual(util.format('1', () => {}), '1 [Function (anonymous)]');
+assert.strictEqual(util.format(1, () => {}), '1 [Function (anonymous)]');
+assert.strictEqual(util.format('1', "'"), "1 '");
+assert.strictEqual(util.format(1, "'"), "1 '");
+assert.strictEqual(util.format('1', 'number'), '1 number');
+assert.strictEqual(util.format(1, 'number'), '1 number');
+assert.strictEqual(util.format(5n), '5n');
+assert.strictEqual(util.format(5n, 5n), '5n 5n');
+
+// Check `formatWithOptions`.
+assert.strictEqual(
+ util.formatWithOptions(
+ { colors: true },
+ true, undefined, Symbol(), 1, 5n, null, 'foobar'
+ ),
+ '\u001b[33mtrue\u001b[39m ' +
+ '\u001b[90mundefined\u001b[39m ' +
+ '\u001b[32mSymbol()\u001b[39m ' +
+ '\u001b[33m1\u001b[39m ' +
+ '\u001b[33m5n\u001b[39m ' +
+ '\u001b[1mnull\u001b[22m ' +
+ 'foobar'
+);
+
+// TODO(wafuwafu13): Fix
+// assert.strictEqual(
+// util.format(new SharedArrayBuffer(4)),
+// 'SharedArrayBuffer { [Uint8Contents]: <00 00 00 00>, byteLength: 4 }'
+// );
+
+assert.strictEqual(
+ util.formatWithOptions(
+ { colors: true, compact: 3 },
+ '%s', [ 1, { a: true }]
+ ),
+ '[ 1, [Object] ]'
+);
+
+[
+ undefined,
+ null,
+ false,
+ 5n,
+ 5,
+ 'test',
+ Symbol(),
+].forEach((invalidOptions) => {
+ assert.throws(() => {
+ util.formatWithOptions(invalidOptions, { a: true });
+ }, {
+ code: 'ERR_INVALID_ARG_TYPE',
+ message: /"inspectOptions".+object/
+ });
+});
diff --git a/tests/node_compat/test/parallel/test-util-inherits.js b/tests/node_compat/test/parallel/test-util-inherits.js
new file mode 100644
index 000000000..ac1ab596b
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-util-inherits.js
@@ -0,0 +1,117 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+require('../common');
+const assert = require('assert');
+const { inherits } = require('util');
+
+// Super constructor
+function A() {
+ this._a = 'a';
+}
+A.prototype.a = function() { return this._a; };
+
+// One level of inheritance
+function B(value) {
+ A.call(this);
+ this._b = value;
+}
+inherits(B, A);
+B.prototype.b = function() { return this._b; };
+
+assert.deepStrictEqual(
+ Object.getOwnPropertyDescriptor(B, 'super_'),
+ {
+ value: A,
+ enumerable: false,
+ configurable: true,
+ writable: true
+ }
+);
+
+const b = new B('b');
+assert.strictEqual(b.a(), 'a');
+assert.strictEqual(b.b(), 'b');
+assert.strictEqual(b.constructor, B);
+
+// Two levels of inheritance
+function C() {
+ B.call(this, 'b');
+ this._c = 'c';
+}
+inherits(C, B);
+C.prototype.c = function() { return this._c; };
+C.prototype.getValue = function() { return this.a() + this.b() + this.c(); };
+
+assert.strictEqual(C.super_, B);
+
+const c = new C();
+assert.strictEqual(c.getValue(), 'abc');
+assert.strictEqual(c.constructor, C);
+
+// Inherits can be called after setting prototype properties
+function D() {
+ C.call(this);
+ this._d = 'd';
+}
+
+D.prototype.d = function() { return this._d; };
+inherits(D, C);
+
+assert.strictEqual(D.super_, C);
+
+const d = new D();
+assert.strictEqual(d.c(), 'c');
+assert.strictEqual(d.d(), 'd');
+assert.strictEqual(d.constructor, D);
+
+// ES6 classes can inherit from a constructor function
+class E {
+ constructor() {
+ D.call(this);
+ this._e = 'e';
+ }
+ e() { return this._e; }
+}
+inherits(E, D);
+
+assert.strictEqual(E.super_, D);
+
+const e = new E();
+assert.strictEqual(e.getValue(), 'abc');
+assert.strictEqual(e.d(), 'd');
+assert.strictEqual(e.e(), 'e');
+assert.strictEqual(e.constructor, E);
+
+// Should throw with invalid arguments
+assert.throws(() => {
+ inherits(A, {});
+}, {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: 'The "superCtor.prototype" property must be of type object. ' +
+ 'Received undefined'
+});
+
+assert.throws(() => {
+ inherits(A, null);
+}, {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: 'The "superCtor" argument must be of type function. ' +
+ 'Received null'
+});
+
+assert.throws(() => {
+ inherits(null, A);
+}, {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: 'The "ctor" argument must be of type function. Received null'
+});
diff --git a/tests/node_compat/test/parallel/test-util-inspect-long-running.js b/tests/node_compat/test/parallel/test-util-inspect-long-running.js
new file mode 100644
index 000000000..67dc03ba4
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-util-inspect-long-running.js
@@ -0,0 +1,27 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+require('../common');
+
+// Test that huge objects don't crash due to exceeding the maximum heap size.
+
+const util = require('util');
+
+// Create a difficult to stringify object. Without the artificial limitation
+// this would crash or throw an maximum string size error.
+let last = {};
+const obj = last;
+
+for (let i = 0; i < 1000; i++) {
+ last.next = { circular: obj, last, obj: { a: 1, b: 2, c: true } };
+ last = last.next;
+ obj[i] = last;
+}
+
+util.inspect(obj, { depth: Infinity });
diff --git a/tests/node_compat/test/parallel/test-util-inspect-namespace.js b/tests/node_compat/test/parallel/test-util-inspect-namespace.js
new file mode 100644
index 000000000..786f05671
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-util-inspect-namespace.js
@@ -0,0 +1,28 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 16.13.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// Flags: --experimental-vm-modules
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+
+// TODO(wafuwafu13): Implement 'vm'
+// const { SourceTextModule } = require('vm');
+const { inspect } = require('util');
+
+// (async () => {
+// const m = new SourceTextModule('export const a = 1; export var b = 2');
+// await m.link(() => 0);
+// assert.strictEqual(
+// inspect(m.namespace),
+// '[Module: null prototype] { a: <uninitialized>, b: undefined }');
+// await m.evaluate();
+// assert.strictEqual(
+// inspect(m.namespace),
+// '[Module: null prototype] { a: 1, b: 2 }'
+// );
+// })().then(common.mustCall());
diff --git a/tests/node_compat/test/parallel/test-util-inspect-proxy.js b/tests/node_compat/test/parallel/test-util-inspect-proxy.js
new file mode 100644
index 000000000..ef78ab07a
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-util-inspect-proxy.js
@@ -0,0 +1,172 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 16.13.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// Flags: --expose-internals
+'use strict';
+
+require('../common');
+const assert = require('assert');
+const util = require('util');
+// TODO(wafuwafu13): Implement 'internal/test/binding'
+// const { internalBinding } = require('internal/test/binding');
+// const processUtil = internalBinding('util');
+const opts = { showProxy: true };
+
+// let proxyObj;
+// let called = false;
+// const target = {
+// [util.inspect.custom](depth, { showProxy }) {
+// if (showProxy === false) {
+// called = true;
+// if (proxyObj !== this) {
+// throw new Error('Failed');
+// }
+// }
+// return [1, 2, 3];
+// }
+// };
+
+// // TODO(wafuwafu13): Fix Uncaught Error
+// const handler = {
+// getPrototypeOf() { throw new Error('getPrototypeOf'); },
+// setPrototypeOf() { throw new Error('setPrototypeOf'); },
+// isExtensible() { throw new Error('isExtensible'); },
+// preventExtensions() { throw new Error('preventExtensions'); },
+// getOwnPropertyDescriptor() { throw new Error('getOwnPropertyDescriptor'); },
+// defineProperty() { throw new Error('defineProperty'); },
+// has() { throw new Error('has'); },
+// get() { throw new Error('get'); },
+// set() { throw new Error('set'); },
+// deleteProperty() { throw new Error('deleteProperty'); },
+// ownKeys() { throw new Error('ownKeys'); },
+// apply() { throw new Error('apply'); },
+// construct() { throw new Error('construct'); }
+// };
+// proxyObj = new Proxy(target, handler);
+
+// // Inspecting the proxy should not actually walk it's properties
+// util.inspect(proxyObj, opts);
+
+// // Make sure inspecting object does not trigger any proxy traps.
+// util.format('%s', proxyObj);
+
+// TODO(wafuwafu13): Implement processUtil
+// // getProxyDetails is an internal method, not intended for public use.
+// // This is here to test that the internals are working correctly.
+// let details = processUtil.getProxyDetails(proxyObj, true);
+// assert.strictEqual(target, details[0]);
+// assert.strictEqual(handler, details[1]);
+
+// details = processUtil.getProxyDetails(proxyObj);
+// assert.strictEqual(target, details[0]);
+// assert.strictEqual(handler, details[1]);
+
+// details = processUtil.getProxyDetails(proxyObj, false);
+// assert.strictEqual(target, details);
+
+// assert.strictEqual(
+// util.inspect(proxyObj, opts),
+// 'Proxy [\n' +
+// ' [ 1, 2, 3 ],\n' +
+// ' {\n' +
+// ' getPrototypeOf: [Function: getPrototypeOf],\n' +
+// ' setPrototypeOf: [Function: setPrototypeOf],\n' +
+// ' isExtensible: [Function: isExtensible],\n' +
+// ' preventExtensions: [Function: preventExtensions],\n' +
+// ' getOwnPropertyDescriptor: [Function: getOwnPropertyDescriptor],\n' +
+// ' defineProperty: [Function: defineProperty],\n' +
+// ' has: [Function: has],\n' +
+// ' get: [Function: get],\n' +
+// ' set: [Function: set],\n' +
+// ' deleteProperty: [Function: deleteProperty],\n' +
+// ' ownKeys: [Function: ownKeys],\n' +
+// ' apply: [Function: apply],\n' +
+// ' construct: [Function: construct]\n' +
+// ' }\n' +
+// ']'
+// );
+
+// TODO(wafuwafu13): Implement processUtil
+// // Using getProxyDetails with non-proxy returns undefined
+// assert.strictEqual(processUtil.getProxyDetails({}), undefined);
+
+// // Inspecting a proxy without the showProxy option set to true should not
+// // trigger any proxy handlers.
+// assert.strictEqual(util.inspect(proxyObj), '[ 1, 2, 3 ]');
+// assert(called);
+
+// Yo dawg, I heard you liked Proxy so I put a Proxy
+// inside your Proxy that proxies your Proxy's Proxy.
+const proxy1 = new Proxy({}, {});
+const proxy2 = new Proxy(proxy1, {});
+const proxy3 = new Proxy(proxy2, proxy1);
+const proxy4 = new Proxy(proxy1, proxy2);
+const proxy5 = new Proxy(proxy3, proxy4);
+const proxy6 = new Proxy(proxy5, proxy5);
+const expected0 = '{}';
+const expected1 = 'Proxy [ {}, {} ]';
+const expected2 = 'Proxy [ Proxy [ {}, {} ], {} ]';
+const expected3 = 'Proxy [ Proxy [ Proxy [ {}, {} ], {} ], Proxy [ {}, {} ] ]';
+const expected4 = 'Proxy [ Proxy [ {}, {} ], Proxy [ Proxy [ {}, {} ], {} ] ]';
+const expected5 = 'Proxy [\n ' +
+ 'Proxy [ Proxy [ Proxy [Array], {} ], Proxy [ {}, {} ] ],\n' +
+ ' Proxy [ Proxy [ {}, {} ], Proxy [ Proxy [Array], {} ] ]' +
+ '\n]';
+const expected6 = 'Proxy [\n' +
+ ' Proxy [\n' +
+ ' Proxy [ Proxy [Array], Proxy [Array] ],\n' +
+ ' Proxy [ Proxy [Array], Proxy [Array] ]\n' +
+ ' ],\n' +
+ ' Proxy [\n' +
+ ' Proxy [ Proxy [Array], Proxy [Array] ],\n' +
+ ' Proxy [ Proxy [Array], Proxy [Array] ]\n' +
+ ' ]\n' +
+ ']';
+// assert.strictEqual(
+// util.inspect(proxy1, { showProxy: 1, depth: null }),
+// expected1);
+// assert.strictEqual(util.inspect(proxy2, opts), expected2);
+// assert.strictEqual(util.inspect(proxy3, opts), expected3);
+// assert.strictEqual(util.inspect(proxy4, opts), expected4);
+// assert.strictEqual(util.inspect(proxy5, opts), expected5);
+// assert.strictEqual(util.inspect(proxy6, opts), expected6);
+// assert.strictEqual(util.inspect(proxy1), expected0);
+// assert.strictEqual(util.inspect(proxy2), expected0);
+// assert.strictEqual(util.inspect(proxy3), expected0);
+// assert.strictEqual(util.inspect(proxy4), expected0);
+// assert.strictEqual(util.inspect(proxy5), expected0);
+// assert.strictEqual(util.inspect(proxy6), expected0);
+
+// // Just for fun, let's create a Proxy using Arrays.
+// const proxy7 = new Proxy([], []);
+// const expected7 = 'Proxy [ [], [] ]';
+// assert.strictEqual(util.inspect(proxy7, opts), expected7);
+// assert.strictEqual(util.inspect(proxy7), '[]');
+
+// // Now we're just getting silly, right?
+// const proxy8 = new Proxy(Date, []);
+// const proxy9 = new Proxy(Date, String);
+// const expected8 = 'Proxy [ [Function: Date], [] ]';
+// const expected9 = 'Proxy [ [Function: Date], [Function: String] ]';
+// assert.strictEqual(util.inspect(proxy8, opts), expected8);
+// assert.strictEqual(util.inspect(proxy9, opts), expected9);
+// assert.strictEqual(util.inspect(proxy8), '[Function: Date]');
+// assert.strictEqual(util.inspect(proxy9), '[Function: Date]');
+
+// const proxy10 = new Proxy(() => {}, {});
+// const proxy11 = new Proxy(() => {}, {
+// get() {
+// return proxy11;
+// },
+// apply() {
+// return proxy11;
+// }
+// });
+// const expected10 = '[Function (anonymous)]';
+// const expected11 = '[Function (anonymous)]';
+// assert.strictEqual(util.inspect(proxy10), expected10);
+// assert.strictEqual(util.inspect(proxy11), expected11);
diff --git a/tests/node_compat/test/parallel/test-util-inspect.js b/tests/node_compat/test/parallel/test-util-inspect.js
new file mode 100644
index 000000000..17fafed2e
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-util-inspect.js
@@ -0,0 +1,3201 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 16.13.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// Flags: --expose-internals
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+// TODO(wafuwafu13): Implement 'internal/test/binding'
+// const { internalBinding } = require('internal/test/binding');
+// const JSStream = internalBinding('js_stream').JSStream;
+const util = require('util');
+const vm = require('vm');
+// TODO(wafuwafu13): Implement 'v8'
+// const v8 = require('v8');
+// TODO(wafuwafu13): Implement 'internal/test/binding'
+// const { previewEntries } = internalBinding('util');
+const { inspect } = util;
+// TODO(wafuwafu13): Implement MessageChannel
+// const { MessageChannel } = require('worker_threads');
+
+assert.strictEqual(util.inspect(1), '1');
+assert.strictEqual(util.inspect(false), 'false');
+assert.strictEqual(util.inspect(''), "''");
+assert.strictEqual(util.inspect('hello'), "'hello'");
+assert.strictEqual(util.inspect(function abc() {}), '[Function: abc]');
+assert.strictEqual(util.inspect(() => {}), '[Function (anonymous)]');
+assert.strictEqual(
+ util.inspect(async function() {}),
+ '[AsyncFunction (anonymous)]'
+);
+assert.strictEqual(util.inspect(async () => {}), '[AsyncFunction (anonymous)]');
+
+// Special function inspection.
+{
+ const fn = (() => function*() {})();
+ assert.strictEqual(
+ util.inspect(fn),
+ '[GeneratorFunction (anonymous)]'
+ );
+ // TODO(wafuwafu13): Fix
+ // assert.strictEqual(
+ // util.inspect(async function* abc() {}),
+ // '[AsyncGeneratorFunction: abc]'
+ // );
+ Object.setPrototypeOf(fn, Object.getPrototypeOf(async () => {}));
+ // TODO(wafuwafu13): Fix
+ // assert.strictEqual(
+ // util.inspect(fn),
+ // '[GeneratorFunction (anonymous)] AsyncFunction'
+ // );
+ Object.defineProperty(fn, 'name', { value: 5, configurable: true });
+ // TODO(wafuwafu13): Fix
+ // assert.strictEqual(
+ // util.inspect(fn),
+ // '[GeneratorFunction: 5] AsyncFunction'
+ // );
+ Object.defineProperty(fn, Symbol.toStringTag, {
+ value: 'Foobar',
+ configurable: true
+ });
+ // TODO(wafuwafu13): Fix
+ // assert.strictEqual(
+ // util.inspect({ ['5']: fn }),
+ // "{ '5': [GeneratorFunction: 5] AsyncFunction [Foobar] }"
+ // );
+ Object.defineProperty(fn, 'name', { value: '5', configurable: true });
+ Object.setPrototypeOf(fn, null);
+ // TODO(wafuwafu13): Fix
+ // assert.strictEqual(
+ // util.inspect(fn),
+ // '[GeneratorFunction (null prototype): 5] [Foobar]'
+ // );
+ // assert.strictEqual(
+ // util.inspect({ ['5']: fn }),
+ // "{ '5': [GeneratorFunction (null prototype): 5] [Foobar] }"
+ // );
+}
+
+assert.strictEqual(util.inspect(undefined), 'undefined');
+assert.strictEqual(util.inspect(null), 'null');
+assert.strictEqual(util.inspect(/foo(bar\n)?/gi), '/foo(bar\\n)?/gi');
+assert.strictEqual(
+ util.inspect(new Date('Sun, 14 Feb 2010 11:48:40 GMT')),
+ new Date('2010-02-14T12:48:40+01:00').toISOString()
+);
+assert.strictEqual(util.inspect(new Date('')), (new Date('')).toString());
+assert.strictEqual(util.inspect('\n\x01'), "'\\n\\x01'");
+// TODO(@crowlKats)
+//assert.strictEqual(
+// util.inspect(`${Array(75).fill(1)}'\n\x1d\n\x03\x85\x7f\x7e\x9f\xa0`),
+// // eslint-disable-next-line no-irregular-whitespace
+// `"${Array(75).fill(1)}'\\n" +\n '\\x1D\\n' +\n '\\x03\\x85\\x7F~\\x9F '`
+//);
+assert.strictEqual(util.inspect([]), '[]');
+assert.strictEqual(util.inspect(Object.create([])), 'Array {}');
+assert.strictEqual(util.inspect([1, 2]), '[ 1, 2 ]');
+assert.strictEqual(util.inspect([1, [2, 3]]), '[ 1, [ 2, 3 ] ]');
+assert.strictEqual(util.inspect({}), '{}');
+assert.strictEqual(util.inspect({ a: 1 }), '{ a: 1 }');
+assert.strictEqual(util.inspect({ a: function() {} }), '{ a: [Function: a] }');
+assert.strictEqual(util.inspect({ a: () => {} }), '{ a: [Function: a] }');
+// eslint-disable-next-line func-name-matching
+assert.strictEqual(util.inspect({ a: async function abc() {} }),
+ '{ a: [AsyncFunction: abc] }');
+assert.strictEqual(util.inspect({ a: async () => {} }),
+ '{ a: [AsyncFunction: a] }');
+assert.strictEqual(util.inspect({ a: function*() {} }),
+ '{ a: [GeneratorFunction: a] }');
+assert.strictEqual(util.inspect({ a: 1, b: 2 }), '{ a: 1, b: 2 }');
+assert.strictEqual(util.inspect({ 'a': {} }), '{ a: {} }');
+assert.strictEqual(util.inspect({ 'a': { 'b': 2 } }), '{ a: { b: 2 } }');
+assert.strictEqual(util.inspect({ 'a': { 'b': { 'c': { 'd': 2 } } } }),
+ '{ a: { b: { c: [Object] } } }');
+assert.strictEqual(
+ util.inspect({ 'a': { 'b': { 'c': { 'd': 2 } } } }, false, null),
+ '{\n a: { b: { c: { d: 2 } } }\n}');
+// TODO(wafuwafu13): Fix
+// assert.strictEqual(util.inspect([1, 2, 3], true), '[ 1, 2, 3, [length]: 3 ]');
+assert.strictEqual(util.inspect({ 'a': { 'b': { 'c': 2 } } }, false, 0),
+ '{ a: [Object] }');
+assert.strictEqual(util.inspect({ 'a': { 'b': { 'c': 2 } } }, false, 1),
+ '{ a: { b: [Object] } }');
+assert.strictEqual(util.inspect({ 'a': { 'b': ['c'] } }, false, 1),
+ '{ a: { b: [Array] } }');
+// TODO(wafuwafu13): Fix
+// assert.strictEqual(util.inspect(new Uint8Array(0)), 'Uint8Array(0) []');
+// assert(inspect(new Uint8Array(0), { showHidden: true }).includes('[buffer]'));
+assert.strictEqual(
+ util.inspect(
+ Object.create(
+ {},
+ { visible: { value: 1, enumerable: true }, hidden: { value: 2 } }
+ )
+ ),
+ '{ visible: 1 }'
+);
+// TODO(wafuwafu13): Fix
+// assert.strictEqual(
+// util.inspect(
+// Object.assign(new String('hello'), { [Symbol('foo')]: 123 }),
+// { showHidden: true }
+// ),
+// "[String: 'hello'] { [length]: 5, [Symbol(foo)]: 123 }"
+// );
+
+// TODO(wafuwafu13): Implement JSStream
+// assert.match(util.inspect((new JSStream())._externalStream),
+// /^\[External: [0-9a-f]+\]$/);
+
+{
+ const regexp = /regexp/;
+ regexp.aprop = 42;
+ assert.strictEqual(util.inspect({ a: regexp }, false, 0), '{ a: /regexp/ }');
+}
+
+assert.match(
+ util.inspect({ a: { a: { a: { a: {} } } } }, undefined, undefined, true),
+ /Object/
+);
+assert.doesNotMatch(
+ util.inspect({ a: { a: { a: { a: {} } } } }, undefined, null, true),
+ /Object/
+);
+
+// TODO(wafuwafu13): Fix
+// {
+// const showHidden = true;
+// const ab = new Uint8Array([1, 2, 3, 4]).buffer;
+// const dv = new DataView(ab, 1, 2);
+// assert.strictEqual(
+// util.inspect(ab, showHidden),
+// 'ArrayBuffer { [Uint8Contents]: <01 02 03 04>, byteLength: 4 }'
+// );
+// assert.strictEqual(util.inspect(new DataView(ab, 1, 2), showHidden),
+// 'DataView {\n' +
+// ' byteLength: 2,\n' +
+// ' byteOffset: 1,\n' +
+// ' buffer: ArrayBuffer {' +
+// ' [Uint8Contents]: <01 02 03 04>, byteLength: 4 }\n}');
+// assert.strictEqual(
+// util.inspect(ab, showHidden),
+// 'ArrayBuffer { [Uint8Contents]: <01 02 03 04>, byteLength: 4 }'
+// );
+// assert.strictEqual(util.inspect(dv, showHidden),
+// 'DataView {\n' +
+// ' byteLength: 2,\n' +
+// ' byteOffset: 1,\n' +
+// ' buffer: ArrayBuffer { [Uint8Contents]: ' +
+// '<01 02 03 04>, byteLength: 4 }\n}');
+// ab.x = 42;
+// dv.y = 1337;
+// assert.strictEqual(util.inspect(ab, showHidden),
+// 'ArrayBuffer { [Uint8Contents]: <01 02 03 04>, ' +
+// 'byteLength: 4, x: 42 }');
+// assert.strictEqual(util.inspect(dv, showHidden),
+// 'DataView {\n' +
+// ' byteLength: 2,\n' +
+// ' byteOffset: 1,\n' +
+// ' buffer: ArrayBuffer { [Uint8Contents]: <01 02 03 04>,' +
+// ' byteLength: 4, x: 42 },\n' +
+// ' y: 1337\n}');
+// }
+
+// TODO(wafuwafu13): Implement `MessageChannel`
+// {
+// const ab = new ArrayBuffer(42);
+// assert.strictEqual(ab.byteLength, 42);
+// new MessageChannel().port1.postMessage(ab, [ ab ]);
+// assert.strictEqual(ab.byteLength, 0);
+// assert.strictEqual(util.inspect(ab),
+// 'ArrayBuffer { (detached), byteLength: 0 }');
+// }
+
+// TODO(wafuwafu13): Fix
+// // Truncate output for ArrayBuffers using plural or singular bytes
+// {
+// const ab = new ArrayBuffer(3);
+// assert.strictEqual(util.inspect(ab, { showHidden: true, maxArrayLength: 2 }),
+// 'ArrayBuffer { [Uint8Contents]' +
+// ': <00 00 ... 1 more byte>, byteLength: 3 }');
+// assert.strictEqual(util.inspect(ab, { showHidden: true, maxArrayLength: 1 }),
+// 'ArrayBuffer { [Uint8Contents]' +
+// ': <00 ... 2 more bytes>, byteLength: 3 }');
+// }
+
+// TODO(wafuwafu13): Implement 'vm'
+// // Now do the same checks but from a different context.
+// {
+// const showHidden = false;
+// const ab = vm.runInNewContext('new ArrayBuffer(4)');
+// const dv = vm.runInNewContext('new DataView(ab, 1, 2)', { ab });
+// assert.strictEqual(
+// util.inspect(ab, showHidden),
+// 'ArrayBuffer { [Uint8Contents]: <00 00 00 00>, byteLength: 4 }'
+// );
+// assert.strictEqual(util.inspect(new DataView(ab, 1, 2), showHidden),
+// 'DataView {\n' +
+// ' byteLength: 2,\n' +
+// ' byteOffset: 1,\n' +
+// ' buffer: ArrayBuffer { [Uint8Contents]: <00 00 00 00>,' +
+// ' byteLength: 4 }\n}');
+// assert.strictEqual(
+// util.inspect(ab, showHidden),
+// 'ArrayBuffer { [Uint8Contents]: <00 00 00 00>, byteLength: 4 }'
+// );
+// assert.strictEqual(util.inspect(dv, showHidden),
+// 'DataView {\n' +
+// ' byteLength: 2,\n' +
+// ' byteOffset: 1,\n' +
+// ' buffer: ArrayBuffer { [Uint8Contents]: <00 00 00 00>,' +
+// ' byteLength: 4 }\n}');
+// ab.x = 42;
+// dv.y = 1337;
+// assert.strictEqual(util.inspect(ab, showHidden),
+// 'ArrayBuffer { [Uint8Contents]: <00 00 00 00>, ' +
+// 'byteLength: 4, x: 42 }');
+// assert.strictEqual(util.inspect(dv, showHidden),
+// 'DataView {\n' +
+// ' byteLength: 2,\n' +
+// ' byteOffset: 1,\n' +
+// ' buffer: ArrayBuffer { [Uint8Contents]: <00 00 00 00>,' +
+// ' byteLength: 4, x: 42 },\n' +
+// ' y: 1337\n}');
+// }
+
+// TODO(wafuwafu13): Fix
+// [ Float32Array,
+// Float64Array,
+// Int16Array,
+// Int32Array,
+// Int8Array,
+// Uint16Array,
+// Uint32Array,
+// Uint8Array,
+// Uint8ClampedArray ].forEach((constructor) => {
+// const length = 2;
+// const byteLength = length * constructor.BYTES_PER_ELEMENT;
+// const array = new constructor(new ArrayBuffer(byteLength), 0, length);
+// array[0] = 65;
+// array[1] = 97;
+// assert.strictEqual(
+// util.inspect(array, { showHidden: true }),
+// `${constructor.name}(${length}) [\n` +
+// ' 65,\n' +
+// ' 97,\n' +
+// ` [BYTES_PER_ELEMENT]: ${constructor.BYTES_PER_ELEMENT},\n` +
+// ` [length]: ${length},\n` +
+// ` [byteLength]: ${byteLength},\n` +
+// ' [byteOffset]: 0,\n' +
+// ` [buffer]: ArrayBuffer { byteLength: ${byteLength} }\n]`);
+// assert.strictEqual(
+// util.inspect(array, false),
+// `${constructor.name}(${length}) [ 65, 97 ]`
+// );
+// });
+
+// TODO(wafuwafu13): Implement 'vm'
+// // Now check that declaring a TypedArray in a different context works the same.
+// [ Float32Array,
+// Float64Array,
+// Int16Array,
+// Int32Array,
+// Int8Array,
+// Uint16Array,
+// Uint32Array,
+// Uint8Array,
+// Uint8ClampedArray ].forEach((constructor) => {
+// const length = 2;
+// const byteLength = length * constructor.BYTES_PER_ELEMENT;
+// const array = vm.runInNewContext(
+// 'new constructor(new ArrayBuffer(byteLength), 0, length)',
+// { constructor, byteLength, length }
+// );
+// array[0] = 65;
+// array[1] = 97;
+// assert.strictEqual(
+// util.inspect(array, true),
+// `${constructor.name}(${length}) [\n` +
+// ' 65,\n' +
+// ' 97,\n' +
+// ` [BYTES_PER_ELEMENT]: ${constructor.BYTES_PER_ELEMENT},\n` +
+// ` [length]: ${length},\n` +
+// ` [byteLength]: ${byteLength},\n` +
+// ' [byteOffset]: 0,\n' +
+// ` [buffer]: ArrayBuffer { byteLength: ${byteLength} }\n]`);
+// assert.strictEqual(
+// util.inspect(array, false),
+// `${constructor.name}(${length}) [ 65, 97 ]`
+// );
+// });
+
+// TODO(wafuwafu13): Fix
+// {
+// const brokenLength = new Float32Array(2);
+// Object.defineProperty(brokenLength, 'length', { value: -1 });
+// assert.strictEqual(inspect(brokenLength), 'Float32Array(2) [ 0n, 0n ]');
+// }
+
+assert.strictEqual(
+ util.inspect(Object.create({}, {
+ visible: { value: 1, enumerable: true },
+ hidden: { value: 2 }
+ }), { showHidden: true }),
+ '{ visible: 1, [hidden]: 2 }'
+);
+// Objects without prototype.
+assert.strictEqual(
+ util.inspect(Object.create(null, {
+ name: { value: 'Tim', enumerable: true },
+ hidden: { value: 'secret' }
+ }), { showHidden: true }),
+ "[Object: null prototype] { name: 'Tim', [hidden]: 'secret' }"
+);
+
+assert.strictEqual(
+ util.inspect(Object.create(null, {
+ name: { value: 'Tim', enumerable: true },
+ hidden: { value: 'secret' }
+ })),
+ "[Object: null prototype] { name: 'Tim' }"
+);
+
+// Dynamic properties.
+{
+ assert.strictEqual(
+ util.inspect({ get readonly() { return 1; } }),
+ '{ readonly: [Getter] }');
+
+ assert.strictEqual(
+ util.inspect({ get readwrite() { return 1; }, set readwrite(val) {} }),
+ '{ readwrite: [Getter/Setter] }');
+
+ assert.strictEqual(
+ // eslint-disable-next-line accessor-pairs
+ util.inspect({ set writeonly(val) {} }),
+ '{ writeonly: [Setter] }');
+
+ const value = {};
+ value.a = value;
+ assert.strictEqual(util.inspect(value), '<ref *1> { a: [Circular *1] }');
+ const getterFn = {
+ get one() {
+ return null;
+ }
+ };
+ assert.strictEqual(
+ util.inspect(getterFn, { getters: true }),
+ '{ one: [Getter: null] }'
+ );
+}
+
+// TODO(wafuwafu13): Fix
+// // Array with dynamic properties.
+// {
+// const value = [1, 2, 3];
+// Object.defineProperty(
+// value,
+// 'growingLength',
+// {
+// enumerable: true,
+// get: function() { this.push(true); return this.length; }
+// }
+// );
+// Object.defineProperty(
+// value,
+// '-1',
+// {
+// enumerable: true,
+// value: -1
+// }
+// );
+// assert.strictEqual(util.inspect(value),
+// "[ 1, 2, 3, growingLength: [Getter], '-1': -1 ]");
+// }
+
+// Array with inherited number properties.
+{
+ class CustomArray extends Array {}
+ CustomArray.prototype[5] = 'foo';
+ CustomArray.prototype[49] = 'bar';
+ CustomArray.prototype.foo = true;
+ const arr = new CustomArray(50);
+ arr[49] = 'I win';
+ assert.strictEqual(
+ util.inspect(arr),
+ "CustomArray(50) [ <49 empty items>, 'I win' ]"
+ );
+ // TODO(wafuwafu13): Fix
+ // assert.strictEqual(
+ // util.inspect(arr, { showHidden: true }),
+ // 'CustomArray(50) [\n' +
+ // ' <49 empty items>,\n' +
+ // " 'I win',\n" +
+ // ' [length]: 50,\n' +
+ // " '5': 'foo',\n" +
+ // ' foo: true\n' +
+ // ']'
+ // );
+}
+
+// TODO(wafuwafu13): Fix
+// // Array with extra properties.
+// {
+// const arr = [1, 2, 3, , ];
+// arr.foo = 'bar';
+// assert.strictEqual(util.inspect(arr),
+// "[ 1, 2, 3, <1 empty item>, foo: 'bar' ]");
+
+// const arr2 = [];
+// assert.strictEqual(util.inspect([], { showHidden: true }), '[ [length]: 0 ]');
+// arr2['00'] = 1;
+// assert.strictEqual(util.inspect(arr2), "[ '00': 1 ]");
+// assert.strictEqual(util.inspect(arr2, { showHidden: true }),
+// "[ [length]: 0, '00': 1 ]");
+// arr2[1] = 0;
+// assert.strictEqual(util.inspect(arr2), "[ <1 empty item>, 0, '00': 1 ]");
+// assert.strictEqual(util.inspect(arr2, { showHidden: true }),
+// "[ <1 empty item>, 0, [length]: 2, '00': 1 ]");
+// delete arr2[1];
+// assert.strictEqual(util.inspect(arr2), "[ <2 empty items>, '00': 1 ]");
+// assert.strictEqual(util.inspect(arr2, { showHidden: true }),
+// "[ <2 empty items>, [length]: 2, '00': 1 ]");
+// arr2['01'] = 2;
+// assert.strictEqual(util.inspect(arr2),
+// "[ <2 empty items>, '00': 1, '01': 2 ]");
+// assert.strictEqual(util.inspect(arr2, { showHidden: true }),
+// "[ <2 empty items>, [length]: 2, '00': 1, '01': 2 ]");
+// delete arr2['00'];
+// arr2[0] = 0;
+// assert.strictEqual(util.inspect(arr2),
+// "[ 0, <1 empty item>, '01': 2 ]");
+// assert.strictEqual(util.inspect(arr2, { showHidden: true }),
+// "[ 0, <1 empty item>, [length]: 2, '01': 2 ]");
+// delete arr2['01'];
+// arr2[2 ** 32 - 2] = 'max';
+// arr2[2 ** 32 - 1] = 'too far';
+// assert.strictEqual(
+// util.inspect(arr2),
+// "[ 0, <4294967293 empty items>, 'max', '4294967295': 'too far' ]"
+// );
+
+// const arr3 = [];
+// arr3[-1] = -1;
+// assert.strictEqual(util.inspect(arr3), "[ '-1': -1 ]");
+// }
+
+// TODO(wafuwafu13): Fix
+// // Indices out of bounds.
+// {
+// const arr = [];
+// arr[2 ** 32] = true; // Not a valid array index.
+// assert.strictEqual(util.inspect(arr), "[ '4294967296': true ]");
+// arr[0] = true;
+// arr[10] = true;
+// assert.strictEqual(util.inspect(arr),
+// "[ true, <9 empty items>, true, '4294967296': true ]");
+// arr[2 ** 32 - 2] = true;
+// arr[2 ** 32 - 1] = true;
+// arr[2 ** 32 + 1] = true;
+// delete arr[0];
+// delete arr[10];
+// assert.strictEqual(util.inspect(arr),
+// ['[',
+// '<4294967294 empty items>,',
+// 'true,',
+// "'4294967296': true,",
+// "'4294967295': true,",
+// "'4294967297': true\n]",
+// ].join('\n '));
+// }
+
+// Function with properties.
+{
+ const value = () => {};
+ value.aprop = 42;
+ assert.strictEqual(util.inspect(value), '[Function: value] { aprop: 42 }');
+}
+
+// Anonymous function with properties.
+{
+ const value = (() => function() {})();
+ value.aprop = 42;
+ assert.strictEqual(
+ util.inspect(value),
+ '[Function (anonymous)] { aprop: 42 }'
+ );
+}
+
+// Regular expressions with properties.
+{
+ const value = /123/ig;
+ value.aprop = 42;
+ assert.strictEqual(util.inspect(value), '/123/gi { aprop: 42 }');
+}
+
+// Dates with properties.
+{
+ const value = new Date('Sun, 14 Feb 2010 11:48:40 GMT');
+ value.aprop = 42;
+ assert.strictEqual(util.inspect(value),
+ '2010-02-14T11:48:40.000Z { aprop: 42 }');
+}
+
+// Test the internal isDate implementation.
+{
+ const Date2 = vm.runInNewContext('Date');
+ const d = new Date2();
+ const orig = util.inspect(d);
+ Date2.prototype.foo = 'bar';
+ const after = util.inspect(d);
+ assert.strictEqual(orig, after);
+}
+
+// Test positive/negative zero.
+assert.strictEqual(util.inspect(0), '0');
+assert.strictEqual(util.inspect(-0), '-0');
+// Edge case from check.
+assert.strictEqual(util.inspect(-5e-324), '-5e-324');
+
+// Test for sparse array.
+{
+ const a = ['foo', 'bar', 'baz'];
+ assert.strictEqual(util.inspect(a), "[ 'foo', 'bar', 'baz' ]");
+ delete a[1];
+ assert.strictEqual(util.inspect(a), "[ 'foo', <1 empty item>, 'baz' ]");
+ // TODO(wafuwafu13): Fix
+ // assert.strictEqual(
+ // util.inspect(a, true),
+ // "[ 'foo', <1 empty item>, 'baz', [length]: 3 ]"
+ // );
+ assert.strictEqual(util.inspect(new Array(5)), '[ <5 empty items> ]');
+ a[3] = 'bar';
+ a[100] = 'qux';
+ assert.strictEqual(
+ util.inspect(a, { breakLength: Infinity }),
+ "[ 'foo', <1 empty item>, 'baz', 'bar', <96 empty items>, 'qux' ]"
+ );
+ delete a[3];
+ assert.strictEqual(
+ util.inspect(a, { maxArrayLength: 4 }),
+ "[ 'foo', <1 empty item>, 'baz', <97 empty items>, ... 1 more item ]"
+ );
+ // test 4 special case
+ assert.strictEqual(util.inspect(a, {
+ maxArrayLength: 2
+ }), "[ 'foo', <1 empty item>, ... 99 more items ]");
+}
+
+// TODO(wafuwafu13): Implement `previewEntries`
+// Test for Array constructor in different context.
+// {
+// const map = new Map();
+// map.set(1, 2);
+// // Passing only a single argument to indicate a set iterator.
+// const valsSetIterator = previewEntries(map.entries());
+// // Passing through true to indicate a map iterator.
+// const valsMapIterEntries = previewEntries(map.entries(), true);
+// const valsMapIterKeys = previewEntries(map.keys(), true);
+
+// assert.strictEqual(util.inspect(valsSetIterator), '[ 1, 2 ]');
+// assert.strictEqual(util.inspect(valsMapIterEntries), '[ [ 1, 2 ], true ]');
+// assert.strictEqual(util.inspect(valsMapIterKeys), '[ [ 1 ], false ]');
+// }
+
+// TODO(wafuwafu13): Implement 'vm'
+// // Test for other constructors in different context.
+// {
+// let obj = vm.runInNewContext('(function(){return {}})()', {});
+// assert.strictEqual(util.inspect(obj), '{}');
+// obj = vm.runInNewContext('const m=new Map();m.set(1,2);m', {});
+// assert.strictEqual(util.inspect(obj), 'Map(1) { 1 => 2 }');
+// obj = vm.runInNewContext('const s=new Set();s.add(1);s.add(2);s', {});
+// assert.strictEqual(util.inspect(obj), 'Set(2) { 1, 2 }');
+// obj = vm.runInNewContext('fn=function(){};new Promise(fn,fn)', {});
+// assert.strictEqual(util.inspect(obj), 'Promise { <pending> }');
+// }
+
+// Test for property descriptors.
+{
+ const getter = Object.create(null, {
+ a: {
+ get: function() { return 'aaa'; }
+ }
+ });
+ const setter = Object.create(null, {
+ b: { // eslint-disable-line accessor-pairs
+ set: function() {}
+ }
+ });
+ const getterAndSetter = Object.create(null, {
+ c: {
+ get: function() { return 'ccc'; },
+ set: function() {}
+ }
+ });
+ assert.strictEqual(
+ util.inspect(getter, true),
+ '[Object: null prototype] { [a]: [Getter] }'
+ );
+ assert.strictEqual(
+ util.inspect(setter, true),
+ '[Object: null prototype] { [b]: [Setter] }'
+ );
+ assert.strictEqual(
+ util.inspect(getterAndSetter, true),
+ '[Object: null prototype] { [c]: [Getter/Setter] }'
+ );
+}
+
+// Exceptions should print the error message, not '{}'.
+{
+ [
+ new Error(),
+ new Error('FAIL'),
+ new TypeError('FAIL'),
+ new SyntaxError('FAIL'),
+ ].forEach((err) => {
+ assert.strictEqual(util.inspect(err), err.stack);
+ });
+ assert.throws(
+ () => undef(), // eslint-disable-line no-undef
+ (e) => {
+ assert.strictEqual(util.inspect(e), e.stack);
+ return true;
+ }
+ );
+
+ const ex = util.inspect(new Error('FAIL'), true);
+ assert(ex.includes('Error: FAIL'));
+ assert(ex.includes('[stack]'));
+ assert(ex.includes('[message]'));
+}
+
+{
+ const tmp = Error.stackTraceLimit;
+ Error.stackTraceLimit = 0;
+ const err = new Error('foo');
+ const err2 = new Error('foo\nbar');
+ assert.strictEqual(util.inspect(err, { compact: true }), '[Error: foo]');
+ assert(err.stack);
+ delete err.stack;
+ assert(!err.stack);
+ assert.strictEqual(util.inspect(err, { compact: true }), '[Error: foo]');
+ assert.strictEqual(
+ util.inspect(err2, { compact: true }),
+ '[Error: foo\nbar]'
+ );
+
+ err.bar = true;
+ err2.bar = true;
+
+ assert.strictEqual(
+ util.inspect(err, { compact: true }),
+ '{ [Error: foo] bar: true }'
+ );
+ assert.strictEqual(
+ util.inspect(err2, { compact: true }),
+ '{ [Error: foo\nbar]\n bar: true }'
+ );
+ assert.strictEqual(
+ util.inspect(err, { compact: true, breakLength: 5 }),
+ '{ [Error: foo]\n bar: true }'
+ );
+ assert.strictEqual(
+ util.inspect(err, { compact: true, breakLength: 1 }),
+ '{ [Error: foo]\n bar:\n true }'
+ );
+ assert.strictEqual(
+ util.inspect(err2, { compact: true, breakLength: 5 }),
+ '{ [Error: foo\nbar]\n bar: true }'
+ );
+ assert.strictEqual(
+ util.inspect(err, { compact: false }),
+ '[Error: foo] {\n bar: true\n}'
+ );
+ assert.strictEqual(
+ util.inspect(err2, { compact: false }),
+ '[Error: foo\nbar] {\n bar: true\n}'
+ );
+
+ Error.stackTraceLimit = tmp;
+}
+
+// TODO(wafuwafu13): Fix
+// // Prevent enumerable error properties from being printed.
+// {
+// let err = new Error();
+// err.message = 'foobar';
+// let out = util.inspect(err).split('\n');
+// assert.strictEqual(out[0], 'Error: foobar');
+// assert(out[out.length - 1].startsWith(' at '));
+// // Reset the error, the stack is otherwise not recreated.
+// err = new Error();
+// err.message = 'foobar';
+// err.name = 'Unique';
+// Object.defineProperty(err, 'stack', { value: err.stack, enumerable: true });
+// out = util.inspect(err).split('\n');
+// assert.strictEqual(out[0], 'Unique: foobar');
+// assert(out[out.length - 1].startsWith(' at '));
+// err.name = 'Baz';
+// out = util.inspect(err).split('\n');
+// assert.strictEqual(out[0], 'Unique: foobar');
+// assert.strictEqual(out[out.length - 2], " name: 'Baz'");
+// assert.strictEqual(out[out.length - 1], '}');
+// }
+
+// // Doesn't capture stack trace.
+{
+ function BadCustomError(msg) {
+ Error.call(this);
+ Object.defineProperty(this, 'message',
+ { value: msg, enumerable: false });
+ Object.defineProperty(this, 'name',
+ { value: 'BadCustomError', enumerable: false });
+ }
+ Object.setPrototypeOf(BadCustomError.prototype, Error.prototype);
+ Object.setPrototypeOf(BadCustomError, Error);
+ assert.strictEqual(
+ util.inspect(new BadCustomError('foo')),
+ '[BadCustomError: foo]'
+ );
+}
+
+// TODO(wafuwafu13): Fix
+// // Tampered error stack or name property (different type than string).
+// // Note: Symbols are not supported by `Error#toString()` which is called by
+// // accessing the `stack` property.
+// [
+// [404, '404: foo', '[404]'],
+// [0, '0: foo', '[RangeError: foo]'],
+// [0n, '0: foo', '[RangeError: foo]'],
+// [null, 'null: foo', '[RangeError: foo]'],
+// [undefined, 'RangeError: foo', '[RangeError: foo]'],
+// [false, 'false: foo', '[RangeError: foo]'],
+// ['', 'foo', '[RangeError: foo]'],
+// [[1, 2, 3], '1,2,3: foo', '[1,2,3]'],
+// ].forEach(([value, outputStart, stack]) => {
+// let err = new RangeError('foo');
+// err.name = value;
+// assert(
+// util.inspect(err).startsWith(outputStart),
+// util.format(
+// 'The name set to %o did not result in the expected output "%s"',
+// value,
+// outputStart
+// )
+// );
+
+// err = new RangeError('foo');
+// err.stack = value;
+// assert.strictEqual(util.inspect(err), stack);
+// });
+
+// https://github.com/nodejs/node-v0.x-archive/issues/1941
+// TODO(@crowlKats)
+//assert.strictEqual(util.inspect(Object.create(Date.prototype)), 'Date {}');
+
+// https://github.com/nodejs/node-v0.x-archive/issues/1944
+{
+ const d = new Date();
+ d.toUTCString = null;
+ util.inspect(d);
+}
+
+// TODO(wafuwafu13): Fix
+// // Should not throw.
+// {
+// const d = new Date();
+// d.toISOString = null;
+// util.inspect(d);
+// }
+
+// TODO(wafuwafu13): Fix
+// // Should not throw.
+// {
+// const r = /regexp/;
+// r.toString = null;
+// util.inspect(r);
+// }
+
+// TODO(wafuwafu13): Fix
+// // See https://github.com/nodejs/node-v0.x-archive/issues/2225
+// {
+// const x = { [util.inspect.custom]: util.inspect };
+// assert(util.inspect(x).includes(
+// '[Symbol(nodejs.util.inspect.custom)]: [Function: inspect] {\n'));
+// }
+
+// TODO(wafuwafu13): Fix
+// // `util.inspect` should display the escaped value of a key.
+// {
+// const w = {
+// '\\': 1,
+// '\\\\': 2,
+// '\\\\\\': 3,
+// '\\\\\\\\': 4,
+// '\n': 5,
+// '\r': 6
+// };
+
+// const y = ['a', 'b', 'c'];
+// y['\\\\'] = 'd';
+// y['\n'] = 'e';
+// y['\r'] = 'f';
+
+// assert.strictEqual(
+// util.inspect(w),
+// "{ '\\\\': 1, '\\\\\\\\': 2, '\\\\\\\\\\\\': 3, " +
+// "'\\\\\\\\\\\\\\\\': 4, '\\n': 5, '\\r': 6 }"
+// );
+// assert.strictEqual(
+// util.inspect(y),
+// "[ 'a', 'b', 'c', '\\\\\\\\': 'd', " +
+// "'\\n': 'e', '\\r': 'f' ]"
+// );
+// }
+
+// Test util.inspect.styles and util.inspect.colors.
+{
+ function testColorStyle(style, input, implicit) {
+ const colorName = util.inspect.styles[style];
+ let color = ['', ''];
+ if (util.inspect.colors[colorName])
+ color = util.inspect.colors[colorName];
+
+ const withoutColor = util.inspect(input, false, 0, false);
+ const withColor = util.inspect(input, false, 0, true);
+ const expect = `\u001b[${color[0]}m${withoutColor}\u001b[${color[1]}m`;
+ assert.strictEqual(
+ withColor,
+ expect,
+ `util.inspect color for style ${style}`);
+ }
+
+ testColorStyle('special', function() {});
+ testColorStyle('number', 123.456);
+ testColorStyle('boolean', true);
+ testColorStyle('undefined', undefined);
+ testColorStyle('null', null);
+ testColorStyle('string', 'test string');
+ testColorStyle('date', new Date());
+ testColorStyle('regexp', /regexp/);
+}
+
+// An object with "hasOwnProperty" overwritten should not throw.
+util.inspect({ hasOwnProperty: null });
+
+// New API, accepts an "options" object.
+{
+ const subject = { foo: 'bar', hello: 31, a: { b: { c: { d: 0 } } } };
+ Object.defineProperty(subject, 'hidden', { enumerable: false, value: null });
+
+ assert.strictEqual(
+ util.inspect(subject, { showHidden: false }).includes('hidden'),
+ false
+ );
+ assert.strictEqual(
+ util.inspect(subject, { showHidden: true }).includes('hidden'),
+ true
+ );
+ assert.strictEqual(
+ util.inspect(subject, { colors: false }).includes('\u001b[32m'),
+ false
+ );
+ assert.strictEqual(
+ util.inspect(subject, { colors: true }).includes('\u001b[32m'),
+ true
+ );
+ assert.strictEqual(
+ util.inspect(subject, { depth: 2 }).includes('c: [Object]'),
+ true
+ );
+ assert.strictEqual(
+ util.inspect(subject, { depth: 0 }).includes('a: [Object]'),
+ true
+ );
+ assert.strictEqual(
+ util.inspect(subject, { depth: null }).includes('{ d: 0 }'),
+ true
+ );
+ assert.strictEqual(
+ util.inspect(subject, { depth: undefined }).includes('{ d: 0 }'),
+ true
+ );
+}
+
+{
+ // "customInspect" option can enable/disable calling [util.inspect.custom]().
+ const subject = { [util.inspect.custom]: () => 123 };
+
+ assert.strictEqual(
+ util.inspect(subject, { customInspect: true }).includes('123'),
+ true
+ );
+ assert.strictEqual(
+ util.inspect(subject, { customInspect: true }).includes('inspect'),
+ false
+ );
+ assert.strictEqual(
+ util.inspect(subject, { customInspect: false }).includes('123'),
+ false
+ );
+ // TODO(wafuwafu13): Fix
+ // assert.strictEqual(
+ // util.inspect(subject, { customInspect: false }).includes('inspect'),
+ // true
+ // );
+
+ // A custom [util.inspect.custom]() should be able to return other Objects.
+ subject[util.inspect.custom] = () => ({ foo: 'bar' });
+
+ assert.strictEqual(util.inspect(subject), "{ foo: 'bar' }");
+
+ subject[util.inspect.custom] = common.mustCall((depth, opts) => {
+ const clone = { ...opts };
+ // This might change at some point but for now we keep the stylize function.
+ // The function should either be documented or an alternative should be
+ // implemented.
+ assert.strictEqual(typeof opts.stylize, 'function');
+ assert.strictEqual(opts.seen, undefined);
+ assert.strictEqual(opts.budget, undefined);
+ assert.strictEqual(opts.indentationLvl, undefined);
+ assert.strictEqual(opts.showHidden, false);
+ // TODO(@crowlKats)
+ //assert.deepStrictEqual(
+ // new Set(Object.keys(util.inspect.defaultOptions).concat(['stylize'])),
+ // new Set(Object.keys(opts))
+ //);
+ opts.showHidden = true;
+ return { [util.inspect.custom]: common.mustCall((depth, opts2) => {
+ assert.deepStrictEqual(clone, opts2);
+ }) };
+ });
+
+ util.inspect(subject);
+
+ // util.inspect.custom is a shared symbol which can be accessed as
+ // Symbol.for("nodejs.util.inspect.custom").
+ const inspect = Symbol.for('nodejs.util.inspect.custom');
+
+ subject[inspect] = () => ({ baz: 'quux' });
+
+ assert.strictEqual(util.inspect(subject), '{ baz: \'quux\' }');
+
+ subject[inspect] = (depth, opts) => {
+ assert.strictEqual(opts.customInspectOptions, true);
+ assert.strictEqual(opts.seen, null);
+ return {};
+ };
+
+ util.inspect(subject, { customInspectOptions: true, seen: null });
+}
+
+{
+ const subject = { [util.inspect.custom]: common.mustCall((depth, opts) => {
+ assert.strictEqual(depth, null);
+ assert.strictEqual(opts.compact, true);
+ }) };
+ util.inspect(subject, { depth: null, compact: true });
+}
+
+// TODO(wafuwafu13): Fix
+// {
+// // Returning `this` from a custom inspection function works.
+// const subject = { a: 123, [util.inspect.custom]() { return this; } };
+// const UIC = 'nodejs.util.inspect.custom';
+// assert.strictEqual(
+// util.inspect(subject),
+// `{\n a: 123,\n [Symbol(${UIC})]: [Function: [${UIC}]]\n}`
+// );
+// }
+
+// Verify that it's possible to use the stylize function to manipulate input.
+assert.strictEqual(
+ util.inspect([1, 2, 3], { stylize() { return 'x'; } }),
+ '[ x, x, x ]'
+);
+
+// Using `util.inspect` with "colors" option should produce as many lines as
+// without it.
+{
+ function testLines(input) {
+ const countLines = (str) => (str.match(/\n/g) || []).length;
+ const withoutColor = util.inspect(input);
+ const withColor = util.inspect(input, { colors: true });
+ assert.strictEqual(countLines(withoutColor), countLines(withColor));
+ }
+
+ const bigArray = new Array(100).fill().map((value, index) => index);
+
+ testLines([1, 2, 3, 4, 5, 6, 7]);
+ testLines(bigArray);
+ testLines({ foo: 'bar', baz: 35, b: { a: 35 } });
+ testLines({ a: { a: 3, b: 1, c: 1, d: 1, e: 1, f: 1, g: 1, h: 1 }, b: 1 });
+ testLines({
+ foo: 'bar',
+ baz: 35,
+ b: { a: 35 },
+ veryLongKey: 'very long value',
+ evenLongerKey: ['with even longer value in array']
+ });
+}
+
+// Test boxed primitives output the correct values.
+assert.strictEqual(util.inspect(new String('test')), "[String: 'test']");
+assert.strictEqual(
+ util.inspect(new String('test'), { colors: true }),
+ "\u001b[32m[String: 'test']\u001b[39m"
+);
+assert.strictEqual(
+ util.inspect(Object(Symbol('test'))),
+ '[Symbol: Symbol(test)]'
+);
+assert.strictEqual(util.inspect(new Boolean(false)), '[Boolean: false]');
+// TODO(wafuwafu13): Fix
+// assert.strictEqual(
+// util.inspect(Object.setPrototypeOf(new Boolean(true), null)),
+// '[Boolean (null prototype): true]'
+// );
+// assert.strictEqual(util.inspect(new Number(0)), '[Number: 0]');
+// assert.strictEqual(
+// util.inspect(
+// Object.defineProperty(
+// Object.setPrototypeOf(new Number(-0), Array.prototype),
+// Symbol.toStringTag,
+// { value: 'Foobar' }
+// )
+// ),
+// '[Number (Array): -0] [Foobar]'
+// );
+assert.strictEqual(util.inspect(new Number(-1.1)), '[Number: -1.1]');
+assert.strictEqual(util.inspect(new Number(13.37)), '[Number: 13.37]');
+
+// Test boxed primitives with own properties.
+{
+ const str = new String('baz');
+ str.foo = 'bar';
+ assert.strictEqual(util.inspect(str), "[String: 'baz'] { foo: 'bar' }");
+
+ const bool = new Boolean(true);
+ bool.foo = 'bar';
+ assert.strictEqual(util.inspect(bool), "[Boolean: true] { foo: 'bar' }");
+
+ const num = new Number(13.37);
+ num.foo = 'bar';
+ assert.strictEqual(util.inspect(num), "[Number: 13.37] { foo: 'bar' }");
+
+ const sym = Object(Symbol('foo'));
+ sym.foo = 'bar';
+ assert.strictEqual(util.inspect(sym), "[Symbol: Symbol(foo)] { foo: 'bar' }");
+
+ const big = Object(BigInt(55));
+ big.foo = 'bar';
+ assert.strictEqual(util.inspect(big), "[BigInt: 55n] { foo: 'bar' }");
+}
+
+// Test es6 Symbol.
+if (typeof Symbol !== 'undefined') {
+ assert.strictEqual(util.inspect(Symbol()), 'Symbol()');
+ //assert.strictEqual(util.inspect(Symbol(123)), 'Symbol(123)');
+ //assert.strictEqual(util.inspect(Symbol('hi')), 'Symbol(hi)');
+ assert.strictEqual(util.inspect([Symbol()]), '[ Symbol() ]');
+ assert.strictEqual(util.inspect({ foo: Symbol() }), '{ foo: Symbol() }');
+
+ const options = { showHidden: true };
+ let subject = {};
+
+ subject[Symbol('sym\nbol')] = 42;
+
+ // TODO(wafuwafu13): Fix
+ // assert.strictEqual(util.inspect(subject), '{ [Symbol(sym\\nbol)]: 42 }');
+ // assert.strictEqual(
+ // util.inspect(subject, options),
+ // '{ [Symbol(sym\\nbol)]: 42 }'
+ // );
+
+ // Object.defineProperty(
+ // subject,
+ // Symbol(),
+ // { enumerable: false, value: 'non-enum' });
+ // assert.strictEqual(util.inspect(subject), '{ [Symbol(sym\\nbol)]: 42 }');
+ // assert.strictEqual(
+ // util.inspect(subject, options),
+ // "{ [Symbol(sym\\nbol)]: 42, [Symbol()]: 'non-enum' }"
+ // );
+
+ // subject = [1, 2, 3];
+ // subject[Symbol('symbol')] = 42;
+
+ // assert.strictEqual(util.inspect(subject),
+ // '[ 1, 2, 3, [Symbol(symbol)]: 42 ]');
+}
+
+// Test Set.
+{
+ assert.strictEqual(util.inspect(new Set()), 'Set(0) {}');
+ // TODO(wafuwafu13): Fix
+ // assert.strictEqual(util.inspect(new Set([1, 2, 3])), 'Set(3) { 1, 2, 3 }');
+ // const set = new Set(['foo']);
+ // set.bar = 42;
+ // assert.strictEqual(
+ // util.inspect(set, { showHidden: true }),
+ // "Set(1) { 'foo', bar: 42 }"
+ // );
+}
+
+// TODO(wafuwafu13): Fix
+// // Test circular Set.
+// {
+// const set = new Set();
+// set.add(set);
+// assert.strictEqual(util.inspect(set), '<ref *1> Set(1) { [Circular *1] }');
+// }
+
+// Test Map.
+{
+ assert.strictEqual(util.inspect(new Map()), 'Map(0) {}');
+ assert.strictEqual(util.inspect(new Map([[1, 'a'], [2, 'b'], [3, 'c']])),
+ "Map(3) { 1 => 'a', 2 => 'b', 3 => 'c' }");
+ const map = new Map([['foo', null]]);
+ map.bar = 42;
+ assert.strictEqual(util.inspect(map, true),
+ "Map(1) { 'foo' => null, bar: 42 }");
+}
+
+// Test circular Map.
+{
+ const map = new Map();
+ map.set(map, 'map');
+ assert.strictEqual(
+ inspect(map),
+ "<ref *1> Map(1) { [Circular *1] => 'map' }"
+ );
+ map.set(map, map);
+ assert.strictEqual(
+ inspect(map),
+ '<ref *1> Map(1) { [Circular *1] => [Circular *1] }'
+ );
+ map.delete(map);
+ map.set('map', map);
+ assert.strictEqual(
+ inspect(map),
+ "<ref *1> Map(1) { 'map' => [Circular *1] }"
+ );
+}
+
+// Test multiple circular references.
+{
+ const obj = {};
+ obj.a = [obj];
+ obj.b = {};
+ obj.b.inner = obj.b;
+ obj.b.obj = obj;
+
+ assert.strictEqual(
+ inspect(obj),
+ '<ref *1> {\n' +
+ ' a: [ [Circular *1] ],\n' +
+ ' b: <ref *2> { inner: [Circular *2], obj: [Circular *1] }\n' +
+ '}'
+ );
+}
+
+// TODO(wafuwafu13): Fix
+// // Test Promise.
+// {
+// const resolved = Promise.resolve(3);
+// assert.strictEqual(util.inspect(resolved), 'Promise { 3 }');
+
+// const rejected = Promise.reject(3);
+// assert.strictEqual(util.inspect(rejected), 'Promise { <rejected> 3 }');
+// // Squelch UnhandledPromiseRejection.
+// rejected.catch(() => {});
+
+// const pending = new Promise(() => {});
+// assert.strictEqual(util.inspect(pending), 'Promise { <pending> }');
+
+// const promiseWithProperty = Promise.resolve('foo');
+// promiseWithProperty.bar = 42;
+// assert.strictEqual(util.inspect(promiseWithProperty),
+// "Promise { 'foo', bar: 42 }");
+// }
+
+// Make sure it doesn't choke on polyfills. Unlike Set/Map, there is no standard
+// interface to synchronously inspect a Promise, so our techniques only work on
+// a bonafide native Promise.
+{
+ const oldPromise = Promise;
+ global.Promise = function() { this.bar = 42; };
+ assert.strictEqual(util.inspect(new Promise()), '{ bar: 42 }');
+ global.Promise = oldPromise;
+}
+
+// TODO(wafuwafu13): Fix
+// // Test Map iterators.
+// {
+// const map = new Map([['foo', 'bar']]);
+// assert.strictEqual(util.inspect(map.keys()), '[Map Iterator] { \'foo\' }');
+// const mapValues = map.values();
+// Object.defineProperty(mapValues, Symbol.toStringTag, { value: 'Foo' });
+// assert.strictEqual(
+// util.inspect(mapValues),
+// '[Foo] [Map Iterator] { \'bar\' }'
+// );
+// map.set('A', 'B!');
+// assert.strictEqual(util.inspect(map.entries(), { maxArrayLength: 1 }),
+// "[Map Entries] { [ 'foo', 'bar' ], ... 1 more item }");
+// // Make sure the iterator doesn't get consumed.
+// const keys = map.keys();
+// assert.strictEqual(util.inspect(keys), "[Map Iterator] { 'foo', 'A' }");
+// assert.strictEqual(util.inspect(keys), "[Map Iterator] { 'foo', 'A' }");
+// keys.extra = true;
+// assert.strictEqual(
+// util.inspect(keys, { maxArrayLength: 0 }),
+// '[Map Iterator] { ... 2 more items, extra: true }');
+// }
+
+// TODO(wafuwafu13): Fix
+// // Test Set iterators.
+// {
+// const aSet = new Set([1]);
+// assert.strictEqual(util.inspect(aSet.entries(), { compact: false }),
+// '[Set Entries] {\n [\n 1,\n 1\n ]\n}');
+// aSet.add(3);
+// assert.strictEqual(util.inspect(aSet.keys()), '[Set Iterator] { 1, 3 }');
+// assert.strictEqual(util.inspect(aSet.values()), '[Set Iterator] { 1, 3 }');
+// const setEntries = aSet.entries();
+// Object.defineProperty(setEntries, Symbol.toStringTag, { value: 'Foo' });
+// assert.strictEqual(util.inspect(setEntries),
+// '[Foo] [Set Entries] { [ 1, 1 ], [ 3, 3 ] }');
+// // Make sure the iterator doesn't get consumed.
+// const keys = aSet.keys();
+// Object.defineProperty(keys, Symbol.toStringTag, { value: null });
+// assert.strictEqual(util.inspect(keys), '[Set Iterator] { 1, 3 }');
+// assert.strictEqual(util.inspect(keys), '[Set Iterator] { 1, 3 }');
+// keys.extra = true;
+// assert.strictEqual(
+// util.inspect(keys, { maxArrayLength: 1 }),
+// '[Set Iterator] { 1, ... 1 more item, extra: true }');
+// }
+
+// Minimal inspection should still return as much information as possible about
+// the constructor and Symbol.toStringTag.
+{
+ class Foo {
+ get [Symbol.toStringTag]() {
+ return 'ABC';
+ }
+ }
+ const a = new Foo();
+ assert.strictEqual(inspect(a, { depth: -1 }), 'Foo [ABC] {}');
+ a.foo = true;
+ assert.strictEqual(inspect(a, { depth: -1 }), '[Foo [ABC]]');
+ Object.defineProperty(a, Symbol.toStringTag, {
+ value: 'Foo',
+ configurable: true,
+ writable: true
+ });
+ assert.strictEqual(inspect(a, { depth: -1 }), '[Foo]');
+ delete a[Symbol.toStringTag];
+ Object.setPrototypeOf(a, null);
+ // TODO(wafuwafu13): Fix
+ // assert.strictEqual(inspect(a, { depth: -1 }), '[Foo: null prototype]');
+ // delete a.foo;
+ // assert.strictEqual(inspect(a, { depth: -1 }), '[Foo: null prototype] {}');
+ // Object.defineProperty(a, Symbol.toStringTag, {
+ // value: 'ABC',
+ // configurable: true
+ // });
+ // assert.strictEqual(
+ // inspect(a, { depth: -1 }),
+ // '[Foo: null prototype] [ABC] {}'
+ // );
+ // Object.defineProperty(a, Symbol.toStringTag, {
+ // value: 'Foo',
+ // configurable: true
+ // });
+ // assert.strictEqual(
+ // inspect(a, { depth: -1 }),
+ // '[Object: null prototype] [Foo] {}'
+ // );
+}
+
+// Test alignment of items in container.
+// Assumes that the first numeric character is the start of an item.
+{
+ function checkAlignment(container, start, lineX, end) {
+ const lines = util.inspect(container).split('\n');
+ lines.forEach((line, i) => {
+ if (i === 0) {
+ assert.strictEqual(line, start);
+ } else if (i === lines.length - 1) {
+ assert.strictEqual(line, end);
+ } else {
+ let expected = lineX.replace('X', i - 1);
+ if (i !== lines.length - 2)
+ expected += ',';
+ assert.strictEqual(line, expected);
+ }
+ });
+ }
+
+ const bigArray = [];
+ for (let i = 0; i < 100; i++) {
+ bigArray.push(i);
+ }
+
+ const obj = {};
+ bigArray.forEach((prop) => {
+ obj[prop] = null;
+ });
+
+ checkAlignment(obj, '{', " 'X': null", '}');
+ // TODO(wafuwafu13): Fix
+ // checkAlignment(new Set(bigArray), 'Set(100) {', ' X', '}');
+ checkAlignment(
+ new Map(bigArray.map((number) => [number, null])),
+ 'Map(100) {', ' X => null', '}'
+ );
+}
+
+
+// Test display of constructors.
+{
+ class ObjectSubclass {}
+ class ArraySubclass extends Array {}
+ class SetSubclass extends Set {}
+ class MapSubclass extends Map {}
+ class PromiseSubclass extends Promise {}
+
+ const x = new ObjectSubclass();
+ x.foo = 42;
+ assert.strictEqual(util.inspect(x),
+ 'ObjectSubclass { foo: 42 }');
+ assert.strictEqual(util.inspect(new ArraySubclass(1, 2, 3)),
+ 'ArraySubclass(3) [ 1, 2, 3 ]');
+ // TODO(wafuwafu13): Fix
+ // assert.strictEqual(util.inspect(new SetSubclass([1, 2, 3])),
+ // 'SetSubclass(3) [Set] { 1, 2, 3 }');
+ assert.strictEqual(util.inspect(new MapSubclass([['foo', 42]])),
+ "MapSubclass(1) [Map] { 'foo' => 42 }");
+ // TODO(wafuwafu13): Fix
+ // assert.strictEqual(util.inspect(new PromiseSubclass(() => {})),
+ // 'PromiseSubclass [Promise] { <pending> }');
+ assert.strictEqual(
+ util.inspect({ a: { b: new ArraySubclass([1, [2], 3]) } }, { depth: 1 }),
+ '{ a: { b: [ArraySubclass] } }'
+ );
+ // TODO(wafuwafu13): Fix
+ // assert.strictEqual(
+ // util.inspect(Object.setPrototypeOf(x, null)),
+ // '[ObjectSubclass: null prototype] { foo: 42 }'
+ // );
+}
+
+// Empty and circular before depth.
+{
+ const arr = [[[[]]]];
+ assert.strictEqual(util.inspect(arr), '[ [ [ [] ] ] ]');
+ arr[0][0][0][0] = [];
+ assert.strictEqual(util.inspect(arr), '[ [ [ [Array] ] ] ]');
+ arr[0][0][0] = {};
+ assert.strictEqual(util.inspect(arr), '[ [ [ {} ] ] ]');
+ arr[0][0][0] = { a: 2 };
+ assert.strictEqual(util.inspect(arr), '[ [ [ [Object] ] ] ]');
+ arr[0][0][0] = arr;
+ assert.strictEqual(util.inspect(arr), '<ref *1> [ [ [ [Circular *1] ] ] ]');
+ arr[0][0][0] = arr[0][0];
+ assert.strictEqual(util.inspect(arr), '[ [ <ref *1> [ [Circular *1] ] ] ]');
+}
+
+// Corner cases.
+{
+ const x = { constructor: 42 };
+ assert.strictEqual(util.inspect(x), '{ constructor: 42 }');
+}
+
+{
+ const x = {};
+ Object.defineProperty(x, 'constructor', {
+ get: function() {
+ throw new Error('should not access constructor');
+ },
+ enumerable: true
+ });
+ assert.strictEqual(util.inspect(x), '{ constructor: [Getter] }');
+}
+
+{
+ const x = new function() {}; // eslint-disable-line new-parens
+ assert.strictEqual(util.inspect(x), '{}');
+}
+
+{
+ const x = Object.create(null);
+ assert.strictEqual(util.inspect(x), '[Object: null prototype] {}');
+}
+
+// TODO(wafuwafu13): Fix
+// {
+// const x = [];
+// x[''] = 1;
+// assert.strictEqual(util.inspect(x), "[ '': 1 ]");
+// }
+
+// TODO(wafuwafu13): Fix
+// // The following maxArrayLength tests were introduced after v6.0.0 was released.
+// // Do not backport to v5/v4 unless all of
+// // https://github.com/nodejs/node/pull/6334 is backported.
+// {
+// const x = new Array(101).fill();
+// assert(util.inspect(x).endsWith('1 more item\n]'));
+// assert(!util.inspect(x, { maxArrayLength: 101 }).endsWith('1 more item\n]'));
+// assert.strictEqual(
+// util.inspect(x, { maxArrayLength: -1 }),
+// '[ ... 101 more items ]'
+// );
+// assert.strictEqual(util.inspect(x, { maxArrayLength: 0 }),
+// '[ ... 101 more items ]');
+// }
+
+{
+ const x = Array(101);
+ assert.strictEqual(util.inspect(x, { maxArrayLength: 0 }),
+ '[ ... 101 more items ]');
+ assert(!util.inspect(x, { maxArrayLength: null }).endsWith('1 more item\n]'));
+ assert(!util.inspect(
+ x, { maxArrayLength: Infinity }
+ ).endsWith('1 more item ]'));
+}
+
+{
+ const x = new Uint8Array(101);
+ // TODO(wafuwafu13): Fix
+ // assert(util.inspect(x).endsWith('1 more item\n]'));
+ assert(!util.inspect(x, { maxArrayLength: 101 }).includes('1 more item'));
+ // TODO(wafuwafu13): Fix
+ // assert.strictEqual(util.inspect(x, { maxArrayLength: 0 }),
+ // 'Uint8Array(101) [ ... 101 more items ]');
+ assert(!util.inspect(x, { maxArrayLength: null }).includes('1 more item'));
+ // TODO(wafuwafu13): Fix
+ // assert(util.inspect(x, { maxArrayLength: Infinity }).endsWith(' 0, 0\n]'));
+}
+
+{
+ const obj = { foo: 'abc', bar: 'xyz' };
+ const oneLine = util.inspect(obj, { breakLength: Infinity });
+ // Subtract four for the object's two curly braces and two spaces of padding.
+ // Add one more to satisfy the strictly greater than condition in the code.
+ const breakpoint = oneLine.length - 5;
+ const twoLines = util.inspect(obj, { breakLength: breakpoint });
+
+ assert.strictEqual(oneLine, "{ foo: 'abc', bar: 'xyz' }");
+ assert.strictEqual(
+ util.inspect(obj, { breakLength: breakpoint + 1 }),
+ twoLines
+ );
+ assert.strictEqual(twoLines, "{\n foo: 'abc',\n bar: 'xyz'\n}");
+}
+
+// util.inspect.defaultOptions tests.
+{
+ const arr = new Array(101).fill();
+ const obj = { a: { a: { a: { a: 1 } } } };
+
+ const oldOptions = { ...util.inspect.defaultOptions };
+
+ // Set single option through property assignment.
+ util.inspect.defaultOptions.maxArrayLength = null;
+ assert.doesNotMatch(util.inspect(arr), /1 more item/);
+ util.inspect.defaultOptions.maxArrayLength = oldOptions.maxArrayLength;
+ // TODO(wafuwafu13): Fix
+ // assert.match(util.inspect(arr), /1 more item/);
+ util.inspect.defaultOptions.depth = null;
+ assert.doesNotMatch(util.inspect(obj), /Object/);
+ util.inspect.defaultOptions.depth = oldOptions.depth;
+ assert.match(util.inspect(obj), /Object/);
+ assert.strictEqual(
+ JSON.stringify(util.inspect.defaultOptions),
+ JSON.stringify(oldOptions)
+ );
+
+ // Set multiple options through object assignment.
+ util.inspect.defaultOptions = { maxArrayLength: null, depth: 2 };
+ assert.doesNotMatch(util.inspect(arr), /1 more item/);
+ assert.match(util.inspect(obj), /Object/);
+ util.inspect.defaultOptions = oldOptions;
+ // assert.match(util.inspect(arr), /1 more item/);
+ assert.match(util.inspect(obj), /Object/);
+ assert.strictEqual(
+ JSON.stringify(util.inspect.defaultOptions),
+ JSON.stringify(oldOptions)
+ );
+
+ assert.throws(() => {
+ util.inspect.defaultOptions = null;
+ }, {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: 'The "options" argument must be of type object. ' +
+ 'Received null'
+ }
+ );
+
+ assert.throws(() => {
+ util.inspect.defaultOptions = 'bad';
+ }, {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: 'The "options" argument must be of type object. ' +
+ "Received type string ('bad')"
+ }
+ );
+}
+
+util.inspect(process);
+
+// TODO(wafuwafu13): Fix
+// // Setting custom inspect property to a non-function should do nothing.
+// {
+// const obj = { [util.inspect.custom]: 'fhqwhgads' };
+// assert.strictEqual(
+// util.inspect(obj),
+// "{ [Symbol(nodejs.util.inspect.custom)]: 'fhqwhgads' }"
+// );
+// }
+
+{
+ // @@toStringTag
+ const obj = { [Symbol.toStringTag]: 'a' };
+ // TODO(wafuwafu13): Fix
+ // assert.strictEqual(
+ // util.inspect(obj),
+ // "{ [Symbol(Symbol.toStringTag)]: 'a' }"
+ // );
+ Object.defineProperty(obj, Symbol.toStringTag, {
+ value: 'a',
+ enumerable: false
+ });
+ assert.strictEqual(util.inspect(obj), 'Object [a] {}');
+ // TODO(wafuwafu13): Fix
+ // assert.strictEqual(
+ // util.inspect(obj, { showHidden: true }),
+ // "{ [Symbol(Symbol.toStringTag)]: 'a' }"
+ // );
+
+ class Foo {
+ constructor() {
+ this.foo = 'bar';
+ }
+
+ get [Symbol.toStringTag]() {
+ return this.foo;
+ }
+ }
+
+ // TODO(wafuwafu13): Fix
+ // assert.strictEqual(util.inspect(
+ // Object.create(null, { [Symbol.toStringTag]: { value: 'foo' } })),
+ // '[Object: null prototype] [foo] {}');
+
+ assert.strictEqual(util.inspect(new Foo()), "Foo [bar] { foo: 'bar' }");
+
+ assert.strictEqual(
+ util.inspect(new (class extends Foo {})()),
+ "Foo [bar] { foo: 'bar' }");
+
+ assert.strictEqual(
+ util.inspect(Object.create(Object.create(Foo.prototype), {
+ foo: { value: 'bar', enumerable: true }
+ })),
+ "Foo [bar] { foo: 'bar' }");
+
+ class ThrowingClass {
+ get [Symbol.toStringTag]() {
+ throw new Error('toStringTag error');
+ }
+ }
+
+ assert.throws(() => util.inspect(new ThrowingClass()), /toStringTag error/);
+
+ class NotStringClass {
+ get [Symbol.toStringTag]() {
+ return null;
+ }
+ }
+
+ assert.strictEqual(util.inspect(new NotStringClass()),
+ 'NotStringClass {}');
+}
+
+{
+ const o = {
+ a: [1, 2, [[
+ 'Lorem ipsum dolor\nsit amet,\tconsectetur adipiscing elit, sed do ' +
+ 'eiusmod tempor incididunt ut labore et dolore magna aliqua.',
+ 'test',
+ 'foo']], 4],
+ b: new Map([['za', 1], ['zb', 'test']])
+ };
+
+ let out = util.inspect(o, { compact: true, depth: 5, breakLength: 80 });
+ let expect = [
+ '{ a:',
+ ' [ 1,',
+ ' 2,',
+ " [ [ 'Lorem ipsum dolor\\nsit amet,\\tconsectetur adipiscing elit, " +
+ "sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',",
+ " 'test',",
+ " 'foo' ] ],",
+ ' 4 ],',
+ " b: Map(2) { 'za' => 1, 'zb' => 'test' } }",
+ ].join('\n');
+ assert.strictEqual(out, expect);
+
+ out = util.inspect(o, { compact: false, depth: 5, breakLength: 60 });
+ expect = [
+ '{',
+ ' a: [',
+ ' 1,',
+ ' 2,',
+ ' [',
+ ' [',
+ " 'Lorem ipsum dolor\\n' +",
+ " 'sit amet,\\tconsectetur adipiscing elit, sed do eiusmod " +
+ "tempor incididunt ut labore et dolore magna aliqua.',",
+ " 'test',",
+ " 'foo'",
+ ' ]',
+ ' ],',
+ ' 4',
+ ' ],',
+ ' b: Map(2) {',
+ " 'za' => 1,",
+ " 'zb' => 'test'",
+ ' }',
+ '}',
+ ].join('\n');
+ assert.strictEqual(out, expect);
+
+ out = util.inspect(o.a[2][0][0], { compact: false, breakLength: 30 });
+ expect = [
+ "'Lorem ipsum dolor\\n' +",
+ " 'sit amet,\\tconsectetur adipiscing elit, sed do eiusmod tempor " +
+ "incididunt ut labore et dolore magna aliqua.'",
+ ].join('\n');
+ assert.strictEqual(out, expect);
+
+ out = util.inspect(
+ '12345678901234567890123456789012345678901234567890',
+ { compact: false, breakLength: 3 });
+ expect = "'12345678901234567890123456789012345678901234567890'";
+ assert.strictEqual(out, expect);
+
+ out = util.inspect(
+ '12 45 78 01 34 67 90 23 56 89 123456789012345678901234567890',
+ { compact: false, breakLength: 3 });
+ expect = [
+ "'12 45 78 01 34 67 90 23 56 89 123456789012345678901234567890'",
+ ].join('\n');
+ assert.strictEqual(out, expect);
+
+ // TODO(wafuwafu13): Fix
+ o.a = () => {};
+ o.b = new Number(3);
+ out = util.inspect(o, { compact: false, breakLength: 3 });
+ expect = [
+ '{',
+ ' a: [Function (anonymous)],',
+ ' b: [Number: 3]',
+ '}',
+ ].join('\n');
+ assert.strictEqual(out, expect);
+
+ out = util.inspect(o, { compact: false, breakLength: 3, showHidden: true });
+ expect = [
+ '{',
+ ' a: [Function (anonymous)] {',
+ ' [length]: 0,',
+ " [name]: ''",
+ ' },',
+ ' b: [Number: 3]',
+ '}',
+ ].join('\n');
+ assert.strictEqual(out, expect);
+
+ o[util.inspect.custom] = () => 42;
+ out = util.inspect(o, { compact: false, breakLength: 3 });
+ expect = '42';
+ assert.strictEqual(out, expect);
+
+ o[util.inspect.custom] = () => '12 45 78 01 34 67 90 23';
+ out = util.inspect(o, { compact: false, breakLength: 3 });
+ expect = '12 45 78 01 34 67 90 23';
+ assert.strictEqual(out, expect);
+
+ o[util.inspect.custom] = () => ({ a: '12 45 78 01 34 67 90 23' });
+ out = util.inspect(o, { compact: false, breakLength: 3 });
+ expect = "{\n a: '12 45 78 01 34 67 90 23'\n}";
+ assert.strictEqual(out, expect);
+}
+
+// TODO(wafuwafu13): Fix
+// // Check compact indentation.
+// {
+// const typed = new Uint8Array();
+// typed.buffer.foo = true;
+// const set = new Set([[1, 2]]);
+// const promise = Promise.resolve([[1, set]]);
+// const map = new Map([[promise, typed]]);
+// map.set(set.values(), map.values());
+
+// let out = util.inspect(map, { compact: false, showHidden: true, depth: 9 });
+// let expected = [
+// 'Map(2) {',
+// ' Promise {',
+// ' [',
+// ' [',
+// ' 1,',
+// ' Set(1) {',
+// ' [',
+// ' 1,',
+// ' 2,',
+// ' [length]: 2',
+// ' ]',
+// ' },',
+// ' [length]: 2',
+// ' ],',
+// ' [length]: 1',
+// ' ]',
+// ' } => Uint8Array(0) [',
+// ' [BYTES_PER_ELEMENT]: 1,',
+// ' [length]: 0,',
+// ' [byteLength]: 0,',
+// ' [byteOffset]: 0,',
+// ' [buffer]: ArrayBuffer {',
+// ' byteLength: 0,',
+// ' foo: true',
+// ' }',
+// ' ],',
+// ' [Set Iterator] {',
+// ' [',
+// ' 1,',
+// ' 2,',
+// ' [length]: 2',
+// ' ],',
+// " [Symbol(Symbol.toStringTag)]: 'Set Iterator'",
+// ' } => <ref *1> [Map Iterator] {',
+// ' Uint8Array(0) [',
+// ' [BYTES_PER_ELEMENT]: 1,',
+// ' [length]: 0,',
+// ' [byteLength]: 0,',
+// ' [byteOffset]: 0,',
+// ' [buffer]: ArrayBuffer {',
+// ' byteLength: 0,',
+// ' foo: true',
+// ' }',
+// ' ],',
+// ' [Circular *1],',
+// " [Symbol(Symbol.toStringTag)]: 'Map Iterator'",
+// ' }',
+// '}',
+// ].join('\n');
+
+// assert.strict.equal(out, expected);
+
+// out = util.inspect(map, { compact: 2, showHidden: true, depth: 9 });
+
+// expected = [
+// 'Map(2) {',
+// ' Promise {',
+// ' [',
+// ' [',
+// ' 1,',
+// ' Set(1) { [ 1, 2, [length]: 2 ] },',
+// ' [length]: 2',
+// ' ],',
+// ' [length]: 1',
+// ' ]',
+// ' } => Uint8Array(0) [',
+// ' [BYTES_PER_ELEMENT]: 1,',
+// ' [length]: 0,',
+// ' [byteLength]: 0,',
+// ' [byteOffset]: 0,',
+// ' [buffer]: ArrayBuffer { byteLength: 0, foo: true }',
+// ' ],',
+// ' [Set Iterator] {',
+// ' [ 1, 2, [length]: 2 ],',
+// " [Symbol(Symbol.toStringTag)]: 'Set Iterator'",
+// ' } => <ref *1> [Map Iterator] {',
+// ' Uint8Array(0) [',
+// ' [BYTES_PER_ELEMENT]: 1,',
+// ' [length]: 0,',
+// ' [byteLength]: 0,',
+// ' [byteOffset]: 0,',
+// ' [buffer]: ArrayBuffer { byteLength: 0, foo: true }',
+// ' ],',
+// ' [Circular *1],',
+// " [Symbol(Symbol.toStringTag)]: 'Map Iterator'",
+// ' }',
+// '}',
+// ].join('\n');
+
+// assert.strict.equal(out, expected);
+
+// out = util.inspect(map, {
+// showHidden: true, depth: 9, breakLength: 4, compact: true
+// });
+// expected = [
+// 'Map(2) {',
+// ' Promise {',
+// ' [ [ 1,',
+// ' Set(1) {',
+// ' [ 1,',
+// ' 2,',
+// ' [length]: 2 ] },',
+// ' [length]: 2 ],',
+// ' [length]: 1 ] } => Uint8Array(0) [',
+// ' [BYTES_PER_ELEMENT]: 1,',
+// ' [length]: 0,',
+// ' [byteLength]: 0,',
+// ' [byteOffset]: 0,',
+// ' [buffer]: ArrayBuffer {',
+// ' byteLength: 0,',
+// ' foo: true } ],',
+// ' [Set Iterator] {',
+// ' [ 1,',
+// ' 2,',
+// ' [length]: 2 ],',
+// ' [Symbol(Symbol.toStringTag)]:',
+// " 'Set Iterator' } => <ref *1> [Map Iterator] {",
+// ' Uint8Array(0) [',
+// ' [BYTES_PER_ELEMENT]: 1,',
+// ' [length]: 0,',
+// ' [byteLength]: 0,',
+// ' [byteOffset]: 0,',
+// ' [buffer]: ArrayBuffer {',
+// ' byteLength: 0,',
+// ' foo: true } ],',
+// ' [Circular *1],',
+// ' [Symbol(Symbol.toStringTag)]:',
+// " 'Map Iterator' } }",
+// ].join('\n');
+
+// assert.strict.equal(out, expected);
+// }
+
+// TODO(wafuwafu13): Fix
+// { // Test WeakMap && WeakSet
+// const obj = {};
+// const arr = [];
+// const weakMap = new WeakMap([[obj, arr], [arr, obj]]);
+// let out = util.inspect(weakMap, { showHidden: true });
+// let expect = 'WeakMap { [ [length]: 0 ] => {}, {} => [ [length]: 0 ] }';
+// assert.strictEqual(out, expect);
+
+// out = util.inspect(weakMap);
+// expect = 'WeakMap { <items unknown> }';
+// assert.strictEqual(out, expect);
+
+// out = util.inspect(weakMap, { maxArrayLength: 0, showHidden: true });
+// expect = 'WeakMap { ... 2 more items }';
+// assert.strictEqual(out, expect);
+
+// weakMap.extra = true;
+// out = util.inspect(weakMap, { maxArrayLength: 1, showHidden: true });
+// // It is not possible to determine the output reliable.
+// expect = 'WeakMap { [ [length]: 0 ] => {}, ... 1 more item, extra: true }';
+// let expectAlt = 'WeakMap { {} => [ [length]: 0 ], ... 1 more item, ' +
+// 'extra: true }';
+// assert(out === expect || out === expectAlt,
+// `Found: "${out}"\nrather than: "${expect}"\nor: "${expectAlt}"`);
+
+// // Test WeakSet
+// arr.push(1);
+// const weakSet = new WeakSet([obj, arr]);
+// out = util.inspect(weakSet, { showHidden: true });
+// expect = 'WeakSet { [ 1, [length]: 1 ], {} }';
+// assert.strictEqual(out, expect);
+
+// out = util.inspect(weakSet);
+// expect = 'WeakSet { <items unknown> }';
+// assert.strictEqual(out, expect);
+
+// out = util.inspect(weakSet, { maxArrayLength: -2, showHidden: true });
+// expect = 'WeakSet { ... 2 more items }';
+// assert.strictEqual(out, expect);
+
+// weakSet.extra = true;
+// out = util.inspect(weakSet, { maxArrayLength: 1, showHidden: true });
+// // It is not possible to determine the output reliable.
+// expect = 'WeakSet { {}, ... 1 more item, extra: true }';
+// expectAlt = 'WeakSet { [ 1, [length]: 1 ], ... 1 more item, extra: true }';
+// assert(out === expect || out === expectAlt,
+// `Found: "${out}"\nrather than: "${expect}"\nor: "${expectAlt}"`);
+// // Keep references to the WeakMap entries, otherwise they could be GCed too
+// // early.
+// assert(obj && arr);
+// }
+
+{ // Test argument objects.
+ const args = (function() { return arguments; })('a');
+ assert.strictEqual(util.inspect(args), "[Arguments] { '0': 'a' }");
+}
+
+{
+ // Test that a long linked list can be inspected without throwing an error.
+ const list = {};
+ let head = list;
+ // A linked list of length 100k should be inspectable in some way, even though
+ // the real cutoff value is much lower than 100k.
+ for (let i = 0; i < 100000; i++)
+ head = head.next = {};
+ assert.strictEqual(
+ util.inspect(list),
+ '{ next: { next: { next: [Object] } } }'
+ );
+ const longList = util.inspect(list, { depth: Infinity });
+ const match = longList.match(/next/g);
+ assert(match.length > 500 && match.length < 10000);
+ // TODO(wafuwafu13): Fix
+ // assert(longList.includes('[Object: Inspection interrupted ' +
+ // 'prematurely. Maximum call stack size exceeded.]'));
+}
+
+// Do not escape single quotes if no double quote or backtick is present.
+assert.strictEqual(util.inspect("'"), '"\'"');
+assert.strictEqual(util.inspect('"\''), '`"\'`');
+// eslint-disable-next-line no-template-curly-in-string
+// TODO(@crowlKats)
+//assert.strictEqual(util.inspect('"\'${a}'), "'\"\\'${a}'");
+
+// TODO(wafuwafu13): Fix
+// // Errors should visualize as much information as possible.
+// // If the name is not included in the stack, visualize it as well.
+// [
+// [class Foo extends TypeError {}, 'test'],
+// [class Foo extends TypeError {}, undefined],
+// [class BarError extends Error {}, 'test'],
+// [class BazError extends Error {
+// get name() {
+// return 'BazError';
+// }
+// }, undefined],
+// ].forEach(([Class, message], i) => {
+// console.log('Test %i', i);
+// const foo = new Class(message);
+// const name = foo.name;
+// const extra = Class.name.includes('Error') ? '' : ` [${foo.name}]`;
+// assert(
+// util.inspect(foo).startsWith(
+// `${Class.name}${extra}${message ? `: ${message}` : '\n'}`),
+// util.inspect(foo)
+// );
+// Object.defineProperty(foo, Symbol.toStringTag, {
+// value: 'WOW',
+// writable: true,
+// configurable: true
+// });
+// const stack = foo.stack;
+// foo.stack = 'This is a stack';
+// assert.strictEqual(
+// util.inspect(foo),
+// '[This is a stack]'
+// );
+// foo.stack = stack;
+// assert(
+// util.inspect(foo).startsWith(
+// `${Class.name} [WOW]${extra}${message ? `: ${message}` : '\n'}`),
+// util.inspect(foo)
+// );
+// Object.setPrototypeOf(foo, null);
+// assert(
+// util.inspect(foo).startsWith(
+// `[${name}: null prototype] [WOW]${message ? `: ${message}` : '\n'}`
+// ),
+// util.inspect(foo)
+// );
+// foo.bar = true;
+// delete foo[Symbol.toStringTag];
+// assert(
+// util.inspect(foo).startsWith(
+// `[${name}: null prototype]${message ? `: ${message}` : '\n'}`),
+// util.inspect(foo)
+// );
+// foo.stack = 'This is a stack';
+// assert.strictEqual(
+// util.inspect(foo),
+// '[[Error: null prototype]: This is a stack] { bar: true }'
+// );
+// foo.stack = stack.split('\n')[0];
+// assert.strictEqual(
+// util.inspect(foo),
+// `[[${name}: null prototype]${message ? `: ${message}` : ''}] { bar: true }`
+// );
+// });
+
+// TODO(wafuwafu13): Fix
+// // Verify that classes are properly inspected.
+// [
+// /* eslint-disable spaced-comment, no-multi-spaces, brace-style */
+// // The whitespace is intentional.
+// [class { }, '[class (anonymous)]'],
+// [class extends Error { log() {} }, '[class (anonymous) extends Error]'],
+// [class A { constructor(a) { this.a = a; } log() { return this.a; } },
+// '[class A]'],
+// [class
+// // Random { // comments /* */ are part of the toString() result
+// /* eslint-disable-next-line space-before-blocks */
+// äß/**/extends/*{*/TypeError{}, '[class äß extends TypeError]'],
+// /* The whitespace and new line is intended! */
+// // Foobar !!!
+// [class X extends /****/ Error
+// // More comments
+// {}, '[class X extends Error]'],
+// /* eslint-enable spaced-comment, no-multi-spaces, brace-style */
+// ].forEach(([clazz, string]) => {
+// const inspected = util.inspect(clazz);
+// assert.strictEqual(inspected, string);
+// Object.defineProperty(clazz, Symbol.toStringTag, {
+// value: 'Woohoo'
+// });
+// const parts = inspected.slice(0, -1).split(' ');
+// const [, name, ...rest] = parts;
+// rest.unshift('[Woohoo]');
+// if (rest.length) {
+// rest[rest.length - 1] += ']';
+// }
+// assert.strictEqual(
+// util.inspect(clazz),
+// ['[class', name, ...rest].join(' ')
+// );
+// if (rest.length) {
+// rest[rest.length - 1] = rest[rest.length - 1].slice(0, -1);
+// rest.length = 1;
+// }
+// Object.setPrototypeOf(clazz, Map.prototype);
+// assert.strictEqual(
+// util.inspect(clazz),
+// ['[class', name, '[Map]', ...rest].join(' ') + ']'
+// );
+// Object.setPrototypeOf(clazz, null);
+// assert.strictEqual(
+// util.inspect(clazz),
+// ['[class', name, ...rest, 'extends [null prototype]]'].join(' ')
+// );
+// Object.defineProperty(clazz, 'name', { value: 'Foo' });
+// const res = ['[class', 'Foo', ...rest, 'extends [null prototype]]'].join(' ');
+// assert.strictEqual(util.inspect(clazz), res);
+// clazz.foo = true;
+// assert.strictEqual(util.inspect(clazz), `${res} { foo: true }`);
+// });
+
+// "class" properties should not be detected as "class".
+{
+ // eslint-disable-next-line space-before-function-paren
+ let obj = { class () {} };
+ assert.strictEqual(
+ util.inspect(obj),
+ '{ class: [Function: class] }'
+ );
+ obj = { class: () => {} };
+ assert.strictEqual(
+ util.inspect(obj),
+ '{ class: [Function: class] }'
+ );
+ obj = { ['class Foo {}']() {} };
+ assert.strictEqual(
+ util.inspect(obj),
+ "{ 'class Foo {}': [Function: class Foo {}] }"
+ );
+ function Foo() {}
+ Object.defineProperty(Foo, 'toString', { value: () => 'class Foo {}' });
+ assert.strictEqual(
+ util.inspect(Foo),
+ '[Function: Foo]'
+ );
+ function fn() {}
+ Object.defineProperty(fn, 'name', { value: 'class Foo {}' });
+ assert.strictEqual(
+ util.inspect(fn),
+ '[Function: class Foo {}]'
+ );
+}
+
+// TODO(wafuwafu13): Fix
+// // Verify that throwing in valueOf and toString still produces nice results.
+// [
+// [new String(55), "[String: '55']"],
+// [new Boolean(true), '[Boolean: true]'],
+// [new Number(55), '[Number: 55]'],
+// [Object(BigInt(55)), '[BigInt: 55n]'],
+// [Object(Symbol('foo')), '[Symbol: Symbol(foo)]'],
+// [function() {}, '[Function (anonymous)]'],
+// [() => {}, '[Function (anonymous)]'],
+// [[1, 2], '[ 1, 2 ]'],
+// [[, , 5, , , , ], '[ <2 empty items>, 5, <3 empty items> ]'],
+// [{ a: 5 }, '{ a: 5 }'],
+// [new Set([1, 2]), 'Set(2) { 1, 2 }'],
+// [new Map([[1, 2]]), 'Map(1) { 1 => 2 }'],
+// [new Set([1, 2]).entries(), '[Set Entries] { [ 1, 1 ], [ 2, 2 ] }'],
+// [new Map([[1, 2]]).keys(), '[Map Iterator] { 1 }'],
+// [new Date(2000), '1970-01-01T00:00:02.000Z'],
+// [new Uint8Array(2), 'Uint8Array(2) [ 0, 0 ]'],
+// [new Promise((resolve) => setTimeout(resolve, 10)), 'Promise { <pending> }'],
+// [new WeakSet(), 'WeakSet { <items unknown> }'],
+// [new WeakMap(), 'WeakMap { <items unknown> }'],
+// [/foobar/g, '/foobar/g'],
+// ].forEach(([value, expected]) => {
+// Object.defineProperty(value, 'valueOf', {
+// get() {
+// throw new Error('valueOf');
+// }
+// });
+// Object.defineProperty(value, 'toString', {
+// get() {
+// throw new Error('toString');
+// }
+// });
+// assert.strictEqual(util.inspect(value), expected);
+// value.foo = 'bar';
+// assert.notStrictEqual(util.inspect(value), expected);
+// delete value.foo;
+// value[Symbol('foo')] = 'yeah';
+// assert.notStrictEqual(util.inspect(value), expected);
+// });
+
+// TODO(wafuwafu13): Fix
+// // Verify that having no prototype still produces nice results.
+// [
+// [[1, 3, 4], '[Array(3): null prototype] [ 1, 3, 4 ]'],
+// [new Set([1, 2]), '[Set(2): null prototype] { 1, 2 }'],
+// [new Map([[1, 2]]), '[Map(1): null prototype] { 1 => 2 }'],
+// [new Promise((resolve) => setTimeout(resolve, 10)),
+// '[Promise: null prototype] { <pending> }'],
+// [new WeakSet(), '[WeakSet: null prototype] { <items unknown> }'],
+// [new WeakMap(), '[WeakMap: null prototype] { <items unknown> }'],
+// [new Uint8Array(2), '[Uint8Array(2): null prototype] [ 0, 0 ]'],
+// [new Uint16Array(2), '[Uint16Array(2): null prototype] [ 0, 0 ]'],
+// [new Uint32Array(2), '[Uint32Array(2): null prototype] [ 0, 0 ]'],
+// [new Int8Array(2), '[Int8Array(2): null prototype] [ 0, 0 ]'],
+// [new Int16Array(2), '[Int16Array(2): null prototype] [ 0, 0 ]'],
+// [new Int32Array(2), '[Int32Array(2): null prototype] [ 0, 0 ]'],
+// [new Float32Array(2), '[Float32Array(2): null prototype] [ 0, 0 ]'],
+// [new Float64Array(2), '[Float64Array(2): null prototype] [ 0, 0 ]'],
+// [new BigInt64Array(2), '[BigInt64Array(2): null prototype] [ 0n, 0n ]'],
+// [new BigUint64Array(2), '[BigUint64Array(2): null prototype] [ 0n, 0n ]'],
+// [new ArrayBuffer(16), '[ArrayBuffer: null prototype] {\n' +
+// ' [Uint8Contents]: <00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00>,\n' +
+// ' byteLength: undefined\n}'],
+// [new DataView(new ArrayBuffer(16)),
+// '[DataView: null prototype] {\n byteLength: undefined,\n ' +
+// 'byteOffset: undefined,\n buffer: undefined\n}'],
+// [new SharedArrayBuffer(2), '[SharedArrayBuffer: null prototype] ' +
+// '{\n [Uint8Contents]: <00 00>,\n byteLength: undefined\n}'],
+// [/foobar/, '[RegExp: null prototype] /foobar/'],
+// [new Date('Sun, 14 Feb 2010 11:48:40 GMT'),
+// '[Date: null prototype] 2010-02-14T11:48:40.000Z'],
+// ].forEach(([value, expected]) => {
+// assert.strictEqual(
+// util.inspect(Object.setPrototypeOf(value, null)),
+// expected
+// );
+// value.foo = 'bar';
+// assert.notStrictEqual(util.inspect(value), expected);
+// delete value.foo;
+// value[Symbol('foo')] = 'yeah';
+// assert.notStrictEqual(util.inspect(value), expected);
+// });
+
+// TODO(wafuwafu13): Fix
+// // Verify that subclasses with and without prototype produce nice results.
+// [
+// [RegExp, ['foobar', 'g'], '/foobar/g'],
+// [WeakSet, [[{}]], '{ <items unknown> }'],
+// [WeakMap, [[[{}, {}]]], '{ <items unknown> }'],
+// [BigInt64Array,
+// [10],
+// '[\n 0n, 0n, 0n, 0n, 0n,\n 0n, 0n, 0n, 0n, 0n\n]'],
+// [Date, ['Sun, 14 Feb 2010 11:48:40 GMT'], '2010-02-14T11:48:40.000Z'],
+// [Date, ['invalid_date'], 'Invalid Date'],
+// ].forEach(([base, input, rawExpected]) => {
+// class Foo extends base {}
+// const value = new Foo(...input);
+// const symbol = value[Symbol.toStringTag];
+// const size = base.name.includes('Array') ? `(${input[0]})` : '';
+// const expected = `Foo${size} ${symbol ? `[${symbol}] ` : ''}${rawExpected}`;
+// const expectedWithoutProto =
+// `[${base.name}${size}: null prototype] ${rawExpected}`;
+// assert.strictEqual(util.inspect(value), expected);
+// value.foo = 'bar';
+// assert.notStrictEqual(util.inspect(value), expected);
+// delete value.foo;
+// assert.strictEqual(
+// util.inspect(Object.setPrototypeOf(value, null)),
+// expectedWithoutProto
+// );
+// value.foo = 'bar';
+// let res = util.inspect(value);
+// assert.notStrictEqual(res, expectedWithoutProto);
+// assert.match(res, /foo: 'bar'/);
+// delete value.foo;
+// value[Symbol('foo')] = 'yeah';
+// res = util.inspect(value);
+// assert.notStrictEqual(res, expectedWithoutProto);
+// assert.match(res, /\[Symbol\(foo\)]: 'yeah'/);
+// });
+
+assert.strictEqual(inspect(1n), '1n');
+assert.strictEqual(inspect(Object(-1n)), '[BigInt: -1n]');
+assert.strictEqual(inspect(Object(13n)), '[BigInt: 13n]');
+// TODO(wafuwafu13): Fix
+// assert.strictEqual(inspect(new BigInt64Array([0n])), 'BigInt64Array(1) [ 0n ]');
+// assert.strictEqual(
+// inspect(new BigUint64Array([0n])), 'BigUint64Array(1) [ 0n ]');
+
+// Verify non-enumerable keys get escaped.
+{
+ const obj = {};
+ Object.defineProperty(obj, 'Non\nenumerable\tkey', { value: true });
+ assert.strictEqual(
+ util.inspect(obj, { showHidden: true }),
+ '{ [Non\\nenumerable\\tkey]: true }'
+ );
+}
+
+// Check for special colors.
+{
+ const special = inspect.colors[inspect.styles.special];
+ const string = inspect.colors[inspect.styles.string];
+
+ assert.strictEqual(
+ inspect(new WeakSet(), { colors: true }),
+ `WeakSet { \u001b[${special[0]}m<items unknown>\u001b[${special[1]}m }`
+ );
+ assert.strictEqual(
+ inspect(new WeakMap(), { colors: true }),
+ `WeakMap { \u001b[${special[0]}m<items unknown>\u001b[${special[1]}m }`
+ );
+ // TODO(wafuwafu13): Fix
+ // assert.strictEqual(
+ // inspect(new Promise(() => {}), { colors: true }),
+ // `Promise { \u001b[${special[0]}m<pending>\u001b[${special[1]}m }`
+ // );
+
+ // const rejection = Promise.reject('Oh no!');
+ // assert.strictEqual(
+ // inspect(rejection, { colors: true }),
+ // `Promise { \u001b[${special[0]}m<rejected>\u001b[${special[1]}m ` +
+ // `\u001b[${string[0]}m'Oh no!'\u001b[${string[1]}m }`
+ // );
+ // rejection.catch(() => {});
+
+ // Verify that aliases do not show up as key while checking `inspect.colors`.
+ const colors = Object.keys(inspect.colors);
+ const aliases = Object.getOwnPropertyNames(inspect.colors)
+ .filter((c) => !colors.includes(c));
+ assert(!colors.includes('grey'));
+ assert(colors.includes('gray'));
+ // Verify that all aliases are correctly mapped.
+ for (const alias of aliases) {
+ assert(Array.isArray(inspect.colors[alias]));
+ }
+ // Check consistent naming.
+ [
+ 'black',
+ 'red',
+ 'green',
+ 'yellow',
+ 'blue',
+ 'magenta',
+ 'cyan',
+ 'white',
+ ].forEach((color, i) => {
+ assert.deepStrictEqual(inspect.colors[color], [30 + i, 39]);
+ assert.deepStrictEqual(inspect.colors[`${color}Bright`], [90 + i, 39]);
+ const bgColor = `bg${color[0].toUpperCase()}${color.slice(1)}`;
+ assert.deepStrictEqual(inspect.colors[bgColor], [40 + i, 49]);
+ assert.deepStrictEqual(inspect.colors[`${bgColor}Bright`], [100 + i, 49]);
+ });
+
+ // Unknown colors are handled gracefully:
+ const stringStyle = inspect.styles.string;
+ inspect.styles.string = 'UNKNOWN';
+ assert.strictEqual(inspect('foobar', { colors: true }), "'foobar'");
+ inspect.styles.string = stringStyle;
+}
+
+assert.strictEqual(
+ inspect([1, 3, 2], { sorted: true }),
+ inspect([1, 3, 2])
+);
+assert.strictEqual(
+ inspect({ c: 3, a: 1, b: 2 }, { sorted: true }),
+ '{ a: 1, b: 2, c: 3 }'
+);
+assert.strictEqual(
+ inspect(
+ { a200: 4, a100: 1, a102: 3, a101: 2 },
+ { sorted(a, b) { return b.localeCompare(a); } }
+ ),
+ '{ a200: 4, a102: 3, a101: 2, a100: 1 }'
+);
+
+// TODO(wafuwafu13): Fix
+// // Non-indices array properties are sorted as well.
+// {
+// const arr = [3, 2, 1];
+// arr.b = 2;
+// arr.c = 3;
+// arr.a = 1;
+// arr[Symbol('b')] = true;
+// arr[Symbol('a')] = false;
+// assert.strictEqual(
+// inspect(arr, { sorted: true }),
+// '[ 3, 2, 1, [Symbol(a)]: false, [Symbol(b)]: true, a: 1, b: 2, c: 3 ]'
+// );
+// }
+
+// TODO(wafuwafu13): Fix
+// // Manipulate the prototype in weird ways.
+// {
+// let obj = { a: true };
+// let value = (function() { return function() {}; })();
+// Object.setPrototypeOf(value, null);
+// Object.setPrototypeOf(obj, value);
+// assert.strictEqual(
+// util.inspect(obj),
+// 'Object <[Function (null prototype) (anonymous)]> { a: true }'
+// );
+// assert.strictEqual(
+// util.inspect(obj, { colors: true }),
+// 'Object <\u001b[36m[Function (null prototype) (anonymous)]\u001b[39m> ' +
+// '{ a: \u001b[33mtrue\u001b[39m }'
+// );
+
+// obj = { a: true };
+// value = [];
+// Object.setPrototypeOf(value, null);
+// Object.setPrototypeOf(obj, value);
+// assert.strictEqual(
+// util.inspect(obj),
+// 'Object <[Array(0): null prototype] []> { a: true }'
+// );
+
+// function StorageObject() {}
+// StorageObject.prototype = Object.create(null);
+// assert.strictEqual(
+// util.inspect(new StorageObject()),
+// 'StorageObject <[Object: null prototype] {}> {}'
+// );
+
+// obj = [1, 2, 3];
+// Object.setPrototypeOf(obj, Number.prototype);
+// assert.strictEqual(inspect(obj), "Number { '0': 1, '1': 2, '2': 3 }");
+
+// Object.setPrototypeOf(obj, Object.create(null));
+// assert.strictEqual(
+// inspect(obj),
+// "Array <[Object: null prototype] {}> { '0': 1, '1': 2, '2': 3 }"
+// );
+
+// StorageObject.prototype = Object.create(null);
+// Object.setPrototypeOf(StorageObject.prototype, Object.create(null));
+// Object.setPrototypeOf(
+// Object.getPrototypeOf(StorageObject.prototype),
+// Object.create(null)
+// );
+// assert.strictEqual(
+// util.inspect(new StorageObject()),
+// 'StorageObject <Object <Object <[Object: null prototype] {}>>> {}'
+// );
+// assert.strictEqual(
+// util.inspect(new StorageObject(), { depth: 1 }),
+// 'StorageObject <Object <Object <Complex prototype>>> {}'
+// );
+// }
+
+// TODO(wafuwafu13): Fix
+// // Check that the fallback always works.
+// {
+// const obj = new Set([1, 2]);
+// const iterator = obj[Symbol.iterator];
+// Object.setPrototypeOf(obj, null);
+// Object.defineProperty(obj, Symbol.iterator, {
+// value: iterator,
+// configurable: true
+// });
+// assert.strictEqual(util.inspect(obj), '[Set(2): null prototype] { 1, 2 }');
+// Object.defineProperty(obj, Symbol.iterator, {
+// value: true,
+// configurable: true
+// });
+// Object.defineProperty(obj, 'size', {
+// value: NaN,
+// configurable: true,
+// enumerable: true
+// });
+// assert.strictEqual(
+// util.inspect(obj),
+// '[Set(2): null prototype] { 1, 2, size: NaN }'
+// );
+// }
+
+// TODO(wafuwafu13): Fix
+// Check the getter option.
+{
+ let foo = 1;
+ const get = { get foo() { return foo; } };
+ const getset = {
+ get foo() { return foo; },
+ set foo(val) { foo = val; },
+ get inc() { return ++foo; }
+ };
+ const thrower = { get foo() { throw new Error('Oops'); } };
+ assert.strictEqual(
+ inspect(get, { getters: true, colors: true }),
+ '{ foo: \u001b[36m[Getter:\u001b[39m ' +
+ '\u001b[33m1\u001b[39m\u001b[36m]\u001b[39m }');
+ assert.strictEqual(
+ inspect(thrower, { getters: true }),
+ '{ foo: [Getter: <Inspection threw (Oops)>] }');
+ assert.strictEqual(
+ inspect(getset, { getters: true }),
+ '{ foo: [Getter/Setter: 1], inc: [Getter: 2] }');
+ assert.strictEqual(
+ inspect(getset, { getters: 'get' }),
+ '{ foo: [Getter/Setter], inc: [Getter: 3] }');
+ assert.strictEqual(
+ inspect(getset, { getters: 'set' }),
+ '{ foo: [Getter/Setter: 3], inc: [Getter] }');
+ getset.foo = new Set([[{ a: true }, 2, {}], 'foobar', { x: 1 }]);
+ // assert.strictEqual(
+ // inspect(getset, { getters: true }),
+ // '{\n foo: [Getter/Setter] Set(3) { [ [Object], 2, {} ], ' +
+ // "'foobar', { x: 1 } },\n inc: [Getter: NaN]\n}");
+}
+
+// Check compact number mode.
+{
+ let obj = {
+ a: {
+ b: {
+ x: 5,
+ c: {
+ x: '10000000000000000 00000000000000000 '.repeat(1e1),
+ d: 2,
+ e: 3
+ }
+ }
+ },
+ b: [
+ 1,
+ 2,
+ [ 1, 2, { a: 1, b: 2, c: 3 } ],
+ ],
+ c: ['foo', 4, 444444],
+ d: Array.from({ length: 101 }).map((e, i) => {
+ return i % 2 === 0 ? i * i : i;
+ }),
+ e: Array(6).fill('foobar'),
+ f: Array(9).fill('foobar'),
+ g: Array(21).fill('foobar baz'),
+ h: [100].concat(Array.from({ length: 9 }).map((e, n) => (n))),
+ long: Array(9).fill('This text is too long for grouping!')
+ };
+
+ let out = util.inspect(obj, { compact: 3, depth: 10, breakLength: 60 });
+ let expected = [
+ '{',
+ ' a: {',
+ ' b: {',
+ ' x: 5,',
+ ' c: {',
+ " x: '10000000000000000 00000000000000000 10000000000000000 " +
+ '00000000000000000 10000000000000000 00000000000000000 ' +
+ '10000000000000000 00000000000000000 10000000000000000 ' +
+ '00000000000000000 10000000000000000 00000000000000000 ' +
+ '10000000000000000 00000000000000000 10000000000000000 ' +
+ '00000000000000000 10000000000000000 00000000000000000 ' +
+ "10000000000000000 00000000000000000 ',",
+ ' d: 2,',
+ ' e: 3',
+ ' }',
+ ' }',
+ ' },',
+ ' b: [ 1, 2, [ 1, 2, { a: 1, b: 2, c: 3 } ] ],',
+ " c: [ 'foo', 4, 444444 ],",
+ ' d: [',
+ ' 0, 1, 4, 3, 16, 5, 36, 7, 64,',
+ ' 9, 100, 11, 144, 13, 196, 15, 256, 17,',
+ ' 324, 19, 400, 21, 484, 23, 576, 25, 676,',
+ ' 27, 784, 29, 900, 31, 1024, 33, 1156, 35,',
+ ' 1296, 37, 1444, 39, 1600, 41, 1764, 43, 1936,',
+ ' 45, 2116, 47, 2304, 49, 2500, 51, 2704, 53,',
+ ' 2916, 55, 3136, 57, 3364, 59, 3600, 61, 3844,',
+ ' 63, 4096, 65, 4356, 67, 4624, 69, 4900, 71,',
+ ' 5184, 73, 5476, 75, 5776, 77, 6084, 79, 6400,',
+ ' 81, 6724, 83, 7056, 85, 7396, 87, 7744, 89,',
+ ' 8100, 91, 8464, 93, 8836, 95, 9216, 97, 9604,',
+ ' 99,',
+ ' ... 1 more item',
+ ' ],',
+ ' e: [',
+ " 'foobar',",
+ " 'foobar',",
+ " 'foobar',",
+ " 'foobar',",
+ " 'foobar',",
+ " 'foobar'",
+ ' ],',
+ ' f: [',
+ " 'foobar', 'foobar',",
+ " 'foobar', 'foobar',",
+ " 'foobar', 'foobar',",
+ " 'foobar', 'foobar',",
+ " 'foobar'",
+ ' ],',
+ ' g: [',
+ " 'foobar baz', 'foobar baz',",
+ " 'foobar baz', 'foobar baz',",
+ " 'foobar baz', 'foobar baz',",
+ " 'foobar baz', 'foobar baz',",
+ " 'foobar baz', 'foobar baz',",
+ " 'foobar baz', 'foobar baz',",
+ " 'foobar baz', 'foobar baz',",
+ " 'foobar baz', 'foobar baz',",
+ " 'foobar baz', 'foobar baz',",
+ " 'foobar baz', 'foobar baz',",
+ " 'foobar baz'",
+ ' ],',
+ ' h: [',
+ ' 100, 0, 1, 2, 3,',
+ ' 4, 5, 6, 7, 8',
+ ' ],',
+ ' long: [',
+ " 'This text is too long for grouping!',",
+ " 'This text is too long for grouping!',",
+ " 'This text is too long for grouping!',",
+ " 'This text is too long for grouping!',",
+ " 'This text is too long for grouping!',",
+ " 'This text is too long for grouping!',",
+ " 'This text is too long for grouping!',",
+ " 'This text is too long for grouping!',",
+ " 'This text is too long for grouping!'",
+ ' ]',
+ '}',
+ ].join('\n');
+
+ // TODO(wafuwafu13): Fix
+ // assert.strictEqual(out, expected);
+
+ obj = [
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 123456789,
+ ];
+
+ out = util.inspect(obj, { compact: 3 });
+
+ expected = [
+ '[',
+ ' 1, 1, 1, 1,',
+ ' 1, 1, 1, 1,',
+ ' 1, 1, 1, 1,',
+ ' 1, 1, 1, 1,',
+ ' 1, 1, 1, 1,',
+ ' 1, 1, 1, 1,',
+ ' 1, 1, 123456789',
+ ']',
+ ].join('\n');
+
+ // TODO(wafuwafu13): Fix
+ // assert.strictEqual(out, expected);
+
+ // Unicode support. あ has a length of one and a width of two.
+ obj = [
+ '123', '123', '123', '123', 'あああ',
+ '123', '123', '123', '123', 'あああ',
+ ];
+
+ out = util.inspect(obj, { compact: 3 });
+
+ expected = [
+ '[',
+ " '123', '123',",
+ " '123', '123',",
+ " 'あああ', '123',",
+ " '123', '123',",
+ " '123', 'あああ'",
+ ']',
+ ].join('\n');
+
+ // TODO(wafuwafu13): Fix
+ // assert.strictEqual(out, expected);
+
+ // Verify that array grouping and line consolidation does not happen together.
+ obj = {
+ a: {
+ b: {
+ x: 5,
+ c: {
+ d: 2,
+ e: 3
+ }
+ }
+ },
+ b: Array.from({ length: 9 }).map((e, n) => {
+ return n % 2 === 0 ? 'foobar' : 'baz';
+ })
+ };
+
+ out = util.inspect(obj, { compact: 1, breakLength: Infinity, colors: true });
+
+ expected = [
+ '{',
+ ' a: {',
+ ' b: { x: \u001b[33m5\u001b[39m, c: \u001b[36m[Object]\u001b[39m }',
+ ' },',
+ ' b: [',
+ " \u001b[32m'foobar'\u001b[39m, \u001b[32m'baz'\u001b[39m,",
+ " \u001b[32m'foobar'\u001b[39m, \u001b[32m'baz'\u001b[39m,",
+ " \u001b[32m'foobar'\u001b[39m, \u001b[32m'baz'\u001b[39m,",
+ " \u001b[32m'foobar'\u001b[39m, \u001b[32m'baz'\u001b[39m,",
+ " \u001b[32m'foobar'\u001b[39m",
+ ' ]',
+ '}',
+ ].join('\n');
+
+ // TODO(wafuwafu13): Fix
+ // assert.strictEqual(out, expected);
+
+ obj = Array.from({ length: 60 }).map((e, i) => i);
+ out = util.inspect(obj, { compact: 1, breakLength: Infinity, colors: true });
+
+ expected = [
+ '[',
+ /* eslint-disable max-len */
+ ' \u001b[33m0\u001b[39m, \u001b[33m1\u001b[39m, \u001b[33m2\u001b[39m, \u001b[33m3\u001b[39m,',
+ ' \u001b[33m4\u001b[39m, \u001b[33m5\u001b[39m, \u001b[33m6\u001b[39m, \u001b[33m7\u001b[39m,',
+ ' \u001b[33m8\u001b[39m, \u001b[33m9\u001b[39m, \u001b[33m10\u001b[39m, \u001b[33m11\u001b[39m,',
+ ' \u001b[33m12\u001b[39m, \u001b[33m13\u001b[39m, \u001b[33m14\u001b[39m, \u001b[33m15\u001b[39m,',
+ ' \u001b[33m16\u001b[39m, \u001b[33m17\u001b[39m, \u001b[33m18\u001b[39m, \u001b[33m19\u001b[39m,',
+ ' \u001b[33m20\u001b[39m, \u001b[33m21\u001b[39m, \u001b[33m22\u001b[39m, \u001b[33m23\u001b[39m,',
+ ' \u001b[33m24\u001b[39m, \u001b[33m25\u001b[39m, \u001b[33m26\u001b[39m, \u001b[33m27\u001b[39m,',
+ ' \u001b[33m28\u001b[39m, \u001b[33m29\u001b[39m, \u001b[33m30\u001b[39m, \u001b[33m31\u001b[39m,',
+ ' \u001b[33m32\u001b[39m, \u001b[33m33\u001b[39m, \u001b[33m34\u001b[39m, \u001b[33m35\u001b[39m,',
+ ' \u001b[33m36\u001b[39m, \u001b[33m37\u001b[39m, \u001b[33m38\u001b[39m, \u001b[33m39\u001b[39m,',
+ ' \u001b[33m40\u001b[39m, \u001b[33m41\u001b[39m, \u001b[33m42\u001b[39m, \u001b[33m43\u001b[39m,',
+ ' \u001b[33m44\u001b[39m, \u001b[33m45\u001b[39m, \u001b[33m46\u001b[39m, \u001b[33m47\u001b[39m,',
+ ' \u001b[33m48\u001b[39m, \u001b[33m49\u001b[39m, \u001b[33m50\u001b[39m, \u001b[33m51\u001b[39m,',
+ ' \u001b[33m52\u001b[39m, \u001b[33m53\u001b[39m, \u001b[33m54\u001b[39m, \u001b[33m55\u001b[39m,',
+ ' \u001b[33m56\u001b[39m, \u001b[33m57\u001b[39m, \u001b[33m58\u001b[39m, \u001b[33m59\u001b[39m',
+ /* eslint-enable max-len */
+ ']',
+ ].join('\n');
+
+ // TODO(wafuwafu13): Fix
+ // assert.strictEqual(out, expected);
+
+ out = util.inspect([1, 2, 3, 4], { compact: 1, colors: true });
+ expected = '[ \u001b[33m1\u001b[39m, \u001b[33m2\u001b[39m, ' +
+ '\u001b[33m3\u001b[39m, \u001b[33m4\u001b[39m ]';
+
+ assert.strictEqual(out, expected);
+
+ obj = [
+ 'Object', 'Function', 'Array',
+ 'Number', 'parseFloat', 'parseInt',
+ 'Infinity', 'NaN', 'undefined',
+ 'Boolean', 'String', 'Symbol',
+ 'Date', 'Promise', 'RegExp',
+ 'Error', 'EvalError', 'RangeError',
+ 'ReferenceError', 'SyntaxError', 'TypeError',
+ 'URIError', 'JSON', 'Math',
+ 'console', 'Intl', 'ArrayBuffer',
+ 'Uint8Array', 'Int8Array', 'Uint16Array',
+ 'Int16Array', 'Uint32Array', 'Int32Array',
+ 'Float32Array', 'Float64Array', 'Uint8ClampedArray',
+ 'BigUint64Array', 'BigInt64Array', 'DataView',
+ 'Map', 'BigInt', 'Set',
+ 'WeakMap', 'WeakSet', 'Proxy',
+ 'Reflect', 'decodeURI', 'decodeURIComponent',
+ 'encodeURI', 'encodeURIComponent', 'escape',
+ 'unescape', 'eval', 'isFinite',
+ 'isNaN', 'SharedArrayBuffer', 'Atomics',
+ 'globalThis', 'WebAssembly', 'global',
+ 'process', 'Buffer', 'URL',
+ 'URLSearchParams', 'TextEncoder', 'TextDecoder',
+ 'clearInterval', 'clearTimeout', 'setInterval',
+ 'setTimeout', 'queueMicrotask', 'clearImmediate',
+ 'setImmediate', 'module', 'require',
+ 'assert', 'async_hooks', 'buffer',
+ 'child_process', 'cluster', 'crypto',
+ 'dgram', 'dns', 'domain',
+ 'events', 'fs', 'http',
+ 'http2', 'https', 'inspector',
+ 'net', 'os', 'path',
+ 'perf_hooks', 'punycode', 'querystring',
+ 'readline', 'repl', 'stream',
+ 'string_decoder', 'tls', 'trace_events',
+ 'tty', 'url', 'v8',
+ 'vm', 'worker_threads', 'zlib',
+ '_', '_error', 'util',
+ ];
+
+ out = util.inspect(
+ obj,
+ { compact: 3, breakLength: 80, maxArrayLength: 250 }
+ );
+ expected = [
+ '[',
+ " 'Object', 'Function', 'Array',",
+ " 'Number', 'parseFloat', 'parseInt',",
+ " 'Infinity', 'NaN', 'undefined',",
+ " 'Boolean', 'String', 'Symbol',",
+ " 'Date', 'Promise', 'RegExp',",
+ " 'Error', 'EvalError', 'RangeError',",
+ " 'ReferenceError', 'SyntaxError', 'TypeError',",
+ " 'URIError', 'JSON', 'Math',",
+ " 'console', 'Intl', 'ArrayBuffer',",
+ " 'Uint8Array', 'Int8Array', 'Uint16Array',",
+ " 'Int16Array', 'Uint32Array', 'Int32Array',",
+ " 'Float32Array', 'Float64Array', 'Uint8ClampedArray',",
+ " 'BigUint64Array', 'BigInt64Array', 'DataView',",
+ " 'Map', 'BigInt', 'Set',",
+ " 'WeakMap', 'WeakSet', 'Proxy',",
+ " 'Reflect', 'decodeURI', 'decodeURIComponent',",
+ " 'encodeURI', 'encodeURIComponent', 'escape',",
+ " 'unescape', 'eval', 'isFinite',",
+ " 'isNaN', 'SharedArrayBuffer', 'Atomics',",
+ " 'globalThis', 'WebAssembly', 'global',",
+ " 'process', 'Buffer', 'URL',",
+ " 'URLSearchParams', 'TextEncoder', 'TextDecoder',",
+ " 'clearInterval', 'clearTimeout', 'setInterval',",
+ " 'setTimeout', 'queueMicrotask', 'clearImmediate',",
+ " 'setImmediate', 'module', 'require',",
+ " 'assert', 'async_hooks', 'buffer',",
+ " 'child_process', 'cluster', 'crypto',",
+ " 'dgram', 'dns', 'domain',",
+ " 'events', 'fs', 'http',",
+ " 'http2', 'https', 'inspector',",
+ " 'net', 'os', 'path',",
+ " 'perf_hooks', 'punycode', 'querystring',",
+ " 'readline', 'repl', 'stream',",
+ " 'string_decoder', 'tls', 'trace_events',",
+ " 'tty', 'url', 'v8',",
+ " 'vm', 'worker_threads', 'zlib',",
+ " '_', '_error', 'util'",
+ ']',
+ ].join('\n');
+
+ // TODO(wafuwafu13): Fix
+ // assert.strictEqual(out, expected);
+}
+
+// TODO(wafuwafu13): Fix
+// {
+// // Use a fake stack to verify the expected colored outcome.
+// const stack = [
+// 'TypedError: Wonderful message!',
+// ' at A.<anonymous> (/test/node_modules/foo/node_modules/bar/baz.js:2:7)',
+// ' at Module._compile (node:internal/modules/cjs/loader:827:30)',
+// ' at Fancy (node:vm:697:32)',
+// // This file is not an actual Node.js core file.
+// ' at tryModuleLoad (node:internal/modules/cjs/foo:629:12)',
+// ' at Function.Module._load (node:internal/modules/cjs/loader:621:3)',
+// // This file is not an actual Node.js core file.
+// ' at Module.require [as weird/name] (node:internal/aaaaa/loader:735:19)',
+// ' at require (node:internal/modules/cjs/helpers:14:16)',
+// ' at /test/test-util-inspect.js:2239:9',
+// ' at getActual (node:assert:592:5)',
+// ];
+// const isNodeCoreFile = [
+// false, false, true, true, false, true, false, true, false, true,
+// ];
+// const err = new TypeError('Wonderful message!');
+// err.stack = stack.join('\n');
+// util.inspect(err, { colors: true }).split('\n').forEach((line, i) => {
+// let actual = stack[i].replace(/node_modules\/([a-z]+)/g, (a, m) => {
+// return `node_modules/\u001b[4m${m}\u001b[24m`;
+// });
+// if (isNodeCoreFile[i]) {
+// actual = `\u001b[90m${actual}\u001b[39m`;
+// }
+// assert.strictEqual(actual, line);
+// });
+// }
+
+// {
+// // Cross platform checks.
+// const err = new Error('foo');
+// util.inspect(err, { colors: true }).split('\n').forEach((line, i) => {
+// assert(i < 2 || line.startsWith('\u001b[90m'));
+// });
+// }
+
+// TODO(wafuwafu13): Implement "trace_events"
+// {
+// // Tracing class respects inspect depth.
+// try {
+// const trace = require('trace_events').createTracing({ categories: ['fo'] });
+// const actualDepth0 = util.inspect({ trace }, { depth: 0 });
+// assert.strictEqual(actualDepth0, '{ trace: [Tracing] }');
+// const actualDepth1 = util.inspect({ trace }, { depth: 1 });
+// assert.strictEqual(
+// actualDepth1,
+// "{ trace: Tracing { enabled: false, categories: 'fo' } }"
+// );
+// } catch (err) {
+// if (err.code !== 'ERR_TRACE_EVENTS_UNAVAILABLE')
+// throw err;
+// }
+// }
+
+// Inspect prototype properties.
+{
+ class Foo extends Map {
+ prop = false;
+ prop2 = true;
+ get abc() {
+ return true;
+ }
+ get def() {
+ return false;
+ }
+ set def(v) {}
+ get xyz() {
+ return 'Should be ignored';
+ }
+ func(a) {}
+ [util.inspect.custom]() {
+ return this;
+ }
+ }
+
+ class Bar extends Foo {
+ abc = true;
+ prop = true;
+ get xyz() {
+ return 'YES!';
+ }
+ [util.inspect.custom]() {
+ return this;
+ }
+ }
+
+ const bar = new Bar();
+
+ assert.strictEqual(
+ inspect(bar),
+ 'Bar(0) [Map] { prop: true, prop2: true, abc: true }'
+ );
+ // TODO(wafuwafu13): Fix
+ // assert.strictEqual(
+ // inspect(bar, { showHidden: true, getters: true, colors: false }),
+ // 'Bar(0) [Map] {\n' +
+ // ' prop: true,\n' +
+ // ' prop2: true,\n' +
+ // ' abc: true,\n' +
+ // " [xyz]: [Getter: 'YES!'],\n" +
+ // ' [def]: [Getter/Setter: false]\n' +
+ // '}'
+ // );
+ // assert.strictEqual(
+ // inspect(bar, { showHidden: true, getters: false, colors: true }),
+ // 'Bar(0) [Map] {\n' +
+ // ' prop: \x1B[33mtrue\x1B[39m,\n' +
+ // ' prop2: \x1B[33mtrue\x1B[39m,\n' +
+ // ' abc: \x1B[33mtrue\x1B[39m,\n' +
+ // ' \x1B[2m[xyz]: \x1B[36m[Getter]\x1B[39m\x1B[22m,\n' +
+ // ' \x1B[2m[def]: \x1B[36m[Getter/Setter]\x1B[39m\x1B[22m\n' +
+ // '}'
+ // );
+
+ // const obj = Object.create({ abc: true, def: 5, toString() {} });
+ // assert.strictEqual(
+ // inspect(obj, { showHidden: true, colors: true }),
+ // '{ \x1B[2mabc: \x1B[33mtrue\x1B[39m\x1B[22m, ' +
+ // '\x1B[2mdef: \x1B[33m5\x1B[39m\x1B[22m }'
+ // );
+
+ // assert.strictEqual(
+ // inspect(Object.getPrototypeOf(bar), { showHidden: true, getters: true }),
+ // '<ref *1> Foo [Map] {\n' +
+ // ' [constructor]: [class Bar extends Foo] {\n' +
+ // ' [length]: 0,\n' +
+ // " [name]: 'Bar',\n" +
+ // ' [prototype]: [Circular *1],\n' +
+ // ' [Symbol(Symbol.species)]: [Getter: <Inspection threw ' +
+ // "(Symbol.prototype.toString requires that 'this' be a Symbol)>]\n" +
+ // ' },\n' +
+ // " [xyz]: [Getter: 'YES!'],\n" +
+ // ' [Symbol(nodejs.util.inspect.custom)]: ' +
+ // '[Function: [nodejs.util.inspect.custom]] {\n' +
+ // ' [length]: 0,\n' +
+ // " [name]: '[nodejs.util.inspect.custom]'\n" +
+ // ' },\n' +
+ // ' [abc]: [Getter: true],\n' +
+ // ' [def]: [Getter/Setter: false]\n' +
+ // ' }'
+ // );
+
+ // assert.strictEqual(
+ // inspect(Object.getPrototypeOf(bar)),
+ // 'Foo [Map] {}'
+ // );
+
+ // assert.strictEqual(
+ // inspect(Object.getPrototypeOf(new Foo())),
+ // 'Map {}'
+ // );
+}
+
+// Check that prototypes with a null prototype are inspectable.
+// Regression test for https://github.com/nodejs/node/issues/35730
+{
+ function Func() {}
+ Func.prototype = null;
+ const object = {};
+ object.constructor = Func;
+
+ assert.strictEqual(util.inspect(object), '{ constructor: [Function: Func] }');
+}
+
+// Test changing util.inspect.colors colors and aliases.
+{
+ const colors = util.inspect.colors;
+
+ const originalValue = colors.gray;
+
+ // "grey" is reference-equal alias of "gray".
+ assert.strictEqual(colors.grey, colors.gray);
+
+ // Assigninging one should assign the other. This tests that the alias setter
+ // function keeps things reference-equal.
+ colors.gray = [0, 0];
+ assert.deepStrictEqual(colors.gray, [0, 0]);
+ assert.strictEqual(colors.grey, colors.gray);
+
+ colors.grey = [1, 1];
+ assert.deepStrictEqual(colors.grey, [1, 1]);
+ assert.strictEqual(colors.grey, colors.gray);
+
+ // Restore original value to avoid side effects in other tests.
+ colors.gray = originalValue;
+ assert.deepStrictEqual(colors.gray, originalValue);
+ assert.strictEqual(colors.grey, colors.gray);
+}
+
+// TODO(wafuwafu13): Implement 'vm'
+// // https://github.com/nodejs/node/issues/31889
+// {
+// v8.setFlagsFromString('--allow-natives-syntax');
+// const undetectable = vm.runInThisContext('%GetUndetectable()');
+// v8.setFlagsFromString('--no-allow-natives-syntax');
+// assert.strictEqual(inspect(undetectable), '{}');
+// }
+
+// Truncate output for Primitives with 1 character left
+{
+ assert.strictEqual(util.inspect('bl', { maxStringLength: 1 }),
+ "'b'... 1 more character");
+}
+
+{
+ const x = 'a'.repeat(1e6);
+ assert(util.inspect(x).endsWith('... 990000 more characters'));
+ assert.strictEqual(
+ util.inspect(x, { maxStringLength: 4 }),
+ "'aaaa'... 999996 more characters"
+ );
+ assert.match(util.inspect(x, { maxStringLength: null }), /a'$/);
+}
+
+// TODO(wafuwafu13): Implement 'vm'
+// {
+// // Verify that util.inspect() invokes custom inspect functions on objects
+// // from other vm.Contexts but does not pass data from its own Context to that
+// // function.
+// const target = vm.runInNewContext(`
+// ({
+// [Symbol.for('nodejs.util.inspect.custom')](depth, ctx) {
+// this.depth = depth;
+// this.ctx = ctx;
+// try {
+// this.stylized = ctx.stylize('🐈');
+// } catch (e) {
+// this.stylizeException = e;
+// }
+// return this.stylized;
+// }
+// })
+// `, Object.create(null));
+// assert.strictEqual(target.ctx, undefined);
+
+// {
+// // Subtest 1: Just try to inspect the object with default options.
+// assert.strictEqual(util.inspect(target), '🐈');
+// assert.strictEqual(typeof target.ctx, 'object');
+// const objectGraph = fullObjectGraph(target);
+// assert(!objectGraph.has(Object));
+// assert(!objectGraph.has(Function));
+// }
+
+// {
+// // Subtest 2: Use a stylize function that returns a non-primitive.
+// const output = util.inspect(target, {
+// stylize: common.mustCall((str) => {
+// return {};
+// })
+// });
+// assert.strictEqual(output, '[object Object]');
+// assert.strictEqual(typeof target.ctx, 'object');
+// const objectGraph = fullObjectGraph(target);
+// assert(!objectGraph.has(Object));
+// assert(!objectGraph.has(Function));
+// }
+
+// {
+// // Subtest 3: Use a stylize function that throws an exception.
+// const output = util.inspect(target, {
+// stylize: common.mustCall((str) => {
+// throw new Error('oops');
+// })
+// });
+// assert.strictEqual(output, '🐈');
+// assert.strictEqual(typeof target.ctx, 'object');
+// const objectGraph = fullObjectGraph(target);
+// assert(!objectGraph.has(Object));
+// assert(!objectGraph.has(Function));
+// }
+
+// function fullObjectGraph(value) {
+// const graph = new Set([value]);
+
+// for (const entry of graph) {
+// if ((typeof entry !== 'object' && typeof entry !== 'function') ||
+// entry === null) {
+// continue;
+// }
+
+// graph.add(Object.getPrototypeOf(entry));
+// const descriptors = Object.values(
+// Object.getOwnPropertyDescriptors(entry));
+// for (const descriptor of descriptors) {
+// graph.add(descriptor.value);
+// graph.add(descriptor.set);
+// graph.add(descriptor.get);
+// }
+// }
+
+// return graph;
+// }
+
+// // Consistency check.
+// assert(fullObjectGraph(global).has(Function.prototype));
+// }
+
+{
+ // Confirm that own constructor value displays correctly.
+
+ function Fhqwhgads() {}
+
+ const sterrance = new Fhqwhgads();
+ sterrance.constructor = Fhqwhgads;
+
+ assert.strictEqual(
+ util.inspect(sterrance, { showHidden: true }),
+ 'Fhqwhgads {\n' +
+ ' constructor: <ref *1> [Function: Fhqwhgads] {\n' +
+ ' [length]: 0,\n' +
+ " [name]: 'Fhqwhgads',\n" +
+ ' [prototype]: { [constructor]: [Circular *1] }\n' +
+ ' }\n' +
+ '}'
+ );
+}
+
+// TODO(wafuwafu13): Fix TypeError: main.hasOwnProperty is not a function
+// {
+// // Confirm null prototype of generator prototype displays as expected.
+
+// function getProtoOfProto() {
+// return Object.getPrototypeOf(Object.getPrototypeOf(function* () {}));
+// }
+
+// function* generator() {}
+
+// const generatorPrototype = Object.getPrototypeOf(generator);
+// const originalProtoOfProto = Object.getPrototypeOf(generatorPrototype);
+// assert.strictEqual(getProtoOfProto(), originalProtoOfProto);
+// Object.setPrototypeOf(generatorPrototype, null);
+// assert.notStrictEqual(getProtoOfProto, originalProtoOfProto);
+
+// // This is the actual test. The other assertions in this block are about
+// // making sure the test is set up correctly and isn't polluting other tests.
+// assert.strictEqual(
+// util.inspect(generator, { showHidden: true }),
+// '[GeneratorFunction: generator] {\n' +
+// ' [length]: 0,\n' +
+// " [name]: 'generator',\n" +
+// " [prototype]: Object [Generator] { [Symbol(Symbol.toStringTag)]: 'Generator' },\n" + // eslint-disable-line max-len
+// " [Symbol(Symbol.toStringTag)]: 'GeneratorFunction'\n" +
+// '}'
+// );
+
+// // Reset so we don't pollute other tests
+// Object.setPrototypeOf(generatorPrototype, originalProtoOfProto);
+// assert.strictEqual(getProtoOfProto(), originalProtoOfProto);
+// }
+
+{
+ // Test for when breakLength results in a single column.
+ const obj = Array(9).fill('fhqwhgadshgnsdhjsdbkhsdabkfabkveybvf');
+ assert.strictEqual(
+ util.inspect(obj, { breakLength: 256 }),
+ '[\n' +
+ " 'fhqwhgadshgnsdhjsdbkhsdabkfabkveybvf',\n" +
+ " 'fhqwhgadshgnsdhjsdbkhsdabkfabkveybvf',\n" +
+ " 'fhqwhgadshgnsdhjsdbkhsdabkfabkveybvf',\n" +
+ " 'fhqwhgadshgnsdhjsdbkhsdabkfabkveybvf',\n" +
+ " 'fhqwhgadshgnsdhjsdbkhsdabkfabkveybvf',\n" +
+ " 'fhqwhgadshgnsdhjsdbkhsdabkfabkveybvf',\n" +
+ " 'fhqwhgadshgnsdhjsdbkhsdabkfabkveybvf',\n" +
+ " 'fhqwhgadshgnsdhjsdbkhsdabkfabkveybvf',\n" +
+ " 'fhqwhgadshgnsdhjsdbkhsdabkfabkveybvf'\n" +
+ ']'
+ );
+}
+
+{
+ assert.strictEqual(
+ util.inspect({ ['__proto__']: { a: 1 } }),
+ "{ ['__proto__']: { a: 1 } }"
+ );
+}
diff --git a/tests/node_compat/test/parallel/test-util-isDeepStrictEqual.js b/tests/node_compat/test/parallel/test-util-isDeepStrictEqual.js
new file mode 100644
index 000000000..25caac1f7
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-util-isDeepStrictEqual.js
@@ -0,0 +1,608 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 16.13.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+"use strict";
+
+// Confirm functionality of `util.isDeepStrictEqual()`.
+
+require("../common");
+
+const assert = require("assert");
+const util = require("util");
+
+class MyDate extends Date {
+ constructor(...args) {
+ super(...args);
+ this[0] = "1";
+ }
+}
+
+class MyRegExp extends RegExp {
+ constructor(...args) {
+ super(...args);
+ this[0] = "1";
+ }
+}
+
+{
+ const arr = new Uint8Array([120, 121, 122, 10]);
+ const buf = Buffer.from(arr);
+ // They have different [[Prototype]]
+ assert.strictEqual(util.isDeepStrictEqual(arr, buf), false);
+
+ const buf2 = Buffer.from(arr);
+ buf2.prop = 1;
+
+ assert.strictEqual(util.isDeepStrictEqual(buf2, buf), false);
+
+ const arr2 = new Uint8Array([120, 121, 122, 10]);
+ arr2.prop = 5;
+ assert.strictEqual(util.isDeepStrictEqual(arr, arr2), false);
+}
+
+{
+ const date = new Date("2016");
+
+ const date2 = new MyDate("2016");
+
+ // deepStrictEqual checks own properties
+ assert.strictEqual(util.isDeepStrictEqual(date, date2), false);
+ assert.strictEqual(util.isDeepStrictEqual(date2, date), false);
+}
+
+{
+ const re1 = new RegExp("test");
+ const re2 = new MyRegExp("test");
+
+ // deepStrictEqual checks all properties
+ assert.strictEqual(util.isDeepStrictEqual(re1, re2), false);
+}
+
+{
+ // For these cases, deepStrictEqual should throw.
+ const similar = new Set([
+ { 0: "1" }, // Object
+ { 0: 1 }, // Object
+ new String("1"), // Object
+ ["1"], // Array
+ [1], // Array
+ new MyDate("2016"), // Date with this[0] = '1'
+ new MyRegExp("test"), // RegExp with this[0] = '1'
+ new Int8Array([1]), // Int8Array
+ new Uint8Array([1]), // Uint8Array
+ new Int16Array([1]), // Int16Array
+ new Uint16Array([1]), // Uint16Array
+ new Int32Array([1]), // Int32Array
+ new Uint32Array([1]), // Uint32Array
+ Buffer.from([1]), // Buffer
+ ]);
+
+ for (const a of similar) {
+ for (const b of similar) {
+ if (a !== b) {
+ assert.strictEqual(util.isDeepStrictEqual(a, b), false);
+ }
+ }
+ }
+}
+
+function utilIsDeepStrict(a, b) {
+ assert.strictEqual(util.isDeepStrictEqual(a, b), true);
+ assert.strictEqual(util.isDeepStrictEqual(b, a), true);
+}
+function notUtilIsDeepStrict(a, b) {
+ assert.strictEqual(util.isDeepStrictEqual(a, b), false);
+ assert.strictEqual(util.isDeepStrictEqual(b, a), false);
+}
+
+// es6 Maps and Sets
+utilIsDeepStrict(new Set(), new Set());
+utilIsDeepStrict(new Map(), new Map());
+
+utilIsDeepStrict(new Set([1, 2, 3]), new Set([1, 2, 3]));
+notUtilIsDeepStrict(new Set([1, 2, 3]), new Set([1, 2, 3, 4]));
+notUtilIsDeepStrict(new Set([1, 2, 3, 4]), new Set([1, 2, 3]));
+utilIsDeepStrict(new Set(["1", "2", "3"]), new Set(["1", "2", "3"]));
+utilIsDeepStrict(
+ new Set([
+ [1, 2],
+ [3, 4],
+ ]),
+ new Set([
+ [3, 4],
+ [1, 2],
+ ])
+);
+
+{
+ const a = [1, 2];
+ const b = [3, 4];
+ const c = [1, 2];
+ const d = [3, 4];
+
+ utilIsDeepStrict(
+ { a: a, b: b, s: new Set([a, b]) },
+ { a: c, b: d, s: new Set([d, c]) }
+ );
+}
+
+utilIsDeepStrict(
+ new Map([
+ [1, 1],
+ [2, 2],
+ ]),
+ new Map([
+ [1, 1],
+ [2, 2],
+ ])
+);
+utilIsDeepStrict(
+ new Map([
+ [1, 1],
+ [2, 2],
+ ]),
+ new Map([
+ [2, 2],
+ [1, 1],
+ ])
+);
+notUtilIsDeepStrict(
+ new Map([
+ [1, 1],
+ [2, 2],
+ ]),
+ new Map([
+ [1, 2],
+ [2, 1],
+ ])
+);
+notUtilIsDeepStrict(
+ new Map([
+ [[1], 1],
+ [{}, 2],
+ ]),
+ new Map([
+ [[1], 2],
+ [{}, 1],
+ ])
+);
+
+notUtilIsDeepStrict(new Set([1]), [1]);
+notUtilIsDeepStrict(new Set(), []);
+notUtilIsDeepStrict(new Set(), {});
+
+notUtilIsDeepStrict(new Map([["a", 1]]), { a: 1 });
+notUtilIsDeepStrict(new Map(), []);
+notUtilIsDeepStrict(new Map(), {});
+
+notUtilIsDeepStrict(new Set(["1"]), new Set([1]));
+
+notUtilIsDeepStrict(new Map([["1", "a"]]), new Map([[1, "a"]]));
+notUtilIsDeepStrict(new Map([["a", "1"]]), new Map([["a", 1]]));
+notUtilIsDeepStrict(new Map([["a", "1"]]), new Map([["a", 2]]));
+
+utilIsDeepStrict(new Set([{}]), new Set([{}]));
+
+// Ref: https://github.com/nodejs/node/issues/13347
+notUtilIsDeepStrict(
+ new Set([{ a: 1 }, { a: 1 }]),
+ new Set([{ a: 1 }, { a: 2 }])
+);
+notUtilIsDeepStrict(
+ new Set([{ a: 1 }, { a: 1 }, { a: 2 }]),
+ new Set([{ a: 1 }, { a: 2 }, { a: 2 }])
+);
+notUtilIsDeepStrict(
+ new Map([
+ [{ x: 1 }, 5],
+ [{ x: 1 }, 5],
+ ]),
+ new Map([
+ [{ x: 1 }, 5],
+ [{ x: 2 }, 5],
+ ])
+);
+
+notUtilIsDeepStrict(new Set([3, "3"]), new Set([3, 4]));
+notUtilIsDeepStrict(
+ new Map([
+ [3, 0],
+ ["3", 0],
+ ]),
+ new Map([
+ [3, 0],
+ [4, 0],
+ ])
+);
+
+notUtilIsDeepStrict(
+ new Set([{ a: 1 }, { a: 1 }, { a: 2 }]),
+ new Set([{ a: 1 }, { a: 2 }, { a: 2 }])
+);
+
+// Mixed primitive and object keys
+utilIsDeepStrict(
+ new Map([
+ [1, "a"],
+ [{}, "a"],
+ ]),
+ new Map([
+ [1, "a"],
+ [{}, "a"],
+ ])
+);
+utilIsDeepStrict(new Set([1, "a", [{}, "a"]]), new Set([1, "a", [{}, "a"]]));
+
+// This is an awful case, where a map contains multiple equivalent keys:
+notUtilIsDeepStrict(
+ new Map([
+ [1, "a"],
+ ["1", "b"],
+ ]),
+ new Map([
+ ["1", "a"],
+ [true, "b"],
+ ])
+);
+notUtilIsDeepStrict(new Set(["a"]), new Set(["b"]));
+utilIsDeepStrict(
+ new Map([
+ [{}, "a"],
+ [{}, "b"],
+ ]),
+ new Map([
+ [{}, "b"],
+ [{}, "a"],
+ ])
+);
+notUtilIsDeepStrict(
+ new Map([
+ [true, "a"],
+ ["1", "b"],
+ [1, "a"],
+ ]),
+ new Map([
+ ["1", "a"],
+ [1, "b"],
+ [true, "a"],
+ ])
+);
+notUtilIsDeepStrict(
+ new Map([
+ [true, "a"],
+ ["1", "b"],
+ [1, "c"],
+ ]),
+ new Map([
+ ["1", "a"],
+ [1, "b"],
+ [true, "a"],
+ ])
+);
+
+// Similar object keys
+notUtilIsDeepStrict(new Set([{}, {}]), new Set([{}, 1]));
+notUtilIsDeepStrict(
+ new Set([
+ [{}, 1],
+ [{}, 1],
+ ]),
+ new Set([
+ [{}, 1],
+ [1, 1],
+ ])
+);
+notUtilIsDeepStrict(
+ new Map([
+ [{}, 1],
+ [{}, 1],
+ ]),
+ new Map([
+ [{}, 1],
+ [1, 1],
+ ])
+);
+notUtilIsDeepStrict(
+ new Map([
+ [{}, 1],
+ [true, 1],
+ ]),
+ new Map([
+ [{}, 1],
+ [1, 1],
+ ])
+);
+
+// Similar primitive key / values
+notUtilIsDeepStrict(new Set([1, true, false]), new Set(["1", 0, "0"]));
+notUtilIsDeepStrict(
+ new Map([
+ [1, 5],
+ [true, 5],
+ [false, 5],
+ ]),
+ new Map([
+ ["1", 5],
+ [0, 5],
+ ["0", 5],
+ ])
+);
+
+// Undefined value in Map
+utilIsDeepStrict(new Map([[1, undefined]]), new Map([[1, undefined]]));
+notUtilIsDeepStrict(new Map([[1, null]]), new Map([["1", undefined]]));
+notUtilIsDeepStrict(new Map([[1, undefined]]), new Map([[2, undefined]]));
+
+// null as key
+utilIsDeepStrict(new Map([[null, 3]]), new Map([[null, 3]]));
+notUtilIsDeepStrict(new Map([[null, undefined]]), new Map([[undefined, null]]));
+notUtilIsDeepStrict(new Set([null]), new Set([undefined]));
+
+// GH-6416. Make sure circular refs don't throw.
+{
+ const b = {};
+ b.b = b;
+ const c = {};
+ c.b = c;
+
+ utilIsDeepStrict(b, c);
+
+ const d = {};
+ d.a = 1;
+ d.b = d;
+ const e = {};
+ e.a = 1;
+ e.b = {};
+
+ notUtilIsDeepStrict(d, e);
+}
+
+// GH-14441. Circular structures should be consistent
+{
+ const a = {};
+ const b = {};
+ a.a = a;
+ b.a = {};
+ b.a.a = a;
+ utilIsDeepStrict(a, b);
+}
+
+{
+ const a = new Set();
+ const b = new Set();
+ const c = new Set();
+ a.add(a);
+ b.add(b);
+ c.add(a);
+ utilIsDeepStrict(b, c);
+}
+
+// GH-7178. Ensure reflexivity of deepEqual with `arguments` objects.
+{
+ const args = (function () {
+ return arguments;
+ })();
+ notUtilIsDeepStrict([], args);
+}
+
+// More checking that arguments objects are handled correctly
+{
+ // eslint-disable-next-line func-style
+ const returnArguments = function () {
+ return arguments;
+ };
+
+ const someArgs = returnArguments("a");
+ const sameArgs = returnArguments("a");
+ const diffArgs = returnArguments("b");
+
+ notUtilIsDeepStrict(someArgs, ["a"]);
+ notUtilIsDeepStrict(someArgs, { 0: "a" });
+ notUtilIsDeepStrict(someArgs, diffArgs);
+ utilIsDeepStrict(someArgs, sameArgs);
+}
+
+{
+ const values = [
+ 123,
+ Infinity,
+ 0,
+ null,
+ undefined,
+ false,
+ true,
+ {},
+ [],
+ () => {},
+ ];
+ utilIsDeepStrict(new Set(values), new Set(values));
+ utilIsDeepStrict(new Set(values), new Set(values.reverse()));
+
+ const mapValues = values.map((v) => [v, { a: 5 }]);
+ utilIsDeepStrict(new Map(mapValues), new Map(mapValues));
+ utilIsDeepStrict(new Map(mapValues), new Map(mapValues.reverse()));
+}
+
+{
+ const s1 = new Set();
+ const s2 = new Set();
+ s1.add(1);
+ s1.add(2);
+ s2.add(2);
+ s2.add(1);
+ utilIsDeepStrict(s1, s2);
+}
+
+{
+ const m1 = new Map();
+ const m2 = new Map();
+ const obj = { a: 5, b: 6 };
+ m1.set(1, obj);
+ m1.set(2, "hi");
+ m1.set(3, [1, 2, 3]);
+
+ m2.set(2, "hi"); // different order
+ m2.set(1, obj);
+ m2.set(3, [1, 2, 3]); // Deep equal, but not reference equal.
+
+ utilIsDeepStrict(m1, m2);
+}
+
+{
+ const m1 = new Map();
+ const m2 = new Map();
+
+ // m1 contains itself.
+ m1.set(1, m1);
+ m2.set(1, new Map());
+
+ notUtilIsDeepStrict(m1, m2);
+}
+
+{
+ const map1 = new Map([[1, 1]]);
+ const map2 = new Map([[1, "1"]]);
+ assert.strictEqual(util.isDeepStrictEqual(map1, map2), false);
+}
+
+{
+ // Two equivalent sets / maps with different key/values applied shouldn't be
+ // the same. This is a terrible idea to do in practice, but deepEqual should
+ // still check for it.
+ const s1 = new Set();
+ const s2 = new Set();
+ s1.x = 5;
+ notUtilIsDeepStrict(s1, s2);
+
+ const m1 = new Map();
+ const m2 = new Map();
+ m1.x = 5;
+ notUtilIsDeepStrict(m1, m2);
+}
+
+{
+ // Circular references.
+ const s1 = new Set();
+ s1.add(s1);
+ const s2 = new Set();
+ s2.add(s2);
+ utilIsDeepStrict(s1, s2);
+
+ const m1 = new Map();
+ m1.set(2, m1);
+ const m2 = new Map();
+ m2.set(2, m2);
+ utilIsDeepStrict(m1, m2);
+
+ const m3 = new Map();
+ m3.set(m3, 2);
+ const m4 = new Map();
+ m4.set(m4, 2);
+ utilIsDeepStrict(m3, m4);
+}
+
+// Handle sparse arrays
+utilIsDeepStrict([1, , , 3], [1, , , 3]);
+notUtilIsDeepStrict([1, , , 3], [1, , , 3, , ,]);
+
+// Handle different error messages
+{
+ const err1 = new Error("foo1");
+ const err2 = new Error("foo2");
+ const err3 = new TypeError("foo1");
+ notUtilIsDeepStrict(err1, err2, assert.AssertionError);
+ notUtilIsDeepStrict(err1, err3, assert.AssertionError);
+ notUtilIsDeepStrict(err1, {}, assert.AssertionError);
+}
+
+// Handle NaN
+assert.strictEqual(util.isDeepStrictEqual(NaN, NaN), true);
+assert.strictEqual(util.isDeepStrictEqual({ a: NaN }, { a: NaN }), true);
+assert.strictEqual(
+ util.isDeepStrictEqual([1, 2, NaN, 4], [1, 2, NaN, 4]),
+ true
+);
+
+// Handle boxed primitives
+{
+ const boxedString = new String("test");
+ const boxedSymbol = Object(Symbol());
+ notUtilIsDeepStrict(new Boolean(true), Object(false));
+ notUtilIsDeepStrict(Object(true), new Number(1));
+ notUtilIsDeepStrict(new Number(2), new Number(1));
+ notUtilIsDeepStrict(boxedSymbol, Object(Symbol()));
+ notUtilIsDeepStrict(boxedSymbol, {});
+ utilIsDeepStrict(boxedSymbol, boxedSymbol);
+ utilIsDeepStrict(Object(true), Object(true));
+ utilIsDeepStrict(Object(2), Object(2));
+ utilIsDeepStrict(boxedString, Object("test"));
+ boxedString.slow = true;
+ notUtilIsDeepStrict(boxedString, Object("test"));
+ boxedSymbol.slow = true;
+ notUtilIsDeepStrict(boxedSymbol, {});
+ utilIsDeepStrict(Object(BigInt(1)), Object(BigInt(1)));
+ notUtilIsDeepStrict(Object(BigInt(1)), Object(BigInt(2)));
+
+ const booleanish = new Boolean(true);
+ Object.defineProperty(booleanish, Symbol.toStringTag, { value: "String" });
+ Object.setPrototypeOf(booleanish, String.prototype);
+ notUtilIsDeepStrict(booleanish, new String("true"));
+
+ const numberish = new Number(42);
+ Object.defineProperty(numberish, Symbol.toStringTag, { value: "String" });
+ Object.setPrototypeOf(numberish, String.prototype);
+ notUtilIsDeepStrict(numberish, new String("42"));
+
+ const stringish = new String("0");
+ Object.defineProperty(stringish, Symbol.toStringTag, { value: "Number" });
+ Object.setPrototypeOf(stringish, Number.prototype);
+ notUtilIsDeepStrict(stringish, new Number(0));
+
+ const bigintish = new Object(BigInt(42));
+ Object.defineProperty(bigintish, Symbol.toStringTag, { value: "String" });
+ Object.setPrototypeOf(bigintish, String.prototype);
+ notUtilIsDeepStrict(bigintish, new String("42"));
+
+ const symbolish = new Object(Symbol("fhqwhgads"));
+ Object.defineProperty(symbolish, Symbol.toStringTag, { value: "String" });
+ Object.setPrototypeOf(symbolish, String.prototype);
+ notUtilIsDeepStrict(symbolish, new String("fhqwhgads"));
+}
+
+// Minus zero
+notUtilIsDeepStrict(0, -0);
+utilIsDeepStrict(-0, -0);
+
+// Handle symbols (enumerable only)
+{
+ const symbol1 = Symbol();
+ const obj1 = { [symbol1]: 1 };
+ const obj2 = { [symbol1]: 1 };
+ const obj3 = { [Symbol()]: 1 };
+ const obj4 = {};
+ // Add a non enumerable symbol as well. It is going to be ignored!
+ Object.defineProperty(obj2, Symbol(), { value: 1 });
+ Object.defineProperty(obj4, symbol1, { value: 1 });
+ notUtilIsDeepStrict(obj1, obj3);
+ utilIsDeepStrict(obj1, obj2);
+ notUtilIsDeepStrict(obj1, obj4);
+ // TypedArrays have a fast path. Test for this as well.
+ const a = new Uint8Array(4);
+ const b = new Uint8Array(4);
+ a[symbol1] = true;
+ b[symbol1] = false;
+ notUtilIsDeepStrict(a, b);
+ b[symbol1] = true;
+ utilIsDeepStrict(a, b);
+ // The same as TypedArrays is valid for boxed primitives
+ const boxedStringA = new String("test");
+ const boxedStringB = new String("test");
+ boxedStringA[symbol1] = true;
+ notUtilIsDeepStrict(boxedStringA, boxedStringB);
+ boxedStringA[symbol1] = true;
+ utilIsDeepStrict(a, b);
+}
diff --git a/tests/node_compat/test/parallel/test-util-promisify.js b/tests/node_compat/test/parallel/test-util-promisify.js
new file mode 100644
index 000000000..8046f6fb8
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-util-promisify.js
@@ -0,0 +1,218 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 16.13.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+'use strict';
+// Flags: --expose-internals
+const common = require('../common');
+const assert = require('assert');
+const fs = require('fs');
+const vm = require('vm');
+const { promisify } = require('util');
+const { customPromisifyArgs } = require('internal/util');
+
+const stat = promisify(fs.stat);
+
+// TODO(wafuwafu13): Fix
+// {
+// const promise = stat(__filename);
+// assert(promise instanceof Promise);
+// promise.then(common.mustCall((value) => {
+// assert.deepStrictEqual(value, fs.statSync(__filename));
+// }));
+// }
+
+{
+ const promise = stat('/dontexist');
+ promise.catch(common.mustCall((error) => {
+ assert(error.message.includes('ENOENT: no such file or directory, stat'));
+ }));
+}
+
+{
+ function fn() {}
+
+ function promisifedFn() {}
+ fn[promisify.custom] = promisifedFn;
+ assert.strictEqual(promisify(fn), promisifedFn);
+ assert.strictEqual(promisify(promisify(fn)), promisifedFn);
+}
+
+{
+ function fn() {}
+
+ function promisifiedFn() {}
+
+ // util.promisify.custom is a shared symbol which can be accessed
+ // as `Symbol.for("nodejs.util.promisify.custom")`.
+ const kCustomPromisifiedSymbol = Symbol.for('nodejs.util.promisify.custom');
+ fn[kCustomPromisifiedSymbol] = promisifiedFn;
+
+ assert.strictEqual(kCustomPromisifiedSymbol, promisify.custom);
+ assert.strictEqual(promisify(fn), promisifiedFn);
+ assert.strictEqual(promisify(promisify(fn)), promisifiedFn);
+}
+
+{
+ function fn() {}
+ fn[promisify.custom] = 42;
+ assert.throws(
+ () => promisify(fn),
+ { code: 'ERR_INVALID_ARG_TYPE', name: 'TypeError' }
+ );
+}
+
+// TODO(wafuwafu13): Fix
+// {
+// const firstValue = 5;
+// const secondValue = 17;
+
+// function fn(callback) {
+// callback(null, firstValue, secondValue);
+// }
+
+// fn[customPromisifyArgs] = ['first', 'second'];
+
+// promisify(fn)().then(common.mustCall((obj) => {
+// assert.deepStrictEqual(obj, { first: firstValue, second: secondValue });
+// }));
+// }
+
+{
+ const fn = vm.runInNewContext('(function() {})');
+ assert.notStrictEqual(Object.getPrototypeOf(promisify(fn)),
+ Function.prototype);
+}
+
+{
+ function fn(callback) {
+ callback(null, 'foo', 'bar');
+ }
+ promisify(fn)().then(common.mustCall((value) => {
+ assert.deepStrictEqual(value, 'foo');
+ }));
+}
+
+{
+ function fn(callback) {
+ callback(null);
+ }
+ promisify(fn)().then(common.mustCall((value) => {
+ assert.strictEqual(value, undefined);
+ }));
+}
+
+{
+ function fn(callback) {
+ callback();
+ }
+ promisify(fn)().then(common.mustCall((value) => {
+ assert.strictEqual(value, undefined);
+ }));
+}
+
+{
+ function fn(err, val, callback) {
+ callback(err, val);
+ }
+ promisify(fn)(null, 42).then(common.mustCall((value) => {
+ assert.strictEqual(value, 42);
+ }));
+}
+
+{
+ function fn(err, val, callback) {
+ callback(err, val);
+ }
+ promisify(fn)(new Error('oops'), null).catch(common.mustCall((err) => {
+ assert.strictEqual(err.message, 'oops');
+ }));
+}
+
+{
+ function fn(err, val, callback) {
+ callback(err, val);
+ }
+
+ (async () => {
+ const value = await promisify(fn)(null, 42);
+ assert.strictEqual(value, 42);
+ })().then(common.mustCall());
+}
+
+{
+ const o = {};
+ const fn = promisify(function(cb) {
+
+ cb(null, this === o);
+ });
+
+ o.fn = fn;
+
+ o.fn().then(common.mustCall((val) => assert(val)));
+}
+
+{
+ const err = new Error('Should not have called the callback with the error.');
+ const stack = err.stack;
+
+ const fn = promisify(function(cb) {
+ cb(null);
+ cb(err);
+ });
+
+ (async () => {
+ await fn();
+ await Promise.resolve();
+ return assert.strictEqual(stack, err.stack);
+ })().then(common.mustCall());
+}
+
+{
+ function c() { }
+ const a = promisify(function() { });
+ const b = promisify(a);
+ assert.notStrictEqual(c, a);
+ assert.strictEqual(a, b);
+}
+
+{
+ let errToThrow;
+ const thrower = promisify(function(a, b, c, cb) {
+ errToThrow = new Error();
+ throw errToThrow;
+ });
+ thrower(1, 2, 3)
+ .then(assert.fail)
+ .then(assert.fail, (e) => assert.strictEqual(e, errToThrow));
+}
+
+{
+ const err = new Error();
+
+ const a = promisify((cb) => cb(err))();
+ const b = promisify(() => { throw err; })();
+
+ Promise.all([
+ a.then(assert.fail, function(e) {
+ assert.strictEqual(err, e);
+ }),
+ b.then(assert.fail, function(e) {
+ assert.strictEqual(err, e);
+ }),
+ ]);
+}
+
+[undefined, null, true, 0, 'str', {}, [], Symbol()].forEach((input) => {
+ assert.throws(
+ () => promisify(input),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: 'The "original" argument must be of type function.' +
+ common.invalidArgTypeHelper(input)
+ });
+});
diff --git a/tests/node_compat/test/parallel/test-util-types-exists.js b/tests/node_compat/test/parallel/test-util-types-exists.js
new file mode 100644
index 000000000..0c04a38b0
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-util-types-exists.js
@@ -0,0 +1,13 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+require('../common');
+const assert = require('assert');
+
+assert.strictEqual(require('util/types'), require('util').types);
diff --git a/tests/node_compat/test/parallel/test-util-types.js b/tests/node_compat/test/parallel/test-util-types.js
new file mode 100644
index 000000000..d401a282c
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-util-types.js
@@ -0,0 +1,304 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 16.13.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// Flags: --experimental-vm-modules --expose-internals
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const { types, inspect } = require('util');
+const vm = require('vm');
+// TODO(wafuwafu13): Implement "internalBinding"
+// const { internalBinding } = require('internal/test/binding');
+// const { JSStream } = internalBinding('js_stream');
+
+// TODO(wafuwafu13): Implement "JSStream"
+// const external = (new JSStream())._externalStream;
+
+for (const [ value, _method ] of [
+ // TODO(wafuwafu13): Implement "JSStream"
+ // [ external, 'isExternal' ],
+ [ new Date() ],
+ [ (function() { return arguments; })(), 'isArgumentsObject' ],
+ [ new Boolean(), 'isBooleanObject' ],
+ [ new Number(), 'isNumberObject' ],
+ [ new String(), 'isStringObject' ],
+ [ Object(Symbol()), 'isSymbolObject' ],
+ [ Object(BigInt(0)), 'isBigIntObject' ],
+ [ new Error(), 'isNativeError' ],
+ [ new RegExp() ],
+ [ async function() {}, 'isAsyncFunction' ],
+ [ function*() {}, 'isGeneratorFunction' ],
+ [ (function*() {})(), 'isGeneratorObject' ],
+ [ Promise.resolve() ],
+ [ new Map() ],
+ [ new Set() ],
+ [ (new Map())[Symbol.iterator](), 'isMapIterator' ],
+ [ (new Set())[Symbol.iterator](), 'isSetIterator' ],
+ [ new WeakMap() ],
+ [ new WeakSet() ],
+ [ new ArrayBuffer() ],
+ [ new Uint8Array() ],
+ [ new Uint8ClampedArray() ],
+ [ new Uint16Array() ],
+ [ new Uint32Array() ],
+ [ new Int8Array() ],
+ [ new Int16Array() ],
+ [ new Int32Array() ],
+ [ new Float32Array() ],
+ [ new Float64Array() ],
+ [ new BigInt64Array() ],
+ [ new BigUint64Array() ],
+ // [ Object.defineProperty(new Uint8Array(),
+ // Symbol.toStringTag,
+ // { value: 'foo' }) ],
+ [ new DataView(new ArrayBuffer()) ],
+ [ new SharedArrayBuffer() ],
+ [ new Proxy({}, {}), 'isProxy' ],
+]) {
+ const method = _method || `is${value.constructor.name}`;
+ assert(method in types, `Missing ${method} for ${inspect(value)}`);
+ assert(types[method](value), `Want ${inspect(value)} to match ${method}`);
+
+ for (const key of Object.keys(types)) {
+ if ((types.isArrayBufferView(value) ||
+ types.isAnyArrayBuffer(value)) && key.includes('Array') ||
+ key === 'isBoxedPrimitive') {
+ continue;
+ }
+
+ assert.strictEqual(types[key](value),
+ key === method,
+ `${inspect(value)}: ${key}, ` +
+ `${method}, ${types[key](value)}`);
+ }
+}
+
+// Check boxed primitives.
+[
+ new Boolean(),
+ new Number(),
+ new String(),
+ Object(Symbol()),
+ Object(BigInt(0)),
+].forEach((entry) => assert(types.isBoxedPrimitive(entry)));
+
+{
+ assert(!types.isUint8Array({ [Symbol.toStringTag]: 'Uint8Array' }));
+ assert(types.isUint8Array(vm.runInNewContext('new Uint8Array')));
+
+ assert(!types.isUint8ClampedArray({
+ [Symbol.toStringTag]: 'Uint8ClampedArray'
+ }));
+ assert(types.isUint8ClampedArray(
+ vm.runInNewContext('new Uint8ClampedArray')
+ ));
+
+ assert(!types.isUint16Array({ [Symbol.toStringTag]: 'Uint16Array' }));
+ assert(types.isUint16Array(vm.runInNewContext('new Uint16Array')));
+
+ assert(!types.isUint32Array({ [Symbol.toStringTag]: 'Uint32Array' }));
+ assert(types.isUint32Array(vm.runInNewContext('new Uint32Array')));
+
+ assert(!types.isInt8Array({ [Symbol.toStringTag]: 'Int8Array' }));
+ assert(types.isInt8Array(vm.runInNewContext('new Int8Array')));
+
+ assert(!types.isInt16Array({ [Symbol.toStringTag]: 'Int16Array' }));
+ assert(types.isInt16Array(vm.runInNewContext('new Int16Array')));
+
+ assert(!types.isInt32Array({ [Symbol.toStringTag]: 'Int32Array' }));
+ assert(types.isInt32Array(vm.runInNewContext('new Int32Array')));
+
+ assert(!types.isFloat32Array({ [Symbol.toStringTag]: 'Float32Array' }));
+ assert(types.isFloat32Array(vm.runInNewContext('new Float32Array')));
+
+ assert(!types.isFloat64Array({ [Symbol.toStringTag]: 'Float64Array' }));
+ assert(types.isFloat64Array(vm.runInNewContext('new Float64Array')));
+
+ assert(!types.isBigInt64Array({ [Symbol.toStringTag]: 'BigInt64Array' }));
+ assert(types.isBigInt64Array(vm.runInNewContext('new BigInt64Array')));
+
+ assert(!types.isBigUint64Array({ [Symbol.toStringTag]: 'BigUint64Array' }));
+ assert(types.isBigUint64Array(vm.runInNewContext('new BigUint64Array')));
+}
+
+{
+ const primitive = true;
+ const arrayBuffer = new ArrayBuffer();
+ const buffer = Buffer.from(arrayBuffer);
+ const dataView = new DataView(arrayBuffer);
+ const uint8Array = new Uint8Array(arrayBuffer);
+ const uint8ClampedArray = new Uint8ClampedArray(arrayBuffer);
+ const uint16Array = new Uint16Array(arrayBuffer);
+ const uint32Array = new Uint32Array(arrayBuffer);
+ const int8Array = new Int8Array(arrayBuffer);
+ const int16Array = new Int16Array(arrayBuffer);
+ const int32Array = new Int32Array(arrayBuffer);
+ const float32Array = new Float32Array(arrayBuffer);
+ const float64Array = new Float64Array(arrayBuffer);
+ const bigInt64Array = new BigInt64Array(arrayBuffer);
+ const bigUint64Array = new BigUint64Array(arrayBuffer);
+
+ const fakeBuffer = Object.create(Buffer.prototype);
+ const fakeDataView = Object.create(DataView.prototype);
+ const fakeUint8Array = Object.create(Uint8Array.prototype);
+ const fakeUint8ClampedArray = Object.create(Uint8ClampedArray.prototype);
+ const fakeUint16Array = Object.create(Uint16Array.prototype);
+ const fakeUint32Array = Object.create(Uint32Array.prototype);
+ const fakeInt8Array = Object.create(Int8Array.prototype);
+ const fakeInt16Array = Object.create(Int16Array.prototype);
+ const fakeInt32Array = Object.create(Int32Array.prototype);
+ const fakeFloat32Array = Object.create(Float32Array.prototype);
+ const fakeFloat64Array = Object.create(Float64Array.prototype);
+ const fakeBigInt64Array = Object.create(BigInt64Array.prototype);
+ const fakeBigUint64Array = Object.create(BigUint64Array.prototype);
+
+ const stealthyDataView =
+ Object.setPrototypeOf(new DataView(arrayBuffer), Uint8Array.prototype);
+ const stealthyUint8Array =
+ Object.setPrototypeOf(new Uint8Array(arrayBuffer), ArrayBuffer.prototype);
+ const stealthyUint8ClampedArray =
+ Object.setPrototypeOf(
+ new Uint8ClampedArray(arrayBuffer), ArrayBuffer.prototype
+ );
+ const stealthyUint16Array =
+ Object.setPrototypeOf(new Uint16Array(arrayBuffer), Uint16Array.prototype);
+ const stealthyUint32Array =
+ Object.setPrototypeOf(new Uint32Array(arrayBuffer), Uint32Array.prototype);
+ const stealthyInt8Array =
+ Object.setPrototypeOf(new Int8Array(arrayBuffer), Int8Array.prototype);
+ const stealthyInt16Array =
+ Object.setPrototypeOf(new Int16Array(arrayBuffer), Int16Array.prototype);
+ const stealthyInt32Array =
+ Object.setPrototypeOf(new Int32Array(arrayBuffer), Int32Array.prototype);
+ const stealthyFloat32Array =
+ Object.setPrototypeOf(
+ new Float32Array(arrayBuffer), Float32Array.prototype
+ );
+ const stealthyFloat64Array =
+ Object.setPrototypeOf(
+ new Float64Array(arrayBuffer), Float64Array.prototype
+ );
+ const stealthyBigInt64Array =
+ Object.setPrototypeOf(
+ new BigInt64Array(arrayBuffer), BigInt64Array.prototype
+ );
+ const stealthyBigUint64Array =
+ Object.setPrototypeOf(
+ new BigUint64Array(arrayBuffer), BigUint64Array.prototype
+ );
+
+ const all = [
+ primitive, arrayBuffer, buffer, fakeBuffer,
+ dataView, fakeDataView, stealthyDataView,
+ uint8Array, fakeUint8Array, stealthyUint8Array,
+ uint8ClampedArray, fakeUint8ClampedArray, stealthyUint8ClampedArray,
+ uint16Array, fakeUint16Array, stealthyUint16Array,
+ uint32Array, fakeUint32Array, stealthyUint32Array,
+ int8Array, fakeInt8Array, stealthyInt8Array,
+ int16Array, fakeInt16Array, stealthyInt16Array,
+ int32Array, fakeInt32Array, stealthyInt32Array,
+ float32Array, fakeFloat32Array, stealthyFloat32Array,
+ float64Array, fakeFloat64Array, stealthyFloat64Array,
+ bigInt64Array, fakeBigInt64Array, stealthyBigInt64Array,
+ bigUint64Array, fakeBigUint64Array, stealthyBigUint64Array,
+ ];
+
+ const expected = {
+ isArrayBufferView: [
+ buffer,
+ dataView, stealthyDataView,
+ uint8Array, stealthyUint8Array,
+ uint8ClampedArray, stealthyUint8ClampedArray,
+ uint16Array, stealthyUint16Array,
+ uint32Array, stealthyUint32Array,
+ int8Array, stealthyInt8Array,
+ int16Array, stealthyInt16Array,
+ int32Array, stealthyInt32Array,
+ float32Array, stealthyFloat32Array,
+ float64Array, stealthyFloat64Array,
+ bigInt64Array, stealthyBigInt64Array,
+ bigUint64Array, stealthyBigUint64Array,
+ ],
+ isTypedArray: [
+ buffer,
+ uint8Array, stealthyUint8Array,
+ uint8ClampedArray, stealthyUint8ClampedArray,
+ uint16Array, stealthyUint16Array,
+ uint32Array, stealthyUint32Array,
+ int8Array, stealthyInt8Array,
+ int16Array, stealthyInt16Array,
+ int32Array, stealthyInt32Array,
+ float32Array, stealthyFloat32Array,
+ float64Array, stealthyFloat64Array,
+ bigInt64Array, stealthyBigInt64Array,
+ bigUint64Array, stealthyBigUint64Array,
+ ],
+ isUint8Array: [
+ buffer, uint8Array, stealthyUint8Array,
+ ],
+ isUint8ClampedArray: [
+ uint8ClampedArray, stealthyUint8ClampedArray,
+ ],
+ isUint16Array: [
+ uint16Array, stealthyUint16Array,
+ ],
+ isUint32Array: [
+ uint32Array, stealthyUint32Array,
+ ],
+ isInt8Array: [
+ int8Array, stealthyInt8Array,
+ ],
+ isInt16Array: [
+ int16Array, stealthyInt16Array,
+ ],
+ isInt32Array: [
+ int32Array, stealthyInt32Array,
+ ],
+ isFloat32Array: [
+ float32Array, stealthyFloat32Array,
+ ],
+ isFloat64Array: [
+ float64Array, stealthyFloat64Array,
+ ],
+ isBigInt64Array: [
+ bigInt64Array, stealthyBigInt64Array,
+ ],
+ isBigUint64Array: [
+ bigUint64Array, stealthyBigUint64Array,
+ ]
+ };
+
+ for (const testedFunc of Object.keys(expected)) {
+ const func = types[testedFunc];
+ const yup = [];
+ for (const value of all) {
+ if (func(value)) {
+ yup.push(value);
+ }
+ }
+ console.log('Testing', testedFunc);
+ assert.deepStrictEqual(yup, expected[testedFunc]);
+ }
+}
+
+// TODO(wafuwafu13): Implement "vm"
+// (async () => {
+// const m = new vm.SourceTextModule('');
+// await m.link(() => 0);
+// await m.evaluate();
+// assert.ok(types.isModuleNamespaceObject(m.namespace));
+// })().then(common.mustCall());
+
+{
+ // eslint-disable-next-line node-core/crypto-check
+ if (common.hasCrypto) {
+ const crypto = require('crypto');
+ assert.ok(!types.isKeyObject(crypto.createHash('sha1')));
+ }
+ assert.ok(!types.isCryptoKey());
+ assert.ok(!types.isKeyObject());
+}
diff --git a/tests/node_compat/test/parallel/test-util.js b/tests/node_compat/test/parallel/test-util.js
new file mode 100644
index 000000000..eaffc7f6d
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-util.js
@@ -0,0 +1,202 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 16.13.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+// Flags: --expose-internals
+const common = require('../common');
+const assert = require('assert');
+const util = require('util');
+const errors = require('internal/errors');
+// TODO(wafuwafu13): Enable this when "vm" is ready.
+// const context = require('vm').runInNewContext;
+
+// isArray
+assert.strictEqual(util.isArray([]), true);
+assert.strictEqual(util.isArray(Array()), true);
+assert.strictEqual(util.isArray(new Array()), true);
+assert.strictEqual(util.isArray(new Array(5)), true);
+assert.strictEqual(util.isArray(new Array('with', 'some', 'entries')), true);
+// TODO(wafuwafu13): Enable this when "vm" is ready.
+// assert.strictEqual(util.isArray(context('Array')()), true);
+assert.strictEqual(util.isArray({}), false);
+assert.strictEqual(util.isArray({ push: function() {} }), false);
+assert.strictEqual(util.isArray(/regexp/), false);
+assert.strictEqual(util.isArray(new Error()), false);
+assert.strictEqual(util.isArray(Object.create(Array.prototype)), false);
+
+// isRegExp
+assert.strictEqual(util.isRegExp(/regexp/), true);
+assert.strictEqual(util.isRegExp(RegExp(), 'foo'), true);
+assert.strictEqual(util.isRegExp(new RegExp()), true);
+// TODO(wafuwafu13): Enable this when "vm" is ready.
+// assert.strictEqual(util.isRegExp(context('RegExp')()), true);
+assert.strictEqual(util.isRegExp({}), false);
+assert.strictEqual(util.isRegExp([]), false);
+assert.strictEqual(util.isRegExp(new Date()), false);
+// TODO(wafuwafu13): Enable this.
+assert.strictEqual(util.isRegExp(Object.create(RegExp.prototype)), false);
+
+// isDate
+assert.strictEqual(util.isDate(new Date()), true);
+assert.strictEqual(util.isDate(new Date(0), 'foo'), true);
+// TODO(wafuwafu13): Enable this when "vm" is ready.
+// assert.strictEqual(util.isDate(new (context('Date'))()), true);
+assert.strictEqual(util.isDate(Date()), false);
+assert.strictEqual(util.isDate({}), false);
+assert.strictEqual(util.isDate([]), false);
+assert.strictEqual(util.isDate(new Error()), false);
+assert.strictEqual(util.isDate(Object.create(Date.prototype)), false);
+
+// isError
+assert.strictEqual(util.isError(new Error()), true);
+assert.strictEqual(util.isError(new TypeError()), true);
+assert.strictEqual(util.isError(new SyntaxError()), true);
+// TODO(wafuwafu13): Enable this when "vm" is ready.
+// assert.strictEqual(util.isError(new (context('Error'))()), true);
+// assert.strictEqual(util.isError(new (context('TypeError'))()), true);
+// assert.strictEqual(util.isError(new (context('SyntaxError'))()), true);
+assert.strictEqual(util.isError({}), false);
+assert.strictEqual(util.isError({ name: 'Error', message: '' }), false);
+assert.strictEqual(util.isError([]), false);
+assert.strictEqual(util.isError(Object.create(Error.prototype)), true);
+
+// isObject
+assert.strictEqual(util.isObject({}), true);
+assert.strictEqual(util.isObject([]), true);
+assert.strictEqual(util.isObject(new Number(3)), true);
+assert.strictEqual(util.isObject(Number(4)), false);
+assert.strictEqual(util.isObject(1), false);
+
+// isPrimitive
+assert.strictEqual(util.isPrimitive({}), false);
+assert.strictEqual(util.isPrimitive(new Error()), false);
+assert.strictEqual(util.isPrimitive(new Date()), false);
+assert.strictEqual(util.isPrimitive([]), false);
+assert.strictEqual(util.isPrimitive(/regexp/), false);
+assert.strictEqual(util.isPrimitive(function() {}), false);
+assert.strictEqual(util.isPrimitive(new Number(1)), false);
+assert.strictEqual(util.isPrimitive(new String('bla')), false);
+assert.strictEqual(util.isPrimitive(new Boolean(true)), false);
+assert.strictEqual(util.isPrimitive(1), true);
+assert.strictEqual(util.isPrimitive('bla'), true);
+assert.strictEqual(util.isPrimitive(true), true);
+assert.strictEqual(util.isPrimitive(undefined), true);
+assert.strictEqual(util.isPrimitive(null), true);
+assert.strictEqual(util.isPrimitive(Infinity), true);
+assert.strictEqual(util.isPrimitive(NaN), true);
+assert.strictEqual(util.isPrimitive(Symbol('symbol')), true);
+
+// isBuffer
+assert.strictEqual(util.isBuffer('foo'), false);
+assert.strictEqual(util.isBuffer(Buffer.from('foo')), true);
+
+// _extend
+assert.deepStrictEqual(util._extend({ a: 1 }), { a: 1 });
+assert.deepStrictEqual(util._extend({ a: 1 }, []), { a: 1 });
+assert.deepStrictEqual(util._extend({ a: 1 }, null), { a: 1 });
+assert.deepStrictEqual(util._extend({ a: 1 }, true), { a: 1 });
+assert.deepStrictEqual(util._extend({ a: 1 }, false), { a: 1 });
+assert.deepStrictEqual(util._extend({ a: 1 }, { b: 2 }), { a: 1, b: 2 });
+assert.deepStrictEqual(util._extend({ a: 1, b: 2 }, { b: 3 }), { a: 1, b: 3 });
+
+// deprecated
+assert.strictEqual(util.isBoolean(true), true);
+assert.strictEqual(util.isBoolean(false), true);
+assert.strictEqual(util.isBoolean('string'), false);
+
+assert.strictEqual(util.isNull(null), true);
+assert.strictEqual(util.isNull(undefined), false);
+assert.strictEqual(util.isNull(), false);
+assert.strictEqual(util.isNull('string'), false);
+
+assert.strictEqual(util.isUndefined(undefined), true);
+assert.strictEqual(util.isUndefined(), true);
+assert.strictEqual(util.isUndefined(null), false);
+assert.strictEqual(util.isUndefined('string'), false);
+
+assert.strictEqual(util.isNullOrUndefined(null), true);
+assert.strictEqual(util.isNullOrUndefined(undefined), true);
+assert.strictEqual(util.isNullOrUndefined(), true);
+assert.strictEqual(util.isNullOrUndefined('string'), false);
+
+assert.strictEqual(util.isNumber(42), true);
+assert.strictEqual(util.isNumber(), false);
+assert.strictEqual(util.isNumber('string'), false);
+
+assert.strictEqual(util.isString('string'), true);
+assert.strictEqual(util.isString(), false);
+assert.strictEqual(util.isString(42), false);
+
+assert.strictEqual(util.isSymbol(Symbol()), true);
+assert.strictEqual(util.isSymbol(), false);
+assert.strictEqual(util.isSymbol('string'), false);
+
+assert.strictEqual(util.isFunction(() => {}), true);
+assert.strictEqual(util.isFunction(function() {}), true);
+assert.strictEqual(util.isFunction(), false);
+assert.strictEqual(util.isFunction('string'), false);
+
+assert.strictEqual(util.toUSVString('string\ud801'), 'string\ufffd');
+
+{
+ assert.strictEqual(util.types.isNativeError(new Error()), true);
+ assert.strictEqual(util.types.isNativeError(new TypeError()), true);
+ assert.strictEqual(util.types.isNativeError(new SyntaxError()), true);
+ // TODO(wafuwafu13): Enable this when "vm" is ready.
+ // assert.strictEqual(util.types.isNativeError(new (context('Error'))()), true);
+ // assert.strictEqual(
+ // util.types.isNativeError(new (context('TypeError'))()),
+ // true
+ // );
+ // assert.strictEqual(
+ // util.types.isNativeError(new (context('SyntaxError'))()),
+ // true
+ // );
+ assert.strictEqual(util.types.isNativeError({}), false);
+ assert.strictEqual(
+ util.types.isNativeError({ name: 'Error', message: '' }),
+ false
+ );
+ assert.strictEqual(util.types.isNativeError([]), false);
+ assert.strictEqual(
+ util.types.isNativeError(Object.create(Error.prototype)),
+ false
+ );
+ assert.strictEqual(
+ util.types.isNativeError(new errors.codes.ERR_IPC_CHANNEL_CLOSED()),
+ true
+ );
+}
+
+assert.throws(() => {
+ util.stripVTControlCharacters({});
+}, {
+ code: 'ERR_INVALID_ARG_TYPE',
+ message: 'The "str" argument must be of type string.' +
+ common.invalidArgTypeHelper({})
+});
diff --git a/tests/node_compat/test/parallel/test-vm-new-script-this-context.js b/tests/node_compat/test/parallel/test-vm-new-script-this-context.js
new file mode 100644
index 000000000..9a9d8fb13
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-vm-new-script-this-context.js
@@ -0,0 +1,75 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const Script = require('vm').Script;
+
+// Run a string
+let script = new Script('\'passed\';');
+const result = script.runInThisContext(script);
+assert.strictEqual(result, 'passed');
+
+// Thrown error
+script = new Script('throw new Error(\'test\');');
+assert.throws(() => {
+ script.runInThisContext(script);
+}, /^Error: test$/);
+
+global.hello = 5;
+script = new Script('hello = 2');
+script.runInThisContext(script);
+assert.strictEqual(global.hello, 2);
+
+
+// Pass values
+global.code = 'foo = 1;' +
+ 'bar = 2;' +
+ 'if (typeof baz !== "undefined") throw new Error("test fail");';
+global.foo = 2;
+global.obj = { foo: 0, baz: 3 };
+script = new Script(global.code);
+script.runInThisContext(script);
+assert.strictEqual(global.obj.foo, 0);
+assert.strictEqual(global.bar, 2);
+assert.strictEqual(global.foo, 1);
+
+// Call a function
+global.f = function() { global.foo = 100; };
+script = new Script('f()');
+script.runInThisContext(script);
+assert.strictEqual(global.foo, 100);
+
+common.allowGlobals(
+ global.hello,
+ global.code,
+ global.foo,
+ global.obj,
+ global.f
+);
diff --git a/tests/node_compat/test/parallel/test-vm-static-this.js b/tests/node_compat/test/parallel/test-vm-static-this.js
new file mode 100644
index 000000000..c6804cfc0
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-vm-static-this.js
@@ -0,0 +1,72 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+/* eslint-disable strict */
+const common = require('../common');
+const assert = require('assert');
+const vm = require('vm');
+
+// Run a string
+const result = vm.runInThisContext('\'passed\';');
+assert.strictEqual(result, 'passed');
+
+// thrown error
+assert.throws(function() {
+ vm.runInThisContext('throw new Error(\'test\');');
+}, /test/);
+
+global.hello = 5;
+vm.runInThisContext('hello = 2');
+assert.strictEqual(global.hello, 2);
+
+
+// pass values
+const code = 'foo = 1;' +
+ 'bar = 2;' +
+ 'if (typeof baz !== \'undefined\')' +
+ 'throw new Error(\'test fail\');';
+global.foo = 2;
+global.obj = { foo: 0, baz: 3 };
+/* eslint-disable no-unused-vars */
+const baz = vm.runInThisContext(code);
+/* eslint-enable no-unused-vars */
+assert.strictEqual(global.obj.foo, 0);
+assert.strictEqual(global.bar, 2);
+assert.strictEqual(global.foo, 1);
+
+// call a function
+global.f = function() { global.foo = 100; };
+vm.runInThisContext('f()');
+assert.strictEqual(global.foo, 100);
+
+common.allowGlobals(
+ global.hello,
+ global.foo,
+ global.obj,
+ global.f
+);
diff --git a/tests/node_compat/test/parallel/test-webcrypto-sign-verify.js b/tests/node_compat/test/parallel/test-webcrypto-sign-verify.js
new file mode 100644
index 000000000..23df883ee
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-webcrypto-sign-verify.js
@@ -0,0 +1,154 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 16.13.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+'use strict';
+
+const common = require('../common');
+
+if (!common.hasCrypto)
+ common.skip('missing crypto');
+
+const assert = require('assert');
+const { subtle } = require('crypto').webcrypto;
+
+// This is only a partial test. The WebCrypto Web Platform Tests
+// will provide much greater coverage.
+
+// Test Sign/Verify RSASSA-PKCS1-v1_5
+{
+ async function test(data) {
+ const ec = new TextEncoder();
+ const { publicKey, privateKey } = await subtle.generateKey({
+ name: 'RSASSA-PKCS1-v1_5',
+ modulusLength: 1024,
+ publicExponent: new Uint8Array([1, 0, 1]),
+ hash: 'SHA-256'
+ }, true, ['sign', 'verify']);
+
+ const signature = await subtle.sign({
+ name: 'RSASSA-PKCS1-v1_5'
+ }, privateKey, ec.encode(data));
+
+ assert(await subtle.verify({
+ name: 'RSASSA-PKCS1-v1_5'
+ }, publicKey, signature, ec.encode(data)));
+ }
+
+ test('hello world').then(common.mustCall());
+}
+
+// Test Sign/Verify RSA-PSS
+{
+ async function test(data) {
+ const ec = new TextEncoder();
+ const { publicKey, privateKey } = await subtle.generateKey({
+ name: 'RSA-PSS',
+ modulusLength: 4096,
+ publicExponent: new Uint8Array([1, 0, 1]),
+ hash: 'SHA-256'
+ }, true, ['sign', 'verify']);
+
+ const signature = await subtle.sign({
+ name: 'RSA-PSS',
+ saltLength: 256,
+ }, privateKey, ec.encode(data));
+
+ assert(await subtle.verify({
+ name: 'RSA-PSS',
+ saltLength: 256,
+ }, publicKey, signature, ec.encode(data)));
+ }
+
+ test('hello world').then(common.mustCall());
+}
+
+// Test Sign/Verify ECDSA
+{
+ async function test(data) {
+ const ec = new TextEncoder();
+ const { publicKey, privateKey } = await subtle.generateKey({
+ name: 'ECDSA',
+ namedCurve: 'P-384',
+ }, true, ['sign', 'verify']);
+
+ const signature = await subtle.sign({
+ name: 'ECDSA',
+ hash: 'SHA-384',
+ }, privateKey, ec.encode(data));
+
+ assert(await subtle.verify({
+ name: 'ECDSA',
+ hash: 'SHA-384',
+ }, publicKey, signature, ec.encode(data)));
+ }
+
+ test('hello world').then(common.mustCall());
+}
+
+// Test Sign/Verify HMAC
+{
+ async function test(data) {
+ const ec = new TextEncoder();
+
+ const key = await subtle.generateKey({
+ name: 'HMAC',
+ length: 256,
+ hash: 'SHA-256'
+ }, true, ['sign', 'verify']);
+
+ const signature = await subtle.sign({
+ name: 'HMAC',
+ }, key, ec.encode(data));
+
+ assert(await subtle.verify({
+ name: 'HMAC',
+ }, key, signature, ec.encode(data)));
+ }
+
+ test('hello world').then(common.mustCall());
+}
+
+// Test Sign/Verify Ed25519
+{
+ async function test(data) {
+ const ec = new TextEncoder();
+ const { publicKey, privateKey } = await subtle.generateKey({
+ name: 'Ed25519',
+ }, true, ['sign', 'verify']);
+
+ const signature = await subtle.sign({
+ name: 'Ed25519',
+ }, privateKey, ec.encode(data));
+
+ assert(await subtle.verify({
+ name: 'Ed25519',
+ }, publicKey, signature, ec.encode(data)));
+ }
+
+ test('hello world').then(common.mustCall());
+}
+
+// Test Sign/Verify Ed448
+// TODO(cjihrig): Pending support in Deno core.
+// {
+// async function test(data) {
+// const ec = new TextEncoder();
+// const { publicKey, privateKey } = await subtle.generateKey({
+// name: 'Ed448',
+// }, true, ['sign', 'verify']);
+
+// const signature = await subtle.sign({
+// name: 'Ed448',
+// }, privateKey, ec.encode(data));
+
+// assert(await subtle.verify({
+// name: 'Ed448',
+// }, publicKey, signature, ec.encode(data)));
+// }
+
+// test('hello world').then(common.mustCall());
+// }
diff --git a/tests/node_compat/test/parallel/test-whatwg-encoding-custom-api-basics.js b/tests/node_compat/test/parallel/test-whatwg-encoding-custom-api-basics.js
new file mode 100644
index 000000000..e423c25d0
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-whatwg-encoding-custom-api-basics.js
@@ -0,0 +1,68 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+// From: https://github.com/w3c/web-platform-tests/blob/master/encoding/api-basics.html
+// This is the part that can be run without ICU
+
+require('../common');
+
+const assert = require('assert');
+
+function testDecodeSample(encoding, string, bytes) {
+ assert.strictEqual(
+ new TextDecoder(encoding).decode(new Uint8Array(bytes)),
+ string);
+ assert.strictEqual(
+ new TextDecoder(encoding).decode(new Uint8Array(bytes).buffer),
+ string);
+}
+
+// `z` (ASCII U+007A), cent (Latin-1 U+00A2), CJK water (BMP U+6C34),
+// G-Clef (non-BMP U+1D11E), PUA (BMP U+F8FF), PUA (non-BMP U+10FFFD)
+// byte-swapped BOM (non-character U+FFFE)
+const sample = 'z\xA2\u6C34\uD834\uDD1E\uF8FF\uDBFF\uDFFD\uFFFE';
+
+{
+ const encoding = 'utf-8';
+ const string = sample;
+ const bytes = [
+ 0x7A, 0xC2, 0xA2, 0xE6, 0xB0, 0xB4,
+ 0xF0, 0x9D, 0x84, 0x9E, 0xEF, 0xA3,
+ 0xBF, 0xF4, 0x8F, 0xBF, 0xBD, 0xEF,
+ 0xBF, 0xBE,
+ ];
+ const encoded = new TextEncoder().encode(string);
+ assert.deepStrictEqual([].slice.call(encoded), bytes);
+ assert.strictEqual(
+ new TextDecoder(encoding).decode(new Uint8Array(bytes)),
+ string);
+ assert.strictEqual(
+ new TextDecoder(encoding).decode(new Uint8Array(bytes).buffer),
+ string);
+}
+
+testDecodeSample(
+ 'utf-16le',
+ sample,
+ [
+ 0x7A, 0x00, 0xA2, 0x00, 0x34, 0x6C,
+ 0x34, 0xD8, 0x1E, 0xDD, 0xFF, 0xF8,
+ 0xFF, 0xDB, 0xFD, 0xDF, 0xFE, 0xFF,
+ ]
+);
+
+testDecodeSample(
+ 'utf-16',
+ sample,
+ [
+ 0x7A, 0x00, 0xA2, 0x00, 0x34, 0x6C,
+ 0x34, 0xD8, 0x1E, 0xDD, 0xFF, 0xF8,
+ 0xFF, 0xDB, 0xFD, 0xDF, 0xFE, 0xFF,
+ ]
+);
diff --git a/tests/node_compat/test/parallel/test-whatwg-encoding-custom-textdecoder-ignorebom.js b/tests/node_compat/test/parallel/test-whatwg-encoding-custom-textdecoder-ignorebom.js
new file mode 100644
index 000000000..58488d25d
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-whatwg-encoding-custom-textdecoder-ignorebom.js
@@ -0,0 +1,37 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+// From: https://github.com/w3c/web-platform-tests/blob/7f567fa29c/encoding/textdecoder-ignorebom.html
+// This is the part that can be run without ICU
+
+require('../common');
+
+const assert = require('assert');
+
+const cases = [
+ {
+ encoding: 'utf-8',
+ bytes: [0xEF, 0xBB, 0xBF, 0x61, 0x62, 0x63]
+ },
+ {
+ encoding: 'utf-16le',
+ bytes: [0xFF, 0xFE, 0x61, 0x00, 0x62, 0x00, 0x63, 0x00]
+ },
+];
+
+cases.forEach((testCase) => {
+ const BOM = '\uFEFF';
+ let decoder = new TextDecoder(testCase.encoding, { ignoreBOM: true });
+ const bytes = new Uint8Array(testCase.bytes);
+ assert.strictEqual(decoder.decode(bytes), `${BOM}abc`);
+ decoder = new TextDecoder(testCase.encoding, { ignoreBOM: false });
+ assert.strictEqual(decoder.decode(bytes), 'abc');
+ decoder = new TextDecoder(testCase.encoding);
+ assert.strictEqual(decoder.decode(bytes), 'abc');
+});
diff --git a/tests/node_compat/test/parallel/test-whatwg-encoding-custom-textdecoder-streaming.js b/tests/node_compat/test/parallel/test-whatwg-encoding-custom-textdecoder-streaming.js
new file mode 100644
index 000000000..ef9cecc0f
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-whatwg-encoding-custom-textdecoder-streaming.js
@@ -0,0 +1,45 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+// From: https://github.com/w3c/web-platform-tests/blob/fa9436d12c/encoding/textdecoder-streaming.html
+// This is the part that can be run without ICU
+
+require('../common');
+
+const assert = require('assert');
+
+const string =
+ '\x00123ABCabc\x80\xFF\u0100\u1000\uFFFD\uD800\uDC00\uDBFF\uDFFF';
+const octets = {
+ 'utf-8': [
+ 0x00, 0x31, 0x32, 0x33, 0x41, 0x42, 0x43, 0x61, 0x62, 0x63, 0xc2, 0x80,
+ 0xc3, 0xbf, 0xc4, 0x80, 0xe1, 0x80, 0x80, 0xef, 0xbf, 0xbd, 0xf0, 0x90,
+ 0x80, 0x80, 0xf4, 0x8f, 0xbf, 0xbf],
+ 'utf-16le': [
+ 0x00, 0x00, 0x31, 0x00, 0x32, 0x00, 0x33, 0x00, 0x41, 0x00, 0x42, 0x00,
+ 0x43, 0x00, 0x61, 0x00, 0x62, 0x00, 0x63, 0x00, 0x80, 0x00, 0xFF, 0x00,
+ 0x00, 0x01, 0x00, 0x10, 0xFD, 0xFF, 0x00, 0xD8, 0x00, 0xDC, 0xFF, 0xDB,
+ 0xFF, 0xDF]
+};
+
+Object.keys(octets).forEach((encoding) => {
+ for (let len = 1; len <= 5; ++len) {
+ const encoded = octets[encoding];
+ const decoder = new TextDecoder(encoding);
+ let out = '';
+ for (let i = 0; i < encoded.length; i += len) {
+ const sub = [];
+ for (let j = i; j < encoded.length && j < i + len; ++j)
+ sub.push(encoded[j]);
+ out += decoder.decode(new Uint8Array(sub), { stream: true });
+ }
+ out += decoder.decode();
+ assert.strictEqual(out, string);
+ }
+});
diff --git a/tests/node_compat/test/parallel/test-whatwg-events-add-event-listener-options-passive.js b/tests/node_compat/test/parallel/test-whatwg-events-add-event-listener-options-passive.js
new file mode 100644
index 000000000..e2bc96139
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-whatwg-events-add-event-listener-options-passive.js
@@ -0,0 +1,72 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+
+// Manually converted from https://github.com/web-platform-tests/wpt/blob/master/dom/events/AddEventListenerOptions-passive.html
+// in order to define the `document` ourselves
+
+const {
+ fail,
+ ok,
+ strictEqual
+} = require('assert');
+
+{
+ const document = new EventTarget();
+ let supportsPassive = false;
+ const query_options = {
+ get passive() {
+ supportsPassive = true;
+ return false;
+ },
+ get dummy() {
+ fail('dummy value getter invoked');
+ return false;
+ }
+ };
+
+ document.addEventListener('test_event', null, query_options);
+ ok(supportsPassive);
+
+ supportsPassive = false;
+ document.removeEventListener('test_event', null, query_options);
+ strictEqual(supportsPassive, false);
+}
+{
+ function testPassiveValue(optionsValue, expectedDefaultPrevented) {
+ const document = new EventTarget();
+ let defaultPrevented;
+ function handler(e) {
+ if (e.defaultPrevented) {
+ fail('Event prematurely marked defaultPrevented');
+ }
+ e.preventDefault();
+ defaultPrevented = e.defaultPrevented;
+ }
+ document.addEventListener('test', handler, optionsValue);
+ // TODO the WHATWG test is more extensive here and tests dispatching on
+ // document.body, if we ever support getParent we should amend this
+ const ev = new Event('test', { bubbles: true, cancelable: true });
+ const uncanceled = document.dispatchEvent(ev);
+
+ strictEqual(defaultPrevented, expectedDefaultPrevented);
+ strictEqual(uncanceled, !expectedDefaultPrevented);
+
+ document.removeEventListener('test', handler, optionsValue);
+ }
+ testPassiveValue(undefined, true);
+ testPassiveValue({}, true);
+ testPassiveValue({ passive: false }, true);
+
+ common.skip('TODO: passive listeners is still broken');
+ testPassiveValue({ passive: 1 }, false);
+ testPassiveValue({ passive: true }, false);
+ testPassiveValue({ passive: 0 }, true);
+}
diff --git a/tests/node_compat/test/parallel/test-whatwg-events-add-event-listener-options-signal.js b/tests/node_compat/test/parallel/test-whatwg-events-add-event-listener-options-signal.js
new file mode 100644
index 000000000..80d09c4b7
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-whatwg-events-add-event-listener-options-signal.js
@@ -0,0 +1,166 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+require('../common');
+
+const {
+ strictEqual,
+} = require('assert');
+
+// Manually ported from: wpt@dom/events/AddEventListenerOptions-signal.any.js
+
+{
+ // Passing an AbortSignal to addEventListener does not prevent
+ // removeEventListener
+ let count = 0;
+ function handler() {
+ count++;
+ }
+ const et = new EventTarget();
+ const controller = new AbortController();
+ et.addEventListener('test', handler, { signal: controller.signal });
+ et.dispatchEvent(new Event('test'));
+ strictEqual(count, 1, 'Adding a signal still adds a listener');
+ et.dispatchEvent(new Event('test'));
+ strictEqual(count, 2, 'The listener was not added with the once flag');
+ controller.abort();
+ et.dispatchEvent(new Event('test'));
+ strictEqual(count, 2, 'Aborting on the controller removes the listener');
+ // See: https://github.com/nodejs/node/pull/37696 , adding an event listener
+ // should always return undefined.
+ strictEqual(
+ et.addEventListener('test', handler, { signal: controller.signal }),
+ undefined);
+ et.dispatchEvent(new Event('test'));
+ strictEqual(count, 2, 'Passing an aborted signal never adds the handler');
+}
+
+{
+ // Passing an AbortSignal to addEventListener works with the once flag
+ let count = 0;
+ function handler() {
+ count++;
+ }
+ const et = new EventTarget();
+ const controller = new AbortController();
+ et.addEventListener('test', handler, { signal: controller.signal });
+ et.removeEventListener('test', handler);
+ et.dispatchEvent(new Event('test'));
+ strictEqual(count, 0, 'The listener was still removed');
+}
+
+{
+ // Removing a once listener works with a passed signal
+ let count = 0;
+ function handler() {
+ count++;
+ }
+ const et = new EventTarget();
+ const controller = new AbortController();
+ const options = { signal: controller.signal, once: true };
+ et.addEventListener('test', handler, options);
+ controller.abort();
+ et.dispatchEvent(new Event('test'));
+ strictEqual(count, 0, 'The listener was still removed');
+}
+
+{
+ let count = 0;
+ function handler() {
+ count++;
+ }
+ const et = new EventTarget();
+ const controller = new AbortController();
+ const options = { signal: controller.signal, once: true };
+ et.addEventListener('test', handler, options);
+ et.removeEventListener('test', handler);
+ et.dispatchEvent(new Event('test'));
+ strictEqual(count, 0, 'The listener was still removed');
+}
+
+{
+ // Passing an AbortSignal to multiple listeners
+ let count = 0;
+ function handler() {
+ count++;
+ }
+ const et = new EventTarget();
+ const controller = new AbortController();
+ const options = { signal: controller.signal, once: true };
+ et.addEventListener('first', handler, options);
+ et.addEventListener('second', handler, options);
+ controller.abort();
+ et.dispatchEvent(new Event('first'));
+ et.dispatchEvent(new Event('second'));
+ strictEqual(count, 0, 'The listener was still removed');
+}
+
+{
+ // Passing an AbortSignal to addEventListener works with the capture flag
+ let count = 0;
+ function handler() {
+ count++;
+ }
+ const et = new EventTarget();
+ const controller = new AbortController();
+ const options = { signal: controller.signal, capture: true };
+ et.addEventListener('test', handler, options);
+ controller.abort();
+ et.dispatchEvent(new Event('test'));
+ strictEqual(count, 0, 'The listener was still removed');
+}
+
+{
+ // Aborting from a listener does not call future listeners
+ let count = 0;
+ function handler() {
+ count++;
+ }
+ const et = new EventTarget();
+ const controller = new AbortController();
+ const options = { signal: controller.signal };
+ et.addEventListener('test', () => {
+ controller.abort();
+ }, options);
+ et.addEventListener('test', handler, options);
+ et.dispatchEvent(new Event('test'));
+ strictEqual(count, 0, 'The listener was still removed');
+}
+
+{
+ // Adding then aborting a listener in another listener does not call it
+ let count = 0;
+ function handler() {
+ count++;
+ }
+ const et = new EventTarget();
+ const controller = new AbortController();
+ et.addEventListener('test', () => {
+ et.addEventListener('test', handler, { signal: controller.signal });
+ controller.abort();
+ }, { signal: controller.signal });
+ et.dispatchEvent(new Event('test'));
+ strictEqual(count, 0, 'The listener was still removed');
+}
+
+{
+ // Aborting from a nested listener should remove it
+ const et = new EventTarget();
+ const ac = new AbortController();
+ let count = 0;
+ et.addEventListener('foo', () => {
+ et.addEventListener('foo', () => {
+ count++;
+ if (count > 5) ac.abort();
+ et.dispatchEvent(new Event('foo'));
+ }, { signal: ac.signal });
+ et.dispatchEvent(new Event('foo'));
+ }, { once: true });
+ et.dispatchEvent(new Event('foo'));
+}
diff --git a/tests/node_compat/test/parallel/test-whatwg-events-customevent.js b/tests/node_compat/test/parallel/test-whatwg-events-customevent.js
new file mode 100644
index 000000000..749c838de
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-whatwg-events-customevent.js
@@ -0,0 +1,40 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+
+const { strictEqual, throws, equal } = require('assert');
+
+// Manually converted from https://github.com/web-platform-tests/wpt/blob/master/dom/events/CustomEvent.html
+// in order to define the `document` ourselves
+
+{
+ const type = 'foo';
+ const target = new EventTarget();
+
+ target.addEventListener(type, common.mustCall((evt) => {
+ strictEqual(evt.type, type);
+ }));
+
+ target.dispatchEvent(new Event(type));
+}
+
+{
+ throws(() => {
+ new Event();
+ }, TypeError);
+}
+
+{
+ const event = new Event('foo');
+ equal(event.type, 'foo');
+ equal(event.bubbles, false);
+ equal(event.cancelable, false);
+ equal(event.detail, null);
+}
diff --git a/tests/node_compat/test/parallel/test-whatwg-url-custom-deepequal.js b/tests/node_compat/test/parallel/test-whatwg-url-custom-deepequal.js
new file mode 100644
index 000000000..e33590530
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-whatwg-url-custom-deepequal.js
@@ -0,0 +1,25 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+// This tests that the internal flags in URL objects are consistent, as manifest
+// through assert libraries.
+// See https://github.com/nodejs/node/issues/24211
+
+// Tests below are not from WPT.
+
+require('../common');
+const assert = require('assert');
+
+assert.deepStrictEqual(
+ new URL('./foo', 'https://example.com/'),
+ new URL('https://example.com/foo')
+);
+assert.deepStrictEqual(
+ new URL('./foo', 'https://user:pass@example.com/'),
+ new URL('https://user:pass@example.com/foo')
+);
diff --git a/tests/node_compat/test/parallel/test-whatwg-url-custom-global.js b/tests/node_compat/test/parallel/test-whatwg-url-custom-global.js
new file mode 100644
index 000000000..b7880d8c2
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-whatwg-url-custom-global.js
@@ -0,0 +1,33 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+// Tests below are not from WPT.
+
+require('../common');
+const assert = require('assert');
+
+assert.deepStrictEqual(
+ Object.getOwnPropertyDescriptor(global, 'URL'),
+ {
+ value: URL,
+ writable: true,
+ configurable: true,
+ enumerable: false
+ }
+);
+
+assert.deepStrictEqual(
+ Object.getOwnPropertyDescriptor(global, 'URLSearchParams'),
+ {
+ value: URLSearchParams,
+ writable: true,
+ configurable: true,
+ enumerable: false
+ }
+);
diff --git a/tests/node_compat/test/parallel/test-whatwg-url-custom-href-side-effect.js b/tests/node_compat/test/parallel/test-whatwg-url-custom-href-side-effect.js
new file mode 100644
index 000000000..de175e357
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-whatwg-url-custom-href-side-effect.js
@@ -0,0 +1,22 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+// Tests below are not from WPT.
+require('../common');
+const assert = require('assert');
+
+const ref = new URL('http://example.com/path');
+const url = new URL('http://example.com/path');
+assert.throws(() => {
+ url.href = '';
+}, {
+ name: 'TypeError'
+});
+
+assert.deepStrictEqual(url, ref);
diff --git a/tests/node_compat/test/parallel/test-whatwg-url-custom-tostringtag.js b/tests/node_compat/test/parallel/test-whatwg-url-custom-tostringtag.js
new file mode 100644
index 000000000..add70bc34
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-whatwg-url-custom-tostringtag.js
@@ -0,0 +1,39 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+// Tests below are not from WPT.
+
+require('../common');
+const assert = require('assert');
+
+const toString = Object.prototype.toString;
+
+const url = new URL('http://example.org');
+const sp = url.searchParams;
+const spIterator = sp.entries();
+
+const test = [
+ [url, 'URL'],
+ [sp, 'URLSearchParams'],
+ [spIterator, 'URLSearchParams Iterator'],
+ // Web IDL spec says we have to return 'URLPrototype', but it is too
+ // expensive to implement; therefore, use Chrome's behavior for now, until
+ // spec is changed.
+ [Object.getPrototypeOf(url), 'URL'],
+ [Object.getPrototypeOf(sp), 'URLSearchParams'],
+ [Object.getPrototypeOf(spIterator), 'URLSearchParams Iterator'],
+];
+
+test.forEach(([obj, expected]) => {
+ assert.strictEqual(obj[Symbol.toStringTag], expected,
+ `${obj[Symbol.toStringTag]} !== ${expected}`);
+ const str = toString.call(obj);
+ assert.strictEqual(str, `[object ${expected}]`,
+ `${str} !== [object ${expected}]`);
+});
diff --git a/tests/node_compat/test/parallel/test-whatwg-url-override-hostname.js b/tests/node_compat/test/parallel/test-whatwg-url-override-hostname.js
new file mode 100644
index 000000000..1fcdefdf7
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-whatwg-url-override-hostname.js
@@ -0,0 +1,27 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+require('../common');
+const assert = require('assert');
+
+{
+ const url = new (class extends URL { get hostname() { return 'bar.com'; } })('http://foo.com/');
+ assert.strictEqual(url.href, 'http://foo.com/');
+ assert.strictEqual(url.toString(), 'http://foo.com/');
+ assert.strictEqual(url.toJSON(), 'http://foo.com/');
+ assert.strictEqual(url.hash, '');
+ assert.strictEqual(url.host, 'foo.com');
+ assert.strictEqual(url.hostname, 'bar.com');
+ assert.strictEqual(url.origin, 'http://foo.com');
+ assert.strictEqual(url.password, '');
+ assert.strictEqual(url.protocol, 'http:');
+ assert.strictEqual(url.username, '');
+ assert.strictEqual(url.search, '');
+ assert.strictEqual(url.searchParams.toString(), '');
+}
diff --git a/tests/node_compat/test/parallel/test-whatwg-url-properties.js b/tests/node_compat/test/parallel/test-whatwg-url-properties.js
new file mode 100644
index 000000000..8a4f4e57b
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-whatwg-url-properties.js
@@ -0,0 +1,111 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 16.13.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+'use strict';
+require('../common');
+const assert = require('assert');
+const { URL, URLSearchParams } = require('url');
+
+[
+ { name: 'toString' },
+ { name: 'toJSON' },
+ // Deno's URL doesn't support nodejs custom inspect
+ // { name: Symbol.for('nodejs.util.inspect.custom') },
+].forEach(({ name }) => {
+ testMethod(URL.prototype, name);
+});
+
+[
+ { name: 'href' },
+ { name: 'protocol' },
+ { name: 'username' },
+ { name: 'password' },
+ { name: 'host' },
+ { name: 'hostname' },
+ { name: 'port' },
+ { name: 'pathname' },
+ { name: 'search' },
+ { name: 'hash' },
+ { name: 'origin', readonly: true },
+ { name: 'searchParams', readonly: true },
+].forEach(({ name, readonly = false }) => {
+ testAccessor(URL.prototype, name, readonly);
+});
+
+[
+ { name: 'append' },
+ { name: 'delete' },
+ { name: 'get' },
+ { name: 'getAll' },
+ { name: 'has' },
+ { name: 'set' },
+ { name: 'sort' },
+ { name: 'entries' },
+ { name: 'forEach' },
+ { name: 'keys' },
+ { name: 'values' },
+ { name: 'toString' },
+ { name: Symbol.iterator, methodName: 'entries' },
+ // Deno's URL doesn't support nodejs custom inspect
+ // { name: Symbol.for('nodejs.util.inspect.custom') },
+].forEach(({ name, methodName }) => {
+ testMethod(URLSearchParams.prototype, name, methodName);
+});
+
+function stringifyName(name) {
+ if (typeof name === 'symbol') {
+ const { description } = name;
+ if (description === undefined) {
+ return '';
+ }
+ return `[${description}]`;
+ }
+
+ return name;
+}
+
+function testMethod(target, name, methodName = stringifyName(name)) {
+ const desc = Object.getOwnPropertyDescriptor(target, name);
+ assert.notStrictEqual(desc, undefined);
+ assert.strictEqual(desc.enumerable, typeof name === 'string');
+
+ const { value } = desc;
+ assert.strictEqual(typeof value, 'function');
+ assert.strictEqual(value.name, methodName);
+ /* This can't pass with Deno's URL/URLSearchParams
+ assert.strictEqual(
+ Object.prototype.hasOwnProperty.call(value, 'prototype'),
+ false,
+ );
+ */
+}
+
+function testAccessor(target, name, readonly = false) {
+ const desc = Object.getOwnPropertyDescriptor(target, name);
+ assert.notStrictEqual(desc, undefined);
+ assert.strictEqual(desc.enumerable, typeof name === 'string');
+
+ const methodName = stringifyName(name);
+ const { get, set } = desc;
+ assert.strictEqual(typeof get, 'function');
+ assert.strictEqual(get.name, `get ${methodName}`);
+ assert.strictEqual(
+ Object.prototype.hasOwnProperty.call(get, 'prototype'),
+ false,
+ );
+
+ if (readonly) {
+ assert.strictEqual(set, undefined);
+ } else {
+ assert.strictEqual(typeof set, 'function');
+ assert.strictEqual(set.name, `set ${methodName}`);
+ assert.strictEqual(
+ Object.prototype.hasOwnProperty.call(set, 'prototype'),
+ false,
+ );
+ }
+}
diff --git a/tests/node_compat/test/parallel/test-zlib-close-after-error.js b/tests/node_compat/test/parallel/test-zlib-close-after-error.js
new file mode 100644
index 000000000..55f1d6b02
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-zlib-close-after-error.js
@@ -0,0 +1,23 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+// https://github.com/nodejs/node/issues/6034
+
+const common = require('../common');
+const assert = require('assert');
+const zlib = require('zlib');
+
+const decompress = zlib.createGunzip(15);
+
+decompress.on('error', common.mustCall((err) => {
+ assert.strictEqual(decompress._closed, true);
+ decompress.close();
+}));
+
+assert.strictEqual(decompress._closed, false);
+decompress.write('something invalid');
diff --git a/tests/node_compat/test/parallel/test-zlib-close-after-write.js b/tests/node_compat/test/parallel/test-zlib-close-after-write.js
new file mode 100644
index 000000000..94fa4eb20
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-zlib-close-after-write.js
@@ -0,0 +1,37 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const zlib = require('zlib');
+
+zlib.gzip('hello', common.mustCall((err, out) => {
+ const unzip = zlib.createGunzip();
+ unzip.write(out);
+ unzip.close(common.mustCall());
+}));
diff --git a/tests/node_compat/test/parallel/test-zlib-convenience-methods.js b/tests/node_compat/test/parallel/test-zlib-convenience-methods.js
new file mode 100644
index 000000000..cf6694b1f
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-zlib-convenience-methods.js
@@ -0,0 +1,144 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 16.13.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+// Test convenience methods with and without options supplied
+
+const common = require('../common');
+const assert = require('assert');
+const zlib = require('zlib');
+
+// Must be a multiple of 4 characters in total to test all ArrayBufferView
+// types.
+const expectStr = 'blah'.repeat(8);
+const expectBuf = Buffer.from(expectStr);
+
+const opts = {
+ level: 9,
+ chunkSize: 1024,
+};
+
+const optsInfo = {
+ info: true
+};
+
+for (const [type, expect] of [
+ ['string', expectStr],
+ ['Buffer', expectBuf],
+ // FIXME(bartlomieju):
+ // ...common.getBufferSources(expectBuf).map((obj) =>
+ // [obj[Symbol.toStringTag], obj]
+ // ),
+]) {
+ for (const method of [
+ ['gzip', 'gunzip', 'Gzip', 'Gunzip'],
+ ['gzip', 'unzip', 'Gzip', 'Unzip'],
+ ['deflate', 'inflate', 'Deflate', 'Inflate'],
+ ['deflateRaw', 'inflateRaw', 'DeflateRaw', 'InflateRaw'],
+ // FIXME(bartlomieju):
+ // ['brotliCompress', 'brotliDecompress',
+ // 'BrotliCompress', 'BrotliDecompress'],
+ ]) {
+ zlib[method[0]](expect, opts, common.mustCall((err, result) => {
+ zlib[method[1]](result, opts, common.mustCall((err, result) => {
+ assert.strictEqual(result.toString(), expectStr,
+ `Should get original string after ${method[0]}/` +
+ `${method[1]} ${type} with options.`);
+ }));
+ }));
+
+ zlib[method[0]](expect, common.mustCall((err, result) => {
+ zlib[method[1]](result, common.mustCall((err, result) => {
+ assert.strictEqual(result.toString(), expectStr,
+ `Should get original string after ${method[0]}/` +
+ `${method[1]} ${type} without options.`);
+ }));
+ }));
+
+ // FIXME(bartlomieju):
+ // zlib[method[0]](expect, optsInfo, common.mustCall((err, result) => {
+ // assert.ok(result.engine instanceof zlib[method[2]],
+ // `Should get engine ${method[2]} after ${method[0]} ` +
+ // `${type} with info option.`);
+
+ // const compressed = result.buffer;
+ // zlib[method[1]](compressed, optsInfo, common.mustCall((err, result) => {
+ // assert.strictEqual(result.buffer.toString(), expectStr,
+ // `Should get original string after ${method[0]}/` +
+ // `${method[1]} ${type} with info option.`);
+ // assert.ok(result.engine instanceof zlib[method[3]],
+ // `Should get engine ${method[3]} after ${method[0]} ` +
+ // `${type} with info option.`);
+ // }));
+ // }));
+
+ {
+ const compressed = zlib[`${method[0]}Sync`](expect, opts);
+ const decompressed = zlib[`${method[1]}Sync`](compressed, opts);
+ assert.strictEqual(decompressed.toString(), expectStr,
+ `Should get original string after ${method[0]}Sync/` +
+ `${method[1]}Sync ${type} with options.`);
+ }
+
+
+ {
+ const compressed = zlib[`${method[0]}Sync`](expect);
+ const decompressed = zlib[`${method[1]}Sync`](compressed);
+ assert.strictEqual(decompressed.toString(), expectStr,
+ `Should get original string after ${method[0]}Sync/` +
+ `${method[1]}Sync ${type} without options.`);
+ }
+
+ // FIXME(bartlomieju):
+ // {
+ // const compressed = zlib[`${method[0]}Sync`](expect, optsInfo);
+ // assert.ok(compressed.engine instanceof zlib[method[2]],
+ // `Should get engine ${method[2]} after ${method[0]} ` +
+ // `${type} with info option.`);
+ // const decompressed = zlib[`${method[1]}Sync`](compressed.buffer,
+ // optsInfo);
+ // assert.strictEqual(decompressed.buffer.toString(), expectStr,
+ // `Should get original string after ${method[0]}Sync/` +
+ // `${method[1]}Sync ${type} without options.`);
+ // assert.ok(decompressed.engine instanceof zlib[method[3]],
+ // `Should get engine ${method[3]} after ${method[0]} ` +
+ // `${type} with info option.`);
+ // }
+ }
+}
+
+// FIXME(bartlomieju):
+// assert.throws(
+// () => zlib.gzip('abc'),
+// {
+// code: 'ERR_INVALID_ARG_TYPE',
+// name: 'TypeError',
+// message: 'The "callback" argument must be of type function. ' +
+// 'Received undefined'
+// }
+// );
diff --git a/tests/node_compat/test/parallel/test-zlib-deflate-raw-inherits.js b/tests/node_compat/test/parallel/test-zlib-deflate-raw-inherits.js
new file mode 100644
index 000000000..58c069c74
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-zlib-deflate-raw-inherits.js
@@ -0,0 +1,34 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+require('../common');
+const { DeflateRaw } = require('zlib');
+const { Readable } = require('stream');
+
+// Validates that zlib.DeflateRaw can be inherited
+// with Object.setPrototypeOf
+
+function NotInitialized(options) {
+ DeflateRaw.call(this, options);
+ this.prop = true;
+}
+Object.setPrototypeOf(NotInitialized.prototype, DeflateRaw.prototype);
+Object.setPrototypeOf(NotInitialized, DeflateRaw);
+
+const dest = new NotInitialized();
+
+const read = new Readable({
+ read() {
+ this.push(Buffer.from('a test string'));
+ this.push(null);
+ }
+});
+
+read.pipe(dest);
+dest.resume();
diff --git a/tests/node_compat/test/parallel/test-zlib-destroy-pipe.js b/tests/node_compat/test/parallel/test-zlib-destroy-pipe.js
new file mode 100644
index 000000000..274068f9f
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-zlib-destroy-pipe.js
@@ -0,0 +1,28 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+const common = require('../common');
+const zlib = require('zlib');
+const { Writable } = require('stream');
+
+// Verify that the zlib transform does not error in case
+// it is destroyed with data still in flight
+
+const ts = zlib.createGzip();
+
+const ws = new Writable({
+ write: common.mustCall((chunk, enc, cb) => {
+ setImmediate(cb);
+ ts.destroy();
+ })
+});
+
+const buf = Buffer.allocUnsafe(1024 * 1024 * 20);
+ts.end(buf);
+ts.pipe(ws);
diff --git a/tests/node_compat/test/parallel/test-zlib-empty-buffer.js b/tests/node_compat/test/parallel/test-zlib-empty-buffer.js
new file mode 100644
index 000000000..2281ba88e
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-zlib-empty-buffer.js
@@ -0,0 +1,35 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 16.13.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+'use strict';
+const common = require('../common');
+const zlib = require('zlib');
+const { inspect, promisify } = require('util');
+const assert = require('assert');
+const emptyBuffer = Buffer.alloc(0);
+
+(async function() {
+ for (const [ compress, decompress, method ] of [
+ [ zlib.deflateRawSync, zlib.inflateRawSync, 'raw sync' ],
+ [ zlib.deflateSync, zlib.inflateSync, 'deflate sync' ],
+ [ zlib.gzipSync, zlib.gunzipSync, 'gzip sync' ],
+ // FIXME(bartlomieju):
+ // [ zlib.brotliCompressSync, zlib.brotliDecompressSync, 'br sync' ],
+ [ promisify(zlib.deflateRaw), promisify(zlib.inflateRaw), 'raw' ],
+ [ promisify(zlib.deflate), promisify(zlib.inflate), 'deflate' ],
+ [ promisify(zlib.gzip), promisify(zlib.gunzip), 'gzip' ],
+ // FIXME(bartlomieju):
+ // [ promisify(zlib.brotliCompress), promisify(zlib.brotliDecompress), 'br' ],
+ ]) {
+ const compressed = await compress(emptyBuffer);
+ const decompressed = await decompress(compressed);
+ assert.deepStrictEqual(
+ emptyBuffer, decompressed,
+ `Expected ${inspect(compressed)} to match ${inspect(decompressed)} ` +
+ `to match for ${method}`);
+ }
+})().then(common.mustCall());
diff --git a/tests/node_compat/test/parallel/test-zlib-from-string.js b/tests/node_compat/test/parallel/test-zlib-from-string.js
new file mode 100644
index 000000000..dc238220b
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-zlib-from-string.js
@@ -0,0 +1,90 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+// Test compressing and uncompressing a string with zlib
+
+const common = require('../common');
+const assert = require('assert');
+const zlib = require('zlib');
+
+const inputString = 'ΩΩLorem ipsum dolor sit amet, consectetur adipiscing eli' +
+ 't. Morbi faucibus, purus at gravida dictum, libero arcu ' +
+ 'convallis lacus, in commodo libero metus eu nisi. Nullam' +
+ ' commodo, neque nec porta placerat, nisi est fermentum a' +
+ 'ugue, vitae gravida tellus sapien sit amet tellus. Aenea' +
+ 'n non diam orci. Proin quis elit turpis. Suspendisse non' +
+ ' diam ipsum. Suspendisse nec ullamcorper odio. Vestibulu' +
+ 'm arcu mi, sodales non suscipit id, ultrices ut massa. S' +
+ 'ed ac sem sit amet arcu malesuada fermentum. Nunc sed. ';
+const expectedBase64Deflate = 'eJxdUUtOQzEMvMoc4OndgT0gJCT2buJWlpI4jePeqZfpmX' +
+ 'AKLRKbLOzx/HK73q6vOrhCunlF1qIDJhNUeW5I2ozT5OkD' +
+ 'lKWLJWkncJG5403HQXAkT3Jw29B9uIEmToMukglZ0vS6oc' +
+ 'iBh4JG8sV4oVLEUCitK2kxq1WzPnChHDzsaGKy491LofoA' +
+ 'bWh8do43oeuYhB5EPCjcLjzYJo48KrfQBvnJecNFJvHT1+' +
+ 'RSQsGoC7dn2t/xjhduTA1NWyQIZR0pbHwMDatnD+crPqKS' +
+ 'qGPHp1vnlsWM/07ubf7bheF7kqSj84Bm0R1fYTfaK8vqqq' +
+ 'fKBtNMhe3OZh6N95CTvMX5HJJi4xOVzCgUOIMSLH7wmeOH' +
+ 'aFE4RdpnGavKtrB5xzfO/Ll9';
+const expectedBase64Gzip = 'H4sIAAAAAAAAA11RS05DMQy8yhzg6d2BPSAkJPZu4laWkjiN4' +
+ '96pl+mZcAotEpss7PH8crverq86uEK6eUXWogMmE1R5bkjajN' +
+ 'Pk6QOUpYslaSdwkbnjTcdBcCRPcnDb0H24gSZOgy6SCVnS9Lq' +
+ 'hyIGHgkbyxXihUsRQKK0raTGrVbM+cKEcPOxoYrLj3Uuh+gBt' +
+ 'aHx2jjeh65iEHkQ8KNwuPNgmjjwqt9AG+cl5w0Um8dPX5FJCw' +
+ 'agLt2fa3/GOF25MDU1bJAhlHSlsfAwNq2cP5ys+opKoY8enW+' +
+ 'eWxYz/Tu5t/tuF4XuSpKPzgGbRHV9hN9ory+qqp8oG00yF7c5' +
+ 'mHo33kJO8xfkckmLjE5XMKBQ4gxIsfvCZ44doUThF2mcZq8q2' +
+ 'sHnHNzRtagj5AQAA';
+
+zlib.deflate(inputString, common.mustCall((err, buffer) => {
+ zlib.inflate(buffer, common.mustCall((err, inflated) => {
+ assert.strictEqual(inflated.toString(), inputString);
+ }));
+}));
+
+zlib.gzip(inputString, common.mustCall((err, buffer) => {
+ // Can't actually guarantee that we'll get exactly the same
+ // deflated bytes when we compress a string, since the header
+ // depends on stuff other than the input string itself.
+ // However, decrypting it should definitely yield the same
+ // result that we're expecting, and this should match what we get
+ // from inflating the known valid deflate data.
+ zlib.gunzip(buffer, common.mustCall((err, gunzipped) => {
+ assert.strictEqual(gunzipped.toString(), inputString);
+ }));
+}));
+
+let buffer = Buffer.from(expectedBase64Deflate, 'base64');
+zlib.unzip(buffer, common.mustCall((err, buffer) => {
+ assert.strictEqual(buffer.toString(), inputString);
+}));
+
+buffer = Buffer.from(expectedBase64Gzip, 'base64');
+zlib.unzip(buffer, common.mustCall((err, buffer) => {
+ assert.strictEqual(buffer.toString(), inputString);
+}));
diff --git a/tests/node_compat/test/parallel/test-zlib-invalid-input.js b/tests/node_compat/test/parallel/test-zlib-invalid-input.js
new file mode 100644
index 000000000..d8ecae521
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-zlib-invalid-input.js
@@ -0,0 +1,68 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 16.13.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+// Test uncompressing invalid input
+
+const common = require('../common');
+const assert = require('assert');
+const zlib = require('zlib');
+
+const nonStringInputs = [
+ 1,
+ true,
+ { a: 1 },
+ ['a'],
+];
+
+// zlib.Unzip classes need to get valid data, or else they'll throw.
+const unzips = [
+ zlib.Unzip(),
+ zlib.Gunzip(),
+ zlib.Inflate(),
+ zlib.InflateRaw(),
+ // FIXME(bartlomieju):
+ // zlib.BrotliDecompress(),
+];
+
+nonStringInputs.forEach(common.mustCall((input) => {
+ assert.throws(() => {
+ zlib.gunzip(input);
+ }, {
+ name: 'TypeError',
+ code: 'ERR_INVALID_ARG_TYPE'
+ });
+}, nonStringInputs.length));
+
+unzips.forEach(common.mustCall((uz, i) => {
+ uz.on('error', common.mustCall());
+ uz.on('end', common.mustNotCall);
+
+ // This will trigger error event
+ uz.write('this is not valid compressed data.');
+}, unzips.length));
diff --git a/tests/node_compat/test/parallel/test-zlib-no-stream.js b/tests/node_compat/test/parallel/test-zlib-no-stream.js
new file mode 100644
index 000000000..27b352406
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-zlib-no-stream.js
@@ -0,0 +1,21 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+/* eslint-disable node-core/required-modules */
+/* eslint-disable node-core/require-common-first */
+
+'use strict';
+
+// We are not loading common because it will load the stream module,
+// defeating the purpose of this test.
+
+const { gzipSync } = require('zlib');
+
+// Avoid regressions such as https://github.com/nodejs/node/issues/36615
+
+// This must not throw
+gzipSync('fooobar');
diff --git a/tests/node_compat/test/parallel/test-zlib-random-byte-pipes.js b/tests/node_compat/test/parallel/test-zlib-random-byte-pipes.js
new file mode 100644
index 000000000..56409d411
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-zlib-random-byte-pipes.js
@@ -0,0 +1,166 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 16.13.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+if (!common.hasCrypto)
+ common.skip('missing crypto');
+
+const assert = require('assert');
+const crypto = require('crypto');
+const stream = require('stream');
+const zlib = require('zlib');
+
+const Stream = stream.Stream;
+
+// Emit random bytes, and keep a shasum
+class RandomReadStream extends Stream {
+ constructor(opt) {
+ super();
+
+ this.readable = true;
+ this._paused = false;
+ this._processing = false;
+
+ this._hasher = crypto.createHash('sha1');
+ opt = opt || {};
+
+ // base block size.
+ opt.block = opt.block || 256 * 1024;
+
+ // Total number of bytes to emit
+ opt.total = opt.total || 256 * 1024 * 1024;
+ this._remaining = opt.total;
+
+ // How variable to make the block sizes
+ opt.jitter = opt.jitter || 1024;
+
+ this._opt = opt;
+
+ this._process = this._process.bind(this);
+
+ process.nextTick(this._process);
+ }
+
+ pause() {
+ this._paused = true;
+ this.emit('pause');
+ }
+
+ resume() {
+ // console.error("rrs resume");
+ this._paused = false;
+ this.emit('resume');
+ this._process();
+ }
+
+ _process() {
+ if (this._processing) return;
+ if (this._paused) return;
+
+ this._processing = true;
+
+ if (!this._remaining) {
+ this._hash = this._hasher.digest('hex').toLowerCase().trim();
+ this._processing = false;
+
+ this.emit('end');
+ return;
+ }
+
+ // Figure out how many bytes to output
+ // if finished, then just emit end.
+ let block = this._opt.block;
+ const jitter = this._opt.jitter;
+ if (jitter) {
+ block += Math.ceil(Math.random() * jitter - (jitter / 2));
+ }
+ block = Math.min(block, this._remaining);
+ const buf = Buffer.allocUnsafe(block);
+ for (let i = 0; i < block; i++) {
+ buf[i] = Math.random() * 256;
+ }
+
+ this._hasher.update(buf);
+
+ this._remaining -= block;
+
+ this._processing = false;
+
+ this.emit('data', buf);
+ process.nextTick(this._process);
+ }
+}
+
+// A filter that just verifies a shasum
+class HashStream extends Stream {
+ constructor() {
+ super();
+ this.readable = this.writable = true;
+ this._hasher = crypto.createHash('sha1');
+ }
+
+ write(c) {
+ // Simulate the way that an fs.ReadStream returns false
+ // on *every* write, only to resume a moment later.
+ this._hasher.update(c);
+ process.nextTick(() => this.resume());
+ return false;
+ }
+
+ resume() {
+ this.emit('resume');
+ process.nextTick(() => this.emit('drain'));
+ }
+
+ end(c) {
+ if (c) {
+ this.write(c);
+ }
+ this._hash = this._hasher.digest('hex').toLowerCase().trim();
+ this.emit('data', this._hash);
+ this.emit('end');
+ }
+}
+
+for (const [ createCompress, createDecompress ] of [
+ [ zlib.createGzip, zlib.createGunzip ],
+ // TODO(kt3k): Enable this when we support brotli in zlib
+ // [ zlib.createBrotliCompress, zlib.createBrotliDecompress ],
+]) {
+ const inp = new RandomReadStream({ total: 1024, block: 256, jitter: 16 });
+ const out = new HashStream();
+ const gzip = createCompress();
+ const gunz = createDecompress();
+
+ inp.pipe(gzip).pipe(gunz).pipe(out);
+
+ out.on('data', common.mustCall((c) => {
+ assert.strictEqual(c, inp._hash, `Hash '${c}' equals '${inp._hash}'.`);
+ }));
+}
diff --git a/tests/node_compat/test/parallel/test-zlib-sync-no-event.js b/tests/node_compat/test/parallel/test-zlib-sync-no-event.js
new file mode 100644
index 000000000..62019677c
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-zlib-sync-no-event.js
@@ -0,0 +1,26 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const zlib = require('zlib');
+const assert = require('assert');
+
+const message = 'Come on, Fhqwhgads.';
+const buffer = Buffer.from(message);
+
+const zipper = new zlib.Gzip();
+zipper.on('close', common.mustNotCall());
+
+const zipped = zipper._processChunk(buffer, zlib.constants.Z_FINISH);
+
+const unzipper = new zlib.Gunzip();
+unzipper.on('close', common.mustNotCall());
+
+const unzipped = unzipper._processChunk(zipped, zlib.constants.Z_FINISH);
+assert.notStrictEqual(zipped.toString(), message);
+assert.strictEqual(unzipped.toString(), message);
diff --git a/tests/node_compat/test/parallel/test-zlib-truncated.js b/tests/node_compat/test/parallel/test-zlib-truncated.js
new file mode 100644
index 000000000..60e730171
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-zlib-truncated.js
@@ -0,0 +1,71 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+// Tests zlib streams with truncated compressed input
+
+require('../common');
+const assert = require('assert');
+const zlib = require('zlib');
+
+const inputString = 'ΩΩLorem ipsum dolor sit amet, consectetur adipiscing eli' +
+ 't. Morbi faucibus, purus at gravida dictum, libero arcu ' +
+ 'convallis lacus, in commodo libero metus eu nisi. Nullam' +
+ ' commodo, neque nec porta placerat, nisi est fermentum a' +
+ 'ugue, vitae gravida tellus sapien sit amet tellus. Aenea' +
+ 'n non diam orci. Proin quis elit turpis. Suspendisse non' +
+ ' diam ipsum. Suspendisse nec ullamcorper odio. Vestibulu' +
+ 'm arcu mi, sodales non suscipit id, ultrices ut massa. S' +
+ 'ed ac sem sit amet arcu malesuada fermentum. Nunc sed. ';
+
+const errMessage = /unexpected end of file/;
+
+[
+ { comp: 'gzip', decomp: 'gunzip', decompSync: 'gunzipSync' },
+ { comp: 'gzip', decomp: 'unzip', decompSync: 'unzipSync' },
+ { comp: 'deflate', decomp: 'inflate', decompSync: 'inflateSync' },
+ { comp: 'deflateRaw', decomp: 'inflateRaw', decompSync: 'inflateRawSync' },
+].forEach(function(methods) {
+ zlib[methods.comp](inputString, function(err, compressed) {
+ assert.ifError(err);
+ const truncated = compressed.slice(0, compressed.length / 2);
+ const toUTF8 = (buffer) => buffer.toString('utf-8');
+
+ // sync sanity
+ const decompressed = zlib[methods.decompSync](compressed);
+ assert.strictEqual(toUTF8(decompressed), inputString);
+
+ // async sanity
+ zlib[methods.decomp](compressed, function(err, result) {
+ assert.ifError(err);
+ assert.strictEqual(toUTF8(result), inputString);
+ });
+
+ // Sync truncated input test
+ assert.throws(function() {
+ zlib[methods.decompSync](truncated);
+ }, errMessage);
+
+ // Async truncated input test
+ zlib[methods.decomp](truncated, function(err, result) {
+ assert.match(err.message, errMessage);
+ });
+
+ const syncFlushOpt = { finishFlush: zlib.constants.Z_SYNC_FLUSH };
+
+ // Sync truncated input test, finishFlush = Z_SYNC_FLUSH
+ const result = toUTF8(zlib[methods.decompSync](truncated, syncFlushOpt));
+ assert.strictEqual(result, inputString.substr(0, result.length));
+
+ // Async truncated input test, finishFlush = Z_SYNC_FLUSH
+ zlib[methods.decomp](truncated, syncFlushOpt, function(err, decompressed) {
+ assert.ifError(err);
+ const result = toUTF8(decompressed);
+ assert.strictEqual(result, inputString.substr(0, result.length));
+ });
+ });
+});
diff --git a/tests/node_compat/test/parallel/test-zlib-unzip-one-byte-chunks.js b/tests/node_compat/test/parallel/test-zlib-unzip-one-byte-chunks.js
new file mode 100644
index 000000000..62b2050d3
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-zlib-unzip-one-byte-chunks.js
@@ -0,0 +1,37 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const zlib = require('zlib');
+
+const data = Buffer.concat([
+ zlib.gzipSync('abc'),
+ zlib.gzipSync('def'),
+]);
+
+const resultBuffers = [];
+
+const unzip = zlib.createUnzip()
+ .on('error', (err) => {
+ assert.ifError(err);
+ })
+ .on('data', (data) => resultBuffers.push(data))
+ .on('finish', common.mustCall(() => {
+ const unzipped = Buffer.concat(resultBuffers).toString();
+ assert.strictEqual(unzipped, 'abcdef',
+ `'${unzipped}' should match 'abcdef' after zipping ` +
+ 'and unzipping');
+ }));
+
+for (let i = 0; i < data.length; i++) {
+ // Write each single byte individually.
+ unzip.write(Buffer.from([data[i]]));
+}
+
+unzip.end();
diff --git a/tests/node_compat/test/parallel/test-zlib-write-after-end.js b/tests/node_compat/test/parallel/test-zlib-write-after-end.js
new file mode 100644
index 000000000..7c7e3ea35
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-zlib-write-after-end.js
@@ -0,0 +1,23 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+const zlib = require('zlib');
+
+// Regression test for https://github.com/nodejs/node/issues/30976
+// Writes to a stream should finish even after the readable side has been ended.
+
+const data = zlib.deflateRawSync('Welcome');
+
+const inflate = zlib.createInflateRaw();
+
+inflate.resume();
+inflate.write(data, common.mustCall());
+inflate.write(Buffer.from([0x00]), common.mustCall());
+inflate.write(Buffer.from([0x00]), common.mustCall());
+inflate.flush(common.mustCall());
diff --git a/tests/node_compat/test/parallel/test-zlib-write-after-flush.js b/tests/node_compat/test/parallel/test-zlib-write-after-flush.js
new file mode 100644
index 000000000..6f33668c7
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-zlib-write-after-flush.js
@@ -0,0 +1,57 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 16.13.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const zlib = require('zlib');
+
+for (const [ createCompress, createDecompress ] of [
+ [ zlib.createGzip, zlib.createGunzip ],
+ // FIXME(bartlomieju):
+ // [ zlib.createBrotliCompress, zlib.createBrotliDecompress ],
+]) {
+ const gzip = createCompress();
+ const gunz = createDecompress();
+
+ gzip.pipe(gunz);
+
+ let output = '';
+ const input = 'A line of data\n';
+ gunz.setEncoding('utf8');
+ gunz.on('data', (c) => output += c);
+ gunz.on('end', common.mustCall(() => {
+ assert.strictEqual(output, input);
+ }));
+
+ // Make sure that flush/write doesn't trigger an assert failure
+ gzip.flush();
+ gzip.write(input);
+ gzip.end();
+ gunz.read(0);
+}
diff --git a/tests/node_compat/test/parallel/test-zlib-zero-byte.js b/tests/node_compat/test/parallel/test-zlib-zero-byte.js
new file mode 100644
index 000000000..fb12b2280
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-zlib-zero-byte.js
@@ -0,0 +1,53 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 16.13.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const zlib = require('zlib');
+
+for (const Compressor of [ zlib.Gzip,
+ // FIXME(bartlomieju):
+ // zlib.BrotliCompress
+]) {
+ const gz = Compressor();
+ const emptyBuffer = Buffer.alloc(0);
+ let received = 0;
+ gz.on('data', function(c) {
+ received += c.length;
+ });
+
+ gz.on('end', common.mustCall(function() {
+ const expected = Compressor === zlib.Gzip ? 20 : 1;
+ assert.strictEqual(received, expected,
+ `${received}, ${expected}, ${Compressor.name}`);
+ }));
+ gz.on('finish', common.mustCall());
+ gz.write(emptyBuffer);
+ gz.end();
+}
diff --git a/tests/node_compat/test/parallel/test-zlib-zero-windowBits.js b/tests/node_compat/test/parallel/test-zlib-zero-windowBits.js
new file mode 100644
index 000000000..fe74fe6d8
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-zlib-zero-windowBits.js
@@ -0,0 +1,41 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 16.13.0
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+'use strict';
+
+require('../common');
+const assert = require('assert');
+const zlib = require('zlib');
+
+
+// windowBits is a special case in zlib. On the compression side, 0 is invalid.
+// On the decompression side, it indicates that zlib should use the value from
+// the header of the compressed stream.
+{
+ const inflate = zlib.createInflate({ windowBits: 0 });
+ assert(inflate instanceof zlib.Inflate);
+}
+
+{
+ const gunzip = zlib.createGunzip({ windowBits: 0 });
+ assert(gunzip instanceof zlib.Gunzip);
+}
+
+{
+ const unzip = zlib.createUnzip({ windowBits: 0 });
+ assert(unzip instanceof zlib.Unzip);
+}
+
+// FIXME(bartlomieju):
+// {
+// assert.throws(() => zlib.createGzip({ windowBits: 0 }), {
+// code: 'ERR_OUT_OF_RANGE',
+// name: 'RangeError',
+// message: 'The value of "options.windowBits" is out of range. ' +
+// 'It must be >= 9 and <= 15. Received 0'
+// });
+// }
diff --git a/tests/node_compat/test/pseudo-tty/console-dumb-tty.js b/tests/node_compat/test/pseudo-tty/console-dumb-tty.js
new file mode 100644
index 000000000..9b4bd1520
--- /dev/null
+++ b/tests/node_compat/test/pseudo-tty/console-dumb-tty.js
@@ -0,0 +1,16 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+require('../common');
+
+process.env.TERM = 'dumb';
+
+console.log({ foo: 'bar' });
+console.dir({ foo: 'bar' });
+console.log('%s q', 'string');
+console.log('%o with object format param', { foo: 'bar' });
diff --git a/tests/node_compat/test/pseudo-tty/console_colors.js b/tests/node_compat/test/pseudo-tty/console_colors.js
new file mode 100644
index 000000000..2be464457
--- /dev/null
+++ b/tests/node_compat/test/pseudo-tty/console_colors.js
@@ -0,0 +1,29 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+require('../common');
+const vm = require('vm');
+// Make this test OS-independent by overriding stdio getColorDepth().
+process.stdout.getColorDepth = () => 8;
+process.stderr.getColorDepth = () => 8;
+
+console.log({ foo: 'bar' });
+console.log('%s q', 'string');
+console.log('%o with object format param', { foo: 'bar' });
+
+console.log(
+ new Error('test\n at abc (../fixtures/node_modules/bar.js:4:4)\nfoobar'),
+);
+
+try {
+ require('../fixtures/node_modules/node_modules/bar.js');
+} catch (err) {
+ console.log(err);
+}
+
+vm.runInThisContext('console.log(new Error())');
diff --git a/tests/node_compat/test/pseudo-tty/no_dropped_stdio.js b/tests/node_compat/test/pseudo-tty/no_dropped_stdio.js
new file mode 100644
index 000000000..d2bbb92c5
--- /dev/null
+++ b/tests/node_compat/test/pseudo-tty/no_dropped_stdio.js
@@ -0,0 +1,26 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// https://github.com/nodejs/node/issues/6456#issuecomment-219320599
+// https://gist.github.com/isaacs/1495b91ec66b21d30b10572d72ad2cdd
+'use strict';
+const common = require('../common');
+
+// 1000 bytes wrapped at 50 columns
+// \n turns into a double-byte character
+// (48 + {2}) * 20 = 1000
+let out = `${'o'.repeat(48)}\n`.repeat(20);
+// Add the remaining 24 bytes and terminate with an 'O'.
+// This results in 1025 bytes, just enough to overflow the 1kb OS X TTY buffer.
+out += `${'o'.repeat(24)}O`;
+
+// In AIX, the child exits even before the python parent
+// can setup the readloop. Provide a reasonable delay.
+setTimeout(function() {
+ process.stdout.write(out);
+ process.exit(0);
+}, common.isAIX ? 200 : 0);
diff --git a/tests/node_compat/test/pseudo-tty/no_interleaved_stdio.js b/tests/node_compat/test/pseudo-tty/no_interleaved_stdio.js
new file mode 100644
index 000000000..895124420
--- /dev/null
+++ b/tests/node_compat/test/pseudo-tty/no_interleaved_stdio.js
@@ -0,0 +1,28 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+// https://github.com/nodejs/node/issues/6456#issuecomment-219320599
+// https://gist.github.com/isaacs/1495b91ec66b21d30b10572d72ad2cdd
+'use strict';
+const common = require('../common');
+
+// 1000 bytes wrapped at 50 columns
+// \n turns into a double-byte character
+// (48 + {2}) * 20 = 1000
+let out = `${'o'.repeat(48)}\n`.repeat(20);
+// Add the remaining 24 bytes and terminate with an 'O'.
+// This results in 1025 bytes, just enough to overflow the 1kb OS X TTY buffer.
+out += `${'o'.repeat(24)}O`;
+
+const err = '__This is some stderr__';
+
+// In AIX, the child exits even before the python parent
+// can setup the readloop. Provide a reasonable delay.
+setTimeout(function() {
+ process.stdout.write(out);
+ process.stderr.write(err);
+}, common.isAIX ? 200 : 0);
diff --git a/tests/node_compat/test/pseudo-tty/package.json b/tests/node_compat/test/pseudo-tty/package.json
new file mode 100644
index 000000000..0967ef424
--- /dev/null
+++ b/tests/node_compat/test/pseudo-tty/package.json
@@ -0,0 +1 @@
+{}
diff --git a/tests/node_compat/test/pseudo-tty/test-tty-color-support-warning-2.js b/tests/node_compat/test/pseudo-tty/test-tty-color-support-warning-2.js
new file mode 100644
index 000000000..6a969ac9e
--- /dev/null
+++ b/tests/node_compat/test/pseudo-tty/test-tty-color-support-warning-2.js
@@ -0,0 +1,15 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+require('../common');
+
+process.env.NODE_DISABLE_COLORS = '1';
+process.env.FORCE_COLOR = '3';
+
+console.log();
diff --git a/tests/node_compat/test/pseudo-tty/test-tty-color-support-warning.js b/tests/node_compat/test/pseudo-tty/test-tty-color-support-warning.js
new file mode 100644
index 000000000..a9338105c
--- /dev/null
+++ b/tests/node_compat/test/pseudo-tty/test-tty-color-support-warning.js
@@ -0,0 +1,16 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+
+require('../common');
+
+process.env.NO_COLOR = '1';
+process.env.NODE_DISABLE_COLORS = '1';
+process.env.FORCE_COLOR = '3';
+
+console.log();
diff --git a/tests/node_compat/test/pseudo-tty/test-tty-stdin-end.js b/tests/node_compat/test/pseudo-tty/test-tty-stdin-end.js
new file mode 100644
index 000000000..ee38cbd2c
--- /dev/null
+++ b/tests/node_compat/test/pseudo-tty/test-tty-stdin-end.js
@@ -0,0 +1,14 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+require('../common');
+
+// This test ensures that Node.js doesn't crash on `process.stdin.emit("end")`.
+// https://github.com/nodejs/node/issues/1068
+
+process.stdin.emit('end');
diff --git a/tests/node_compat/test/pseudo-tty/test-tty-stdout-end.js b/tests/node_compat/test/pseudo-tty/test-tty-stdout-end.js
new file mode 100644
index 000000000..bd30a9a2e
--- /dev/null
+++ b/tests/node_compat/test/pseudo-tty/test-tty-stdout-end.js
@@ -0,0 +1,11 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
+
+'use strict';
+require('../common');
+
+process.stdout.end();
diff --git a/tests/node_compat/test/pummel/package.json b/tests/node_compat/test/pummel/package.json
new file mode 100644
index 000000000..0967ef424
--- /dev/null
+++ b/tests/node_compat/test/pummel/package.json
@@ -0,0 +1 @@
+{}
diff --git a/tests/node_compat/test/sequential/package.json b/tests/node_compat/test/sequential/package.json
new file mode 100644
index 000000000..0967ef424
--- /dev/null
+++ b/tests/node_compat/test/sequential/package.json
@@ -0,0 +1 @@
+{}
diff --git a/tests/node_compat/test/sequential/test-child-process-exit.js b/tests/node_compat/test/sequential/test-child-process-exit.js
new file mode 100644
index 000000000..c8930b059
--- /dev/null
+++ b/tests/node_compat/test/sequential/test-child-process-exit.js
@@ -0,0 +1,69 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// TODO(PolarETech): The process.argv[3] to be assigned to gen should be argv[2],
+// and the arguments array passed to spawn() should not need to include "require.ts".
+
+'use strict';
+require('../common');
+
+// Open a chain of five Node processes each a child of the next. The final
+// process exits immediately. Each process in the chain is instructed to exit
+// when its child exits.
+// https://github.com/joyent/node/issues/1726
+
+const assert = require('assert');
+const ch = require('child_process');
+
+const gen = +(process.argv[3] || 0);
+const maxGen = 5;
+
+
+if (gen === maxGen) {
+ console.error('hit maxGen, exiting', maxGen);
+ return;
+}
+
+const child = ch.spawn(process.execPath, ['require.ts', __filename, gen + 1], {
+ stdio: [ 'ignore', 'pipe', 'ignore' ]
+});
+assert.ok(!child.stdin);
+assert.ok(child.stdout);
+assert.ok(!child.stderr);
+
+console.error('gen=%d, pid=%d', gen, process.pid);
+
+child.on('exit', function(code) {
+ console.error('exit %d from gen %d', code, gen + 1);
+});
+
+child.stdout.pipe(process.stdout);
+
+child.stdout.on('close', function() {
+ console.error('child.stdout close gen=%d', gen);
+});