summaryrefslogtreecommitdiff
path: root/tests/node_compat/test/parallel/test-stream2-transform.js
diff options
context:
space:
mode:
Diffstat (limited to 'tests/node_compat/test/parallel/test-stream2-transform.js')
-rw-r--r--tests/node_compat/test/parallel/test-stream2-transform.js501
1 files changed, 501 insertions, 0 deletions
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'));
+}