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