• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright Joyent, Inc. and other Node contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a
4// copy of this software and associated documentation files (the
5// "Software"), to deal in the Software without restriction, including
6// without limitation the rights to use, copy, modify, merge, publish,
7// distribute, sublicense, and/or sell copies of the Software, and to permit
8// persons to whom the Software is furnished to do so, subject to the
9// following conditions:
10//
11// The above copyright notice and this permission notice shall be included
12// in all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20// USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22'use strict';
23const common = require('../common');
24const assert = require('assert');
25const util = require('util');
26
27const {
28  hijackStdout,
29  hijackStderr,
30  restoreStdout,
31  restoreStderr
32} = require('../common/hijackstdio');
33
34assert.ok(process.stdout.writable);
35assert.ok(process.stderr.writable);
36// Support legacy API
37if (common.isMainThread) {
38  assert.strictEqual(typeof process.stdout.fd, 'number');
39  assert.strictEqual(typeof process.stderr.fd, 'number');
40}
41
42common.expectWarning(
43  'Warning',
44  [
45    ['Count for \'noLabel\' does not exist'],
46    ['No such label \'noLabel\' for console.timeLog()'],
47    ['No such label \'noLabel\' for console.timeEnd()'],
48    ['Count for \'default\' does not exist'],
49    ['No such label \'default\' for console.timeLog()'],
50    ['No such label \'default\' for console.timeEnd()'],
51    ['Label \'default\' already exists for console.time()'],
52    ['Label \'test\' already exists for console.time()'],
53  ]
54);
55
56console.countReset('noLabel');
57console.timeLog('noLabel');
58console.timeEnd('noLabel');
59
60console.time('label');
61console.timeEnd('label');
62
63// Test using the default label
64// on console.time(), console.countReset(), console.timeLog(), console.timeEnd()
65console.countReset();
66console.timeLog();
67console.timeEnd();
68
69console.time();
70console.time();
71console.timeLog();
72console.timeEnd();
73
74// Check that the `Error` is a `TypeError` but do not check the message as it
75// will be different in different JavaScript engines.
76assert.throws(() => console.time(Symbol('test')),
77              TypeError);
78assert.throws(() => console.timeEnd(Symbol('test')),
79              TypeError);
80
81
82// An Object with a custom inspect function.
83const custom_inspect = { foo: 'bar', [util.inspect.custom]: () => 'inspect' };
84
85const strings = [];
86const errStrings = [];
87process.stdout.isTTY = false;
88hijackStdout(function(data) {
89  strings.push(data);
90});
91process.stderr.isTTY = false;
92hijackStderr(function(data) {
93  errStrings.push(data);
94});
95
96// Test console.log() goes to stdout
97console.log('foo');
98console.log('foo', 'bar');
99console.log('%s %s', 'foo', 'bar', 'hop');
100console.log({ slashes: '\\\\' });
101console.log(custom_inspect);
102
103// Test console.debug() goes to stdout
104console.debug('foo');
105console.debug('foo', 'bar');
106console.debug('%s %s', 'foo', 'bar', 'hop');
107console.debug({ slashes: '\\\\' });
108console.debug(custom_inspect);
109
110// Test console.info() goes to stdout
111console.info('foo');
112console.info('foo', 'bar');
113console.info('%s %s', 'foo', 'bar', 'hop');
114console.info({ slashes: '\\\\' });
115console.info(custom_inspect);
116
117// Test console.error() goes to stderr
118console.error('foo');
119console.error('foo', 'bar');
120console.error('%s %s', 'foo', 'bar', 'hop');
121console.error({ slashes: '\\\\' });
122console.error(custom_inspect);
123
124// Test console.warn() goes to stderr
125console.warn('foo');
126console.warn('foo', 'bar');
127console.warn('%s %s', 'foo', 'bar', 'hop');
128console.warn({ slashes: '\\\\' });
129console.warn(custom_inspect);
130
131// test console.dir()
132console.dir(custom_inspect);
133console.dir(custom_inspect, { showHidden: false });
134console.dir({ foo: { bar: { baz: true } } }, { depth: 0 });
135console.dir({ foo: { bar: { baz: true } } }, { depth: 1 });
136
137// Test console.dirxml()
138console.dirxml(custom_inspect, custom_inspect);
139console.dirxml(
140  { foo: { bar: { baz: true } } },
141  { foo: { bar: { quux: false } } },
142  { foo: { bar: { quux: true } } }
143);
144
145// Test console.trace()
146console.trace('This is a %j %d', { formatted: 'trace' }, 10, 'foo');
147
148// Test console.time() and console.timeEnd() output
149console.time('label');
150console.timeEnd('label');
151
152// Verify that Object.prototype properties can be used as labels
153console.time('__proto__');
154console.timeEnd('__proto__');
155console.time('constructor');
156console.timeEnd('constructor');
157console.time('hasOwnProperty');
158console.timeEnd('hasOwnProperty');
159
160// Verify that values are coerced to strings.
161console.time([]);
162console.timeEnd([]);
163console.time({});
164console.timeEnd({});
165// Repeat the object call to verify that everything really worked.
166console.time({});
167console.timeEnd({});
168console.time(null);
169console.timeEnd(null);
170console.time(undefined);
171console.timeEnd('default');
172console.time('default');
173console.timeEnd();
174console.time(NaN);
175console.timeEnd(NaN);
176
177// Make sure calling time twice without timeEnd doesn't reset the timer.
178console.time('test');
179const time = console._times.get('test');
180setTimeout(() => {
181  console.time('test');
182  assert.deepStrictEqual(console._times.get('test'), time);
183  console.timeEnd('test');
184}, 1);
185
186console.time('log1');
187console.timeLog('log1');
188console.timeLog('log1', 'test');
189console.timeLog('log1', {}, [1, 2, 3]);
190console.timeEnd('log1');
191
192console.assert(false, '%s should', 'console.assert', 'not throw');
193assert.strictEqual(errStrings[errStrings.length - 1],
194                   'Assertion failed: console.assert should not throw\n');
195
196console.assert(false);
197assert.strictEqual(errStrings[errStrings.length - 1], 'Assertion failed\n');
198
199console.assert(true, 'this should not throw');
200
201console.assert(true);
202
203assert.strictEqual(strings.length, process.stdout.writeTimes);
204assert.strictEqual(errStrings.length, process.stderr.writeTimes);
205restoreStdout();
206restoreStderr();
207
208// Verify that console.timeEnd() doesn't leave dead links
209const timesMapSize = console._times.size;
210console.time('label1');
211console.time('label2');
212console.time('label3');
213console.timeEnd('label1');
214console.timeEnd('label2');
215console.timeEnd('label3');
216assert.strictEqual(console._times.size, timesMapSize);
217
218const expectedStrings = [
219  'foo', 'foo bar', 'foo bar hop', "{ slashes: '\\\\\\\\' }", 'inspect',
220];
221
222for (const expected of expectedStrings) {
223  assert.strictEqual(strings.shift(), `${expected}\n`);
224  assert.strictEqual(errStrings.shift(), `${expected}\n`);
225}
226
227for (const expected of expectedStrings) {
228  assert.strictEqual(strings.shift(), `${expected}\n`);
229  assert.strictEqual(errStrings.shift(), `${expected}\n`);
230}
231
232for (const expected of expectedStrings) {
233  assert.strictEqual(strings.shift(), `${expected}\n`);
234}
235
236assert.strictEqual(strings.shift(),
237                   "{\n  foo: 'bar',\n  [Symbol(nodejs.util.inspect.custom)]:" +
238                    ' [Function: [nodejs.util.inspect.custom]]\n}\n');
239assert.strictEqual(strings.shift(),
240                   "{\n  foo: 'bar',\n  [Symbol(nodejs.util.inspect.custom)]:" +
241                    ' [Function: [nodejs.util.inspect.custom]]\n}\n');
242assert.ok(strings.shift().includes('foo: [Object]'));
243assert.strictEqual(strings.shift().includes('baz'), false);
244assert.strictEqual(strings.shift(), 'inspect inspect\n');
245assert.ok(strings[0].includes('foo: { bar: { baz:'));
246assert.ok(strings[0].includes('quux'));
247assert.ok(strings.shift().includes('quux: true'));
248
249assert.ok(/^label: \d+(\.\d{1,3})?(ms|s)$/.test(strings.shift().trim()));
250assert.ok(/^__proto__: \d+(\.\d{1,3})?(ms|s)$/.test(strings.shift().trim()));
251assert.ok(/^constructor: \d+(\.\d{1,3})?(ms|s)$/.test(strings.shift().trim()));
252assert.ok(/^hasOwnProperty: \d+(\.\d{1,3})?(ms|s)$/.test(strings.shift().trim()));
253
254// Verify that console.time() coerces label values to strings as expected
255assert.ok(/^: \d+(\.\d{1,3})?(ms|s)$/.test(strings.shift().trim()));
256assert.ok(/^\[object Object\]: \d+(\.\d{1,3})?(ms|s)$/.test(strings.shift().trim()));
257assert.ok(/^\[object Object\]: \d+(\.\d{1,3})?(ms|s)$/.test(strings.shift().trim()));
258assert.ok(/^null: \d+(\.\d{1,3})?(ms|s)$/.test(strings.shift().trim()));
259assert.ok(/^default: \d+(\.\d{1,3})?(ms|s)$/.test(strings.shift().trim()));
260assert.ok(/^default: \d+(\.\d{1,3})?(ms|s)$/.test(strings.shift().trim()));
261assert.ok(/^NaN: \d+(\.\d{1,3})?(ms|s)$/.test(strings.shift().trim()));
262
263assert.ok(/^log1: \d+(\.\d{1,3})?(ms|s)$/.test(strings.shift().trim()));
264assert.ok(/^log1: \d+(\.\d{1,3})?(ms|s) test$/.test(strings.shift().trim()));
265assert.ok(/^log1: \d+(\.\d{1,3})?(ms|s) {} \[ 1, 2, 3 ]$/.test(strings.shift().trim()));
266assert.ok(/^log1: \d+(\.\d{1,3})?(ms|s)$/.test(strings.shift().trim()));
267
268// Make sure that we checked all strings
269assert.strictEqual(strings.length, 0);
270
271assert.strictEqual(errStrings.shift().split('\n').shift(),
272                   'Trace: This is a {"formatted":"trace"} 10 foo');
273
274// Hijack stderr to catch `process.emitWarning` which is using
275// `process.nextTick`
276hijackStderr(common.mustCall(function(data) {
277  restoreStderr();
278
279  // stderr.write will catch sync error, so use `process.nextTick` here
280  process.nextTick(function() {
281    assert.strictEqual(data.includes('noLabel'), true);
282  });
283}));
284