From 4fc2fbe81f48afdb9f1305c3184356bd5e0cfcd9 Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Fri, 12 Oct 2018 08:38:40 -0700 Subject: [PATCH 1/4] lib: make the global console [[Prototype]] an empty object From the WHATWG console spec: > For historical web-compatibility reasons, the namespace object for > console must have as its [[Prototype]] an empty object, created as > if by ObjectCreate(%ObjectPrototype%), instead of %ObjectPrototype%. Since in Node.js, the Console constructor has been exposed through require('console'), we need to keep the Console constructor but we cannot actually use `new Console` to construct the global console. This patch changes the prototype chain of the global console object, so the console.Console.prototype is not in the global console prototype chain anymore. ``` const proto = Object.getPrototypeOf(global.console); // Before this patch proto.constructor === global.console.Console // After this patch proto.constructor === Object ``` But, we still maintain that ``` global.console instanceof global.console.Console ``` through a custom Symbol.hasInstance function of Console that tests for a special symbol kIsConsole for backwards compatibility. This fixes a case in the console Web Platform Test that we commented out. PR-URL: https://github.com/nodejs/node/pull/23509 Refs: https://github.com/whatwg/console/issues/3 Refs: https://console.spec.whatwg.org/#console-namespace Reviewed-By: Gus Caplan Reviewed-By: Matteo Collina Reviewed-By: Tiancheng "Timothy" Gu Reviewed-By: Denys Otrishko Reviewed-By: James M Snell Reviewed-By: Rich Trott Reviewed-By: Colin Ihrig Reviewed-By: Sakthipriyan Vairamani Reviewed-By: John-David Dalton --- lib/console.js | 56 ++++++++++++++++-- test/parallel/test-console-instance.js | 79 ++++++++++++++++---------- 2 files changed, 98 insertions(+), 37 deletions(-) diff --git a/lib/console.js b/lib/console.js index 496280d72c3a83..53297c901cd336 100644 --- a/lib/console.js +++ b/lib/console.js @@ -60,17 +60,21 @@ let cliTable; // Track amount of indentation required via `console.group()`. const kGroupIndent = Symbol('kGroupIndent'); - const kFormatForStderr = Symbol('kFormatForStderr'); const kFormatForStdout = Symbol('kFormatForStdout'); const kGetInspectOptions = Symbol('kGetInspectOptions'); const kColorMode = Symbol('kColorMode'); +const kIsConsole = Symbol('kIsConsole'); function Console(options /* or: stdout, stderr, ignoreErrors = true */) { - if (!(this instanceof Console)) { + // We have to test new.target here to see if this function is called + // with new, because we need to define a custom instanceof to accommodate + // the global console. + if (!new.target) { return new Console(...arguments); } + this[kIsConsole] = true; if (!options || typeof options.write === 'function') { options = { stdout: options, @@ -128,7 +132,7 @@ function Console(options /* or: stdout, stderr, ignoreErrors = true */) { var keys = Object.keys(Console.prototype); for (var v = 0; v < keys.length; v++) { var k = keys[v]; - this[k] = this[k].bind(this); + this[k] = Console.prototype[k].bind(this); } } @@ -470,10 +474,50 @@ Console.prototype.table = function(tabularData, properties) { return final(keys, values); }; -module.exports = new Console({ +function noop() {} + +// See https://console.spec.whatwg.org/#console-namespace +// > For historical web-compatibility reasons, the namespace object +// > for console must have as its [[Prototype]] an empty object, +// > created as if by ObjectCreate(%ObjectPrototype%), +// > instead of %ObjectPrototype%. + +// Since in Node.js, the Console constructor has been exposed through +// require('console'), we need to keep the Console constructor but +// we cannot actually use `new Console` to construct the global console. +// Therefore, the console.Console.prototype is not +// in the global console prototype chain anymore. +const globalConsole = Object.create({}); +const tempConsole = new Console({ stdout: process.stdout, stderr: process.stderr }); -module.exports.Console = Console; -function noop() {} +// Since Console is not on the prototype chain of the global console, +// the symbol properties on Console.prototype have to be looked up from +// the global console itself. +for (const prop of Object.getOwnPropertySymbols(Console.prototype)) { + globalConsole[prop] = Console.prototype[prop]; +} + +// Reflect.ownKeys() is used here for retrieving Symbols +for (const prop of Reflect.ownKeys(tempConsole)) { + const desc = { ...(Reflect.getOwnPropertyDescriptor(tempConsole, prop)) }; + // Since Console would bind method calls onto the instance, + // make sure the methods are called on globalConsole instead of + // tempConsole. + if (typeof Console.prototype[prop] === 'function') { + desc.value = Console.prototype[prop].bind(globalConsole); + } + Reflect.defineProperty(globalConsole, prop, desc); +} + +globalConsole.Console = Console; + +Object.defineProperty(Console, Symbol.hasInstance, { + value(instance) { + return instance[kIsConsole]; + } +}); + +module.exports = globalConsole; diff --git a/test/parallel/test-console-instance.js b/test/parallel/test-console-instance.js index 91d130f260184b..0f1453cb8d0d4b 100644 --- a/test/parallel/test-console-instance.js +++ b/test/parallel/test-console-instance.js @@ -23,7 +23,8 @@ const common = require('../common'); const assert = require('assert'); const Stream = require('stream'); -const Console = require('console').Console; +const requiredConsole = require('console'); +const Console = requiredConsole.Console; const out = new Stream(); const err = new Stream(); @@ -35,6 +36,11 @@ process.stdout.write = process.stderr.write = common.mustNotCall(); // Make sure that the "Console" function exists. assert.strictEqual(typeof Console, 'function'); +assert.strictEqual(requiredConsole, global.console); +// Make sure the custom instanceof of Console works +assert.ok(global.console instanceof Console); +assert.ok(!({} instanceof Console)); + // Make sure that the Console constructor throws // when not given a writable stream instance. common.expectsError( @@ -62,46 +68,57 @@ common.expectsError( out.write = err.write = (d) => {}; -const c = new Console(out, err); +{ + const c = new Console(out, err); + assert.ok(c instanceof Console); -out.write = err.write = common.mustCall((d) => { - assert.strictEqual(d, 'test\n'); -}, 2); + out.write = err.write = common.mustCall((d) => { + assert.strictEqual(d, 'test\n'); + }, 2); -c.log('test'); -c.error('test'); + c.log('test'); + c.error('test'); -out.write = common.mustCall((d) => { - assert.strictEqual(d, '{ foo: 1 }\n'); -}); + out.write = common.mustCall((d) => { + assert.strictEqual(d, '{ foo: 1 }\n'); + }); -c.dir({ foo: 1 }); + c.dir({ foo: 1 }); -// Ensure that the console functions are bound to the console instance. -let called = 0; -out.write = common.mustCall((d) => { - called++; - assert.strictEqual(d, `${called} ${called - 1} [ 1, 2, 3 ]\n`); -}, 3); + // Ensure that the console functions are bound to the console instance. + let called = 0; + out.write = common.mustCall((d) => { + called++; + assert.strictEqual(d, `${called} ${called - 1} [ 1, 2, 3 ]\n`); + }, 3); -[1, 2, 3].forEach(c.log); + [1, 2, 3].forEach(c.log); +} -// Console() detects if it is called without `new` keyword. -Console(out, err); +// Test calling Console without the `new` keyword. +{ + const withoutNew = Console(out, err); + assert.ok(withoutNew instanceof Console); +} -// Extending Console works. -class MyConsole extends Console { - hello() {} +// Test extending Console +{ + class MyConsole extends Console { + hello() {} + } + const myConsole = new MyConsole(process.stdout); + assert.strictEqual(typeof myConsole.hello, 'function'); + assert.ok(myConsole instanceof Console); } -const myConsole = new MyConsole(process.stdout); -assert.strictEqual(typeof myConsole.hello, 'function'); // Instance that does not ignore the stream errors. -const c2 = new Console(out, err, false); +{ + const c2 = new Console(out, err, false); -out.write = () => { throw new Error('out'); }; -err.write = () => { throw new Error('err'); }; + out.write = () => { throw new Error('out'); }; + err.write = () => { throw new Error('err'); }; -assert.throws(() => c2.log('foo'), /^Error: out$/); -assert.throws(() => c2.warn('foo'), /^Error: err$/); -assert.throws(() => c2.dir('foo'), /^Error: out$/); + assert.throws(() => c2.log('foo'), /^Error: out$/); + assert.throws(() => c2.warn('foo'), /^Error: err$/); + assert.throws(() => c2.dir('foo'), /^Error: out$/); +} From c67021ae972e45081c5ea3022403c149b02b8599 Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Thu, 10 Jan 2019 01:55:07 +0800 Subject: [PATCH 2/4] console: create the global console from Console constructor Specifically for v11.x. Refs: https://github.com/nodejs/node/pull/23509 --- lib/console.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/console.js b/lib/console.js index 53297c901cd336..32713ec5556d03 100644 --- a/lib/console.js +++ b/lib/console.js @@ -487,7 +487,8 @@ function noop() {} // we cannot actually use `new Console` to construct the global console. // Therefore, the console.Console.prototype is not // in the global console prototype chain anymore. -const globalConsole = Object.create({}); +// This is only here for v11.x conflict resolution. +const globalConsole = Object.create(Console.prototype); const tempConsole = new Console({ stdout: process.stdout, stderr: process.stderr From 132f8605deb31c04d54400fbb5b52bcdfb83e35d Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Sat, 3 Nov 2018 03:20:23 +0800 Subject: [PATCH 3/4] console: bind methods from the prototype chain in Console In 62232361 we made the console.Console function construct an object with methods from Console.prototype bound to the instance, instead of with methods found on the prototype chain to be bound on the instances, thus breaking users overriding these methods when subclassing Console because they are not expecting this function to construct a namespace whose methods are not looked up from the prototype chain. This patch restores the previous behavior since it does not affect the characteristics of the global console anyway. So after this patch, the Console function still constructs normal objects with function properties looked up from the prototype chain but bound to the instances always. PR-URL: https://github.com/nodejs/node/pull/24047 Reviewed-By: John-David Dalton Reviewed-By: Luigi Pinca Reviewed-By: Colin Ihrig --- lib/console.js | 5 ++++- test/parallel/test-console-instance.js | 6 ++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/console.js b/lib/console.js index 32713ec5556d03..179acc4a504c9e 100644 --- a/lib/console.js +++ b/lib/console.js @@ -132,7 +132,10 @@ function Console(options /* or: stdout, stderr, ignoreErrors = true */) { var keys = Object.keys(Console.prototype); for (var v = 0; v < keys.length; v++) { var k = keys[v]; - this[k] = Console.prototype[k].bind(this); + // We have to bind the methods grabbed from the instance instead of from + // the prototype so that users extending the Console can override them + // from the prototype chain of the subclass. + this[k] = this[k].bind(this); } } diff --git a/test/parallel/test-console-instance.js b/test/parallel/test-console-instance.js index 0f1453cb8d0d4b..127e59e6e5b981 100644 --- a/test/parallel/test-console-instance.js +++ b/test/parallel/test-console-instance.js @@ -105,10 +105,16 @@ out.write = err.write = (d) => {}; { class MyConsole extends Console { hello() {} + // See if the methods on Console.prototype are overridable. + log() { return 'overridden'; } } const myConsole = new MyConsole(process.stdout); assert.strictEqual(typeof myConsole.hello, 'function'); assert.ok(myConsole instanceof Console); + assert.strictEqual(myConsole.log(), 'overridden'); + + const log = myConsole.log; + assert.strictEqual(log(), 'overridden'); } // Instance that does not ignore the stream errors. From de29e85f0b847769ebf707babff3694270307dab Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Wed, 21 Nov 2018 07:31:25 +0800 Subject: [PATCH 4/4] console: lazy load process.stderr and process.stdout This patch: - Refactors the Console constructor: moves the property binding code into and the writable streams binding code into two methods defined on the Console.prototype with symbols. - Refactors the global console creation: we only need to share the property binding code from the Console constructor. To bind the streams we can lazy load `process.stdio` and `process.stderr` so that we don't create these streams when they are not used. This significantly reduces the number of modules loaded during bootstrap. Also, by calling the refactored-out method directly we can skip the unnecessary typechecks when creating the global console and there is no need to create a temporary Console anymore. - Refactors the error handler creation and the `write` method: use a `kUseStdout` symbol to tell the internals which stream should be loaded from the console instance. Also put the `write` method on the Console prototype so it just loads other properties directly off the console instance which simplifies the call sites. Also leaves a few TODOs for further refactoring of the console bootstrap. PR-URL: https://github.com/nodejs/node/pull/24534 Reviewed-By: Gus Caplan --- lib/console.js | 197 +++++++++++------- test/parallel/test-bootstrap-modules.js | 18 +- .../test-stderr-stdout-handle-sigwinch.out | 2 +- 3 files changed, 133 insertions(+), 84 deletions(-) diff --git a/lib/console.js b/lib/console.js index 179acc4a504c9e..f0b9a74cfc7df8 100644 --- a/lib/console.js +++ b/lib/console.js @@ -65,7 +65,15 @@ const kFormatForStdout = Symbol('kFormatForStdout'); const kGetInspectOptions = Symbol('kGetInspectOptions'); const kColorMode = Symbol('kColorMode'); const kIsConsole = Symbol('kIsConsole'); - +const kWriteToConsole = Symbol('kWriteToConsole'); +const kBindProperties = Symbol('kBindProperties'); +const kBindStreamsEager = Symbol('kBindStreamsEager'); +const kBindStreamsLazy = Symbol('kBindStreamsLazy'); +const kUseStdout = Symbol('kUseStdout'); +const kUseStderr = Symbol('kUseStderr'); + +// This constructor is not used to construct the global console. +// It's exported for backwards compatibility. function Console(options /* or: stdout, stderr, ignoreErrors = true */) { // We have to test new.target here to see if this function is called // with new, because we need to define a custom instanceof to accommodate @@ -74,7 +82,6 @@ function Console(options /* or: stdout, stderr, ignoreErrors = true */) { return new Console(...arguments); } - this[kIsConsole] = true; if (!options || typeof options.write === 'function') { options = { stdout: options, @@ -97,37 +104,9 @@ function Console(options /* or: stdout, stderr, ignoreErrors = true */) { throw new ERR_CONSOLE_WRITABLE_STREAM('stderr'); } - const prop = { - writable: true, - enumerable: false, - configurable: true - }; - Object.defineProperty(this, '_stdout', { ...prop, value: stdout }); - Object.defineProperty(this, '_stderr', { ...prop, value: stderr }); - Object.defineProperty(this, '_ignoreErrors', { - ...prop, - value: Boolean(ignoreErrors), - }); - Object.defineProperty(this, '_times', { ...prop, value: new Map() }); - Object.defineProperty(this, '_stdoutErrorHandler', { - ...prop, - value: createWriteErrorHandler(stdout), - }); - Object.defineProperty(this, '_stderrErrorHandler', { - ...prop, - value: createWriteErrorHandler(stderr), - }); - if (typeof colorMode !== 'boolean' && colorMode !== 'auto') throw new ERR_INVALID_ARG_VALUE('colorMode', colorMode); - // Corresponds to https://console.spec.whatwg.org/#count-map - this[kCounts] = new Map(); - this[kColorMode] = colorMode; - - Object.defineProperty(this, kGroupIndent, { writable: true }); - this[kGroupIndent] = ''; - // Bind the prototype functions to this Console instance var keys = Object.keys(Console.prototype); for (var v = 0; v < keys.length; v++) { @@ -137,14 +116,92 @@ function Console(options /* or: stdout, stderr, ignoreErrors = true */) { // from the prototype chain of the subclass. this[k] = this[k].bind(this); } + + this[kBindStreamsEager](stdout, stderr); + this[kBindProperties](ignoreErrors, colorMode); } +const consolePropAttributes = { + writable: true, + enumerable: false, + configurable: true +}; + +// Fixup global.console instanceof global.console.Console +Object.defineProperty(Console, Symbol.hasInstance, { + value(instance) { + return instance[kIsConsole]; + } +}); + +// Eager version for the Console constructor +Console.prototype[kBindStreamsEager] = function(stdout, stderr) { + Object.defineProperties(this, { + '_stdout': { ...consolePropAttributes, value: stdout }, + '_stderr': { ...consolePropAttributes, value: stderr } + }); +}; + +// Lazily load the stdout and stderr from an object so we don't +// create the stdio streams when they are not even accessed +Console.prototype[kBindStreamsLazy] = function(object) { + let stdout; + let stderr; + Object.defineProperties(this, { + '_stdout': { + enumerable: false, + configurable: true, + get() { + if (!stdout) stdout = object.stdout; + return stdout; + }, + set(value) { stdout = value; } + }, + '_stderr': { + enumerable: false, + configurable: true, + get() { + if (!stderr) { stderr = object.stderr; } + return stderr; + }, + set(value) { stderr = value; } + } + }); +}; + +Console.prototype[kBindProperties] = function(ignoreErrors, colorMode) { + Object.defineProperties(this, { + '_stdoutErrorHandler': { + ...consolePropAttributes, + value: createWriteErrorHandler(this, kUseStdout) + }, + '_stderrErrorHandler': { + ...consolePropAttributes, + value: createWriteErrorHandler(this, kUseStderr) + }, + '_ignoreErrors': { + ...consolePropAttributes, + value: Boolean(ignoreErrors) + }, + '_times': { ...consolePropAttributes, value: new Map() } + }); + + // TODO(joyeecheung): use consolePropAttributes for these + // Corresponds to https://console.spec.whatwg.org/#count-map + this[kCounts] = new Map(); + this[kColorMode] = colorMode; + this[kIsConsole] = true; + this[kGroupIndent] = ''; +}; + // Make a function that can serve as the callback passed to `stream.write()`. -function createWriteErrorHandler(stream) { +function createWriteErrorHandler(instance, streamSymbol) { return (err) => { // This conditional evaluates to true if and only if there was an error // that was not already emitted (which happens when the _write callback // is invoked asynchronously). + const stream = streamSymbol === kUseStdout ? + instance._stdout : instance._stderr; if (err !== null && !stream._writableState.errorEmitted) { // If there was an error, it will be emitted on `stream` as // an `error` event. Adding a `once` listener will keep that error @@ -158,7 +215,15 @@ function createWriteErrorHandler(stream) { }; } -function write(ignoreErrors, stream, string, errorhandler, groupIndent) { +Console.prototype[kWriteToConsole] = function(streamSymbol, string) { + const ignoreErrors = this._ignoreErrors; + const groupIndent = this[kGroupIndent]; + + const useStdout = streamSymbol === kUseStdout; + const stream = useStdout ? this._stdout : this._stderr; + const errorHandler = useStdout ? + this._stdoutErrorHandler : this._stderrErrorHandler; + if (groupIndent.length !== 0) { if (string.indexOf('\n') !== -1) { string = string.replace(/\n/g, `\n${groupIndent}`); @@ -176,7 +241,7 @@ function write(ignoreErrors, stream, string, errorhandler, groupIndent) { // Add and later remove a noop error handler to catch synchronous errors. stream.once('error', noop); - stream.write(string, errorhandler); + stream.write(string, errorHandler); } catch (e) { // Console is a debugging utility, so it swallowing errors is not desirable // even in edge cases such as low stack space. @@ -186,7 +251,7 @@ function write(ignoreErrors, stream, string, errorhandler, groupIndent) { } finally { stream.removeListener('error', noop); } -} +}; const kColorInspectOptions = { colors: true }; const kNoColorInspectOptions = {}; @@ -212,23 +277,17 @@ Console.prototype[kFormatForStderr] = function(args) { }; Console.prototype.log = function log(...args) { - write(this._ignoreErrors, - this._stdout, - this[kFormatForStdout](args), - this._stdoutErrorHandler, - this[kGroupIndent]); + this[kWriteToConsole](kUseStdout, this[kFormatForStdout](args)); }; + Console.prototype.debug = Console.prototype.log; Console.prototype.info = Console.prototype.log; Console.prototype.dirxml = Console.prototype.log; Console.prototype.warn = function warn(...args) { - write(this._ignoreErrors, - this._stderr, - this[kFormatForStderr](args), - this._stderrErrorHandler, - this[kGroupIndent]); + this[kWriteToConsole](kUseStderr, this[kFormatForStderr](args)); }; + Console.prototype.error = Console.prototype.warn; Console.prototype.dir = function dir(object, options) { @@ -237,11 +296,7 @@ Console.prototype.dir = function dir(object, options) { ...this[kGetInspectOptions](this._stdout), ...options }; - write(this._ignoreErrors, - this._stdout, - util.inspect(object, options), - this._stdoutErrorHandler, - this[kGroupIndent]); + this[kWriteToConsole](kUseStdout, util.inspect(object, options)); }; Console.prototype.time = function time(label = 'default') { @@ -301,7 +356,7 @@ Console.prototype.trace = function trace(...args) { Console.prototype.assert = function assert(expression, ...args) { if (!expression) { args[0] = `Assertion failed${args.length === 0 ? '' : `: ${args[0]}`}`; - this.warn(this[kFormatForStderr](args)); + this.warn(...args); // the arguments will be formatted in warn() again } }; @@ -363,7 +418,6 @@ const valuesKey = 'Values'; const indexKey = '(index)'; const iterKey = '(iteration index)'; - const isArray = (v) => ArrayIsArray(v) || isTypedArray(v) || isBuffer(v); // https://console.spec.whatwg.org/#table @@ -490,38 +544,31 @@ function noop() {} // we cannot actually use `new Console` to construct the global console. // Therefore, the console.Console.prototype is not // in the global console prototype chain anymore. + +// TODO(joyeecheung): +// - Move the Console constructor into internal/console.js +// - Move the global console creation code along with the inspector console +// wrapping code in internal/bootstrap/node.js into a separate file. +// - Make this file a simple re-export of those two files. // This is only here for v11.x conflict resolution. const globalConsole = Object.create(Console.prototype); -const tempConsole = new Console({ - stdout: process.stdout, - stderr: process.stderr -}); // Since Console is not on the prototype chain of the global console, // the symbol properties on Console.prototype have to be looked up from -// the global console itself. -for (const prop of Object.getOwnPropertySymbols(Console.prototype)) { - globalConsole[prop] = Console.prototype[prop]; -} - -// Reflect.ownKeys() is used here for retrieving Symbols -for (const prop of Reflect.ownKeys(tempConsole)) { - const desc = { ...(Reflect.getOwnPropertyDescriptor(tempConsole, prop)) }; - // Since Console would bind method calls onto the instance, - // make sure the methods are called on globalConsole instead of - // tempConsole. - if (typeof Console.prototype[prop] === 'function') { - desc.value = Console.prototype[prop].bind(globalConsole); +// the global console itself. In addition, we need to make the global +// console a namespace by binding the console methods directly onto +// the global console with the receiver fixed. +for (const prop of Reflect.ownKeys(Console.prototype)) { + if (prop === 'constructor') { continue; } + const desc = Reflect.getOwnPropertyDescriptor(Console.prototype, prop); + if (typeof desc.value === 'function') { // fix the receiver + desc.value = desc.value.bind(globalConsole); } Reflect.defineProperty(globalConsole, prop, desc); } -globalConsole.Console = Console; - -Object.defineProperty(Console, Symbol.hasInstance, { - value(instance) { - return instance[kIsConsole]; - } -}); +globalConsole[kBindStreamsLazy](process); +globalConsole[kBindProperties](true, 'auto'); module.exports = globalConsole; +module.exports.Console = Console; diff --git a/test/parallel/test-bootstrap-modules.js b/test/parallel/test-bootstrap-modules.js index 70011637e08af4..272dec40060624 100644 --- a/test/parallel/test-bootstrap-modules.js +++ b/test/parallel/test-bootstrap-modules.js @@ -1,14 +1,16 @@ -/* eslint-disable node-core/required-modules */ - +// Flags: --expose-internals 'use strict'; -// Ordinarily test files must require('common') but that action causes -// the global console to be compiled, defeating the purpose of this test. -// This makes sure no additional files are added without carefully considering -// lazy loading. Please adjust the value if necessary. - +// This list must be computed before we require any modules to +// to eliminate the noise. const list = process.moduleLoadList.slice(); +const common = require('../common'); const assert = require('assert'); -assert(list.length <= 78, list); +const isMainThread = common.isMainThread; +const kMaxModuleCount = isMainThread ? 56 : 78; + +assert(list.length <= kMaxModuleCount, + `Total length: ${list.length}\n` + list.join('\n') +); diff --git a/test/pseudo-tty/test-stderr-stdout-handle-sigwinch.out b/test/pseudo-tty/test-stderr-stdout-handle-sigwinch.out index dffbe030404487..4023b51f479747 100644 --- a/test/pseudo-tty/test-stderr-stdout-handle-sigwinch.out +++ b/test/pseudo-tty/test-stderr-stdout-handle-sigwinch.out @@ -1,2 +1,2 @@ -calling stdout._refreshSize calling stderr._refreshSize +calling stdout._refreshSize