• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Flags: --expose-internals
2// Copyright Joyent, Inc. and other Node contributors.
3//
4// Permission is hereby granted, free of charge, to any person obtaining a
5// copy of this software and associated documentation files (the
6// "Software"), to deal in the Software without restriction, including
7// without limitation the rights to use, copy, modify, merge, publish,
8// distribute, sublicense, and/or sell copies of the Software, and to permit
9// persons to whom the Software is furnished to do so, subject to the
10// following conditions:
11//
12// The above copyright notice and this permission notice shall be included
13// in all copies or substantial portions of the Software.
14//
15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
18// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
19// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21// USE OR OTHER DEALINGS IN THE SOFTWARE.
22'use strict';
23const common = require('../common');
24const assert = require('assert');
25const { internalBinding } = require('internal/test/binding');
26const JSStream = internalBinding('js_stream').JSStream;
27const util = require('util');
28const vm = require('vm');
29const v8 = require('v8');
30const { previewEntries } = internalBinding('util');
31const { inspect } = util;
32const { MessageChannel } = require('worker_threads');
33const url = require('url');
34
35assert.strictEqual(util.inspect(1), '1');
36assert.strictEqual(util.inspect(false), 'false');
37assert.strictEqual(util.inspect(''), "''");
38assert.strictEqual(util.inspect('hello'), "'hello'");
39assert.strictEqual(util.inspect(function abc() {}), '[Function: abc]');
40assert.strictEqual(util.inspect(() => {}), '[Function (anonymous)]');
41assert.strictEqual(
42  util.inspect(async function() {}),
43  '[AsyncFunction (anonymous)]'
44);
45assert.strictEqual(util.inspect(async () => {}), '[AsyncFunction (anonymous)]');
46
47// Special function inspection.
48{
49  const fn = (() => function*() {})();
50  assert.strictEqual(
51    util.inspect(fn),
52    '[GeneratorFunction (anonymous)]'
53  );
54  assert.strictEqual(
55    util.inspect(async function* abc() {}),
56    '[AsyncGeneratorFunction: abc]'
57  );
58  Object.setPrototypeOf(fn, Object.getPrototypeOf(async () => {}));
59  assert.strictEqual(
60    util.inspect(fn),
61    '[GeneratorFunction (anonymous)] AsyncFunction'
62  );
63  Object.defineProperty(fn, 'name', { value: 5, configurable: true });
64  assert.strictEqual(
65    util.inspect(fn),
66    '[GeneratorFunction: 5] AsyncFunction'
67  );
68  Object.defineProperty(fn, Symbol.toStringTag, {
69    value: 'Foobar',
70    configurable: true
71  });
72  assert.strictEqual(
73    util.inspect({ ['5']: fn }),
74    "{ '5': [GeneratorFunction: 5] AsyncFunction [Foobar] }"
75  );
76  Object.defineProperty(fn, 'name', { value: '5', configurable: true });
77  Object.setPrototypeOf(fn, null);
78  assert.strictEqual(
79    util.inspect(fn),
80    '[GeneratorFunction (null prototype): 5] [Foobar]'
81  );
82  assert.strictEqual(
83    util.inspect({ ['5']: fn }),
84    "{ '5': [GeneratorFunction (null prototype): 5] [Foobar] }"
85  );
86}
87
88assert.strictEqual(util.inspect(undefined), 'undefined');
89assert.strictEqual(util.inspect(null), 'null');
90assert.strictEqual(util.inspect(/foo(bar\n)?/gi), '/foo(bar\\n)?/gi');
91assert.strictEqual(
92  util.inspect(new Date('Sun, 14 Feb 2010 11:48:40 GMT')),
93  new Date('2010-02-14T12:48:40+01:00').toISOString()
94);
95assert.strictEqual(util.inspect(new Date('')), (new Date('')).toString());
96assert.strictEqual(util.inspect('\n\x01'), "'\\n\\x01'");
97assert.strictEqual(
98  util.inspect(`${Array(75).fill(1)}'\n\x1d\n\x03\x85\x7f\x7e\x9f\xa0`),
99  // eslint-disable-next-line no-irregular-whitespace
100  `"${Array(75).fill(1)}'\\n" +\n  '\\x1D\\n' +\n  '\\x03\\x85\\x7F~\\x9F '`
101);
102assert.strictEqual(util.inspect([]), '[]');
103assert.strictEqual(util.inspect(Object.create([])), 'Array {}');
104assert.strictEqual(util.inspect([1, 2]), '[ 1, 2 ]');
105assert.strictEqual(util.inspect([1, [2, 3]]), '[ 1, [ 2, 3 ] ]');
106assert.strictEqual(util.inspect({}), '{}');
107assert.strictEqual(util.inspect({ a: 1 }), '{ a: 1 }');
108assert.strictEqual(util.inspect({ a: function() {} }), '{ a: [Function: a] }');
109assert.strictEqual(util.inspect({ a: () => {} }), '{ a: [Function: a] }');
110// eslint-disable-next-line func-name-matching
111assert.strictEqual(util.inspect({ a: async function abc() {} }),
112                   '{ a: [AsyncFunction: abc] }');
113assert.strictEqual(util.inspect({ a: async () => {} }),
114                   '{ a: [AsyncFunction: a] }');
115assert.strictEqual(util.inspect({ a: function*() {} }),
116                   '{ a: [GeneratorFunction: a] }');
117assert.strictEqual(util.inspect({ a: 1, b: 2 }), '{ a: 1, b: 2 }');
118assert.strictEqual(util.inspect({ 'a': {} }), '{ a: {} }');
119assert.strictEqual(util.inspect({ 'a': { 'b': 2 } }), '{ a: { b: 2 } }');
120assert.strictEqual(util.inspect({ 'a': { 'b': { 'c': { 'd': 2 } } } }),
121                   '{ a: { b: { c: [Object] } } }');
122assert.strictEqual(
123  util.inspect({ 'a': { 'b': { 'c': { 'd': 2 } } } }, false, null),
124  '{\n  a: { b: { c: { d: 2 } } }\n}');
125assert.strictEqual(util.inspect([1, 2, 3], true), '[ 1, 2, 3, [length]: 3 ]');
126assert.strictEqual(util.inspect({ 'a': { 'b': { 'c': 2 } } }, false, 0),
127                   '{ a: [Object] }');
128assert.strictEqual(util.inspect({ 'a': { 'b': { 'c': 2 } } }, false, 1),
129                   '{ a: { b: [Object] } }');
130assert.strictEqual(util.inspect({ 'a': { 'b': ['c'] } }, false, 1),
131                   '{ a: { b: [Array] } }');
132assert.strictEqual(util.inspect(new Uint8Array(0)), 'Uint8Array(0) []');
133assert(inspect(new Uint8Array(0), { showHidden: true }).includes('[buffer]'));
134assert.strictEqual(
135  util.inspect(
136    Object.create(
137      {},
138      { visible: { value: 1, enumerable: true }, hidden: { value: 2 } }
139    )
140  ),
141  '{ visible: 1 }'
142);
143assert.strictEqual(
144  util.inspect(
145    Object.assign(new String('hello'), { [Symbol('foo')]: 123 }),
146    { showHidden: true }
147  ),
148  "[String: 'hello'] { [length]: 5, [Symbol(foo)]: 123 }"
149);
150
151assert.match(util.inspect((new JSStream())._externalStream),
152             /^\[External: [0-9a-f]+\]$/);
153
154{
155  const regexp = /regexp/;
156  regexp.aprop = 42;
157  assert.strictEqual(util.inspect({ a: regexp }, false, 0), '{ a: /regexp/ }');
158}
159
160assert.match(
161  util.inspect({ a: { a: { a: { a: {} } } } }, undefined, undefined, true),
162  /Object/
163);
164assert.doesNotMatch(
165  util.inspect({ a: { a: { a: { a: {} } } } }, undefined, null, true),
166  /Object/
167);
168
169{
170  const showHidden = true;
171  const ab = new Uint8Array([1, 2, 3, 4]).buffer;
172  const dv = new DataView(ab, 1, 2);
173  assert.strictEqual(
174    util.inspect(ab, showHidden),
175    'ArrayBuffer { [Uint8Contents]: <01 02 03 04>, byteLength: 4 }'
176  );
177  assert.strictEqual(util.inspect(new DataView(ab, 1, 2), showHidden),
178                     'DataView {\n' +
179                     '  byteLength: 2,\n' +
180                     '  byteOffset: 1,\n' +
181                     '  buffer: ArrayBuffer {' +
182                      ' [Uint8Contents]: <01 02 03 04>, byteLength: 4 }\n}');
183  assert.strictEqual(
184    util.inspect(ab, showHidden),
185    'ArrayBuffer { [Uint8Contents]: <01 02 03 04>, byteLength: 4 }'
186  );
187  assert.strictEqual(util.inspect(dv, showHidden),
188                     'DataView {\n' +
189                     '  byteLength: 2,\n' +
190                     '  byteOffset: 1,\n' +
191                     '  buffer: ArrayBuffer { [Uint8Contents]: ' +
192                       '<01 02 03 04>, byteLength: 4 }\n}');
193  ab.x = 42;
194  dv.y = 1337;
195  assert.strictEqual(util.inspect(ab, showHidden),
196                     'ArrayBuffer { [Uint8Contents]: <01 02 03 04>, ' +
197                       'byteLength: 4, x: 42 }');
198  assert.strictEqual(util.inspect(dv, showHidden),
199                     'DataView {\n' +
200                     '  byteLength: 2,\n' +
201                     '  byteOffset: 1,\n' +
202                     '  buffer: ArrayBuffer { [Uint8Contents]: <01 02 03 04>,' +
203                       ' byteLength: 4, x: 42 },\n' +
204                     '  y: 1337\n}');
205}
206
207{
208  const ab = new ArrayBuffer(42);
209  assert.strictEqual(ab.byteLength, 42);
210  new MessageChannel().port1.postMessage(ab, [ ab ]);
211  assert.strictEqual(ab.byteLength, 0);
212  assert.strictEqual(util.inspect(ab),
213                     'ArrayBuffer { (detached), byteLength: 0 }');
214}
215
216// Truncate output for ArrayBuffers using plural or singular bytes
217{
218  const ab = new ArrayBuffer(3);
219  assert.strictEqual(util.inspect(ab, { showHidden: true, maxArrayLength: 2 }),
220                     'ArrayBuffer { [Uint8Contents]' +
221                      ': <00 00 ... 1 more byte>, byteLength: 3 }');
222  assert.strictEqual(util.inspect(ab, { showHidden: true, maxArrayLength: 1 }),
223                     'ArrayBuffer { [Uint8Contents]' +
224                      ': <00 ... 2 more bytes>, byteLength: 3 }');
225}
226
227// Now do the same checks but from a different context.
228{
229  const showHidden = false;
230  const ab = vm.runInNewContext('new ArrayBuffer(4)');
231  const dv = vm.runInNewContext('new DataView(ab, 1, 2)', { ab });
232  assert.strictEqual(
233    util.inspect(ab, showHidden),
234    'ArrayBuffer { [Uint8Contents]: <00 00 00 00>, byteLength: 4 }'
235  );
236  assert.strictEqual(util.inspect(new DataView(ab, 1, 2), showHidden),
237                     'DataView {\n' +
238                     '  byteLength: 2,\n' +
239                     '  byteOffset: 1,\n' +
240                     '  buffer: ArrayBuffer { [Uint8Contents]: <00 00 00 00>,' +
241                       ' byteLength: 4 }\n}');
242  assert.strictEqual(
243    util.inspect(ab, showHidden),
244    'ArrayBuffer { [Uint8Contents]: <00 00 00 00>, byteLength: 4 }'
245  );
246  assert.strictEqual(util.inspect(dv, showHidden),
247                     'DataView {\n' +
248                     '  byteLength: 2,\n' +
249                     '  byteOffset: 1,\n' +
250                     '  buffer: ArrayBuffer { [Uint8Contents]: <00 00 00 00>,' +
251                       ' byteLength: 4 }\n}');
252  ab.x = 42;
253  dv.y = 1337;
254  assert.strictEqual(util.inspect(ab, showHidden),
255                     'ArrayBuffer { [Uint8Contents]: <00 00 00 00>, ' +
256                       'byteLength: 4, x: 42 }');
257  assert.strictEqual(util.inspect(dv, showHidden),
258                     'DataView {\n' +
259                     '  byteLength: 2,\n' +
260                     '  byteOffset: 1,\n' +
261                     '  buffer: ArrayBuffer { [Uint8Contents]: <00 00 00 00>,' +
262                       ' byteLength: 4, x: 42 },\n' +
263                     '  y: 1337\n}');
264}
265
266[ Float32Array,
267  Float64Array,
268  Int16Array,
269  Int32Array,
270  Int8Array,
271  Uint16Array,
272  Uint32Array,
273  Uint8Array,
274  Uint8ClampedArray ].forEach((constructor) => {
275  const length = 2;
276  const byteLength = length * constructor.BYTES_PER_ELEMENT;
277  const array = new constructor(new ArrayBuffer(byteLength), 0, length);
278  array[0] = 65;
279  array[1] = 97;
280  assert.strictEqual(
281    util.inspect(array, { showHidden: true }),
282    `${constructor.name}(${length}) [\n` +
283      '  65,\n' +
284      '  97,\n' +
285      `  [BYTES_PER_ELEMENT]: ${constructor.BYTES_PER_ELEMENT},\n` +
286      `  [length]: ${length},\n` +
287      `  [byteLength]: ${byteLength},\n` +
288      '  [byteOffset]: 0,\n' +
289      `  [buffer]: ArrayBuffer { byteLength: ${byteLength} }\n]`);
290  assert.strictEqual(
291    util.inspect(array, false),
292    `${constructor.name}(${length}) [ 65, 97 ]`
293  );
294});
295
296// Now check that declaring a TypedArray in a different context works the same.
297[ Float32Array,
298  Float64Array,
299  Int16Array,
300  Int32Array,
301  Int8Array,
302  Uint16Array,
303  Uint32Array,
304  Uint8Array,
305  Uint8ClampedArray ].forEach((constructor) => {
306  const length = 2;
307  const byteLength = length * constructor.BYTES_PER_ELEMENT;
308  const array = vm.runInNewContext(
309    'new constructor(new ArrayBuffer(byteLength), 0, length)',
310    { constructor, byteLength, length }
311  );
312  array[0] = 65;
313  array[1] = 97;
314  assert.strictEqual(
315    util.inspect(array, true),
316    `${constructor.name}(${length}) [\n` +
317      '  65,\n' +
318      '  97,\n' +
319      `  [BYTES_PER_ELEMENT]: ${constructor.BYTES_PER_ELEMENT},\n` +
320      `  [length]: ${length},\n` +
321      `  [byteLength]: ${byteLength},\n` +
322      '  [byteOffset]: 0,\n' +
323      `  [buffer]: ArrayBuffer { byteLength: ${byteLength} }\n]`);
324  assert.strictEqual(
325    util.inspect(array, false),
326    `${constructor.name}(${length}) [ 65, 97 ]`
327  );
328});
329
330{
331  const brokenLength = new Float32Array(2);
332  Object.defineProperty(brokenLength, 'length', { value: -1 });
333  assert.strictEqual(inspect(brokenLength), 'Float32Array(2) [ 0n, 0n ]');
334}
335
336assert.strictEqual(
337  util.inspect(Object.create({}, {
338    visible: { value: 1, enumerable: true },
339    hidden: { value: 2 }
340  }), { showHidden: true }),
341  '{ visible: 1, [hidden]: 2 }'
342);
343// Objects without prototype.
344assert.strictEqual(
345  util.inspect(Object.create(null, {
346    name: { value: 'Tim', enumerable: true },
347    hidden: { value: 'secret' }
348  }), { showHidden: true }),
349  "[Object: null prototype] { name: 'Tim', [hidden]: 'secret' }"
350);
351
352assert.strictEqual(
353  util.inspect(Object.create(null, {
354    name: { value: 'Tim', enumerable: true },
355    hidden: { value: 'secret' }
356  })),
357  "[Object: null prototype] { name: 'Tim' }"
358);
359
360// Dynamic properties.
361{
362  assert.strictEqual(
363    util.inspect({ get readonly() { return 1; } }),
364    '{ readonly: [Getter] }');
365
366  assert.strictEqual(
367    util.inspect({ get readwrite() { return 1; }, set readwrite(val) {} }),
368    '{ readwrite: [Getter/Setter] }');
369
370  assert.strictEqual(
371    // eslint-disable-next-line accessor-pairs
372    util.inspect({ set writeonly(val) {} }),
373    '{ writeonly: [Setter] }');
374
375  const value = {};
376  value.a = value;
377  assert.strictEqual(util.inspect(value), '<ref *1> { a: [Circular *1] }');
378  const getterFn = {
379    get one() {
380      return null;
381    }
382  };
383  assert.strictEqual(
384    util.inspect(getterFn, { getters: true }),
385    '{ one: [Getter: null] }'
386  );
387}
388
389// Array with dynamic properties.
390{
391  const value = [1, 2, 3];
392  Object.defineProperty(
393    value,
394    'growingLength',
395    {
396      enumerable: true,
397      get: function() { this.push(true); return this.length; }
398    }
399  );
400  Object.defineProperty(
401    value,
402    '-1',
403    {
404      enumerable: true,
405      value: -1
406    }
407  );
408  assert.strictEqual(util.inspect(value),
409                     "[ 1, 2, 3, growingLength: [Getter], '-1': -1 ]");
410}
411
412// Array with inherited number properties.
413{
414  class CustomArray extends Array {}
415  CustomArray.prototype[5] = 'foo';
416  CustomArray.prototype[49] = 'bar';
417  CustomArray.prototype.foo = true;
418  const arr = new CustomArray(50);
419  arr[49] = 'I win';
420  assert.strictEqual(
421    util.inspect(arr),
422    "CustomArray(50) [ <49 empty items>, 'I win' ]"
423  );
424  assert.strictEqual(
425    util.inspect(arr, { showHidden: true }),
426    'CustomArray(50) [\n' +
427    '  <49 empty items>,\n' +
428    "  'I win',\n" +
429    '  [length]: 50,\n' +
430    "  '5': 'foo',\n" +
431    '  foo: true\n' +
432    ']'
433  );
434}
435
436// Array with extra properties.
437{
438  const arr = [1, 2, 3, , ]; // eslint-disable-line no-sparse-arrays
439  arr.foo = 'bar';
440  assert.strictEqual(util.inspect(arr),
441                     "[ 1, 2, 3, <1 empty item>, foo: 'bar' ]");
442
443  const arr2 = [];
444  assert.strictEqual(util.inspect([], { showHidden: true }), '[ [length]: 0 ]');
445  arr2['00'] = 1;
446  assert.strictEqual(util.inspect(arr2), "[ '00': 1 ]");
447  assert.strictEqual(util.inspect(arr2, { showHidden: true }),
448                     "[ [length]: 0, '00': 1 ]");
449  arr2[1] = 0;
450  assert.strictEqual(util.inspect(arr2), "[ <1 empty item>, 0, '00': 1 ]");
451  assert.strictEqual(util.inspect(arr2, { showHidden: true }),
452                     "[ <1 empty item>, 0, [length]: 2, '00': 1 ]");
453  delete arr2[1];
454  assert.strictEqual(util.inspect(arr2), "[ <2 empty items>, '00': 1 ]");
455  assert.strictEqual(util.inspect(arr2, { showHidden: true }),
456                     "[ <2 empty items>, [length]: 2, '00': 1 ]");
457  arr2['01'] = 2;
458  assert.strictEqual(util.inspect(arr2),
459                     "[ <2 empty items>, '00': 1, '01': 2 ]");
460  assert.strictEqual(util.inspect(arr2, { showHidden: true }),
461                     "[ <2 empty items>, [length]: 2, '00': 1, '01': 2 ]");
462  delete arr2['00'];
463  arr2[0] = 0;
464  assert.strictEqual(util.inspect(arr2),
465                     "[ 0, <1 empty item>, '01': 2 ]");
466  assert.strictEqual(util.inspect(arr2, { showHidden: true }),
467                     "[ 0, <1 empty item>, [length]: 2, '01': 2 ]");
468  delete arr2['01'];
469  arr2[2 ** 32 - 2] = 'max';
470  arr2[2 ** 32 - 1] = 'too far';
471  assert.strictEqual(
472    util.inspect(arr2),
473    "[ 0, <4294967293 empty items>, 'max', '4294967295': 'too far' ]"
474  );
475
476  const arr3 = [];
477  arr3[-1] = -1;
478  assert.strictEqual(util.inspect(arr3), "[ '-1': -1 ]");
479}
480
481// Indices out of bounds.
482{
483  const arr = [];
484  arr[2 ** 32] = true; // Not a valid array index.
485  assert.strictEqual(util.inspect(arr), "[ '4294967296': true ]");
486  arr[0] = true;
487  arr[10] = true;
488  assert.strictEqual(util.inspect(arr),
489                     "[ true, <9 empty items>, true, '4294967296': true ]");
490  arr[2 ** 32 - 2] = true;
491  arr[2 ** 32 - 1] = true;
492  arr[2 ** 32 + 1] = true;
493  delete arr[0];
494  delete arr[10];
495  assert.strictEqual(util.inspect(arr),
496                     ['[',
497                      '<4294967294 empty items>,',
498                      'true,',
499                      "'4294967296': true,",
500                      "'4294967295': true,",
501                      "'4294967297': true\n]",
502                     ].join('\n  '));
503}
504
505// Function with properties.
506{
507  const value = () => {};
508  value.aprop = 42;
509  assert.strictEqual(util.inspect(value), '[Function: value] { aprop: 42 }');
510}
511
512// Anonymous function with properties.
513{
514  const value = (() => function() {})();
515  value.aprop = 42;
516  assert.strictEqual(
517    util.inspect(value),
518    '[Function (anonymous)] { aprop: 42 }'
519  );
520}
521
522// Regular expressions with properties.
523{
524  const value = /123/ig;
525  value.aprop = 42;
526  assert.strictEqual(util.inspect(value), '/123/gi { aprop: 42 }');
527}
528
529// Dates with properties.
530{
531  const value = new Date('Sun, 14 Feb 2010 11:48:40 GMT');
532  value.aprop = 42;
533  assert.strictEqual(util.inspect(value),
534                     '2010-02-14T11:48:40.000Z { aprop: 42 }');
535}
536
537// Test the internal isDate implementation.
538{
539  const Date2 = vm.runInNewContext('Date');
540  const d = new Date2();
541  const orig = util.inspect(d);
542  Date2.prototype.foo = 'bar';
543  const after = util.inspect(d);
544  assert.strictEqual(orig, after);
545}
546
547// Test positive/negative zero.
548assert.strictEqual(util.inspect(0), '0');
549assert.strictEqual(util.inspect(-0), '-0');
550// Edge case from check.
551assert.strictEqual(util.inspect(-5e-324), '-5e-324');
552
553// Test for sparse array.
554{
555  const a = ['foo', 'bar', 'baz'];
556  assert.strictEqual(util.inspect(a), "[ 'foo', 'bar', 'baz' ]");
557  delete a[1];
558  assert.strictEqual(util.inspect(a), "[ 'foo', <1 empty item>, 'baz' ]");
559  assert.strictEqual(
560    util.inspect(a, true),
561    "[ 'foo', <1 empty item>, 'baz', [length]: 3 ]"
562  );
563  assert.strictEqual(util.inspect(new Array(5)), '[ <5 empty items> ]');
564  a[3] = 'bar';
565  a[100] = 'qux';
566  assert.strictEqual(
567    util.inspect(a, { breakLength: Infinity }),
568    "[ 'foo', <1 empty item>, 'baz', 'bar', <96 empty items>, 'qux' ]"
569  );
570  delete a[3];
571  assert.strictEqual(
572    util.inspect(a, { maxArrayLength: 4 }),
573    "[ 'foo', <1 empty item>, 'baz', <97 empty items>, ... 1 more item ]"
574  );
575  // test 4 special case
576  assert.strictEqual(util.inspect(a, {
577    maxArrayLength: 2
578  }), "[ 'foo', <1 empty item>, ... 99 more items ]");
579}
580
581// Test for Array constructor in different context.
582{
583  const map = new Map();
584  map.set(1, 2);
585  // Passing only a single argument to indicate a set iterator.
586  const valsSetIterator = previewEntries(map.entries());
587  // Passing through true to indicate a map iterator.
588  const valsMapIterEntries = previewEntries(map.entries(), true);
589  const valsMapIterKeys = previewEntries(map.keys(), true);
590
591  assert.strictEqual(util.inspect(valsSetIterator), '[ 1, 2 ]');
592  assert.strictEqual(util.inspect(valsMapIterEntries), '[ [ 1, 2 ], true ]');
593  assert.strictEqual(util.inspect(valsMapIterKeys), '[ [ 1 ], false ]');
594}
595
596// Test for other constructors in different context.
597{
598  let obj = vm.runInNewContext('(function(){return {}})()', {});
599  assert.strictEqual(util.inspect(obj), '{}');
600  obj = vm.runInNewContext('const m=new Map();m.set(1,2);m', {});
601  assert.strictEqual(util.inspect(obj), 'Map(1) { 1 => 2 }');
602  obj = vm.runInNewContext('const s=new Set();s.add(1);s.add(2);s', {});
603  assert.strictEqual(util.inspect(obj), 'Set(2) { 1, 2 }');
604  obj = vm.runInNewContext('fn=function(){};new Promise(fn,fn)', {});
605  assert.strictEqual(util.inspect(obj), 'Promise { <pending> }');
606}
607
608// Test for property descriptors.
609{
610  const getter = Object.create(null, {
611    a: {
612      get: function() { return 'aaa'; }
613    }
614  });
615  const setter = Object.create(null, {
616    b: { // eslint-disable-line accessor-pairs
617      set: function() {}
618    }
619  });
620  const getterAndSetter = Object.create(null, {
621    c: {
622      get: function() { return 'ccc'; },
623      set: function() {}
624    }
625  });
626  assert.strictEqual(
627    util.inspect(getter, true),
628    '[Object: null prototype] { [a]: [Getter] }'
629  );
630  assert.strictEqual(
631    util.inspect(setter, true),
632    '[Object: null prototype] { [b]: [Setter] }'
633  );
634  assert.strictEqual(
635    util.inspect(getterAndSetter, true),
636    '[Object: null prototype] { [c]: [Getter/Setter] }'
637  );
638}
639
640// Exceptions should print the error message, not '{}'.
641{
642  [
643    new Error(),
644    new Error('FAIL'),
645    new TypeError('FAIL'),
646    new SyntaxError('FAIL'),
647  ].forEach((err) => {
648    assert.strictEqual(util.inspect(err), err.stack);
649  });
650  assert.throws(
651    () => undef(), // eslint-disable-line no-undef
652    (e) => {
653      assert.strictEqual(util.inspect(e), e.stack);
654      return true;
655    }
656  );
657
658  const ex = util.inspect(new Error('FAIL'), true);
659  assert(ex.includes('Error: FAIL'));
660  assert(ex.includes('[stack]'));
661  assert(ex.includes('[message]'));
662}
663
664{
665  const falsyCause1 = new Error('', { cause: false });
666  delete falsyCause1.stack;
667  const falsyCause2 = new Error(undefined, { cause: null });
668  falsyCause2.stack = '';
669  const undefinedCause = new Error('', { cause: undefined });
670  undefinedCause.stack = '';
671
672  assert.strictEqual(util.inspect(falsyCause1), '[Error] { [cause]: false }');
673  assert.strictEqual(util.inspect(falsyCause2), '[Error] { [cause]: null }');
674  assert.strictEqual(
675    util.inspect(undefinedCause),
676    '[Error] { [cause]: undefined }'
677  );
678}
679
680{
681  const tmp = Error.stackTraceLimit;
682  Error.stackTraceLimit = 0;
683  const err = new Error('foo');
684  const err2 = new Error('foo\nbar');
685  assert.strictEqual(util.inspect(err, { compact: true }), '[Error: foo]');
686  assert(err.stack);
687  delete err.stack;
688  assert(!err.stack);
689  assert.strictEqual(util.inspect(err, { compact: true }), '[Error: foo]');
690  assert.strictEqual(
691    util.inspect(err2, { compact: true }),
692    '[Error: foo\nbar]'
693  );
694
695  err.bar = true;
696  err2.bar = true;
697
698  assert.strictEqual(
699    util.inspect(err, { compact: true }),
700    '{ [Error: foo] bar: true }'
701  );
702  assert.strictEqual(
703    util.inspect(err2, { compact: true }),
704    '{ [Error: foo\nbar]\n  bar: true }'
705  );
706  assert.strictEqual(
707    util.inspect(err, { compact: true, breakLength: 5 }),
708    '{ [Error: foo]\n  bar: true }'
709  );
710  assert.strictEqual(
711    util.inspect(err, { compact: true, breakLength: 1 }),
712    '{ [Error: foo]\n  bar:\n   true }'
713  );
714  assert.strictEqual(
715    util.inspect(err2, { compact: true, breakLength: 5 }),
716    '{ [Error: foo\nbar]\n  bar: true }'
717  );
718  assert.strictEqual(
719    util.inspect(err, { compact: false }),
720    '[Error: foo] {\n  bar: true\n}'
721  );
722  assert.strictEqual(
723    util.inspect(err2, { compact: false }),
724    '[Error: foo\nbar] {\n  bar: true\n}'
725  );
726
727  Error.stackTraceLimit = tmp;
728}
729
730// Prevent enumerable error properties from being printed.
731{
732  let err = new Error();
733  err.message = 'foobar';
734  let out = util.inspect(err).split('\n');
735  assert.strictEqual(out[0], 'Error: foobar');
736  assert(out[out.length - 1].startsWith('    at '));
737  // Reset the error, the stack is otherwise not recreated.
738  err = new Error();
739  err.message = 'foobar';
740  err.name = 'Unique';
741  Object.defineProperty(err, 'stack', { value: err.stack, enumerable: true });
742  out = util.inspect(err).split('\n');
743  assert.strictEqual(out[0], 'Unique: foobar');
744  assert(out[out.length - 1].startsWith('    at '));
745  err.name = 'Baz';
746  out = util.inspect(err).split('\n');
747  assert.strictEqual(out[0], 'Unique: foobar');
748  assert.strictEqual(out[out.length - 2], "  name: 'Baz'");
749  assert.strictEqual(out[out.length - 1], '}');
750}
751
752// Doesn't capture stack trace.
753{
754  function BadCustomError(msg) {
755    Error.call(this);
756    Object.defineProperty(this, 'message',
757                          { value: msg, enumerable: false });
758    Object.defineProperty(this, 'name',
759                          { value: 'BadCustomError', enumerable: false });
760  }
761  Object.setPrototypeOf(BadCustomError.prototype, Error.prototype);
762  Object.setPrototypeOf(BadCustomError, Error);
763  assert.strictEqual(
764    util.inspect(new BadCustomError('foo')),
765    '[BadCustomError: foo]'
766  );
767}
768
769// Tampered error stack or name property (different type than string).
770// Note: Symbols are not supported by `Error#toString()` which is called by
771// accessing the `stack` property.
772[
773  [404, '404: foo', '[404]'],
774  [0, '0: foo', '[RangeError: foo]'],
775  [0n, '0: foo', '[RangeError: foo]'],
776  [null, 'null: foo', '[RangeError: foo]'],
777  [undefined, 'RangeError: foo', '[RangeError: foo]'],
778  [false, 'false: foo', '[RangeError: foo]'],
779  ['', 'foo', '[RangeError: foo]'],
780  [[1, 2, 3], '1,2,3: foo', '[1,2,3]'],
781].forEach(([value, outputStart, stack]) => {
782  let err = new RangeError('foo');
783  err.name = value;
784  assert(
785    util.inspect(err).startsWith(outputStart),
786    util.format(
787      'The name set to %o did not result in the expected output "%s"',
788      value,
789      outputStart
790    )
791  );
792
793  err = new RangeError('foo');
794  err.stack = value;
795  assert.strictEqual(util.inspect(err), stack);
796});
797
798// https://github.com/nodejs/node-v0.x-archive/issues/1941
799assert.strictEqual(util.inspect(Object.create(Date.prototype)), 'Date {}');
800
801// https://github.com/nodejs/node-v0.x-archive/issues/1944
802{
803  const d = new Date();
804  d.toUTCString = null;
805  util.inspect(d);
806}
807
808// Should not throw.
809{
810  const d = new Date();
811  d.toISOString = null;
812  util.inspect(d);
813}
814
815// Should not throw.
816{
817  const r = /regexp/;
818  r.toString = null;
819  util.inspect(r);
820}
821
822// See https://github.com/nodejs/node-v0.x-archive/issues/2225
823{
824  const x = { [util.inspect.custom]: util.inspect };
825  assert(util.inspect(x).includes(
826    '[Symbol(nodejs.util.inspect.custom)]: [Function: inspect] {\n'));
827}
828
829// `util.inspect` should display the escaped value of a key.
830{
831  const w = {
832    '\\': 1,
833    '\\\\': 2,
834    '\\\\\\': 3,
835    '\\\\\\\\': 4,
836    '\n': 5,
837    '\r': 6
838  };
839
840  const y = ['a', 'b', 'c'];
841  y['\\\\'] = 'd';
842  y['\n'] = 'e';
843  y['\r'] = 'f';
844
845  assert.strictEqual(
846    util.inspect(w),
847    "{ '\\\\': 1, '\\\\\\\\': 2, '\\\\\\\\\\\\': 3, " +
848    "'\\\\\\\\\\\\\\\\': 4, '\\n': 5, '\\r': 6 }"
849  );
850  assert.strictEqual(
851    util.inspect(y),
852    "[ 'a', 'b', 'c', '\\\\\\\\': 'd', " +
853    "'\\n': 'e', '\\r': 'f' ]"
854  );
855}
856
857// Escape unpaired surrogate pairs.
858{
859  const edgeChar = String.fromCharCode(0xd799);
860
861  for (let charCode = 0xD800; charCode < 0xDFFF; charCode++) {
862    const surrogate = String.fromCharCode(charCode);
863
864    assert.strictEqual(
865      util.inspect(surrogate),
866      `'\\u${charCode.toString(16)}'`
867    );
868    assert.strictEqual(
869      util.inspect(`${'a'.repeat(200)}${surrogate}`),
870      `'${'a'.repeat(200)}\\u${charCode.toString(16)}'`
871    );
872    assert.strictEqual(
873      util.inspect(`${surrogate}${'a'.repeat(200)}`),
874      `'\\u${charCode.toString(16)}${'a'.repeat(200)}'`
875    );
876    if (charCode < 0xdc00) {
877      const highSurrogate = surrogate;
878      const lowSurrogate = String.fromCharCode(charCode + 1024);
879      assert(
880        !util.inspect(
881          `${edgeChar}${highSurrogate}${lowSurrogate}${edgeChar}`
882        ).includes('\\u')
883      );
884      assert.strictEqual(
885        (util.inspect(
886          `${highSurrogate}${highSurrogate}${lowSurrogate}`
887        ).match(/\\u/g) ?? []).length,
888        1
889      );
890    } else {
891      assert.strictEqual(
892        util.inspect(`${edgeChar}${surrogate}${edgeChar}`),
893        `'${edgeChar}\\u${charCode.toString(16)}${edgeChar}'`
894      );
895    }
896  }
897}
898
899// Test util.inspect.styles and util.inspect.colors.
900{
901  function testColorStyle(style, input) {
902    const colorName = util.inspect.styles[style];
903    let color = ['', ''];
904    if (util.inspect.colors[colorName])
905      color = util.inspect.colors[colorName];
906
907    const withoutColor = util.inspect(input, false, 0, false);
908    const withColor = util.inspect(input, false, 0, true);
909    const expect = `\u001b[${color[0]}m${withoutColor}\u001b[${color[1]}m`;
910    assert.strictEqual(
911      withColor,
912      expect,
913      `util.inspect color for style ${style}`);
914  }
915
916  testColorStyle('special', function() {});
917  testColorStyle('number', 123.456);
918  testColorStyle('boolean', true);
919  testColorStyle('undefined', undefined);
920  testColorStyle('null', null);
921  testColorStyle('string', 'test string');
922  testColorStyle('date', new Date());
923  testColorStyle('regexp', /regexp/);
924}
925
926// An object with "hasOwnProperty" overwritten should not throw.
927util.inspect({ hasOwnProperty: null });
928
929// New API, accepts an "options" object.
930{
931  const subject = { foo: 'bar', hello: 31, a: { b: { c: { d: 0 } } } };
932  Object.defineProperty(subject, 'hidden', { enumerable: false, value: null });
933
934  assert.strictEqual(
935    util.inspect(subject, { showHidden: false }).includes('hidden'),
936    false
937  );
938  assert.strictEqual(
939    util.inspect(subject, { showHidden: true }).includes('hidden'),
940    true
941  );
942  assert.strictEqual(
943    util.inspect(subject, { colors: false }).includes('\u001b[32m'),
944    false
945  );
946  assert.strictEqual(
947    util.inspect(subject, { colors: true }).includes('\u001b[32m'),
948    true
949  );
950  assert.strictEqual(
951    util.inspect(subject, { depth: 2 }).includes('c: [Object]'),
952    true
953  );
954  assert.strictEqual(
955    util.inspect(subject, { depth: 0 }).includes('a: [Object]'),
956    true
957  );
958  assert.strictEqual(
959    util.inspect(subject, { depth: null }).includes('{ d: 0 }'),
960    true
961  );
962  assert.strictEqual(
963    util.inspect(subject, { depth: undefined }).includes('{ d: 0 }'),
964    true
965  );
966}
967
968{
969  // "customInspect" option can enable/disable calling [util.inspect.custom]().
970  const subject = { [util.inspect.custom]: () => 123 };
971
972  assert.strictEqual(
973    util.inspect(subject, { customInspect: true }).includes('123'),
974    true
975  );
976  assert.strictEqual(
977    util.inspect(subject, { customInspect: true }).includes('inspect'),
978    false
979  );
980  assert.strictEqual(
981    util.inspect(subject, { customInspect: false }).includes('123'),
982    false
983  );
984  assert.strictEqual(
985    util.inspect(subject, { customInspect: false }).includes('inspect'),
986    true
987  );
988
989  // A custom [util.inspect.custom]() should be able to return other Objects.
990  subject[util.inspect.custom] = () => ({ foo: 'bar' });
991
992  assert.strictEqual(util.inspect(subject), "{ foo: 'bar' }");
993
994  subject[util.inspect.custom] = common.mustCall((depth, opts, inspect) => {
995    const clone = { ...opts };
996    // This might change at some point but for now we keep the stylize function.
997    // The function should either be documented or an alternative should be
998    // implemented.
999    assert.strictEqual(typeof opts.stylize, 'function');
1000    assert.strictEqual(opts.seen, undefined);
1001    assert.strictEqual(opts.budget, undefined);
1002    assert.strictEqual(opts.indentationLvl, undefined);
1003    assert.strictEqual(opts.showHidden, false);
1004    assert.strictEqual(inspect, util.inspect);
1005    assert.deepStrictEqual(
1006      new Set(Object.keys(inspect.defaultOptions).concat(['stylize'])),
1007      new Set(Object.keys(opts))
1008    );
1009    opts.showHidden = true;
1010    return { [inspect.custom]: common.mustCall((depth, opts2) => {
1011      assert.deepStrictEqual(clone, opts2);
1012    }) };
1013  });
1014
1015  util.inspect(subject);
1016
1017  // util.inspect.custom is a shared symbol which can be accessed as
1018  // Symbol.for("nodejs.util.inspect.custom").
1019  const inspect = Symbol.for('nodejs.util.inspect.custom');
1020
1021  subject[inspect] = () => ({ baz: 'quux' });
1022
1023  assert.strictEqual(util.inspect(subject), '{ baz: \'quux\' }');
1024
1025  subject[inspect] = (depth, opts) => {
1026    assert.strictEqual(opts.customInspectOptions, true);
1027    assert.strictEqual(opts.seen, null);
1028    return {};
1029  };
1030
1031  util.inspect(subject, { customInspectOptions: true, seen: null });
1032}
1033
1034{
1035  const subject = { [util.inspect.custom]: common.mustCall((depth, opts) => {
1036    assert.strictEqual(depth, null);
1037    assert.strictEqual(opts.compact, true);
1038  }) };
1039  util.inspect(subject, { depth: null, compact: true });
1040}
1041
1042{
1043  // Returning `this` from a custom inspection function works.
1044  const subject = { a: 123, [util.inspect.custom]() { return this; } };
1045  const UIC = 'nodejs.util.inspect.custom';
1046  assert.strictEqual(
1047    util.inspect(subject),
1048    `{\n  a: 123,\n  [Symbol(${UIC})]: [Function: [${UIC}]]\n}`
1049  );
1050}
1051
1052// Verify that it's possible to use the stylize function to manipulate input.
1053assert.strictEqual(
1054  util.inspect([1, 2, 3], { stylize() { return 'x'; } }),
1055  '[ x, x, x ]'
1056);
1057
1058// Using `util.inspect` with "colors" option should produce as many lines as
1059// without it.
1060{
1061  function testLines(input) {
1062    const countLines = (str) => (str.match(/\n/g) || []).length;
1063    const withoutColor = util.inspect(input);
1064    const withColor = util.inspect(input, { colors: true });
1065    assert.strictEqual(countLines(withoutColor), countLines(withColor));
1066  }
1067
1068  const bigArray = new Array(100).fill().map((value, index) => index);
1069
1070  testLines([1, 2, 3, 4, 5, 6, 7]);
1071  testLines(bigArray);
1072  testLines({ foo: 'bar', baz: 35, b: { a: 35 } });
1073  testLines({ a: { a: 3, b: 1, c: 1, d: 1, e: 1, f: 1, g: 1, h: 1 }, b: 1 });
1074  testLines({
1075    foo: 'bar',
1076    baz: 35,
1077    b: { a: 35 },
1078    veryLongKey: 'very long value',
1079    evenLongerKey: ['with even longer value in array']
1080  });
1081}
1082
1083// Test boxed primitives output the correct values.
1084assert.strictEqual(util.inspect(new String('test')), "[String: 'test']");
1085assert.strictEqual(
1086  util.inspect(new String('test'), { colors: true }),
1087  "\u001b[32m[String: 'test']\u001b[39m"
1088);
1089assert.strictEqual(
1090  util.inspect(Object(Symbol('test'))),
1091  '[Symbol: Symbol(test)]'
1092);
1093assert.strictEqual(util.inspect(new Boolean(false)), '[Boolean: false]');
1094assert.strictEqual(
1095  util.inspect(Object.setPrototypeOf(new Boolean(true), null)),
1096  '[Boolean (null prototype): true]'
1097);
1098assert.strictEqual(util.inspect(new Number(0)), '[Number: 0]');
1099assert.strictEqual(
1100  util.inspect(
1101    Object.defineProperty(
1102      Object.setPrototypeOf(new Number(-0), Array.prototype),
1103      Symbol.toStringTag,
1104      { value: 'Foobar' }
1105    )
1106  ),
1107  '[Number (Array): -0] [Foobar]'
1108);
1109assert.strictEqual(util.inspect(new Number(-1.1)), '[Number: -1.1]');
1110assert.strictEqual(util.inspect(new Number(13.37)), '[Number: 13.37]');
1111
1112// Test boxed primitives with own properties.
1113{
1114  const str = new String('baz');
1115  str.foo = 'bar';
1116  assert.strictEqual(util.inspect(str), "[String: 'baz'] { foo: 'bar' }");
1117
1118  const bool = new Boolean(true);
1119  bool.foo = 'bar';
1120  assert.strictEqual(util.inspect(bool), "[Boolean: true] { foo: 'bar' }");
1121
1122  const num = new Number(13.37);
1123  num.foo = 'bar';
1124  assert.strictEqual(util.inspect(num), "[Number: 13.37] { foo: 'bar' }");
1125
1126  const sym = Object(Symbol('foo'));
1127  sym.foo = 'bar';
1128  assert.strictEqual(util.inspect(sym), "[Symbol: Symbol(foo)] { foo: 'bar' }");
1129
1130  const big = Object(BigInt(55));
1131  big.foo = 'bar';
1132  assert.strictEqual(util.inspect(big), "[BigInt: 55n] { foo: 'bar' }");
1133}
1134
1135// Test es6 Symbol.
1136if (typeof Symbol !== 'undefined') {
1137  assert.strictEqual(util.inspect(Symbol()), 'Symbol()');
1138  assert.strictEqual(util.inspect(Symbol(123)), 'Symbol(123)');
1139  assert.strictEqual(util.inspect(Symbol('hi')), 'Symbol(hi)');
1140  assert.strictEqual(util.inspect([Symbol()]), '[ Symbol() ]');
1141  assert.strictEqual(util.inspect({ foo: Symbol() }), '{ foo: Symbol() }');
1142
1143  const options = { showHidden: true };
1144  let subject = {};
1145
1146  subject[Symbol('sym\nbol')] = 42;
1147
1148  assert.strictEqual(util.inspect(subject), '{ [Symbol(sym\\nbol)]: 42 }');
1149  assert.strictEqual(
1150    util.inspect(subject, options),
1151    '{ [Symbol(sym\\nbol)]: 42 }'
1152  );
1153
1154  Object.defineProperty(
1155    subject,
1156    Symbol(),
1157    { enumerable: false, value: 'non-enum' });
1158  assert.strictEqual(util.inspect(subject), '{ [Symbol(sym\\nbol)]: 42 }');
1159  assert.strictEqual(
1160    util.inspect(subject, options),
1161    "{ [Symbol(sym\\nbol)]: 42, [Symbol()]: 'non-enum' }"
1162  );
1163
1164  subject = [1, 2, 3];
1165  subject[Symbol('symbol')] = 42;
1166
1167  assert.strictEqual(util.inspect(subject),
1168                     '[ 1, 2, 3, [Symbol(symbol)]: 42 ]');
1169}
1170
1171// Test Set.
1172{
1173  assert.strictEqual(util.inspect(new Set()), 'Set(0) {}');
1174  assert.strictEqual(util.inspect(new Set([1, 2, 3])), 'Set(3) { 1, 2, 3 }');
1175  const set = new Set(['foo']);
1176  set.bar = 42;
1177  assert.strictEqual(
1178    util.inspect(set, { showHidden: true }),
1179    "Set(1) { 'foo', bar: 42 }"
1180  );
1181}
1182
1183// Test circular Set.
1184{
1185  const set = new Set();
1186  set.add(set);
1187  assert.strictEqual(util.inspect(set), '<ref *1> Set(1) { [Circular *1] }');
1188}
1189
1190// Test Map.
1191{
1192  assert.strictEqual(util.inspect(new Map()), 'Map(0) {}');
1193  assert.strictEqual(util.inspect(new Map([[1, 'a'], [2, 'b'], [3, 'c']])),
1194                     "Map(3) { 1 => 'a', 2 => 'b', 3 => 'c' }");
1195  const map = new Map([['foo', null]]);
1196  map.bar = 42;
1197  assert.strictEqual(util.inspect(map, true),
1198                     "Map(1) { 'foo' => null, bar: 42 }");
1199}
1200
1201// Test circular Map.
1202{
1203  const map = new Map();
1204  map.set(map, 'map');
1205  assert.strictEqual(
1206    inspect(map),
1207    "<ref *1> Map(1) { [Circular *1] => 'map' }"
1208  );
1209  map.set(map, map);
1210  assert.strictEqual(
1211    inspect(map),
1212    '<ref *1> Map(1) { [Circular *1] => [Circular *1] }'
1213  );
1214  map.delete(map);
1215  map.set('map', map);
1216  assert.strictEqual(
1217    inspect(map),
1218    "<ref *1> Map(1) { 'map' => [Circular *1] }"
1219  );
1220}
1221
1222// Test multiple circular references.
1223{
1224  const obj = {};
1225  obj.a = [obj];
1226  obj.b = {};
1227  obj.b.inner = obj.b;
1228  obj.b.obj = obj;
1229
1230  assert.strictEqual(
1231    inspect(obj),
1232    '<ref *1> {\n' +
1233    '  a: [ [Circular *1] ],\n' +
1234    '  b: <ref *2> { inner: [Circular *2], obj: [Circular *1] }\n' +
1235    '}'
1236  );
1237}
1238
1239// Test Promise.
1240{
1241  const resolved = Promise.resolve(3);
1242  assert.strictEqual(util.inspect(resolved), 'Promise { 3 }');
1243
1244  const rejected = Promise.reject(3);
1245  assert.strictEqual(util.inspect(rejected), 'Promise { <rejected> 3 }');
1246  // Squelch UnhandledPromiseRejection.
1247  rejected.catch(() => {});
1248
1249  const pending = new Promise(() => {});
1250  assert.strictEqual(util.inspect(pending), 'Promise { <pending> }');
1251
1252  const promiseWithProperty = Promise.resolve('foo');
1253  promiseWithProperty.bar = 42;
1254  assert.strictEqual(util.inspect(promiseWithProperty),
1255                     "Promise { 'foo', bar: 42 }");
1256}
1257
1258// Make sure it doesn't choke on polyfills. Unlike Set/Map, there is no standard
1259// interface to synchronously inspect a Promise, so our techniques only work on
1260// a bonafide native Promise.
1261{
1262  const oldPromise = Promise;
1263  global.Promise = function() { this.bar = 42; };
1264  assert.strictEqual(util.inspect(new Promise()), '{ bar: 42 }');
1265  global.Promise = oldPromise;
1266}
1267
1268// Test Map iterators.
1269{
1270  const map = new Map([['foo', 'bar']]);
1271  assert.strictEqual(util.inspect(map.keys()), '[Map Iterator] { \'foo\' }');
1272  const mapValues = map.values();
1273  Object.defineProperty(mapValues, Symbol.toStringTag, { value: 'Foo' });
1274  assert.strictEqual(
1275    util.inspect(mapValues),
1276    '[Foo] [Map Iterator] { \'bar\' }'
1277  );
1278  map.set('A', 'B!');
1279  assert.strictEqual(util.inspect(map.entries(), { maxArrayLength: 1 }),
1280                     "[Map Entries] { [ 'foo', 'bar' ], ... 1 more item }");
1281  // Make sure the iterator doesn't get consumed.
1282  const keys = map.keys();
1283  assert.strictEqual(util.inspect(keys), "[Map Iterator] { 'foo', 'A' }");
1284  assert.strictEqual(util.inspect(keys), "[Map Iterator] { 'foo', 'A' }");
1285  keys.extra = true;
1286  assert.strictEqual(
1287    util.inspect(keys, { maxArrayLength: 0 }),
1288    '[Map Iterator] { ... 2 more items, extra: true }');
1289}
1290
1291// Test Set iterators.
1292{
1293  const aSet = new Set([1]);
1294  assert.strictEqual(util.inspect(aSet.entries(), { compact: false }),
1295                     '[Set Entries] {\n  [\n    1,\n    1\n  ]\n}');
1296  aSet.add(3);
1297  assert.strictEqual(util.inspect(aSet.keys()), '[Set Iterator] { 1, 3 }');
1298  assert.strictEqual(util.inspect(aSet.values()), '[Set Iterator] { 1, 3 }');
1299  const setEntries = aSet.entries();
1300  Object.defineProperty(setEntries, Symbol.toStringTag, { value: 'Foo' });
1301  assert.strictEqual(util.inspect(setEntries),
1302                     '[Foo] [Set Entries] { [ 1, 1 ], [ 3, 3 ] }');
1303  // Make sure the iterator doesn't get consumed.
1304  const keys = aSet.keys();
1305  Object.defineProperty(keys, Symbol.toStringTag, { value: null });
1306  assert.strictEqual(util.inspect(keys), '[Set Iterator] { 1, 3 }');
1307  assert.strictEqual(util.inspect(keys), '[Set Iterator] { 1, 3 }');
1308  keys.extra = true;
1309  assert.strictEqual(
1310    util.inspect(keys, { maxArrayLength: 1 }),
1311    '[Set Iterator] { 1, ... 1 more item, extra: true }');
1312}
1313
1314// Minimal inspection should still return as much information as possible about
1315// the constructor and Symbol.toStringTag.
1316{
1317  class Foo {
1318    get [Symbol.toStringTag]() {
1319      return 'ABC';
1320    }
1321  }
1322  const a = new Foo();
1323  assert.strictEqual(inspect(a, { depth: -1 }), 'Foo [ABC] {}');
1324  a.foo = true;
1325  assert.strictEqual(inspect(a, { depth: -1 }), '[Foo [ABC]]');
1326  Object.defineProperty(a, Symbol.toStringTag, {
1327    value: 'Foo',
1328    configurable: true,
1329    writable: true
1330  });
1331  assert.strictEqual(inspect(a, { depth: -1 }), '[Foo]');
1332  delete a[Symbol.toStringTag];
1333  Object.setPrototypeOf(a, null);
1334  assert.strictEqual(inspect(a, { depth: -1 }), '[Foo: null prototype]');
1335  delete a.foo;
1336  assert.strictEqual(inspect(a, { depth: -1 }), '[Foo: null prototype] {}');
1337  Object.defineProperty(a, Symbol.toStringTag, {
1338    value: 'ABC',
1339    configurable: true
1340  });
1341  assert.strictEqual(
1342    inspect(a, { depth: -1 }),
1343    '[Foo: null prototype] [ABC] {}'
1344  );
1345  Object.defineProperty(a, Symbol.toStringTag, {
1346    value: 'Foo',
1347    configurable: true
1348  });
1349  assert.strictEqual(
1350    inspect(a, { depth: -1 }),
1351    '[Object: null prototype] [Foo] {}'
1352  );
1353}
1354
1355// Test alignment of items in container.
1356// Assumes that the first numeric character is the start of an item.
1357{
1358  function checkAlignment(container, start, lineX, end) {
1359    const lines = util.inspect(container).split('\n');
1360    lines.forEach((line, i) => {
1361      if (i === 0) {
1362        assert.strictEqual(line, start);
1363      } else if (i === lines.length - 1) {
1364        assert.strictEqual(line, end);
1365      } else {
1366        let expected = lineX.replace('X', i - 1);
1367        if (i !== lines.length - 2)
1368          expected += ',';
1369        assert.strictEqual(line, expected);
1370      }
1371    });
1372  }
1373
1374  const bigArray = [];
1375  for (let i = 0; i < 100; i++) {
1376    bigArray.push(i);
1377  }
1378
1379  const obj = {};
1380  bigArray.forEach((prop) => {
1381    obj[prop] = null;
1382  });
1383
1384  checkAlignment(obj, '{', "  'X': null", '}');
1385  checkAlignment(new Set(bigArray), 'Set(100) {', '  X', '}');
1386  checkAlignment(
1387    new Map(bigArray.map((number) => [number, null])),
1388    'Map(100) {', '  X => null', '}'
1389  );
1390}
1391
1392
1393// Test display of constructors.
1394{
1395  class ObjectSubclass {}
1396  class ArraySubclass extends Array {}
1397  class SetSubclass extends Set {}
1398  class MapSubclass extends Map {}
1399  class PromiseSubclass extends Promise {}
1400  class SymbolNameClass {
1401    static name = Symbol('name');
1402  }
1403
1404  const x = new ObjectSubclass();
1405  x.foo = 42;
1406  assert.strictEqual(util.inspect(x),
1407                     'ObjectSubclass { foo: 42 }');
1408  assert.strictEqual(util.inspect(new ArraySubclass(1, 2, 3)),
1409                     'ArraySubclass(3) [ 1, 2, 3 ]');
1410  assert.strictEqual(util.inspect(new SetSubclass([1, 2, 3])),
1411                     'SetSubclass(3) [Set] { 1, 2, 3 }');
1412  assert.strictEqual(util.inspect(new MapSubclass([['foo', 42]])),
1413                     "MapSubclass(1) [Map] { 'foo' => 42 }");
1414  assert.strictEqual(util.inspect(new PromiseSubclass(() => {})),
1415                     'PromiseSubclass [Promise] { <pending> }');
1416  assert.strictEqual(util.inspect(new SymbolNameClass()),
1417                     'Symbol(name) {}');
1418  assert.strictEqual(
1419    util.inspect({ a: { b: new ArraySubclass([1, [2], 3]) } }, { depth: 1 }),
1420    '{ a: { b: [ArraySubclass] } }'
1421  );
1422  assert.strictEqual(
1423    util.inspect(Object.setPrototypeOf(x, null)),
1424    '[ObjectSubclass: null prototype] { foo: 42 }'
1425  );
1426}
1427
1428// Empty and circular before depth.
1429{
1430  const arr = [[[[]]]];
1431  assert.strictEqual(util.inspect(arr), '[ [ [ [] ] ] ]');
1432  arr[0][0][0][0] = [];
1433  assert.strictEqual(util.inspect(arr), '[ [ [ [Array] ] ] ]');
1434  arr[0][0][0] = {};
1435  assert.strictEqual(util.inspect(arr), '[ [ [ {} ] ] ]');
1436  arr[0][0][0] = { a: 2 };
1437  assert.strictEqual(util.inspect(arr), '[ [ [ [Object] ] ] ]');
1438  arr[0][0][0] = arr;
1439  assert.strictEqual(util.inspect(arr), '<ref *1> [ [ [ [Circular *1] ] ] ]');
1440  arr[0][0][0] = arr[0][0];
1441  assert.strictEqual(util.inspect(arr), '[ [ <ref *1> [ [Circular *1] ] ] ]');
1442}
1443
1444// Corner cases.
1445{
1446  const x = { constructor: 42 };
1447  assert.strictEqual(util.inspect(x), '{ constructor: 42 }');
1448}
1449
1450{
1451  const x = {};
1452  Object.defineProperty(x, 'constructor', {
1453    get: function() {
1454      throw new Error('should not access constructor');
1455    },
1456    enumerable: true
1457  });
1458  assert.strictEqual(util.inspect(x), '{ constructor: [Getter] }');
1459}
1460
1461{
1462  const x = new function() {}; // eslint-disable-line new-parens
1463  assert.strictEqual(util.inspect(x), '{}');
1464}
1465
1466{
1467  const x = Object.create(null);
1468  assert.strictEqual(util.inspect(x), '[Object: null prototype] {}');
1469}
1470
1471{
1472  const x = [];
1473  x[''] = 1;
1474  assert.strictEqual(util.inspect(x), "[ '': 1 ]");
1475}
1476
1477// The following maxArrayLength tests were introduced after v6.0.0 was released.
1478// Do not backport to v5/v4 unless all of
1479// https://github.com/nodejs/node/pull/6334 is backported.
1480{
1481  const x = new Array(101).fill();
1482  assert(util.inspect(x).endsWith('1 more item\n]'));
1483  assert(!util.inspect(x, { maxArrayLength: 101 }).endsWith('1 more item\n]'));
1484  assert.strictEqual(
1485    util.inspect(x, { maxArrayLength: -1 }),
1486    '[ ... 101 more items ]'
1487  );
1488  assert.strictEqual(util.inspect(x, { maxArrayLength: 0 }),
1489                     '[ ... 101 more items ]');
1490}
1491
1492{
1493  const x = Array(101);
1494  assert.strictEqual(util.inspect(x, { maxArrayLength: 0 }),
1495                     '[ ... 101 more items ]');
1496  assert(!util.inspect(x, { maxArrayLength: null }).endsWith('1 more item\n]'));
1497  assert(!util.inspect(
1498    x, { maxArrayLength: Infinity }
1499  ).endsWith('1 more item ]'));
1500}
1501
1502{
1503  const x = new Uint8Array(101);
1504  assert(util.inspect(x).endsWith('1 more item\n]'));
1505  assert(!util.inspect(x, { maxArrayLength: 101 }).includes('1 more item'));
1506  assert.strictEqual(util.inspect(x, { maxArrayLength: 0 }),
1507                     'Uint8Array(101) [ ... 101 more items ]');
1508  assert(!util.inspect(x, { maxArrayLength: null }).includes('1 more item'));
1509  assert(util.inspect(x, { maxArrayLength: Infinity }).endsWith(' 0, 0\n]'));
1510}
1511
1512{
1513  const obj = { foo: 'abc', bar: 'xyz' };
1514  const oneLine = util.inspect(obj, { breakLength: Infinity });
1515  // Subtract four for the object's two curly braces and two spaces of padding.
1516  // Add one more to satisfy the strictly greater than condition in the code.
1517  const breakpoint = oneLine.length - 5;
1518  const twoLines = util.inspect(obj, { breakLength: breakpoint });
1519
1520  assert.strictEqual(oneLine, "{ foo: 'abc', bar: 'xyz' }");
1521  assert.strictEqual(
1522    util.inspect(obj, { breakLength: breakpoint + 1 }),
1523    twoLines
1524  );
1525  assert.strictEqual(twoLines, "{\n  foo: 'abc',\n  bar: 'xyz'\n}");
1526}
1527
1528// util.inspect.defaultOptions tests.
1529{
1530  const arr = new Array(101).fill();
1531  const obj = { a: { a: { a: { a: 1 } } } };
1532
1533  const oldOptions = { ...util.inspect.defaultOptions };
1534
1535  // Set single option through property assignment.
1536  util.inspect.defaultOptions.maxArrayLength = null;
1537  assert.doesNotMatch(util.inspect(arr), /1 more item/);
1538  util.inspect.defaultOptions.maxArrayLength = oldOptions.maxArrayLength;
1539  assert.match(util.inspect(arr), /1 more item/);
1540  util.inspect.defaultOptions.depth = null;
1541  assert.doesNotMatch(util.inspect(obj), /Object/);
1542  util.inspect.defaultOptions.depth = oldOptions.depth;
1543  assert.match(util.inspect(obj), /Object/);
1544  assert.strictEqual(
1545    JSON.stringify(util.inspect.defaultOptions),
1546    JSON.stringify(oldOptions)
1547  );
1548
1549  // Set multiple options through object assignment.
1550  util.inspect.defaultOptions = { maxArrayLength: null, depth: 2 };
1551  assert.doesNotMatch(util.inspect(arr), /1 more item/);
1552  assert.match(util.inspect(obj), /Object/);
1553  util.inspect.defaultOptions = oldOptions;
1554  assert.match(util.inspect(arr), /1 more item/);
1555  assert.match(util.inspect(obj), /Object/);
1556  assert.strictEqual(
1557    JSON.stringify(util.inspect.defaultOptions),
1558    JSON.stringify(oldOptions)
1559  );
1560
1561  assert.throws(() => {
1562    util.inspect.defaultOptions = null;
1563  }, {
1564    code: 'ERR_INVALID_ARG_TYPE',
1565    name: 'TypeError',
1566    message: 'The "options" argument must be of type object. ' +
1567             'Received null'
1568  }
1569  );
1570
1571  assert.throws(() => {
1572    util.inspect.defaultOptions = 'bad';
1573  }, {
1574    code: 'ERR_INVALID_ARG_TYPE',
1575    name: 'TypeError',
1576    message: 'The "options" argument must be of type object. ' +
1577             "Received type string ('bad')"
1578  }
1579  );
1580}
1581
1582util.inspect(process);
1583
1584// Setting custom inspect property to a non-function should do nothing.
1585{
1586  const obj = { [util.inspect.custom]: 'fhqwhgads' };
1587  assert.strictEqual(
1588    util.inspect(obj),
1589    "{ [Symbol(nodejs.util.inspect.custom)]: 'fhqwhgads' }"
1590  );
1591}
1592
1593{
1594  // @@toStringTag
1595  const obj = { [Symbol.toStringTag]: 'a' };
1596  assert.strictEqual(
1597    util.inspect(obj),
1598    "{ [Symbol(Symbol.toStringTag)]: 'a' }"
1599  );
1600  Object.defineProperty(obj, Symbol.toStringTag, {
1601    value: 'a',
1602    enumerable: false
1603  });
1604  assert.strictEqual(util.inspect(obj), 'Object [a] {}');
1605  assert.strictEqual(
1606    util.inspect(obj, { showHidden: true }),
1607    "{ [Symbol(Symbol.toStringTag)]: 'a' }"
1608  );
1609
1610  class Foo {
1611    constructor() {
1612      this.foo = 'bar';
1613    }
1614
1615    get [Symbol.toStringTag]() {
1616      return this.foo;
1617    }
1618  }
1619
1620  assert.strictEqual(util.inspect(
1621    Object.create(null, { [Symbol.toStringTag]: { value: 'foo' } })),
1622                     '[Object: null prototype] [foo] {}');
1623
1624  assert.strictEqual(util.inspect(new Foo()), "Foo [bar] { foo: 'bar' }");
1625
1626  assert.strictEqual(
1627    util.inspect(new (class extends Foo {})()),
1628    "Foo [bar] { foo: 'bar' }");
1629
1630  assert.strictEqual(
1631    util.inspect(Object.create(Object.create(Foo.prototype), {
1632      foo: { value: 'bar', enumerable: true }
1633    })),
1634    "Foo [bar] { foo: 'bar' }");
1635
1636  class ThrowingClass {
1637    get [Symbol.toStringTag]() {
1638      throw new Error('toStringTag error');
1639    }
1640  }
1641
1642  assert.throws(() => util.inspect(new ThrowingClass()), /toStringTag error/);
1643
1644  class NotStringClass {
1645    get [Symbol.toStringTag]() {
1646      return null;
1647    }
1648  }
1649
1650  assert.strictEqual(util.inspect(new NotStringClass()),
1651                     'NotStringClass {}');
1652}
1653
1654{
1655  const o = {
1656    a: [1, 2, [[
1657      'Lorem ipsum dolor\nsit amet,\tconsectetur adipiscing elit, sed do ' +
1658        'eiusmod tempor incididunt ut labore et dolore magna aliqua.',
1659      'test',
1660      'foo']], 4],
1661    b: new Map([['za', 1], ['zb', 'test']])
1662  };
1663
1664  let out = util.inspect(o, { compact: true, depth: 5, breakLength: 80 });
1665  let expect = [
1666    '{ a:',
1667    '   [ 1,',
1668    '     2,',
1669    "     [ [ 'Lorem ipsum dolor\\nsit amet,\\tconsectetur adipiscing elit, " +
1670      "sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',",
1671    "         'test',",
1672    "         'foo' ] ],",
1673    '     4 ],',
1674    "  b: Map(2) { 'za' => 1, 'zb' => 'test' } }",
1675  ].join('\n');
1676  assert.strictEqual(out, expect);
1677
1678  out = util.inspect(o, { compact: false, depth: 5, breakLength: 60 });
1679  expect = [
1680    '{',
1681    '  a: [',
1682    '    1,',
1683    '    2,',
1684    '    [',
1685    '      [',
1686    "        'Lorem ipsum dolor\\n' +",
1687    "          'sit amet,\\tconsectetur adipiscing elit, sed do eiusmod " +
1688      "tempor incididunt ut labore et dolore magna aliqua.',",
1689    "        'test',",
1690    "        'foo'",
1691    '      ]',
1692    '    ],',
1693    '    4',
1694    '  ],',
1695    '  b: Map(2) {',
1696    "    'za' => 1,",
1697    "    'zb' => 'test'",
1698    '  }',
1699    '}',
1700  ].join('\n');
1701  assert.strictEqual(out, expect);
1702
1703  out = util.inspect(o.a[2][0][0], { compact: false, breakLength: 30 });
1704  expect = [
1705    "'Lorem ipsum dolor\\n' +",
1706    "  'sit amet,\\tconsectetur adipiscing elit, sed do eiusmod tempor " +
1707      "incididunt ut labore et dolore magna aliqua.'",
1708  ].join('\n');
1709  assert.strictEqual(out, expect);
1710
1711  out = util.inspect(
1712    '12345678901234567890123456789012345678901234567890',
1713    { compact: false, breakLength: 3 });
1714  expect = "'12345678901234567890123456789012345678901234567890'";
1715  assert.strictEqual(out, expect);
1716
1717  out = util.inspect(
1718    '12 45 78 01 34 67 90 23 56 89 123456789012345678901234567890',
1719    { compact: false, breakLength: 3 });
1720  expect = [
1721    "'12 45 78 01 34 67 90 23 56 89 123456789012345678901234567890'",
1722  ].join('\n');
1723  assert.strictEqual(out, expect);
1724
1725  o.a = () => {};
1726  o.b = new Number(3);
1727  out = util.inspect(o, { compact: false, breakLength: 3 });
1728  expect = [
1729    '{',
1730    '  a: [Function (anonymous)],',
1731    '  b: [Number: 3]',
1732    '}',
1733  ].join('\n');
1734  assert.strictEqual(out, expect);
1735
1736  out = util.inspect(o, { compact: false, breakLength: 3, showHidden: true });
1737  expect = [
1738    '{',
1739    '  a: [Function (anonymous)] {',
1740    '    [length]: 0,',
1741    "    [name]: ''",
1742    '  },',
1743    '  b: [Number: 3]',
1744    '}',
1745  ].join('\n');
1746  assert.strictEqual(out, expect);
1747
1748  o[util.inspect.custom] = () => 42;
1749  out = util.inspect(o, { compact: false, breakLength: 3 });
1750  expect = '42';
1751  assert.strictEqual(out, expect);
1752
1753  o[util.inspect.custom] = () => '12 45 78 01 34 67 90 23';
1754  out = util.inspect(o, { compact: false, breakLength: 3 });
1755  expect = '12 45 78 01 34 67 90 23';
1756  assert.strictEqual(out, expect);
1757
1758  o[util.inspect.custom] = () => ({ a: '12 45 78 01 34 67 90 23' });
1759  out = util.inspect(o, { compact: false, breakLength: 3 });
1760  expect = "{\n  a: '12 45 78 01 34 67 90 23'\n}";
1761  assert.strictEqual(out, expect);
1762}
1763
1764// Check compact indentation.
1765{
1766  const typed = new Uint8Array();
1767  typed.buffer.foo = true;
1768  const set = new Set([[1, 2]]);
1769  const promise = Promise.resolve([[1, set]]);
1770  const map = new Map([[promise, typed]]);
1771  map.set(set.values(), map.values());
1772
1773  let out = util.inspect(map, { compact: false, showHidden: true, depth: 9 });
1774  let expected = [
1775    'Map(2) {',
1776    '  Promise {',
1777    '    [',
1778    '      [',
1779    '        1,',
1780    '        Set(1) {',
1781    '          [',
1782    '            1,',
1783    '            2,',
1784    '            [length]: 2',
1785    '          ]',
1786    '        },',
1787    '        [length]: 2',
1788    '      ],',
1789    '      [length]: 1',
1790    '    ]',
1791    '  } => Uint8Array(0) [',
1792    '    [BYTES_PER_ELEMENT]: 1,',
1793    '    [length]: 0,',
1794    '    [byteLength]: 0,',
1795    '    [byteOffset]: 0,',
1796    '    [buffer]: ArrayBuffer {',
1797    '      byteLength: 0,',
1798    '      foo: true',
1799    '    }',
1800    '  ],',
1801    '  [Set Iterator] {',
1802    '    [',
1803    '      1,',
1804    '      2,',
1805    '      [length]: 2',
1806    '    ],',
1807    "    [Symbol(Symbol.toStringTag)]: 'Set Iterator'",
1808    '  } => <ref *1> [Map Iterator] {',
1809    '    Uint8Array(0) [',
1810    '      [BYTES_PER_ELEMENT]: 1,',
1811    '      [length]: 0,',
1812    '      [byteLength]: 0,',
1813    '      [byteOffset]: 0,',
1814    '      [buffer]: ArrayBuffer {',
1815    '        byteLength: 0,',
1816    '        foo: true',
1817    '      }',
1818    '    ],',
1819    '    [Circular *1],',
1820    "    [Symbol(Symbol.toStringTag)]: 'Map Iterator'",
1821    '  }',
1822    '}',
1823  ].join('\n');
1824
1825  assert.strict.equal(out, expected);
1826
1827  out = util.inspect(map, { compact: 2, showHidden: true, depth: 9 });
1828
1829  expected = [
1830    'Map(2) {',
1831    '  Promise {',
1832    '    [',
1833    '      [',
1834    '        1,',
1835    '        Set(1) { [ 1, 2, [length]: 2 ] },',
1836    '        [length]: 2',
1837    '      ],',
1838    '      [length]: 1',
1839    '    ]',
1840    '  } => Uint8Array(0) [',
1841    '    [BYTES_PER_ELEMENT]: 1,',
1842    '    [length]: 0,',
1843    '    [byteLength]: 0,',
1844    '    [byteOffset]: 0,',
1845    '    [buffer]: ArrayBuffer { byteLength: 0, foo: true }',
1846    '  ],',
1847    '  [Set Iterator] {',
1848    '    [ 1, 2, [length]: 2 ],',
1849    "    [Symbol(Symbol.toStringTag)]: 'Set Iterator'",
1850    '  } => <ref *1> [Map Iterator] {',
1851    '    Uint8Array(0) [',
1852    '      [BYTES_PER_ELEMENT]: 1,',
1853    '      [length]: 0,',
1854    '      [byteLength]: 0,',
1855    '      [byteOffset]: 0,',
1856    '      [buffer]: ArrayBuffer { byteLength: 0, foo: true }',
1857    '    ],',
1858    '    [Circular *1],',
1859    "    [Symbol(Symbol.toStringTag)]: 'Map Iterator'",
1860    '  }',
1861    '}',
1862  ].join('\n');
1863
1864  assert.strict.equal(out, expected);
1865
1866  out = util.inspect(map, {
1867    showHidden: true, depth: 9, breakLength: 4, compact: true
1868  });
1869  expected = [
1870    'Map(2) {',
1871    '  Promise {',
1872    '    [ [ 1,',
1873    '        Set(1) {',
1874    '          [ 1,',
1875    '            2,',
1876    '            [length]: 2 ] },',
1877    '        [length]: 2 ],',
1878    '      [length]: 1 ] } => Uint8Array(0) [',
1879    '    [BYTES_PER_ELEMENT]: 1,',
1880    '    [length]: 0,',
1881    '    [byteLength]: 0,',
1882    '    [byteOffset]: 0,',
1883    '    [buffer]: ArrayBuffer {',
1884    '      byteLength: 0,',
1885    '      foo: true } ],',
1886    '  [Set Iterator] {',
1887    '    [ 1,',
1888    '      2,',
1889    '      [length]: 2 ],',
1890    '    [Symbol(Symbol.toStringTag)]:',
1891    "     'Set Iterator' } => <ref *1> [Map Iterator] {",
1892    '    Uint8Array(0) [',
1893    '      [BYTES_PER_ELEMENT]: 1,',
1894    '      [length]: 0,',
1895    '      [byteLength]: 0,',
1896    '      [byteOffset]: 0,',
1897    '      [buffer]: ArrayBuffer {',
1898    '        byteLength: 0,',
1899    '        foo: true } ],',
1900    '    [Circular *1],',
1901    '    [Symbol(Symbol.toStringTag)]:',
1902    "     'Map Iterator' } }",
1903  ].join('\n');
1904
1905  assert.strict.equal(out, expected);
1906}
1907
1908{ // Test WeakMap && WeakSet
1909  const obj = {};
1910  const arr = [];
1911  const weakMap = new WeakMap([[obj, arr], [arr, obj]]);
1912  let out = util.inspect(weakMap, { showHidden: true });
1913  let expect = 'WeakMap { [ [length]: 0 ] => {}, {} => [ [length]: 0 ] }';
1914  assert.strictEqual(out, expect);
1915
1916  out = util.inspect(weakMap);
1917  expect = 'WeakMap { <items unknown> }';
1918  assert.strictEqual(out, expect);
1919
1920  out = util.inspect(weakMap, { maxArrayLength: 0, showHidden: true });
1921  expect = 'WeakMap { ... 2 more items }';
1922  assert.strictEqual(out, expect);
1923
1924  weakMap.extra = true;
1925  out = util.inspect(weakMap, { maxArrayLength: 1, showHidden: true });
1926  // It is not possible to determine the output reliable.
1927  expect = 'WeakMap { [ [length]: 0 ] => {}, ... 1 more item, extra: true }';
1928  let expectAlt = 'WeakMap { {} => [ [length]: 0 ], ... 1 more item, ' +
1929                  'extra: true }';
1930  assert(out === expect || out === expectAlt,
1931         `Found: "${out}"\nrather than: "${expect}"\nor: "${expectAlt}"`);
1932
1933  // Test WeakSet
1934  arr.push(1);
1935  const weakSet = new WeakSet([obj, arr]);
1936  out = util.inspect(weakSet, { showHidden: true });
1937  expect = 'WeakSet { [ 1, [length]: 1 ], {} }';
1938  assert.strictEqual(out, expect);
1939
1940  out = util.inspect(weakSet);
1941  expect = 'WeakSet { <items unknown> }';
1942  assert.strictEqual(out, expect);
1943
1944  out = util.inspect(weakSet, { maxArrayLength: -2, showHidden: true });
1945  expect = 'WeakSet { ... 2 more items }';
1946  assert.strictEqual(out, expect);
1947
1948  weakSet.extra = true;
1949  out = util.inspect(weakSet, { maxArrayLength: 1, showHidden: true });
1950  // It is not possible to determine the output reliable.
1951  expect = 'WeakSet { {}, ... 1 more item, extra: true }';
1952  expectAlt = 'WeakSet { [ 1, [length]: 1 ], ... 1 more item, extra: true }';
1953  assert(out === expect || out === expectAlt,
1954         `Found: "${out}"\nrather than: "${expect}"\nor: "${expectAlt}"`);
1955  // Keep references to the WeakMap entries, otherwise they could be GCed too
1956  // early.
1957  assert(obj && arr);
1958}
1959
1960{ // Test argument objects.
1961  const args = (function() { return arguments; })('a');
1962  assert.strictEqual(util.inspect(args), "[Arguments] { '0': 'a' }");
1963}
1964
1965{
1966  // Test that a long linked list can be inspected without throwing an error.
1967  const list = {};
1968  let head = list;
1969  // A linked list of length 100k should be inspectable in some way, even though
1970  // the real cutoff value is much lower than 100k.
1971  for (let i = 0; i < 100000; i++)
1972    head = head.next = {};
1973  assert.strictEqual(
1974    util.inspect(list),
1975    '{ next: { next: { next: [Object] } } }'
1976  );
1977  const longList = util.inspect(list, { depth: Infinity });
1978  const match = longList.match(/next/g);
1979  assert(match.length > 500 && match.length < 10000);
1980  assert(longList.includes('[Object: Inspection interrupted ' +
1981    'prematurely. Maximum call stack size exceeded.]'));
1982}
1983
1984// Do not escape single quotes if no double quote or backtick is present.
1985assert.strictEqual(util.inspect("'"), '"\'"');
1986assert.strictEqual(util.inspect('"\''), '`"\'`');
1987// eslint-disable-next-line no-template-curly-in-string
1988assert.strictEqual(util.inspect('"\'${a}'), "'\"\\'${a}'");
1989
1990// Errors should visualize as much information as possible.
1991// If the name is not included in the stack, visualize it as well.
1992[
1993  [class Foo extends TypeError {}, 'test'],
1994  [class Foo extends TypeError {}, undefined],
1995  [class BarError extends Error {}, 'test'],
1996  [class BazError extends Error {
1997    get name() {
1998      return 'BazError';
1999    }
2000  }, undefined],
2001].forEach(([Class, message], i) => {
2002  console.log('Test %i', i);
2003  const foo = new Class(message);
2004  const name = foo.name;
2005  const extra = Class.name.includes('Error') ? '' : ` [${foo.name}]`;
2006  assert(
2007    util.inspect(foo).startsWith(
2008      `${Class.name}${extra}${message ? `: ${message}` : '\n'}`),
2009    util.inspect(foo)
2010  );
2011  Object.defineProperty(foo, Symbol.toStringTag, {
2012    value: 'WOW',
2013    writable: true,
2014    configurable: true
2015  });
2016  const stack = foo.stack;
2017  foo.stack = 'This is a stack';
2018  assert.strictEqual(
2019    util.inspect(foo),
2020    '[This is a stack]'
2021  );
2022  foo.stack = stack;
2023  assert(
2024    util.inspect(foo).startsWith(
2025      `${Class.name} [WOW]${extra}${message ? `: ${message}` : '\n'}`),
2026    util.inspect(foo)
2027  );
2028  Object.setPrototypeOf(foo, null);
2029  assert(
2030    util.inspect(foo).startsWith(
2031      `[${name}: null prototype] [WOW]${message ? `: ${message}` : '\n'}`
2032    ),
2033    util.inspect(foo)
2034  );
2035  foo.bar = true;
2036  delete foo[Symbol.toStringTag];
2037  assert(
2038    util.inspect(foo).startsWith(
2039      `[${name}: null prototype]${message ? `: ${message}` : '\n'}`),
2040    util.inspect(foo)
2041  );
2042  foo.stack = 'This is a stack';
2043  assert.strictEqual(
2044    util.inspect(foo),
2045    '[[Error: null prototype]: This is a stack] { bar: true }'
2046  );
2047  foo.stack = stack.split('\n')[0];
2048  assert.strictEqual(
2049    util.inspect(foo),
2050    `[[${name}: null prototype]${message ? `: ${message}` : ''}] { bar: true }`
2051  );
2052});
2053
2054// Verify that classes are properly inspected.
2055[
2056  /* eslint-disable spaced-comment, no-multi-spaces, brace-style */
2057  // The whitespace is intentional.
2058  [class   { }, '[class (anonymous)]'],
2059  [class extends Error { log() {} }, '[class (anonymous) extends Error]'],
2060  [class A { constructor(a) { this.a = a; } log() { return this.a; } },
2061   '[class A]'],
2062  [class
2063  // Random { // comments /* */ are part of the toString() result
2064  /* eslint-disable-next-line space-before-blocks */
2065  äß/**/extends/*{*/TypeError{}, '[class äß extends TypeError]'],
2066  /* The whitespace and new line is intended! */
2067  // Foobar !!!
2068  [class X   extends /****/ Error
2069  // More comments
2070  {}, '[class X extends Error]'],
2071  /* eslint-enable spaced-comment, no-multi-spaces, brace-style */
2072].forEach(([clazz, string]) => {
2073  const inspected = util.inspect(clazz);
2074  assert.strictEqual(inspected, string);
2075  Object.defineProperty(clazz, Symbol.toStringTag, {
2076    value: 'Woohoo'
2077  });
2078  const parts = inspected.slice(0, -1).split(' ');
2079  const [, name, ...rest] = parts;
2080  rest.unshift('[Woohoo]');
2081  if (rest.length) {
2082    rest[rest.length - 1] += ']';
2083  }
2084  assert.strictEqual(
2085    util.inspect(clazz),
2086    ['[class', name, ...rest].join(' ')
2087  );
2088  if (rest.length) {
2089    rest[rest.length - 1] = rest[rest.length - 1].slice(0, -1);
2090    rest.length = 1;
2091  }
2092  Object.setPrototypeOf(clazz, Map.prototype);
2093  assert.strictEqual(
2094    util.inspect(clazz),
2095    ['[class', name, '[Map]', ...rest].join(' ') + ']'
2096  );
2097  Object.setPrototypeOf(clazz, null);
2098  assert.strictEqual(
2099    util.inspect(clazz),
2100    ['[class', name, ...rest, 'extends [null prototype]]'].join(' ')
2101  );
2102  Object.defineProperty(clazz, 'name', { value: 'Foo' });
2103  const res = ['[class', 'Foo', ...rest, 'extends [null prototype]]'].join(' ');
2104  assert.strictEqual(util.inspect(clazz), res);
2105  clazz.foo = true;
2106  assert.strictEqual(util.inspect(clazz), `${res} { foo: true }`);
2107});
2108
2109// "class" properties should not be detected as "class".
2110{
2111  // eslint-disable-next-line space-before-function-paren
2112  let obj = { class () {} };
2113  assert.strictEqual(
2114    util.inspect(obj),
2115    '{ class: [Function: class] }'
2116  );
2117  obj = { class: () => {} };
2118  assert.strictEqual(
2119    util.inspect(obj),
2120    '{ class: [Function: class] }'
2121  );
2122  obj = { ['class Foo {}']() {} };
2123  assert.strictEqual(
2124    util.inspect(obj),
2125    "{ 'class Foo {}': [Function: class Foo {}] }"
2126  );
2127  function Foo() {}
2128  Object.defineProperty(Foo, 'toString', { value: () => 'class Foo {}' });
2129  assert.strictEqual(
2130    util.inspect(Foo),
2131    '[Function: Foo]'
2132  );
2133  function fn() {}
2134  Object.defineProperty(fn, 'name', { value: 'class Foo {}' });
2135  assert.strictEqual(
2136    util.inspect(fn),
2137    '[Function: class Foo {}]'
2138  );
2139}
2140
2141// Verify that throwing in valueOf and toString still produces nice results.
2142[
2143  [new String(55), "[String: '55']"],
2144  [new Boolean(true), '[Boolean: true]'],
2145  [new Number(55), '[Number: 55]'],
2146  [Object(BigInt(55)), '[BigInt: 55n]'],
2147  [Object(Symbol('foo')), '[Symbol: Symbol(foo)]'],
2148  [function() {}, '[Function (anonymous)]'],
2149  [() => {}, '[Function (anonymous)]'],
2150  [[1, 2], '[ 1, 2 ]'],
2151  // eslint-disable-next-line no-sparse-arrays
2152  [[, , 5, , , , ], '[ <2 empty items>, 5, <3 empty items> ]'],
2153  [{ a: 5 }, '{ a: 5 }'],
2154  [new Set([1, 2]), 'Set(2) { 1, 2 }'],
2155  [new Map([[1, 2]]), 'Map(1) { 1 => 2 }'],
2156  [new Set([1, 2]).entries(), '[Set Entries] { [ 1, 1 ], [ 2, 2 ] }'],
2157  [new Map([[1, 2]]).keys(), '[Map Iterator] { 1 }'],
2158  [new Date(2000), '1970-01-01T00:00:02.000Z'],
2159  [new Uint8Array(2), 'Uint8Array(2) [ 0, 0 ]'],
2160  [new Promise((resolve) => setTimeout(resolve, 10)), 'Promise { <pending> }'],
2161  [new WeakSet(), 'WeakSet { <items unknown> }'],
2162  [new WeakMap(), 'WeakMap { <items unknown> }'],
2163  [/foobar/g, '/foobar/g'],
2164].forEach(([value, expected]) => {
2165  Object.defineProperty(value, 'valueOf', {
2166    get() {
2167      throw new Error('valueOf');
2168    }
2169  });
2170  Object.defineProperty(value, 'toString', {
2171    get() {
2172      throw new Error('toString');
2173    }
2174  });
2175  assert.strictEqual(util.inspect(value), expected);
2176  value.foo = 'bar';
2177  assert.notStrictEqual(util.inspect(value), expected);
2178  delete value.foo;
2179  value[Symbol('foo')] = 'yeah';
2180  assert.notStrictEqual(util.inspect(value), expected);
2181});
2182
2183// Verify that having no prototype still produces nice results.
2184[
2185  [[1, 3, 4], '[Array(3): null prototype] [ 1, 3, 4 ]'],
2186  [new Set([1, 2]), '[Set(2): null prototype] { 1, 2 }'],
2187  [new Map([[1, 2]]), '[Map(1): null prototype] { 1 => 2 }'],
2188  [new Promise((resolve) => setTimeout(resolve, 10)),
2189   '[Promise: null prototype] { <pending> }'],
2190  [new WeakSet(), '[WeakSet: null prototype] { <items unknown> }'],
2191  [new WeakMap(), '[WeakMap: null prototype] { <items unknown> }'],
2192  [new Uint8Array(2), '[Uint8Array(2): null prototype] [ 0, 0 ]'],
2193  [new Uint16Array(2), '[Uint16Array(2): null prototype] [ 0, 0 ]'],
2194  [new Uint32Array(2), '[Uint32Array(2): null prototype] [ 0, 0 ]'],
2195  [new Int8Array(2), '[Int8Array(2): null prototype] [ 0, 0 ]'],
2196  [new Int16Array(2), '[Int16Array(2): null prototype] [ 0, 0 ]'],
2197  [new Int32Array(2), '[Int32Array(2): null prototype] [ 0, 0 ]'],
2198  [new Float32Array(2), '[Float32Array(2): null prototype] [ 0, 0 ]'],
2199  [new Float64Array(2), '[Float64Array(2): null prototype] [ 0, 0 ]'],
2200  [new BigInt64Array(2), '[BigInt64Array(2): null prototype] [ 0n, 0n ]'],
2201  [new BigUint64Array(2), '[BigUint64Array(2): null prototype] [ 0n, 0n ]'],
2202  [new ArrayBuffer(16), '[ArrayBuffer: null prototype] {\n' +
2203     '  [Uint8Contents]: <00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00>,\n' +
2204     '  byteLength: undefined\n}'],
2205  [new DataView(new ArrayBuffer(16)),
2206   '[DataView: null prototype] {\n  byteLength: undefined,\n  ' +
2207     'byteOffset: undefined,\n  buffer: undefined\n}'],
2208  [new SharedArrayBuffer(2), '[SharedArrayBuffer: null prototype] ' +
2209     '{\n  [Uint8Contents]: <00 00>,\n  byteLength: undefined\n}'],
2210  [/foobar/, '[RegExp: null prototype] /foobar/'],
2211  [new Date('Sun, 14 Feb 2010 11:48:40 GMT'),
2212   '[Date: null prototype] 2010-02-14T11:48:40.000Z'],
2213].forEach(([value, expected]) => {
2214  assert.strictEqual(
2215    util.inspect(Object.setPrototypeOf(value, null)),
2216    expected
2217  );
2218  value.foo = 'bar';
2219  assert.notStrictEqual(util.inspect(value), expected);
2220  delete value.foo;
2221  value[Symbol('foo')] = 'yeah';
2222  assert.notStrictEqual(util.inspect(value), expected);
2223});
2224
2225// Verify that subclasses with and without prototype produce nice results.
2226[
2227  [RegExp, ['foobar', 'g'], '/foobar/g'],
2228  [WeakSet, [[{}]], '{ <items unknown> }'],
2229  [WeakMap, [[[{}, {}]]], '{ <items unknown> }'],
2230  [BigInt64Array,
2231   [10],
2232   '[\n  0n, 0n, 0n, 0n, 0n,\n  0n, 0n, 0n, 0n, 0n\n]'],
2233  [Date, ['Sun, 14 Feb 2010 11:48:40 GMT'], '2010-02-14T11:48:40.000Z'],
2234  [Date, ['invalid_date'], 'Invalid Date'],
2235].forEach(([base, input, rawExpected]) => {
2236  class Foo extends base {}
2237  const value = new Foo(...input);
2238  const symbol = value[Symbol.toStringTag];
2239  const size = base.name.includes('Array') ? `(${input[0]})` : '';
2240  const expected = `Foo${size} ${symbol ? `[${symbol}] ` : ''}${rawExpected}`;
2241  const expectedWithoutProto =
2242    `[${base.name}${size}: null prototype] ${rawExpected}`;
2243  assert.strictEqual(util.inspect(value), expected);
2244  value.foo = 'bar';
2245  assert.notStrictEqual(util.inspect(value), expected);
2246  delete value.foo;
2247  assert.strictEqual(
2248    util.inspect(Object.setPrototypeOf(value, null)),
2249    expectedWithoutProto
2250  );
2251  value.foo = 'bar';
2252  let res = util.inspect(value);
2253  assert.notStrictEqual(res, expectedWithoutProto);
2254  assert.match(res, /foo: 'bar'/);
2255  delete value.foo;
2256  value[Symbol('foo')] = 'yeah';
2257  res = util.inspect(value);
2258  assert.notStrictEqual(res, expectedWithoutProto);
2259  assert.match(res, /\[Symbol\(foo\)]: 'yeah'/);
2260});
2261
2262assert.strictEqual(inspect(1n), '1n');
2263assert.strictEqual(inspect(Object(-1n)), '[BigInt: -1n]');
2264assert.strictEqual(inspect(Object(13n)), '[BigInt: 13n]');
2265assert.strictEqual(inspect(new BigInt64Array([0n])), 'BigInt64Array(1) [ 0n ]');
2266assert.strictEqual(
2267  inspect(new BigUint64Array([0n])), 'BigUint64Array(1) [ 0n ]');
2268
2269// Verify non-enumerable keys get escaped.
2270{
2271  const obj = {};
2272  Object.defineProperty(obj, 'Non\nenumerable\tkey', { value: true });
2273  assert.strictEqual(
2274    util.inspect(obj, { showHidden: true }),
2275    '{ [Non\\nenumerable\\tkey]: true }'
2276  );
2277}
2278
2279// Check for special colors.
2280{
2281  const special = inspect.colors[inspect.styles.special];
2282  const string = inspect.colors[inspect.styles.string];
2283
2284  assert.strictEqual(
2285    inspect(new WeakSet(), { colors: true }),
2286    `WeakSet { \u001b[${special[0]}m<items unknown>\u001b[${special[1]}m }`
2287  );
2288  assert.strictEqual(
2289    inspect(new WeakMap(), { colors: true }),
2290    `WeakMap { \u001b[${special[0]}m<items unknown>\u001b[${special[1]}m }`
2291  );
2292  assert.strictEqual(
2293    inspect(new Promise(() => {}), { colors: true }),
2294    `Promise { \u001b[${special[0]}m<pending>\u001b[${special[1]}m }`
2295  );
2296
2297  const rejection = Promise.reject('Oh no!');
2298  assert.strictEqual(
2299    inspect(rejection, { colors: true }),
2300    `Promise { \u001b[${special[0]}m<rejected>\u001b[${special[1]}m ` +
2301    `\u001b[${string[0]}m'Oh no!'\u001b[${string[1]}m }`
2302  );
2303  rejection.catch(() => {});
2304
2305  // Verify that aliases do not show up as key while checking `inspect.colors`.
2306  const colors = Object.keys(inspect.colors);
2307  const aliases = Object.getOwnPropertyNames(inspect.colors)
2308                  .filter((c) => !colors.includes(c));
2309  assert(!colors.includes('grey'));
2310  assert(colors.includes('gray'));
2311  // Verify that all aliases are correctly mapped.
2312  for (const alias of aliases) {
2313    assert(Array.isArray(inspect.colors[alias]));
2314  }
2315  // Check consistent naming.
2316  [
2317    'black',
2318    'red',
2319    'green',
2320    'yellow',
2321    'blue',
2322    'magenta',
2323    'cyan',
2324    'white',
2325  ].forEach((color, i) => {
2326    assert.deepStrictEqual(inspect.colors[color], [30 + i, 39]);
2327    assert.deepStrictEqual(inspect.colors[`${color}Bright`], [90 + i, 39]);
2328    const bgColor = `bg${color[0].toUpperCase()}${color.slice(1)}`;
2329    assert.deepStrictEqual(inspect.colors[bgColor], [40 + i, 49]);
2330    assert.deepStrictEqual(inspect.colors[`${bgColor}Bright`], [100 + i, 49]);
2331  });
2332
2333  // Unknown colors are handled gracefully:
2334  const stringStyle = inspect.styles.string;
2335  inspect.styles.string = 'UNKNOWN';
2336  assert.strictEqual(inspect('foobar', { colors: true }), "'foobar'");
2337  inspect.styles.string = stringStyle;
2338}
2339
2340assert.strictEqual(
2341  inspect([1, 3, 2], { sorted: true }),
2342  inspect([1, 3, 2])
2343);
2344assert.strictEqual(
2345  inspect({ c: 3, a: 1, b: 2 }, { sorted: true }),
2346  '{ a: 1, b: 2, c: 3 }'
2347);
2348assert.strictEqual(
2349  inspect(
2350    { a200: 4, a100: 1, a102: 3, a101: 2 },
2351    { sorted(a, b) { return b.localeCompare(a); } }
2352  ),
2353  '{ a200: 4, a102: 3, a101: 2, a100: 1 }'
2354);
2355
2356// Non-indices array properties are sorted as well.
2357{
2358  const arr = [3, 2, 1];
2359  arr.b = 2;
2360  arr.c = 3;
2361  arr.a = 1;
2362  arr[Symbol('b')] = true;
2363  arr[Symbol('a')] = false;
2364  assert.strictEqual(
2365    inspect(arr, { sorted: true }),
2366    '[ 3, 2, 1, [Symbol(a)]: false, [Symbol(b)]: true, a: 1, b: 2, c: 3 ]'
2367  );
2368}
2369
2370// Manipulate the prototype in weird ways.
2371{
2372  let obj = { a: true };
2373  let value = (function() { return function() {}; })();
2374  Object.setPrototypeOf(value, null);
2375  Object.setPrototypeOf(obj, value);
2376  assert.strictEqual(
2377    util.inspect(obj),
2378    'Object <[Function (null prototype) (anonymous)]> { a: true }'
2379  );
2380  assert.strictEqual(
2381    util.inspect(obj, { colors: true }),
2382    'Object <\u001b[36m[Function (null prototype) (anonymous)]\u001b[39m> ' +
2383      '{ a: \u001b[33mtrue\u001b[39m }'
2384  );
2385
2386  obj = { a: true };
2387  value = [];
2388  Object.setPrototypeOf(value, null);
2389  Object.setPrototypeOf(obj, value);
2390  assert.strictEqual(
2391    util.inspect(obj),
2392    'Object <[Array(0): null prototype] []> { a: true }'
2393  );
2394
2395  function StorageObject() {}
2396  StorageObject.prototype = Object.create(null);
2397  assert.strictEqual(
2398    util.inspect(new StorageObject()),
2399    'StorageObject <[Object: null prototype] {}> {}'
2400  );
2401
2402  obj = [1, 2, 3];
2403  Object.setPrototypeOf(obj, Number.prototype);
2404  assert.strictEqual(inspect(obj), "Number { '0': 1, '1': 2, '2': 3 }");
2405
2406  Object.setPrototypeOf(obj, Object.create(null));
2407  assert.strictEqual(
2408    inspect(obj),
2409    "Array <[Object: null prototype] {}> { '0': 1, '1': 2, '2': 3 }"
2410  );
2411
2412  StorageObject.prototype = Object.create(null);
2413  Object.setPrototypeOf(StorageObject.prototype, Object.create(null));
2414  Object.setPrototypeOf(
2415    Object.getPrototypeOf(StorageObject.prototype),
2416    Object.create(null)
2417  );
2418  assert.strictEqual(
2419    util.inspect(new StorageObject()),
2420    'StorageObject <Object <Object <[Object: null prototype] {}>>> {}'
2421  );
2422  assert.strictEqual(
2423    util.inspect(new StorageObject(), { depth: 1 }),
2424    'StorageObject <Object <Object <Complex prototype>>> {}'
2425  );
2426}
2427
2428// Check that the fallback always works.
2429{
2430  const obj = new Set([1, 2]);
2431  const iterator = obj[Symbol.iterator];
2432  Object.setPrototypeOf(obj, null);
2433  Object.defineProperty(obj, Symbol.iterator, {
2434    value: iterator,
2435    configurable: true
2436  });
2437  assert.strictEqual(util.inspect(obj), '[Set(2): null prototype] { 1, 2 }');
2438  Object.defineProperty(obj, Symbol.iterator, {
2439    value: true,
2440    configurable: true
2441  });
2442  Object.defineProperty(obj, 'size', {
2443    value: NaN,
2444    configurable: true,
2445    enumerable: true
2446  });
2447  assert.strictEqual(
2448    util.inspect(obj),
2449    '[Set(2): null prototype] { 1, 2, size: NaN }'
2450  );
2451}
2452
2453// Check the getter option.
2454{
2455  let foo = 1;
2456  const get = { get foo() { return foo; } };
2457  const getset = {
2458    get foo() { return foo; },
2459    set foo(val) { foo = val; },
2460    get inc() { return ++foo; }
2461  };
2462  const thrower = { get foo() { throw new Error('Oops'); } };
2463  assert.strictEqual(
2464    inspect(get, { getters: true, colors: true }),
2465    '{ foo: \u001b[36m[Getter:\u001b[39m ' +
2466      '\u001b[33m1\u001b[39m\u001b[36m]\u001b[39m }');
2467  assert.strictEqual(
2468    inspect(thrower, { getters: true }),
2469    '{ foo: [Getter: <Inspection threw (Oops)>] }');
2470  assert.strictEqual(
2471    inspect(getset, { getters: true }),
2472    '{ foo: [Getter/Setter: 1], inc: [Getter: 2] }');
2473  assert.strictEqual(
2474    inspect(getset, { getters: 'get' }),
2475    '{ foo: [Getter/Setter], inc: [Getter: 3] }');
2476  assert.strictEqual(
2477    inspect(getset, { getters: 'set' }),
2478    '{ foo: [Getter/Setter: 3], inc: [Getter] }');
2479  getset.foo = new Set([[{ a: true }, 2, {}], 'foobar', { x: 1 }]);
2480  assert.strictEqual(
2481    inspect(getset, { getters: true }),
2482    '{\n  foo: [Getter/Setter] Set(3) { [ [Object], 2, {} ], ' +
2483      "'foobar', { x: 1 } },\n  inc: [Getter: NaN]\n}");
2484}
2485
2486// Check compact number mode.
2487{
2488  let obj = {
2489    a: {
2490      b: {
2491        x: 5,
2492        c: {
2493          x: '10000000000000000 00000000000000000 '.repeat(1e1),
2494          d: 2,
2495          e: 3
2496        }
2497      }
2498    },
2499    b: [
2500      1,
2501      2,
2502      [ 1, 2, { a: 1, b: 2, c: 3 } ],
2503    ],
2504    c: ['foo', 4, 444444],
2505    d: Array.from({ length: 101 }).map((e, i) => {
2506      return i % 2 === 0 ? i * i : i;
2507    }),
2508    e: Array(6).fill('foobar'),
2509    f: Array(9).fill('foobar'),
2510    g: Array(21).fill('foobar baz'),
2511    h: [100].concat(Array.from({ length: 9 }).map((e, n) => (n))),
2512    long: Array(9).fill('This text is too long for grouping!')
2513  };
2514
2515  let out = util.inspect(obj, { compact: 3, depth: 10, breakLength: 60 });
2516  let expected = [
2517    '{',
2518    '  a: {',
2519    '    b: {',
2520    '      x: 5,',
2521    '      c: {',
2522    "        x: '10000000000000000 00000000000000000 10000000000000000 " +
2523      '00000000000000000 10000000000000000 00000000000000000 ' +
2524      '10000000000000000 00000000000000000 10000000000000000 ' +
2525      '00000000000000000 10000000000000000 00000000000000000 ' +
2526      '10000000000000000 00000000000000000 10000000000000000 ' +
2527      '00000000000000000 10000000000000000 00000000000000000 ' +
2528      "10000000000000000 00000000000000000 ',",
2529    '        d: 2,',
2530    '        e: 3',
2531    '      }',
2532    '    }',
2533    '  },',
2534    '  b: [ 1, 2, [ 1, 2, { a: 1, b: 2, c: 3 } ] ],',
2535    "  c: [ 'foo', 4, 444444 ],",
2536    '  d: [',
2537    '       0,    1,    4,    3,   16,    5,   36,    7,   64,',
2538    '       9,  100,   11,  144,   13,  196,   15,  256,   17,',
2539    '     324,   19,  400,   21,  484,   23,  576,   25,  676,',
2540    '      27,  784,   29,  900,   31, 1024,   33, 1156,   35,',
2541    '    1296,   37, 1444,   39, 1600,   41, 1764,   43, 1936,',
2542    '      45, 2116,   47, 2304,   49, 2500,   51, 2704,   53,',
2543    '    2916,   55, 3136,   57, 3364,   59, 3600,   61, 3844,',
2544    '      63, 4096,   65, 4356,   67, 4624,   69, 4900,   71,',
2545    '    5184,   73, 5476,   75, 5776,   77, 6084,   79, 6400,',
2546    '      81, 6724,   83, 7056,   85, 7396,   87, 7744,   89,',
2547    '    8100,   91, 8464,   93, 8836,   95, 9216,   97, 9604,',
2548    '      99,',
2549    '    ... 1 more item',
2550    '  ],',
2551    '  e: [',
2552    "    'foobar',",
2553    "    'foobar',",
2554    "    'foobar',",
2555    "    'foobar',",
2556    "    'foobar',",
2557    "    'foobar'",
2558    '  ],',
2559    '  f: [',
2560    "    'foobar', 'foobar',",
2561    "    'foobar', 'foobar',",
2562    "    'foobar', 'foobar',",
2563    "    'foobar', 'foobar',",
2564    "    'foobar'",
2565    '  ],',
2566    '  g: [',
2567    "    'foobar baz', 'foobar baz',",
2568    "    'foobar baz', 'foobar baz',",
2569    "    'foobar baz', 'foobar baz',",
2570    "    'foobar baz', 'foobar baz',",
2571    "    'foobar baz', 'foobar baz',",
2572    "    'foobar baz', 'foobar baz',",
2573    "    'foobar baz', 'foobar baz',",
2574    "    'foobar baz', 'foobar baz',",
2575    "    'foobar baz', 'foobar baz',",
2576    "    'foobar baz', 'foobar baz',",
2577    "    'foobar baz'",
2578    '  ],',
2579    '  h: [',
2580    '    100, 0, 1, 2, 3,',
2581    '      4, 5, 6, 7, 8',
2582    '  ],',
2583    '  long: [',
2584    "    'This text is too long for grouping!',",
2585    "    'This text is too long for grouping!',",
2586    "    'This text is too long for grouping!',",
2587    "    'This text is too long for grouping!',",
2588    "    'This text is too long for grouping!',",
2589    "    'This text is too long for grouping!',",
2590    "    'This text is too long for grouping!',",
2591    "    'This text is too long for grouping!',",
2592    "    'This text is too long for grouping!'",
2593    '  ]',
2594    '}',
2595  ].join('\n');
2596
2597  assert.strictEqual(out, expected);
2598
2599  obj = [
2600    1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2601    1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2602    1, 1, 1, 1, 1, 1, 123456789,
2603  ];
2604
2605  out = util.inspect(obj, { compact: 3 });
2606
2607  expected = [
2608    '[',
2609    '  1, 1,         1, 1,',
2610    '  1, 1,         1, 1,',
2611    '  1, 1,         1, 1,',
2612    '  1, 1,         1, 1,',
2613    '  1, 1,         1, 1,',
2614    '  1, 1,         1, 1,',
2615    '  1, 1, 123456789',
2616    ']',
2617  ].join('\n');
2618
2619  assert.strictEqual(out, expected);
2620
2621  // Unicode support. あ has a length of one and a width of two.
2622  obj = [
2623    '123', '123', '123', '123', 'あああ',
2624    '123', '123', '123', '123', 'あああ',
2625  ];
2626
2627  out = util.inspect(obj, { compact: 3 });
2628
2629  expected = [
2630    '[',
2631    "  '123',    '123',",
2632    "  '123',    '123',",
2633    "  'あああ', '123',",
2634    "  '123',    '123',",
2635    "  '123',    'あああ'",
2636    ']',
2637  ].join('\n');
2638
2639  assert.strictEqual(out, expected);
2640
2641  // Array grouping should prevent lining up outer elements on a single line.
2642  obj = [[[1, 2, 3, 4, 5, 6, 7, 8, 9]]];
2643
2644  out = util.inspect(obj, { compact: 3 });
2645
2646  expected = [
2647    '[',
2648    '  [',
2649    '    [',
2650    '      1, 2, 3, 4, 5,',
2651    '      6, 7, 8, 9',
2652    '    ]',
2653    '  ]',
2654    ']',
2655  ].join('\n');
2656
2657  assert.strictEqual(out, expected);
2658
2659  // Verify that array grouping and line consolidation does not happen together.
2660  obj = {
2661    a: {
2662      b: {
2663        x: 5,
2664        c: {
2665          d: 2,
2666          e: 3
2667        }
2668      }
2669    },
2670    b: Array.from({ length: 9 }).map((e, n) => {
2671      return n % 2 === 0 ? 'foobar' : 'baz';
2672    })
2673  };
2674
2675  out = util.inspect(obj, { compact: 1, breakLength: Infinity, colors: true });
2676
2677  expected = [
2678    '{',
2679    '  a: {',
2680    '    b: { x: \u001b[33m5\u001b[39m, c: \u001b[36m[Object]\u001b[39m }',
2681    '  },',
2682    '  b: [',
2683    "    \u001b[32m'foobar'\u001b[39m, \u001b[32m'baz'\u001b[39m,",
2684    "    \u001b[32m'foobar'\u001b[39m, \u001b[32m'baz'\u001b[39m,",
2685    "    \u001b[32m'foobar'\u001b[39m, \u001b[32m'baz'\u001b[39m,",
2686    "    \u001b[32m'foobar'\u001b[39m, \u001b[32m'baz'\u001b[39m,",
2687    "    \u001b[32m'foobar'\u001b[39m",
2688    '  ]',
2689    '}',
2690  ].join('\n');
2691
2692  assert.strictEqual(out, expected);
2693
2694  obj = Array.from({ length: 60 }).map((e, i) => i);
2695  out = util.inspect(obj, { compact: 1, breakLength: Infinity, colors: true });
2696
2697  expected = [
2698    '[',
2699    '   \u001b[33m0\u001b[39m,  \u001b[33m1\u001b[39m,  \u001b[33m2\u001b[39m,  \u001b[33m3\u001b[39m,',
2700    '   \u001b[33m4\u001b[39m,  \u001b[33m5\u001b[39m,  \u001b[33m6\u001b[39m,  \u001b[33m7\u001b[39m,',
2701    '   \u001b[33m8\u001b[39m,  \u001b[33m9\u001b[39m, \u001b[33m10\u001b[39m, \u001b[33m11\u001b[39m,',
2702    '  \u001b[33m12\u001b[39m, \u001b[33m13\u001b[39m, \u001b[33m14\u001b[39m, \u001b[33m15\u001b[39m,',
2703    '  \u001b[33m16\u001b[39m, \u001b[33m17\u001b[39m, \u001b[33m18\u001b[39m, \u001b[33m19\u001b[39m,',
2704    '  \u001b[33m20\u001b[39m, \u001b[33m21\u001b[39m, \u001b[33m22\u001b[39m, \u001b[33m23\u001b[39m,',
2705    '  \u001b[33m24\u001b[39m, \u001b[33m25\u001b[39m, \u001b[33m26\u001b[39m, \u001b[33m27\u001b[39m,',
2706    '  \u001b[33m28\u001b[39m, \u001b[33m29\u001b[39m, \u001b[33m30\u001b[39m, \u001b[33m31\u001b[39m,',
2707    '  \u001b[33m32\u001b[39m, \u001b[33m33\u001b[39m, \u001b[33m34\u001b[39m, \u001b[33m35\u001b[39m,',
2708    '  \u001b[33m36\u001b[39m, \u001b[33m37\u001b[39m, \u001b[33m38\u001b[39m, \u001b[33m39\u001b[39m,',
2709    '  \u001b[33m40\u001b[39m, \u001b[33m41\u001b[39m, \u001b[33m42\u001b[39m, \u001b[33m43\u001b[39m,',
2710    '  \u001b[33m44\u001b[39m, \u001b[33m45\u001b[39m, \u001b[33m46\u001b[39m, \u001b[33m47\u001b[39m,',
2711    '  \u001b[33m48\u001b[39m, \u001b[33m49\u001b[39m, \u001b[33m50\u001b[39m, \u001b[33m51\u001b[39m,',
2712    '  \u001b[33m52\u001b[39m, \u001b[33m53\u001b[39m, \u001b[33m54\u001b[39m, \u001b[33m55\u001b[39m,',
2713    '  \u001b[33m56\u001b[39m, \u001b[33m57\u001b[39m, \u001b[33m58\u001b[39m, \u001b[33m59\u001b[39m',
2714    ']',
2715  ].join('\n');
2716
2717  assert.strictEqual(out, expected);
2718
2719  out = util.inspect([1, 2, 3, 4], { compact: 1, colors: true });
2720  expected = '[ \u001b[33m1\u001b[39m, \u001b[33m2\u001b[39m, ' +
2721    '\u001b[33m3\u001b[39m, \u001b[33m4\u001b[39m ]';
2722
2723  assert.strictEqual(out, expected);
2724
2725  obj = [
2726    'Object', 'Function', 'Array',
2727    'Number', 'parseFloat', 'parseInt',
2728    'Infinity', 'NaN', 'undefined',
2729    'Boolean', 'String', 'Symbol',
2730    'Date', 'Promise', 'RegExp',
2731    'Error', 'EvalError', 'RangeError',
2732    'ReferenceError', 'SyntaxError', 'TypeError',
2733    'URIError', 'JSON', 'Math',
2734    'console', 'Intl', 'ArrayBuffer',
2735    'Uint8Array', 'Int8Array', 'Uint16Array',
2736    'Int16Array', 'Uint32Array', 'Int32Array',
2737    'Float32Array', 'Float64Array', 'Uint8ClampedArray',
2738    'BigUint64Array', 'BigInt64Array', 'DataView',
2739    'Map', 'BigInt', 'Set',
2740    'WeakMap', 'WeakSet', 'Proxy',
2741    'Reflect', 'decodeURI', 'decodeURIComponent',
2742    'encodeURI', 'encodeURIComponent', 'escape',
2743    'unescape', 'eval', 'isFinite',
2744    'isNaN', 'SharedArrayBuffer', 'Atomics',
2745    'globalThis', 'WebAssembly', 'global',
2746    'process', 'Buffer', 'URL',
2747    'URLSearchParams', 'TextEncoder', 'TextDecoder',
2748    'clearInterval', 'clearTimeout', 'setInterval',
2749    'setTimeout', 'queueMicrotask', 'clearImmediate',
2750    'setImmediate', 'module', 'require',
2751    'assert', 'async_hooks', 'buffer',
2752    'child_process', 'cluster', 'crypto',
2753    'dgram', 'dns', 'domain',
2754    'events', 'fs', 'http',
2755    'http2', 'https', 'inspector',
2756    'net', 'os', 'path',
2757    'perf_hooks', 'punycode', 'querystring',
2758    'readline', 'repl', 'stream',
2759    'string_decoder', 'tls', 'trace_events',
2760    'tty', 'url', 'v8',
2761    'vm', 'worker_threads', 'zlib',
2762    '_', '_error', 'util',
2763  ];
2764
2765  out = util.inspect(
2766    obj,
2767    { compact: 3, breakLength: 80, maxArrayLength: 250 }
2768  );
2769  expected = [
2770    '[',
2771    "  'Object',          'Function',           'Array',",
2772    "  'Number',          'parseFloat',         'parseInt',",
2773    "  'Infinity',        'NaN',                'undefined',",
2774    "  'Boolean',         'String',             'Symbol',",
2775    "  'Date',            'Promise',            'RegExp',",
2776    "  'Error',           'EvalError',          'RangeError',",
2777    "  'ReferenceError',  'SyntaxError',        'TypeError',",
2778    "  'URIError',        'JSON',               'Math',",
2779    "  'console',         'Intl',               'ArrayBuffer',",
2780    "  'Uint8Array',      'Int8Array',          'Uint16Array',",
2781    "  'Int16Array',      'Uint32Array',        'Int32Array',",
2782    "  'Float32Array',    'Float64Array',       'Uint8ClampedArray',",
2783    "  'BigUint64Array',  'BigInt64Array',      'DataView',",
2784    "  'Map',             'BigInt',             'Set',",
2785    "  'WeakMap',         'WeakSet',            'Proxy',",
2786    "  'Reflect',         'decodeURI',          'decodeURIComponent',",
2787    "  'encodeURI',       'encodeURIComponent', 'escape',",
2788    "  'unescape',        'eval',               'isFinite',",
2789    "  'isNaN',           'SharedArrayBuffer',  'Atomics',",
2790    "  'globalThis',      'WebAssembly',        'global',",
2791    "  'process',         'Buffer',             'URL',",
2792    "  'URLSearchParams', 'TextEncoder',        'TextDecoder',",
2793    "  'clearInterval',   'clearTimeout',       'setInterval',",
2794    "  'setTimeout',      'queueMicrotask',     'clearImmediate',",
2795    "  'setImmediate',    'module',             'require',",
2796    "  'assert',          'async_hooks',        'buffer',",
2797    "  'child_process',   'cluster',            'crypto',",
2798    "  'dgram',           'dns',                'domain',",
2799    "  'events',          'fs',                 'http',",
2800    "  'http2',           'https',              'inspector',",
2801    "  'net',             'os',                 'path',",
2802    "  'perf_hooks',      'punycode',           'querystring',",
2803    "  'readline',        'repl',               'stream',",
2804    "  'string_decoder',  'tls',                'trace_events',",
2805    "  'tty',             'url',                'v8',",
2806    "  'vm',              'worker_threads',     'zlib',",
2807    "  '_',               '_error',             'util'",
2808    ']',
2809  ].join('\n');
2810
2811  assert.strictEqual(out, expected);
2812}
2813
2814{
2815  const originalCWD = process.cwd();
2816
2817  process.cwd = () => (process.platform === 'win32' ?
2818    'C:\\workspace\\node-test-binary-windows js-suites-%percent-encoded\\node' :
2819    '/home/user directory/repository%encoded/node');
2820
2821  // Use a fake stack to verify the expected colored outcome.
2822  const stack = [
2823    'Error: CWD is grayed out, even cwd that are percent encoded!',
2824    '    at A.<anonymous> (/test/node_modules/foo/node_modules/bar/baz.js:2:7)',
2825    '    at Module._compile (node:internal/modules/cjs/loader:827:30)',
2826    '    at Fancy (node:vm:697:32)',
2827    // This file is not an actual Node.js core file.
2828    '    at tryModuleLoad (node:internal/modules/cjs/foo:629:12)',
2829    '    at Function.Module._load (node:internal/modules/cjs/loader:621:3)',
2830    // This file is not an actual Node.js core file.
2831    '    at Module.require [as weird/name] (node:internal/aaaaa/loader:735:19)',
2832    '    at require (node:internal/modules/helpers:14:16)',
2833    '    at Array.forEach (<anonymous>)',
2834    `    at ${process.cwd()}/test/parallel/test-util-inspect.js:2760:12`,
2835    `    at Object.<anonymous> (${process.cwd()}/node_modules/hyper_module/folder/file.js:2753:10)`,
2836    '    at /test/test-util-inspect.js:2239:9',
2837    '    at getActual (node:assert:592:5)',
2838  ];
2839  const err = new Error('CWD is grayed out, even cwd that are percent encoded!');
2840  err.stack = stack.join('\n');
2841  if (process.platform === 'win32') {
2842    err.stack = stack.map((frame) => (frame.includes('node:') ?
2843      frame :
2844      frame.replaceAll('/', '\\'))
2845    ).join('\n');
2846  }
2847  const escapedCWD = util.inspect(process.cwd()).slice(1, -1);
2848  util.inspect(err, { colors: true }).split('\n').forEach((line, i) => {
2849    let expected = stack[i].replace(/node_modules\/([^/]+)/gi, (_, m) => {
2850      return `node_modules/\u001b[4m${m}\u001b[24m`;
2851    }).replaceAll(new RegExp(`(\\(?${escapedCWD}(\\\\|/))`, 'gi'), (_, m) => {
2852      return `\x1B[90m${m}\x1B[39m`;
2853    });
2854    if (expected.includes(process.cwd()) && expected.endsWith(')')) {
2855      expected = `${expected.slice(0, -1)}\x1B[90m)\x1B[39m`;
2856    }
2857    if (line.includes('node:')) {
2858      if (!line.includes('foo') && !line.includes('aaa')) {
2859        expected = `\u001b[90m${expected}\u001b[39m`;
2860      }
2861    } else if (process.platform === 'win32') {
2862      expected = expected.replaceAll('/', '\\');
2863    }
2864    assert.strictEqual(line, expected);
2865  });
2866
2867  // Check ESM
2868  const encodedCwd = url.pathToFileURL(process.cwd());
2869  const sl = process.platform === 'win32' ? '\\' : '/';
2870
2871  // Use a fake stack to verify the expected colored outcome.
2872  err.stack = 'Error: ESM and CJS mixed are both grayed out!\n' +
2873              `    at ${encodedCwd}/test/parallel/test-esm.mjs:2760:12\n` +
2874              `    at Object.<anonymous> (${encodedCwd}/node_modules/esm_module/folder/file.js:2753:10)\n` +
2875              `    at ${process.cwd()}${sl}test${sl}parallel${sl}test-cjs.js:2760:12\n` +
2876              `    at Object.<anonymous> (${process.cwd()}${sl}node_modules${sl}cjs_module${sl}folder${sl}file.js:2753:10)`;
2877
2878  let actual = util.inspect(err, { colors: true });
2879  let expected = 'Error: ESM and CJS mixed are both grayed out!\n' +
2880    `    at \x1B[90m${encodedCwd}/\x1B[39mtest/parallel/test-esm.mjs:2760:12\n` +
2881    `    at Object.<anonymous> \x1B[90m(${encodedCwd}/\x1B[39mnode_modules/\x1B[4mesm_module\x1B[24m/folder/file.js:2753:10\x1B[90m)\x1B[39m\n` +
2882    `    at \x1B[90m${process.cwd()}${sl}\x1B[39mtest${sl}parallel${sl}test-cjs.js:2760:12\n` +
2883    `    at Object.<anonymous> \x1B[90m(${process.cwd()}${sl}\x1B[39mnode_modules${sl}\x1B[4mcjs_module\x1B[24m${sl}folder${sl}file.js:2753:10\x1B[90m)\x1B[39m`;
2884
2885  assert.strictEqual(actual, expected);
2886
2887  // ESM without need for encoding
2888  process.cwd = () => (process.platform === 'win32' ?
2889    'C:\\workspace\\node-test-binary-windows-js-suites\\node' :
2890    '/home/user/repository/node');
2891  let expectedCwd = process.cwd();
2892  if (process.platform === 'win32') {
2893    expectedCwd = `/${expectedCwd.replaceAll('\\', '/')}`;
2894  }
2895  // Use a fake stack to verify the expected colored outcome.
2896  err.stack = 'Error: ESM without need for encoding!\n' +
2897              `    at file://${expectedCwd}/file.js:15:15`;
2898
2899  actual = util.inspect(err, { colors: true });
2900  expected = 'Error: ESM without need for encoding!\n' +
2901  `    at \x1B[90mfile://${expectedCwd}/\x1B[39mfile.js:15:15`;
2902  assert.strictEqual(actual, expected);
2903
2904  process.cwd = originalCWD;
2905}
2906
2907{
2908  // Cross platform checks.
2909  const err = new Error('foo');
2910  util.inspect(err, { colors: true }).split('\n').forEach((line, i) => {
2911    assert(i < 2 || line.startsWith('\u001b[90m'));
2912  });
2913}
2914
2915{
2916  // Tracing class respects inspect depth.
2917  try {
2918    const trace = require('trace_events').createTracing({ categories: ['fo'] });
2919    const actualDepth0 = util.inspect({ trace }, { depth: 0 });
2920    assert.strictEqual(actualDepth0, '{ trace: [Tracing] }');
2921    const actualDepth1 = util.inspect({ trace }, { depth: 1 });
2922    assert.strictEqual(
2923      actualDepth1,
2924      "{ trace: Tracing { enabled: false, categories: 'fo' } }"
2925    );
2926  } catch (err) {
2927    if (err.code !== 'ERR_TRACE_EVENTS_UNAVAILABLE')
2928      throw err;
2929  }
2930}
2931
2932// Inspect prototype properties.
2933{
2934  class Foo extends Map {
2935    prop = false;
2936    prop2 = true;
2937    get abc() {
2938      return true;
2939    }
2940    get def() {
2941      return false;
2942    }
2943    set def(v) {}
2944    get xyz() {
2945      return 'Should be ignored';
2946    }
2947    func(a) {}
2948    [util.inspect.custom]() {
2949      return this;
2950    }
2951  }
2952
2953  class Bar extends Foo {
2954    abc = true;
2955    prop = true;
2956    get xyz() {
2957      return 'YES!';
2958    }
2959    [util.inspect.custom]() {
2960      return this;
2961    }
2962  }
2963
2964  const bar = new Bar();
2965
2966  assert.strictEqual(
2967    inspect(bar),
2968    'Bar(0) [Map] { prop: true, prop2: true, abc: true }'
2969  );
2970  assert.strictEqual(
2971    inspect(bar, { showHidden: true, getters: true, colors: false }),
2972    'Bar(0) [Map] {\n' +
2973    '  prop: true,\n' +
2974    '  prop2: true,\n' +
2975    '  abc: true,\n' +
2976    "  [xyz]: [Getter: 'YES!'],\n" +
2977    '  [def]: [Getter/Setter: false]\n' +
2978    '}'
2979  );
2980  assert.strictEqual(
2981    inspect(bar, { showHidden: true, getters: false, colors: true }),
2982    'Bar(0) [Map] {\n' +
2983    '  prop: \x1B[33mtrue\x1B[39m,\n' +
2984    '  prop2: \x1B[33mtrue\x1B[39m,\n' +
2985    '  abc: \x1B[33mtrue\x1B[39m,\n' +
2986    '  \x1B[2m[xyz]: \x1B[36m[Getter]\x1B[39m\x1B[22m,\n' +
2987    '  \x1B[2m[def]: \x1B[36m[Getter/Setter]\x1B[39m\x1B[22m\n' +
2988    '}'
2989  );
2990
2991  const obj = Object.create({ abc: true, def: 5, toString() {} });
2992  assert.strictEqual(
2993    inspect(obj, { showHidden: true, colors: true }),
2994    '{ \x1B[2mabc: \x1B[33mtrue\x1B[39m\x1B[22m, ' +
2995      '\x1B[2mdef: \x1B[33m5\x1B[39m\x1B[22m }'
2996  );
2997
2998  assert.strictEqual(
2999    inspect(Object.getPrototypeOf(bar), { showHidden: true, getters: true }),
3000    '<ref *1> Foo [Map] {\n' +
3001    '    [constructor]: [class Bar extends Foo] {\n' +
3002    '      [length]: 0,\n' +
3003    "      [name]: 'Bar',\n" +
3004    '      [prototype]: [Circular *1],\n' +
3005    '      [Symbol(Symbol.species)]: [Getter: <Inspection threw ' +
3006      "(Symbol.prototype.toString requires that 'this' be a Symbol)>]\n" +
3007    '    },\n' +
3008    "    [xyz]: [Getter: 'YES!'],\n" +
3009    '    [Symbol(nodejs.util.inspect.custom)]: ' +
3010      '[Function: [nodejs.util.inspect.custom]] {\n' +
3011    '      [length]: 0,\n' +
3012    "      [name]: '[nodejs.util.inspect.custom]'\n" +
3013    '    },\n' +
3014    '    [abc]: [Getter: true],\n' +
3015    '    [def]: [Getter/Setter: false]\n' +
3016    '  }'
3017  );
3018
3019  assert.strictEqual(
3020    inspect(Object.getPrototypeOf(bar)),
3021    'Foo [Map] {}'
3022  );
3023
3024  assert.strictEqual(
3025    inspect(Object.getPrototypeOf(new Foo())),
3026    'Map {}'
3027  );
3028}
3029
3030// Check that prototypes with a null prototype are inspectable.
3031// Regression test for https://github.com/nodejs/node/issues/35730
3032{
3033  function Func() {}
3034  Func.prototype = null;
3035  const object = {};
3036  object.constructor = Func;
3037
3038  assert.strictEqual(util.inspect(object), '{ constructor: [Function: Func] }');
3039}
3040
3041// Test changing util.inspect.colors colors and aliases.
3042{
3043  const colors = util.inspect.colors;
3044
3045  const originalValue = colors.gray;
3046
3047  // "grey" is reference-equal alias of "gray".
3048  assert.strictEqual(colors.grey, colors.gray);
3049
3050  // Assigninging one should assign the other. This tests that the alias setter
3051  // function keeps things reference-equal.
3052  colors.gray = [0, 0];
3053  assert.deepStrictEqual(colors.gray, [0, 0]);
3054  assert.strictEqual(colors.grey, colors.gray);
3055
3056  colors.grey = [1, 1];
3057  assert.deepStrictEqual(colors.grey, [1, 1]);
3058  assert.strictEqual(colors.grey, colors.gray);
3059
3060  // Restore original value to avoid side effects in other tests.
3061  colors.gray = originalValue;
3062  assert.deepStrictEqual(colors.gray, originalValue);
3063  assert.strictEqual(colors.grey, colors.gray);
3064}
3065
3066// https://github.com/nodejs/node/issues/31889
3067{
3068  v8.setFlagsFromString('--allow-natives-syntax');
3069  const undetectable = vm.runInThisContext('%GetUndetectable()');
3070  v8.setFlagsFromString('--no-allow-natives-syntax');
3071  assert.strictEqual(inspect(undetectable), '{}');
3072}
3073
3074// Truncate output for Primitives with 1 character left
3075{
3076  assert.strictEqual(util.inspect('bl', { maxStringLength: 1 }),
3077                     "'b'... 1 more character");
3078}
3079
3080{
3081  const x = 'a'.repeat(1e6);
3082  assert(util.inspect(x).endsWith('... 990000 more characters'));
3083  assert.strictEqual(
3084    util.inspect(x, { maxStringLength: 4 }),
3085    "'aaaa'... 999996 more characters"
3086  );
3087  assert.match(util.inspect(x, { maxStringLength: null }), /a'$/);
3088}
3089
3090{
3091  // Verify that util.inspect() invokes custom inspect functions on objects
3092  // from other vm.Contexts but does not pass data from its own Context to that
3093  // function.
3094  const target = vm.runInNewContext(`
3095    ({
3096      [Symbol.for('nodejs.util.inspect.custom')](depth, ctx) {
3097        this.depth = depth;
3098        this.ctx = ctx;
3099        try {
3100          this.stylized = ctx.stylize('��');
3101        } catch (e) {
3102          this.stylizeException = e;
3103        }
3104        return this.stylized;
3105      }
3106    })
3107  `, Object.create(null));
3108  assert.strictEqual(target.ctx, undefined);
3109
3110  {
3111    // Subtest 1: Just try to inspect the object with default options.
3112    assert.strictEqual(util.inspect(target), '��');
3113    assert.strictEqual(typeof target.ctx, 'object');
3114    const objectGraph = fullObjectGraph(target);
3115    assert(!objectGraph.has(Object));
3116    assert(!objectGraph.has(Function));
3117  }
3118
3119  {
3120    // Subtest 2: Use a stylize function that returns a non-primitive.
3121    const output = util.inspect(target, {
3122      stylize: common.mustCall((str) => {
3123        return {};
3124      })
3125    });
3126    assert.strictEqual(output, '[object Object]');
3127    assert.strictEqual(typeof target.ctx, 'object');
3128    const objectGraph = fullObjectGraph(target);
3129    assert(!objectGraph.has(Object));
3130    assert(!objectGraph.has(Function));
3131  }
3132
3133  {
3134    // Subtest 3: Use a stylize function that throws an exception.
3135    const output = util.inspect(target, {
3136      stylize: common.mustCall((str) => {
3137        throw new Error('oops');
3138      })
3139    });
3140    assert.strictEqual(output, '��');
3141    assert.strictEqual(typeof target.ctx, 'object');
3142    const objectGraph = fullObjectGraph(target);
3143    assert(!objectGraph.has(Object));
3144    assert(!objectGraph.has(Function));
3145  }
3146
3147  function fullObjectGraph(value) {
3148    const graph = new Set([value]);
3149
3150    for (const entry of graph) {
3151      if ((typeof entry !== 'object' && typeof entry !== 'function') ||
3152          entry === null) {
3153        continue;
3154      }
3155
3156      graph.add(Object.getPrototypeOf(entry));
3157      const descriptors = Object.values(
3158        Object.getOwnPropertyDescriptors(entry));
3159      for (const descriptor of descriptors) {
3160        graph.add(descriptor.value);
3161        graph.add(descriptor.set);
3162        graph.add(descriptor.get);
3163      }
3164    }
3165
3166    return graph;
3167  }
3168
3169  // Consistency check.
3170  assert(fullObjectGraph(global).has(Function.prototype));
3171}
3172
3173{
3174  // Confirm that own constructor value displays correctly.
3175
3176  function Fhqwhgads() {}
3177
3178  const sterrance = new Fhqwhgads();
3179  sterrance.constructor = Fhqwhgads;
3180
3181  assert.strictEqual(
3182    util.inspect(sterrance, { showHidden: true }),
3183    'Fhqwhgads {\n' +
3184      '  constructor: <ref *1> [Function: Fhqwhgads] {\n' +
3185      '    [length]: 0,\n' +
3186      "    [name]: 'Fhqwhgads',\n" +
3187      '    [prototype]: { [constructor]: [Circular *1] }\n' +
3188      '  }\n' +
3189      '}'
3190  );
3191}
3192
3193{
3194  // Confirm null prototype of generator prototype displays as expected.
3195
3196  function getProtoOfProto() {
3197    return Object.getPrototypeOf(Object.getPrototypeOf(function* () {}));
3198  }
3199
3200  function* generator() {}
3201
3202  const generatorPrototype = Object.getPrototypeOf(generator);
3203  const originalProtoOfProto = Object.getPrototypeOf(generatorPrototype);
3204  assert.strictEqual(getProtoOfProto(), originalProtoOfProto);
3205  Object.setPrototypeOf(generatorPrototype, null);
3206  assert.notStrictEqual(getProtoOfProto, originalProtoOfProto);
3207
3208  // This is the actual test. The other assertions in this block are about
3209  // making sure the test is set up correctly and isn't polluting other tests.
3210  assert.strictEqual(
3211    util.inspect(generator, { showHidden: true }),
3212    '[GeneratorFunction: generator] {\n' +
3213    '  [length]: 0,\n' +
3214    "  [name]: 'generator',\n" +
3215    "  [prototype]: Object [Generator] { [Symbol(Symbol.toStringTag)]: 'Generator' },\n" + // eslint-disable-line max-len
3216    "  [Symbol(Symbol.toStringTag)]: 'GeneratorFunction'\n" +
3217    '}'
3218  );
3219
3220  // Reset so we don't pollute other tests
3221  Object.setPrototypeOf(generatorPrototype, originalProtoOfProto);
3222  assert.strictEqual(getProtoOfProto(), originalProtoOfProto);
3223}
3224
3225{
3226  // Test for when breakLength results in a single column.
3227  const obj = Array(9).fill('fhqwhgadshgnsdhjsdbkhsdabkfabkveybvf');
3228  assert.strictEqual(
3229    util.inspect(obj, { breakLength: 256 }),
3230    '[\n' +
3231    "  'fhqwhgadshgnsdhjsdbkhsdabkfabkveybvf',\n" +
3232    "  'fhqwhgadshgnsdhjsdbkhsdabkfabkveybvf',\n" +
3233    "  'fhqwhgadshgnsdhjsdbkhsdabkfabkveybvf',\n" +
3234    "  'fhqwhgadshgnsdhjsdbkhsdabkfabkveybvf',\n" +
3235    "  'fhqwhgadshgnsdhjsdbkhsdabkfabkveybvf',\n" +
3236    "  'fhqwhgadshgnsdhjsdbkhsdabkfabkveybvf',\n" +
3237    "  'fhqwhgadshgnsdhjsdbkhsdabkfabkveybvf',\n" +
3238    "  'fhqwhgadshgnsdhjsdbkhsdabkfabkveybvf',\n" +
3239    "  'fhqwhgadshgnsdhjsdbkhsdabkfabkveybvf'\n" +
3240    ']'
3241  );
3242}
3243
3244{
3245  assert.strictEqual(
3246    util.inspect({ ['__proto__']: { a: 1 } }),
3247    "{ ['__proto__']: { a: 1 } }"
3248  );
3249}
3250
3251{
3252  const { numericSeparator } = util.inspect.defaultOptions;
3253  util.inspect.defaultOptions.numericSeparator = true;
3254
3255  assert.strictEqual(
3256    // eslint-disable-next-line no-loss-of-precision
3257    util.inspect(1234567891234567891234),
3258    '1.234567891234568e+21'
3259  );
3260  assert.strictEqual(
3261    util.inspect(123456789.12345678),
3262    '123_456_789.123_456_78'
3263  );
3264
3265  assert.strictEqual(util.inspect(10_000_000), '10_000_000');
3266  assert.strictEqual(util.inspect(1_000_000), '1_000_000');
3267  assert.strictEqual(util.inspect(100_000), '100_000');
3268  assert.strictEqual(util.inspect(99_999.9), '99_999.9');
3269  assert.strictEqual(util.inspect(9_999), '9_999');
3270  assert.strictEqual(util.inspect(999), '999');
3271  assert.strictEqual(util.inspect(NaN), 'NaN');
3272  assert.strictEqual(util.inspect(Infinity), 'Infinity');
3273  assert.strictEqual(util.inspect(-Infinity), '-Infinity');
3274
3275  assert.strictEqual(
3276    util.inspect(new Float64Array([100_000_000])),
3277    'Float64Array(1) [ 100_000_000 ]'
3278  );
3279  assert.strictEqual(
3280    util.inspect(new BigInt64Array([9_100_000_100n])),
3281    'BigInt64Array(1) [ 9_100_000_100n ]'
3282  );
3283
3284  assert.strictEqual(
3285    util.inspect(123456789),
3286    '123_456_789'
3287  );
3288  assert.strictEqual(
3289    util.inspect(123456789n),
3290    '123_456_789n'
3291  );
3292
3293  util.inspect.defaultOptions.numericSeparator = numericSeparator;
3294
3295  assert.strictEqual(
3296    util.inspect(123456789.12345678, { numericSeparator: true }),
3297    '123_456_789.123_456_78'
3298  );
3299
3300  assert.strictEqual(
3301    util.inspect(-123456789.12345678, { numericSeparator: true }),
3302    '-123_456_789.123_456_78'
3303  );
3304}
3305
3306// Regression test for https://github.com/nodejs/node/issues/41244
3307{
3308  assert.strictEqual(util.inspect({
3309    get [Symbol.iterator]() {
3310      throw new Error();
3311    }
3312  }), '{ [Symbol(Symbol.iterator)]: [Getter] }');
3313}
3314