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