mirror of https://github.com/lukechilds/node.git
Browse Source
Adds destroy() and _destroy() methods to Readable, Writable, Duplex and Transform. It also standardizes the behavior and the implementation of destroy(), which has been inconsistent in userland and core. This PR also updates all the subsystems of core to use the new destroy(). PR-URL: https://github.com/nodejs/node/pull/12925 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Calvin Metcalf <calvin.metcalf@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>v6
18 changed files with 964 additions and 68 deletions
@ -0,0 +1,65 @@ |
|||
'use strict'; |
|||
|
|||
// undocumented cb() API, needed for core, not for public API
|
|||
function destroy(err, cb) { |
|||
const readableDestroyed = this._readableState && |
|||
this._readableState.destroyed; |
|||
const writableDestroyed = this._writableState && |
|||
this._writableState.destroyed; |
|||
|
|||
if (readableDestroyed || writableDestroyed) { |
|||
if (err && (!this._writableState || !this._writableState.errorEmitted)) { |
|||
process.nextTick(emitErrorNT, this, err); |
|||
} |
|||
return; |
|||
} |
|||
|
|||
// we set destroyed to true before firing error callbacks in order
|
|||
// to make it re-entrance safe in case destroy() is called within callbacks
|
|||
|
|||
if (this._readableState) { |
|||
this._readableState.destroyed = true; |
|||
} |
|||
|
|||
// if this is a duplex stream mark the writable part as destroyed as well
|
|||
if (this._writableState) { |
|||
this._writableState.destroyed = true; |
|||
} |
|||
|
|||
this._destroy(err || null, (err) => { |
|||
if (!cb && err) { |
|||
process.nextTick(emitErrorNT, this, err); |
|||
if (this._writableState) { |
|||
this._writableState.errorEmitted = true; |
|||
} |
|||
} else if (cb) { |
|||
cb(err); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
function undestroy() { |
|||
if (this._readableState) { |
|||
this._readableState.destroyed = false; |
|||
this._readableState.reading = false; |
|||
this._readableState.ended = false; |
|||
this._readableState.endEmitted = false; |
|||
} |
|||
|
|||
if (this._writableState) { |
|||
this._writableState.destroyed = false; |
|||
this._writableState.ended = false; |
|||
this._writableState.ending = false; |
|||
this._writableState.finished = false; |
|||
this._writableState.errorEmitted = false; |
|||
} |
|||
} |
|||
|
|||
function emitErrorNT(self, err) { |
|||
self.emit('error', err); |
|||
} |
|||
|
|||
module.exports = { |
|||
destroy, |
|||
undestroy |
|||
}; |
@ -0,0 +1,31 @@ |
|||
'use strict'; |
|||
// Refs: https://github.com/nodejs/node/issues/947
|
|||
const common = require('../common'); |
|||
const assert = require('assert'); |
|||
const cp = require('child_process'); |
|||
|
|||
if (process.argv[2] === 'child') { |
|||
process.on('message', common.mustCall((msg) => { |
|||
assert.strictEqual(msg, 'go'); |
|||
// the following console.log is an integral part
|
|||
// of the test. If this regress, this call will
|
|||
// cause the process to exit with 1
|
|||
console.log('logging should not cause a crash'); |
|||
process.disconnect(); |
|||
})); |
|||
} else { |
|||
// Passing '--inspect', '--inspect-brk' to child.spawn enables
|
|||
// the debugger. This test was added to help debug the fork-based
|
|||
// test with the same name.
|
|||
const child = cp.spawn(process.execPath, [__filename, 'child'], { |
|||
stdio: ['pipe', 'pipe', 'pipe', 'ipc'] |
|||
}); |
|||
|
|||
child.on('close', common.mustCall((exitCode, signal) => { |
|||
assert.strictEqual(exitCode, 0, 'exit successfully'); |
|||
assert.strictEqual(signal, null); |
|||
})); |
|||
|
|||
child.stdout.destroy(); |
|||
child.send('go'); |
|||
} |
@ -0,0 +1,194 @@ |
|||
'use strict'; |
|||
|
|||
const common = require('../common'); |
|||
const { Duplex } = require('stream'); |
|||
const assert = require('assert'); |
|||
const { inherits } = require('util'); |
|||
|
|||
{ |
|||
const duplex = new Duplex({ |
|||
write(chunk, enc, cb) { cb(); }, |
|||
read() {} |
|||
}); |
|||
|
|||
duplex.resume(); |
|||
|
|||
duplex.on('end', common.mustCall()); |
|||
duplex.on('finish', 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.mustCall()); |
|||
duplex.on('finish', common.mustCall()); |
|||
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.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.mustCall()); |
|||
duplex.on('finish', common.mustCall()); |
|||
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.mustCall()); |
|||
duplex.on('end', common.mustCall()); |
|||
|
|||
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); |
|||
} |
|||
|
|||
inherits(MyDuplex, Duplex); |
|||
|
|||
new MyDuplex(); |
|||
} |
@ -0,0 +1,162 @@ |
|||
'use strict'; |
|||
|
|||
const common = require('../common'); |
|||
const { Readable } = require('stream'); |
|||
const assert = require('assert'); |
|||
const { inherits } = require('util'); |
|||
|
|||
{ |
|||
const read = new Readable({ |
|||
read() {} |
|||
}); |
|||
read.resume(); |
|||
|
|||
read.on('end', common.mustCall()); |
|||
|
|||
read.destroy(); |
|||
assert.strictEqual(read.destroyed, true); |
|||
} |
|||
|
|||
{ |
|||
const read = new Readable({ |
|||
read() {} |
|||
}); |
|||
read.resume(); |
|||
|
|||
const expected = new Error('kaboom'); |
|||
|
|||
read.on('end', 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() {} |
|||
}); |
|||
|
|||
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('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.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.destroy(); |
|||
|
|||
read.removeListener('end', fail); |
|||
read.on('end', common.mustCall()); |
|||
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); |
|||
}); |
|||
|
|||
read.on('end', common.mustNotCall('no end event')); |
|||
read.on('error', common.mustCall((err) => { |
|||
assert.strictEqual(err, expected); |
|||
})); |
|||
|
|||
read.destroy(); |
|||
assert.strictEqual(read.destroyed, 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); |
|||
} |
|||
|
|||
inherits(MyReadable, Readable); |
|||
|
|||
new MyReadable(); |
|||
} |
@ -0,0 +1,143 @@ |
|||
'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.mustCall()); |
|||
transform.on('close', common.mustCall()); |
|||
transform.on('finish', common.mustCall()); |
|||
|
|||
transform.destroy(); |
|||
} |
|||
|
|||
{ |
|||
const transform = new Transform({ |
|||
transform(chunk, enc, cb) {} |
|||
}); |
|||
transform.resume(); |
|||
|
|||
const expected = new Error('kaboom'); |
|||
|
|||
transform.on('end', common.mustCall()); |
|||
transform.on('finish', common.mustCall()); |
|||
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.mustNotCall('no close event')); |
|||
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.mustNotCall('no close event')); |
|||
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', fail); |
|||
|
|||
transform.destroy(); |
|||
|
|||
transform.removeListener('end', fail); |
|||
transform.removeListener('finish', fail); |
|||
transform.on('end', common.mustCall()); |
|||
transform.on('finish', common.mustCall()); |
|||
} |
|||
|
|||
{ |
|||
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.mustNotCall('no close event')); |
|||
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(); |
|||
} |
@ -0,0 +1,172 @@ |
|||
'use strict'; |
|||
|
|||
const common = require('../common'); |
|||
const { Writable } = require('stream'); |
|||
const assert = require('assert'); |
|||
const { inherits } = require('util'); |
|||
|
|||
{ |
|||
const write = new Writable({ |
|||
write(chunk, enc, cb) { cb(); } |
|||
}); |
|||
|
|||
write.on('finish', common.mustCall()); |
|||
|
|||
write.destroy(); |
|||
assert.strictEqual(write.destroyed, true); |
|||
} |
|||
|
|||
{ |
|||
const write = new Writable({ |
|||
write(chunk, enc, cb) { cb(); } |
|||
}); |
|||
|
|||
const expected = new Error('kaboom'); |
|||
|
|||
write.on('finish', 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('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')); |
|||
|
|||
// 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.destroy(); |
|||
|
|||
write.removeListener('finish', fail); |
|||
write.on('finish', common.mustCall()); |
|||
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('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(); } |
|||
}); |
|||
|
|||
write.on('error', common.mustCall()); |
|||
|
|||
write.destroy(new Error('kaboom 1')); |
|||
write.destroy(new Error('kaboom 2')); |
|||
assert.strictEqual(write._writableState.errorEmitted, true); |
|||
assert.strictEqual(write.destroyed, 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('finish', common.mustNotCall()); |
|||
write.destroy(); |
|||
} |
|||
|
|||
{ |
|||
function MyWritable() { |
|||
assert.strictEqual(this.destroyed, false); |
|||
this.destroyed = false; |
|||
Writable.call(this); |
|||
} |
|||
|
|||
inherits(MyWritable, Writable); |
|||
|
|||
new MyWritable(); |
|||
} |
@ -1,10 +1,10 @@ |
|||
'use strict'; |
|||
const common = require('../common'); |
|||
const assert = require('assert'); |
|||
|
|||
assert.throws(() => process.stdout.end(), |
|||
common.expectsError({ |
|||
code: 'ERR_STDOUT_CLOSE', |
|||
type: Error, |
|||
message: 'process.stdout cannot be closed' |
|||
})); |
|||
process.on('uncaughtException', common.expectsError({ |
|||
code: 'ERR_STDOUT_CLOSE', |
|||
type: Error, |
|||
message: 'process.stdout cannot be closed' |
|||
})); |
|||
|
|||
process.stdout.end(); |
|||
|
Loading…
Reference in new issue