11cb0ef41Sopenharmony_ci// Copyright Joyent, Inc. and other Node contributors. 21cb0ef41Sopenharmony_ci// 31cb0ef41Sopenharmony_ci// Permission is hereby granted, free of charge, to any person obtaining a 41cb0ef41Sopenharmony_ci// copy of this software and associated documentation files (the 51cb0ef41Sopenharmony_ci// "Software"), to deal in the Software without restriction, including 61cb0ef41Sopenharmony_ci// without limitation the rights to use, copy, modify, merge, publish, 71cb0ef41Sopenharmony_ci// distribute, sublicense, and/or sell copies of the Software, and to permit 81cb0ef41Sopenharmony_ci// persons to whom the Software is furnished to do so, subject to the 91cb0ef41Sopenharmony_ci// following conditions: 101cb0ef41Sopenharmony_ci// 111cb0ef41Sopenharmony_ci// The above copyright notice and this permission notice shall be included 121cb0ef41Sopenharmony_ci// in all copies or substantial portions of the Software. 131cb0ef41Sopenharmony_ci// 141cb0ef41Sopenharmony_ci// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 151cb0ef41Sopenharmony_ci// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 161cb0ef41Sopenharmony_ci// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 171cb0ef41Sopenharmony_ci// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 181cb0ef41Sopenharmony_ci// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 191cb0ef41Sopenharmony_ci// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 201cb0ef41Sopenharmony_ci// USE OR OTHER DEALINGS IN THE SOFTWARE. 211cb0ef41Sopenharmony_ci 221cb0ef41Sopenharmony_ci'use strict'; 231cb0ef41Sopenharmony_ci 241cb0ef41Sopenharmony_ciconst common = require('../common'); 251cb0ef41Sopenharmony_ciconst { Writable: W, Duplex: D } = require('stream'); 261cb0ef41Sopenharmony_ciconst assert = require('assert'); 271cb0ef41Sopenharmony_ci 281cb0ef41Sopenharmony_ciclass TestWriter extends W { 291cb0ef41Sopenharmony_ci constructor(opts) { 301cb0ef41Sopenharmony_ci super(opts); 311cb0ef41Sopenharmony_ci this.buffer = []; 321cb0ef41Sopenharmony_ci this.written = 0; 331cb0ef41Sopenharmony_ci } 341cb0ef41Sopenharmony_ci 351cb0ef41Sopenharmony_ci _write(chunk, encoding, cb) { 361cb0ef41Sopenharmony_ci // Simulate a small unpredictable latency 371cb0ef41Sopenharmony_ci setTimeout(() => { 381cb0ef41Sopenharmony_ci this.buffer.push(chunk.toString()); 391cb0ef41Sopenharmony_ci this.written += chunk.length; 401cb0ef41Sopenharmony_ci cb(); 411cb0ef41Sopenharmony_ci }, Math.floor(Math.random() * 10)); 421cb0ef41Sopenharmony_ci } 431cb0ef41Sopenharmony_ci} 441cb0ef41Sopenharmony_ci 451cb0ef41Sopenharmony_ciconst chunks = new Array(50); 461cb0ef41Sopenharmony_cifor (let i = 0; i < chunks.length; i++) { 471cb0ef41Sopenharmony_ci chunks[i] = 'x'.repeat(i); 481cb0ef41Sopenharmony_ci} 491cb0ef41Sopenharmony_ci 501cb0ef41Sopenharmony_ci{ 511cb0ef41Sopenharmony_ci // Verify fast writing 521cb0ef41Sopenharmony_ci const tw = new TestWriter({ 531cb0ef41Sopenharmony_ci highWaterMark: 100 541cb0ef41Sopenharmony_ci }); 551cb0ef41Sopenharmony_ci 561cb0ef41Sopenharmony_ci tw.on('finish', common.mustCall(function() { 571cb0ef41Sopenharmony_ci // Got chunks in the right order 581cb0ef41Sopenharmony_ci assert.deepStrictEqual(tw.buffer, chunks); 591cb0ef41Sopenharmony_ci })); 601cb0ef41Sopenharmony_ci 611cb0ef41Sopenharmony_ci chunks.forEach(function(chunk) { 621cb0ef41Sopenharmony_ci // Ignore backpressure. Just buffer it all up. 631cb0ef41Sopenharmony_ci tw.write(chunk); 641cb0ef41Sopenharmony_ci }); 651cb0ef41Sopenharmony_ci tw.end(); 661cb0ef41Sopenharmony_ci} 671cb0ef41Sopenharmony_ci 681cb0ef41Sopenharmony_ci{ 691cb0ef41Sopenharmony_ci // Verify slow writing 701cb0ef41Sopenharmony_ci const tw = new TestWriter({ 711cb0ef41Sopenharmony_ci highWaterMark: 100 721cb0ef41Sopenharmony_ci }); 731cb0ef41Sopenharmony_ci 741cb0ef41Sopenharmony_ci tw.on('finish', common.mustCall(function() { 751cb0ef41Sopenharmony_ci // Got chunks in the right order 761cb0ef41Sopenharmony_ci assert.deepStrictEqual(tw.buffer, chunks); 771cb0ef41Sopenharmony_ci })); 781cb0ef41Sopenharmony_ci 791cb0ef41Sopenharmony_ci let i = 0; 801cb0ef41Sopenharmony_ci (function W() { 811cb0ef41Sopenharmony_ci tw.write(chunks[i++]); 821cb0ef41Sopenharmony_ci if (i < chunks.length) 831cb0ef41Sopenharmony_ci setTimeout(W, 10); 841cb0ef41Sopenharmony_ci else 851cb0ef41Sopenharmony_ci tw.end(); 861cb0ef41Sopenharmony_ci })(); 871cb0ef41Sopenharmony_ci} 881cb0ef41Sopenharmony_ci 891cb0ef41Sopenharmony_ci{ 901cb0ef41Sopenharmony_ci // Verify write backpressure 911cb0ef41Sopenharmony_ci const tw = new TestWriter({ 921cb0ef41Sopenharmony_ci highWaterMark: 50 931cb0ef41Sopenharmony_ci }); 941cb0ef41Sopenharmony_ci 951cb0ef41Sopenharmony_ci let drains = 0; 961cb0ef41Sopenharmony_ci 971cb0ef41Sopenharmony_ci tw.on('finish', common.mustCall(function() { 981cb0ef41Sopenharmony_ci // Got chunks in the right order 991cb0ef41Sopenharmony_ci assert.deepStrictEqual(tw.buffer, chunks); 1001cb0ef41Sopenharmony_ci assert.strictEqual(drains, 17); 1011cb0ef41Sopenharmony_ci })); 1021cb0ef41Sopenharmony_ci 1031cb0ef41Sopenharmony_ci tw.on('drain', function() { 1041cb0ef41Sopenharmony_ci drains++; 1051cb0ef41Sopenharmony_ci }); 1061cb0ef41Sopenharmony_ci 1071cb0ef41Sopenharmony_ci let i = 0; 1081cb0ef41Sopenharmony_ci (function W() { 1091cb0ef41Sopenharmony_ci let ret; 1101cb0ef41Sopenharmony_ci do { 1111cb0ef41Sopenharmony_ci ret = tw.write(chunks[i++]); 1121cb0ef41Sopenharmony_ci } while (ret !== false && i < chunks.length); 1131cb0ef41Sopenharmony_ci 1141cb0ef41Sopenharmony_ci if (i < chunks.length) { 1151cb0ef41Sopenharmony_ci assert(tw.writableLength >= 50); 1161cb0ef41Sopenharmony_ci tw.once('drain', W); 1171cb0ef41Sopenharmony_ci } else { 1181cb0ef41Sopenharmony_ci tw.end(); 1191cb0ef41Sopenharmony_ci } 1201cb0ef41Sopenharmony_ci })(); 1211cb0ef41Sopenharmony_ci} 1221cb0ef41Sopenharmony_ci 1231cb0ef41Sopenharmony_ci{ 1241cb0ef41Sopenharmony_ci // Verify write buffersize 1251cb0ef41Sopenharmony_ci const tw = new TestWriter({ 1261cb0ef41Sopenharmony_ci highWaterMark: 100 1271cb0ef41Sopenharmony_ci }); 1281cb0ef41Sopenharmony_ci 1291cb0ef41Sopenharmony_ci const encodings = 1301cb0ef41Sopenharmony_ci [ 'hex', 1311cb0ef41Sopenharmony_ci 'utf8', 1321cb0ef41Sopenharmony_ci 'utf-8', 1331cb0ef41Sopenharmony_ci 'ascii', 1341cb0ef41Sopenharmony_ci 'latin1', 1351cb0ef41Sopenharmony_ci 'binary', 1361cb0ef41Sopenharmony_ci 'base64', 1371cb0ef41Sopenharmony_ci 'ucs2', 1381cb0ef41Sopenharmony_ci 'ucs-2', 1391cb0ef41Sopenharmony_ci 'utf16le', 1401cb0ef41Sopenharmony_ci 'utf-16le', 1411cb0ef41Sopenharmony_ci undefined ]; 1421cb0ef41Sopenharmony_ci 1431cb0ef41Sopenharmony_ci tw.on('finish', function() { 1441cb0ef41Sopenharmony_ci // Got the expected chunks 1451cb0ef41Sopenharmony_ci assert.deepStrictEqual(tw.buffer, chunks); 1461cb0ef41Sopenharmony_ci }); 1471cb0ef41Sopenharmony_ci 1481cb0ef41Sopenharmony_ci chunks.forEach(function(chunk, i) { 1491cb0ef41Sopenharmony_ci const enc = encodings[i % encodings.length]; 1501cb0ef41Sopenharmony_ci chunk = Buffer.from(chunk); 1511cb0ef41Sopenharmony_ci tw.write(chunk.toString(enc), enc); 1521cb0ef41Sopenharmony_ci }); 1531cb0ef41Sopenharmony_ci} 1541cb0ef41Sopenharmony_ci 1551cb0ef41Sopenharmony_ci{ 1561cb0ef41Sopenharmony_ci // Verify write with no buffersize 1571cb0ef41Sopenharmony_ci const tw = new TestWriter({ 1581cb0ef41Sopenharmony_ci highWaterMark: 100, 1591cb0ef41Sopenharmony_ci decodeStrings: false 1601cb0ef41Sopenharmony_ci }); 1611cb0ef41Sopenharmony_ci 1621cb0ef41Sopenharmony_ci tw._write = function(chunk, encoding, cb) { 1631cb0ef41Sopenharmony_ci assert.strictEqual(typeof chunk, 'string'); 1641cb0ef41Sopenharmony_ci chunk = Buffer.from(chunk, encoding); 1651cb0ef41Sopenharmony_ci return TestWriter.prototype._write.call(this, chunk, encoding, cb); 1661cb0ef41Sopenharmony_ci }; 1671cb0ef41Sopenharmony_ci 1681cb0ef41Sopenharmony_ci const encodings = 1691cb0ef41Sopenharmony_ci [ 'hex', 1701cb0ef41Sopenharmony_ci 'utf8', 1711cb0ef41Sopenharmony_ci 'utf-8', 1721cb0ef41Sopenharmony_ci 'ascii', 1731cb0ef41Sopenharmony_ci 'latin1', 1741cb0ef41Sopenharmony_ci 'binary', 1751cb0ef41Sopenharmony_ci 'base64', 1761cb0ef41Sopenharmony_ci 'ucs2', 1771cb0ef41Sopenharmony_ci 'ucs-2', 1781cb0ef41Sopenharmony_ci 'utf16le', 1791cb0ef41Sopenharmony_ci 'utf-16le', 1801cb0ef41Sopenharmony_ci undefined ]; 1811cb0ef41Sopenharmony_ci 1821cb0ef41Sopenharmony_ci tw.on('finish', function() { 1831cb0ef41Sopenharmony_ci // Got the expected chunks 1841cb0ef41Sopenharmony_ci assert.deepStrictEqual(tw.buffer, chunks); 1851cb0ef41Sopenharmony_ci }); 1861cb0ef41Sopenharmony_ci 1871cb0ef41Sopenharmony_ci chunks.forEach(function(chunk, i) { 1881cb0ef41Sopenharmony_ci const enc = encodings[i % encodings.length]; 1891cb0ef41Sopenharmony_ci chunk = Buffer.from(chunk); 1901cb0ef41Sopenharmony_ci tw.write(chunk.toString(enc), enc); 1911cb0ef41Sopenharmony_ci }); 1921cb0ef41Sopenharmony_ci} 1931cb0ef41Sopenharmony_ci 1941cb0ef41Sopenharmony_ci{ 1951cb0ef41Sopenharmony_ci // Verify write callbacks 1961cb0ef41Sopenharmony_ci const callbacks = chunks.map(function(chunk, i) { 1971cb0ef41Sopenharmony_ci return [i, function() { 1981cb0ef41Sopenharmony_ci callbacks._called[i] = chunk; 1991cb0ef41Sopenharmony_ci }]; 2001cb0ef41Sopenharmony_ci }).reduce(function(set, x) { 2011cb0ef41Sopenharmony_ci set[`callback-${x[0]}`] = x[1]; 2021cb0ef41Sopenharmony_ci return set; 2031cb0ef41Sopenharmony_ci }, {}); 2041cb0ef41Sopenharmony_ci callbacks._called = []; 2051cb0ef41Sopenharmony_ci 2061cb0ef41Sopenharmony_ci const tw = new TestWriter({ 2071cb0ef41Sopenharmony_ci highWaterMark: 100 2081cb0ef41Sopenharmony_ci }); 2091cb0ef41Sopenharmony_ci 2101cb0ef41Sopenharmony_ci tw.on('finish', common.mustCall(function() { 2111cb0ef41Sopenharmony_ci process.nextTick(common.mustCall(function() { 2121cb0ef41Sopenharmony_ci // Got chunks in the right order 2131cb0ef41Sopenharmony_ci assert.deepStrictEqual(tw.buffer, chunks); 2141cb0ef41Sopenharmony_ci // Called all callbacks 2151cb0ef41Sopenharmony_ci assert.deepStrictEqual(callbacks._called, chunks); 2161cb0ef41Sopenharmony_ci })); 2171cb0ef41Sopenharmony_ci })); 2181cb0ef41Sopenharmony_ci 2191cb0ef41Sopenharmony_ci chunks.forEach(function(chunk, i) { 2201cb0ef41Sopenharmony_ci tw.write(chunk, callbacks[`callback-${i}`]); 2211cb0ef41Sopenharmony_ci }); 2221cb0ef41Sopenharmony_ci tw.end(); 2231cb0ef41Sopenharmony_ci} 2241cb0ef41Sopenharmony_ci 2251cb0ef41Sopenharmony_ci{ 2261cb0ef41Sopenharmony_ci // Verify end() callback 2271cb0ef41Sopenharmony_ci const tw = new TestWriter(); 2281cb0ef41Sopenharmony_ci tw.end(common.mustCall()); 2291cb0ef41Sopenharmony_ci} 2301cb0ef41Sopenharmony_ci 2311cb0ef41Sopenharmony_ciconst helloWorldBuffer = Buffer.from('hello world'); 2321cb0ef41Sopenharmony_ci 2331cb0ef41Sopenharmony_ci{ 2341cb0ef41Sopenharmony_ci // Verify end() callback with chunk 2351cb0ef41Sopenharmony_ci const tw = new TestWriter(); 2361cb0ef41Sopenharmony_ci tw.end(helloWorldBuffer, common.mustCall()); 2371cb0ef41Sopenharmony_ci} 2381cb0ef41Sopenharmony_ci 2391cb0ef41Sopenharmony_ci{ 2401cb0ef41Sopenharmony_ci // Verify end() callback with chunk and encoding 2411cb0ef41Sopenharmony_ci const tw = new TestWriter(); 2421cb0ef41Sopenharmony_ci tw.end('hello world', 'ascii', common.mustCall()); 2431cb0ef41Sopenharmony_ci} 2441cb0ef41Sopenharmony_ci 2451cb0ef41Sopenharmony_ci{ 2461cb0ef41Sopenharmony_ci // Verify end() callback after write() call 2471cb0ef41Sopenharmony_ci const tw = new TestWriter(); 2481cb0ef41Sopenharmony_ci tw.write(helloWorldBuffer); 2491cb0ef41Sopenharmony_ci tw.end(common.mustCall()); 2501cb0ef41Sopenharmony_ci} 2511cb0ef41Sopenharmony_ci 2521cb0ef41Sopenharmony_ci{ 2531cb0ef41Sopenharmony_ci // Verify end() callback after write() callback 2541cb0ef41Sopenharmony_ci const tw = new TestWriter(); 2551cb0ef41Sopenharmony_ci let writeCalledback = false; 2561cb0ef41Sopenharmony_ci tw.write(helloWorldBuffer, function() { 2571cb0ef41Sopenharmony_ci writeCalledback = true; 2581cb0ef41Sopenharmony_ci }); 2591cb0ef41Sopenharmony_ci tw.end(common.mustCall(function() { 2601cb0ef41Sopenharmony_ci assert.strictEqual(writeCalledback, true); 2611cb0ef41Sopenharmony_ci })); 2621cb0ef41Sopenharmony_ci} 2631cb0ef41Sopenharmony_ci 2641cb0ef41Sopenharmony_ci{ 2651cb0ef41Sopenharmony_ci // Verify encoding is ignored for buffers 2661cb0ef41Sopenharmony_ci const tw = new W(); 2671cb0ef41Sopenharmony_ci const hex = '018b5e9a8f6236ffe30e31baf80d2cf6eb'; 2681cb0ef41Sopenharmony_ci tw._write = common.mustCall(function(chunk) { 2691cb0ef41Sopenharmony_ci assert.strictEqual(chunk.toString('hex'), hex); 2701cb0ef41Sopenharmony_ci }); 2711cb0ef41Sopenharmony_ci const buf = Buffer.from(hex, 'hex'); 2721cb0ef41Sopenharmony_ci tw.write(buf, 'latin1'); 2731cb0ef41Sopenharmony_ci} 2741cb0ef41Sopenharmony_ci 2751cb0ef41Sopenharmony_ci{ 2761cb0ef41Sopenharmony_ci // Verify writables cannot be piped 2771cb0ef41Sopenharmony_ci const w = new W({ autoDestroy: false }); 2781cb0ef41Sopenharmony_ci w._write = common.mustNotCall(); 2791cb0ef41Sopenharmony_ci let gotError = false; 2801cb0ef41Sopenharmony_ci w.on('error', function() { 2811cb0ef41Sopenharmony_ci gotError = true; 2821cb0ef41Sopenharmony_ci }); 2831cb0ef41Sopenharmony_ci w.pipe(process.stdout); 2841cb0ef41Sopenharmony_ci assert.strictEqual(gotError, true); 2851cb0ef41Sopenharmony_ci} 2861cb0ef41Sopenharmony_ci 2871cb0ef41Sopenharmony_ci{ 2881cb0ef41Sopenharmony_ci // Verify that duplex streams cannot be piped 2891cb0ef41Sopenharmony_ci const d = new D(); 2901cb0ef41Sopenharmony_ci d._read = common.mustCall(); 2911cb0ef41Sopenharmony_ci d._write = common.mustNotCall(); 2921cb0ef41Sopenharmony_ci let gotError = false; 2931cb0ef41Sopenharmony_ci d.on('error', function() { 2941cb0ef41Sopenharmony_ci gotError = true; 2951cb0ef41Sopenharmony_ci }); 2961cb0ef41Sopenharmony_ci d.pipe(process.stdout); 2971cb0ef41Sopenharmony_ci assert.strictEqual(gotError, false); 2981cb0ef41Sopenharmony_ci} 2991cb0ef41Sopenharmony_ci 3001cb0ef41Sopenharmony_ci{ 3011cb0ef41Sopenharmony_ci // Verify that end(chunk) twice is an error 3021cb0ef41Sopenharmony_ci const w = new W(); 3031cb0ef41Sopenharmony_ci w._write = common.mustCall((msg) => { 3041cb0ef41Sopenharmony_ci assert.strictEqual(msg.toString(), 'this is the end'); 3051cb0ef41Sopenharmony_ci }); 3061cb0ef41Sopenharmony_ci let gotError = false; 3071cb0ef41Sopenharmony_ci w.on('error', function(er) { 3081cb0ef41Sopenharmony_ci gotError = true; 3091cb0ef41Sopenharmony_ci assert.strictEqual(er.message, 'write after end'); 3101cb0ef41Sopenharmony_ci }); 3111cb0ef41Sopenharmony_ci w.end('this is the end'); 3121cb0ef41Sopenharmony_ci w.end('and so is this'); 3131cb0ef41Sopenharmony_ci process.nextTick(common.mustCall(function() { 3141cb0ef41Sopenharmony_ci assert.strictEqual(gotError, true); 3151cb0ef41Sopenharmony_ci })); 3161cb0ef41Sopenharmony_ci} 3171cb0ef41Sopenharmony_ci 3181cb0ef41Sopenharmony_ci{ 3191cb0ef41Sopenharmony_ci // Verify stream doesn't end while writing 3201cb0ef41Sopenharmony_ci const w = new W(); 3211cb0ef41Sopenharmony_ci let wrote = false; 3221cb0ef41Sopenharmony_ci w._write = function(chunk, e, cb) { 3231cb0ef41Sopenharmony_ci assert.strictEqual(this.writing, undefined); 3241cb0ef41Sopenharmony_ci wrote = true; 3251cb0ef41Sopenharmony_ci this.writing = true; 3261cb0ef41Sopenharmony_ci setTimeout(() => { 3271cb0ef41Sopenharmony_ci this.writing = false; 3281cb0ef41Sopenharmony_ci cb(); 3291cb0ef41Sopenharmony_ci }, 1); 3301cb0ef41Sopenharmony_ci }; 3311cb0ef41Sopenharmony_ci w.on('finish', common.mustCall(function() { 3321cb0ef41Sopenharmony_ci assert.strictEqual(wrote, true); 3331cb0ef41Sopenharmony_ci assert.strictEqual(this.writing, false); 3341cb0ef41Sopenharmony_ci })); 3351cb0ef41Sopenharmony_ci w.write(Buffer.alloc(0)); 3361cb0ef41Sopenharmony_ci w.end(); 3371cb0ef41Sopenharmony_ci} 3381cb0ef41Sopenharmony_ci 3391cb0ef41Sopenharmony_ci{ 3401cb0ef41Sopenharmony_ci // Verify finish does not come before write() callback 3411cb0ef41Sopenharmony_ci const w = new W(); 3421cb0ef41Sopenharmony_ci let writeCb = false; 3431cb0ef41Sopenharmony_ci w._write = function(chunk, e, cb) { 3441cb0ef41Sopenharmony_ci setTimeout(function() { 3451cb0ef41Sopenharmony_ci writeCb = true; 3461cb0ef41Sopenharmony_ci cb(); 3471cb0ef41Sopenharmony_ci }, 10); 3481cb0ef41Sopenharmony_ci }; 3491cb0ef41Sopenharmony_ci w.on('finish', common.mustCall(function() { 3501cb0ef41Sopenharmony_ci assert.strictEqual(writeCb, true); 3511cb0ef41Sopenharmony_ci })); 3521cb0ef41Sopenharmony_ci w.write(Buffer.alloc(0)); 3531cb0ef41Sopenharmony_ci w.end(); 3541cb0ef41Sopenharmony_ci} 3551cb0ef41Sopenharmony_ci 3561cb0ef41Sopenharmony_ci{ 3571cb0ef41Sopenharmony_ci // Verify finish does not come before synchronous _write() callback 3581cb0ef41Sopenharmony_ci const w = new W(); 3591cb0ef41Sopenharmony_ci let writeCb = false; 3601cb0ef41Sopenharmony_ci w._write = function(chunk, e, cb) { 3611cb0ef41Sopenharmony_ci cb(); 3621cb0ef41Sopenharmony_ci }; 3631cb0ef41Sopenharmony_ci w.on('finish', common.mustCall(function() { 3641cb0ef41Sopenharmony_ci assert.strictEqual(writeCb, true); 3651cb0ef41Sopenharmony_ci })); 3661cb0ef41Sopenharmony_ci w.write(Buffer.alloc(0), function() { 3671cb0ef41Sopenharmony_ci writeCb = true; 3681cb0ef41Sopenharmony_ci }); 3691cb0ef41Sopenharmony_ci w.end(); 3701cb0ef41Sopenharmony_ci} 3711cb0ef41Sopenharmony_ci 3721cb0ef41Sopenharmony_ci{ 3731cb0ef41Sopenharmony_ci // Verify finish is emitted if the last chunk is empty 3741cb0ef41Sopenharmony_ci const w = new W(); 3751cb0ef41Sopenharmony_ci w._write = function(chunk, e, cb) { 3761cb0ef41Sopenharmony_ci process.nextTick(cb); 3771cb0ef41Sopenharmony_ci }; 3781cb0ef41Sopenharmony_ci w.on('finish', common.mustCall()); 3791cb0ef41Sopenharmony_ci w.write(Buffer.allocUnsafe(1)); 3801cb0ef41Sopenharmony_ci w.end(Buffer.alloc(0)); 3811cb0ef41Sopenharmony_ci} 3821cb0ef41Sopenharmony_ci 3831cb0ef41Sopenharmony_ci{ 3841cb0ef41Sopenharmony_ci // Verify that finish is emitted after shutdown 3851cb0ef41Sopenharmony_ci const w = new W(); 3861cb0ef41Sopenharmony_ci let shutdown = false; 3871cb0ef41Sopenharmony_ci 3881cb0ef41Sopenharmony_ci w._final = common.mustCall(function(cb) { 3891cb0ef41Sopenharmony_ci assert.strictEqual(this, w); 3901cb0ef41Sopenharmony_ci setTimeout(function() { 3911cb0ef41Sopenharmony_ci shutdown = true; 3921cb0ef41Sopenharmony_ci cb(); 3931cb0ef41Sopenharmony_ci }, 100); 3941cb0ef41Sopenharmony_ci }); 3951cb0ef41Sopenharmony_ci w._write = function(chunk, e, cb) { 3961cb0ef41Sopenharmony_ci process.nextTick(cb); 3971cb0ef41Sopenharmony_ci }; 3981cb0ef41Sopenharmony_ci w.on('finish', common.mustCall(function() { 3991cb0ef41Sopenharmony_ci assert.strictEqual(shutdown, true); 4001cb0ef41Sopenharmony_ci })); 4011cb0ef41Sopenharmony_ci w.write(Buffer.allocUnsafe(1)); 4021cb0ef41Sopenharmony_ci w.end(Buffer.allocUnsafe(0)); 4031cb0ef41Sopenharmony_ci} 4041cb0ef41Sopenharmony_ci 4051cb0ef41Sopenharmony_ci{ 4061cb0ef41Sopenharmony_ci // Verify that error is only emitted once when failing in _finish. 4071cb0ef41Sopenharmony_ci const w = new W(); 4081cb0ef41Sopenharmony_ci 4091cb0ef41Sopenharmony_ci w._final = common.mustCall(function(cb) { 4101cb0ef41Sopenharmony_ci cb(new Error('test')); 4111cb0ef41Sopenharmony_ci }); 4121cb0ef41Sopenharmony_ci w.on('error', common.mustCall((err) => { 4131cb0ef41Sopenharmony_ci assert.strictEqual(w._writableState.errorEmitted, true); 4141cb0ef41Sopenharmony_ci assert.strictEqual(err.message, 'test'); 4151cb0ef41Sopenharmony_ci w.on('error', common.mustNotCall()); 4161cb0ef41Sopenharmony_ci w.destroy(new Error()); 4171cb0ef41Sopenharmony_ci })); 4181cb0ef41Sopenharmony_ci w.end(); 4191cb0ef41Sopenharmony_ci} 4201cb0ef41Sopenharmony_ci 4211cb0ef41Sopenharmony_ci{ 4221cb0ef41Sopenharmony_ci // Verify that error is only emitted once when failing in write. 4231cb0ef41Sopenharmony_ci const w = new W(); 4241cb0ef41Sopenharmony_ci w.on('error', common.mustNotCall()); 4251cb0ef41Sopenharmony_ci assert.throws(() => { 4261cb0ef41Sopenharmony_ci w.write(null); 4271cb0ef41Sopenharmony_ci }, { 4281cb0ef41Sopenharmony_ci code: 'ERR_STREAM_NULL_VALUES' 4291cb0ef41Sopenharmony_ci }); 4301cb0ef41Sopenharmony_ci} 4311cb0ef41Sopenharmony_ci 4321cb0ef41Sopenharmony_ci{ 4331cb0ef41Sopenharmony_ci // Verify that error is only emitted once when failing in write after end. 4341cb0ef41Sopenharmony_ci const w = new W(); 4351cb0ef41Sopenharmony_ci w.on('error', common.mustCall((err) => { 4361cb0ef41Sopenharmony_ci assert.strictEqual(w._writableState.errorEmitted, true); 4371cb0ef41Sopenharmony_ci assert.strictEqual(err.code, 'ERR_STREAM_WRITE_AFTER_END'); 4381cb0ef41Sopenharmony_ci })); 4391cb0ef41Sopenharmony_ci w.end(); 4401cb0ef41Sopenharmony_ci w.write('hello'); 4411cb0ef41Sopenharmony_ci w.destroy(new Error()); 4421cb0ef41Sopenharmony_ci} 4431cb0ef41Sopenharmony_ci 4441cb0ef41Sopenharmony_ci{ 4451cb0ef41Sopenharmony_ci // Verify that finish is not emitted after error 4461cb0ef41Sopenharmony_ci const w = new W(); 4471cb0ef41Sopenharmony_ci 4481cb0ef41Sopenharmony_ci w._final = common.mustCall(function(cb) { 4491cb0ef41Sopenharmony_ci cb(new Error()); 4501cb0ef41Sopenharmony_ci }); 4511cb0ef41Sopenharmony_ci w._write = function(chunk, e, cb) { 4521cb0ef41Sopenharmony_ci process.nextTick(cb); 4531cb0ef41Sopenharmony_ci }; 4541cb0ef41Sopenharmony_ci w.on('error', common.mustCall()); 4551cb0ef41Sopenharmony_ci w.on('prefinish', common.mustNotCall()); 4561cb0ef41Sopenharmony_ci w.on('finish', common.mustNotCall()); 4571cb0ef41Sopenharmony_ci w.write(Buffer.allocUnsafe(1)); 4581cb0ef41Sopenharmony_ci w.end(Buffer.allocUnsafe(0)); 4591cb0ef41Sopenharmony_ci} 460