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