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