diff options
author | Matt Mastracci <matthew@mastracci.com> | 2024-02-10 13:22:13 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-02-10 20:22:13 +0000 |
commit | f5e46c9bf2f50d66a953fa133161fc829cecff06 (patch) | |
tree | 8faf2f5831c1c7b11d842cd9908d141082c869a5 /tests/node_compat/test/parallel/test-stream2-writable.js | |
parent | d2477f780630a812bfd65e3987b70c0d309385bb (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/parallel/test-stream2-writable.js')
-rw-r--r-- | tests/node_compat/test/parallel/test-stream2-writable.js | 466 |
1 files changed, 466 insertions, 0 deletions
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)); +} |