1'use strict'; 2 3require('../common'); 4const assert = require('assert'); 5const util = require('util'); 6const { AssertionError } = assert; 7const defaultMsgStart = 'Expected values to be strictly deep-equal:\n'; 8const defaultMsgStartFull = `${defaultMsgStart}+ actual - expected`; 9 10// Disable colored output to prevent color codes from breaking assertion 11// message comparisons. This should only be an issue when process.stdout 12// is a TTY. 13if (process.stdout.isTTY) 14 process.env.NODE_DISABLE_COLORS = '1'; 15 16// Template tag function turning an error message into a RegExp 17// for assert.throws() 18function re(literals, ...values) { 19 let result = 'Expected values to be loosely deep-equal:\n\n'; 20 for (const [i, value] of values.entries()) { 21 const str = util.inspect(value, { 22 compact: false, 23 depth: 1000, 24 customInspect: false, 25 maxArrayLength: Infinity, 26 breakLength: Infinity, 27 sorted: true, 28 getters: true 29 }); 30 // Need to escape special characters. 31 result += `${str}${literals[i + 1]}`; 32 } 33 return { 34 code: 'ERR_ASSERTION', 35 message: result 36 }; 37} 38 39// The following deepEqual tests might seem very weird. 40// They just describe what it is now. 41// That is why we discourage using deepEqual in our own tests. 42 43// Turn off no-restricted-properties because we are testing deepEqual! 44/* eslint-disable no-restricted-properties */ 45 46const arr = new Uint8Array([120, 121, 122, 10]); 47const buf = Buffer.from(arr); 48// They have different [[Prototype]] 49assert.throws( 50 () => assert.deepStrictEqual(arr, buf), 51 { 52 code: 'ERR_ASSERTION', 53 message: `${defaultMsgStartFull} ... Lines skipped\n\n` + 54 '+ Uint8Array(4) [\n' + 55 '- Buffer(4) [Uint8Array] [\n 120,\n...\n 122,\n 10\n ]' 56 } 57); 58assert.deepEqual(arr, buf); 59 60{ 61 const buf2 = Buffer.from(arr); 62 buf2.prop = 1; 63 64 assert.throws( 65 () => assert.deepStrictEqual(buf2, buf), 66 { 67 code: 'ERR_ASSERTION', 68 message: `${defaultMsgStartFull}\n\n` + 69 ' Buffer(4) [Uint8Array] [\n' + 70 ' 120,\n' + 71 ' 121,\n' + 72 ' 122,\n' + 73 ' 10,\n' + 74 '+ prop: 1\n' + 75 ' ]' 76 } 77 ); 78 assert.notDeepEqual(buf2, buf); 79} 80 81{ 82 const arr2 = new Uint8Array([120, 121, 122, 10]); 83 arr2.prop = 5; 84 assert.throws( 85 () => assert.deepStrictEqual(arr, arr2), 86 { 87 code: 'ERR_ASSERTION', 88 message: `${defaultMsgStartFull}\n\n` + 89 ' Uint8Array(4) [\n' + 90 ' 120,\n' + 91 ' 121,\n' + 92 ' 122,\n' + 93 ' 10,\n' + 94 '- prop: 5\n' + 95 ' ]' 96 } 97 ); 98 assert.notDeepEqual(arr, arr2); 99} 100 101const date = new Date('2016'); 102 103class MyDate extends Date { 104 constructor(...args) { 105 super(...args); 106 this[0] = '1'; 107 } 108} 109 110const date2 = new MyDate('2016'); 111 112assertNotDeepOrStrict(date, date2); 113assert.throws( 114 () => assert.deepStrictEqual(date, date2), 115 { 116 code: 'ERR_ASSERTION', 117 message: `${defaultMsgStartFull}\n\n` + 118 '+ 2016-01-01T00:00:00.000Z\n- MyDate 2016-01-01T00:00:00.000Z' + 119 " {\n- '0': '1'\n- }" 120 } 121); 122assert.throws( 123 () => assert.deepStrictEqual(date2, date), 124 { 125 code: 'ERR_ASSERTION', 126 message: `${defaultMsgStartFull}\n\n` + 127 '+ MyDate 2016-01-01T00:00:00.000Z {\n' + 128 "+ '0': '1'\n+ }\n- 2016-01-01T00:00:00.000Z" 129 } 130); 131 132class MyRegExp extends RegExp { 133 constructor(...args) { 134 super(...args); 135 this[0] = '1'; 136 } 137} 138 139const re1 = new RegExp('test'); 140const re2 = new MyRegExp('test'); 141 142assertNotDeepOrStrict(re1, re2); 143assert.throws( 144 () => assert.deepStrictEqual(re1, re2), 145 { 146 code: 'ERR_ASSERTION', 147 message: `${defaultMsgStartFull}\n\n` + 148 "+ /test/\n- MyRegExp /test/ {\n- '0': '1'\n- }" 149 } 150); 151 152// For these weird cases, deepEqual should pass (at least for now), 153// but deepStrictEqual should throw. 154{ 155 const similar = new Set([ 156 { 0: 1 }, // Object 157 new String('1'), // Object 158 [1], // Array 159 date2, // Date with this[0] = '1' 160 re2, // RegExp with this[0] = '1' 161 new Int8Array([1]), // Int8Array 162 new Int16Array([1]), // Int16Array 163 new Uint16Array([1]), // Uint16Array 164 new Int32Array([1]), // Int32Array 165 new Uint32Array([1]), // Uint32Array 166 Buffer.from([1]), // Uint8Array 167 (function() { return arguments; })(1), 168 ]); 169 170 for (const a of similar) { 171 for (const b of similar) { 172 if (a !== b) { 173 assert.notDeepEqual(a, b); 174 assert.throws( 175 () => assert.deepStrictEqual(a, b), 176 { code: 'ERR_ASSERTION' } 177 ); 178 } 179 } 180 } 181} 182 183function assertDeepAndStrictEqual(a, b) { 184 assert.deepEqual(a, b); 185 assert.deepStrictEqual(a, b); 186 187 assert.deepEqual(b, a); 188 assert.deepStrictEqual(b, a); 189} 190 191function assertNotDeepOrStrict(a, b, err) { 192 assert.throws( 193 () => assert.deepEqual(a, b), 194 err || re`${a}\n\nshould loosely deep-equal\n\n${b}` 195 ); 196 assert.throws( 197 () => assert.deepStrictEqual(a, b), 198 err || { code: 'ERR_ASSERTION' } 199 ); 200 201 assert.throws( 202 () => assert.deepEqual(b, a), 203 err || re`${b}\n\nshould loosely deep-equal\n\n${a}` 204 ); 205 assert.throws( 206 () => assert.deepStrictEqual(b, a), 207 err || { code: 'ERR_ASSERTION' } 208 ); 209} 210 211function assertOnlyDeepEqual(a, b, err) { 212 assert.deepEqual(a, b); 213 assert.throws( 214 () => assert.deepStrictEqual(a, b), 215 err || { code: 'ERR_ASSERTION' } 216 ); 217 218 assert.deepEqual(b, a); 219 assert.throws( 220 () => assert.deepStrictEqual(b, a), 221 err || { code: 'ERR_ASSERTION' } 222 ); 223} 224 225// es6 Maps and Sets 226assertDeepAndStrictEqual(new Set(), new Set()); 227assertDeepAndStrictEqual(new Map(), new Map()); 228 229assertDeepAndStrictEqual(new Set([1, 2, 3]), new Set([1, 2, 3])); 230assertNotDeepOrStrict(new Set([1, 2, 3]), new Set([1, 2, 3, 4])); 231assertNotDeepOrStrict(new Set([1, 2, 3, 4]), new Set([1, 2, 3])); 232assertDeepAndStrictEqual(new Set(['1', '2', '3']), new Set(['1', '2', '3'])); 233assertDeepAndStrictEqual(new Set([[1, 2], [3, 4]]), new Set([[3, 4], [1, 2]])); 234assertNotDeepOrStrict(new Set([{ a: 0 }]), new Set([{ a: 1 }])); 235assertNotDeepOrStrict(new Set([Symbol()]), new Set([Symbol()])); 236 237{ 238 const a = [ 1, 2 ]; 239 const b = [ 3, 4 ]; 240 const c = [ 1, 2 ]; 241 const d = [ 3, 4 ]; 242 243 assertDeepAndStrictEqual( 244 { a: a, b: b, s: new Set([a, b]) }, 245 { a: c, b: d, s: new Set([d, c]) } 246 ); 247} 248 249assertDeepAndStrictEqual(new Map([[1, 1], [2, 2]]), new Map([[1, 1], [2, 2]])); 250assertDeepAndStrictEqual(new Map([[1, 1], [2, 2]]), new Map([[2, 2], [1, 1]])); 251assertNotDeepOrStrict(new Map([[1, 1], [2, 2]]), new Map([[1, 2], [2, 1]])); 252assertNotDeepOrStrict( 253 new Map([[[1], 1], [{}, 2]]), 254 new Map([[[1], 2], [{}, 1]]) 255); 256 257assertNotDeepOrStrict(new Set([1]), [1]); 258assertNotDeepOrStrict(new Set(), []); 259assertNotDeepOrStrict(new Set(), {}); 260 261assertNotDeepOrStrict(new Map([['a', 1]]), { a: 1 }); 262assertNotDeepOrStrict(new Map(), []); 263assertNotDeepOrStrict(new Map(), {}); 264 265assertOnlyDeepEqual(new Set(['1']), new Set([1])); 266 267assertOnlyDeepEqual(new Map([['1', 'a']]), new Map([[1, 'a']])); 268assertOnlyDeepEqual(new Map([['a', '1']]), new Map([['a', 1]])); 269assertNotDeepOrStrict(new Map([['a', '1']]), new Map([['a', 2]])); 270 271assertDeepAndStrictEqual(new Set([{}]), new Set([{}])); 272 273// Ref: https://github.com/nodejs/node/issues/13347 274assertNotDeepOrStrict( 275 new Set([{ a: 1 }, { a: 1 }]), 276 new Set([{ a: 1 }, { a: 2 }]) 277); 278assertNotDeepOrStrict( 279 new Set([{ a: 1 }, { a: 1 }, { a: 2 }]), 280 new Set([{ a: 1 }, { a: 2 }, { a: 2 }]) 281); 282assertNotDeepOrStrict( 283 new Map([[{ x: 1 }, 5], [{ x: 1 }, 5]]), 284 new Map([[{ x: 1 }, 5], [{ x: 2 }, 5]]) 285); 286 287assertNotDeepOrStrict(new Set([3, '3']), new Set([3, 4])); 288assertNotDeepOrStrict(new Map([[3, 0], ['3', 0]]), new Map([[3, 0], [4, 0]])); 289 290assertNotDeepOrStrict( 291 new Set([{ a: 1 }, { a: 1 }, { a: 2 }]), 292 new Set([{ a: 1 }, { a: 2 }, { a: 2 }]) 293); 294 295// Mixed primitive and object keys 296assertDeepAndStrictEqual( 297 new Map([[1, 'a'], [{}, 'a']]), 298 new Map([[1, 'a'], [{}, 'a']]) 299); 300assertDeepAndStrictEqual( 301 new Set([1, 'a', [{}, 'a']]), 302 new Set([1, 'a', [{}, 'a']]) 303); 304 305// This is an awful case, where a map contains multiple equivalent keys: 306assertOnlyDeepEqual( 307 new Map([[1, 'a'], ['1', 'b']]), 308 new Map([['1', 'a'], [true, 'b']]) 309); 310assertNotDeepOrStrict( 311 new Set(['a']), 312 new Set(['b']) 313); 314assertDeepAndStrictEqual( 315 new Map([[{}, 'a'], [{}, 'b']]), 316 new Map([[{}, 'b'], [{}, 'a']]) 317); 318assertOnlyDeepEqual( 319 new Map([[true, 'a'], ['1', 'b'], [1, 'a']]), 320 new Map([['1', 'a'], [1, 'b'], [true, 'a']]) 321); 322assertNotDeepOrStrict( 323 new Map([[true, 'a'], ['1', 'b'], [1, 'c']]), 324 new Map([['1', 'a'], [1, 'b'], [true, 'a']]) 325); 326 327// Similar object keys 328assertNotDeepOrStrict( 329 new Set([{}, {}]), 330 new Set([{}, 1]) 331); 332assertNotDeepOrStrict( 333 new Set([[{}, 1], [{}, 1]]), 334 new Set([[{}, 1], [1, 1]]) 335); 336assertNotDeepOrStrict( 337 new Map([[{}, 1], [{}, 1]]), 338 new Map([[{}, 1], [1, 1]]) 339); 340assertOnlyDeepEqual( 341 new Map([[{}, 1], [true, 1]]), 342 new Map([[{}, 1], [1, 1]]) 343); 344 345// Similar primitive key / values 346assertNotDeepOrStrict( 347 new Set([1, true, false]), 348 new Set(['1', 0, '0']) 349); 350assertNotDeepOrStrict( 351 new Map([[1, 5], [true, 5], [false, 5]]), 352 new Map([['1', 5], [0, 5], ['0', 5]]) 353); 354 355// Undefined value in Map 356assertDeepAndStrictEqual( 357 new Map([[1, undefined]]), 358 new Map([[1, undefined]]) 359); 360assertOnlyDeepEqual( 361 new Map([[1, null], ['', '0']]), 362 new Map([['1', undefined], [false, 0]]) 363); 364assertNotDeepOrStrict( 365 new Map([[1, undefined]]), 366 new Map([[2, undefined]]) 367); 368 369// null as key 370assertDeepAndStrictEqual( 371 new Map([[null, 3]]), 372 new Map([[null, 3]]) 373); 374assertOnlyDeepEqual( 375 new Map([[undefined, null], ['+000', 2n]]), 376 new Map([[null, undefined], [false, '2']]), 377); 378 379assertOnlyDeepEqual( 380 new Set([null, '', 1n, 5, 2n, false]), 381 new Set([undefined, 0, 5n, true, '2', '-000']) 382); 383assertNotDeepOrStrict( 384 new Set(['']), 385 new Set(['0']) 386); 387assertOnlyDeepEqual( 388 new Map([[1, {}]]), 389 new Map([[true, {}]]) 390); 391assertOnlyDeepEqual( 392 new Map([[undefined, true]]), 393 new Map([[null, true]]) 394); 395assertNotDeepOrStrict( 396 new Map([[undefined, true]]), 397 new Map([[true, true]]) 398); 399 400// GH-6416. Make sure circular refs don't throw. 401{ 402 const b = {}; 403 b.b = b; 404 const c = {}; 405 c.b = c; 406 407 assertDeepAndStrictEqual(b, c); 408 409 const d = {}; 410 d.a = 1; 411 d.b = d; 412 const e = {}; 413 e.a = 1; 414 e.b = {}; 415 416 assertNotDeepOrStrict(d, e); 417} 418 419// GH-14441. Circular structures should be consistent 420{ 421 const a = {}; 422 const b = {}; 423 a.a = a; 424 b.a = {}; 425 b.a.a = a; 426 assertDeepAndStrictEqual(a, b); 427} 428 429{ 430 const a = new Set(); 431 const b = new Set(); 432 const c = new Set(); 433 a.add(a); 434 b.add(b); 435 c.add(a); 436 assertDeepAndStrictEqual(b, c); 437} 438 439// https://github.com/nodejs/node-v0.x-archive/pull/7178 440// Ensure reflexivity of deepEqual with `arguments` objects. 441{ 442 const args = (function() { return arguments; })(); 443 assertNotDeepOrStrict([], args); 444} 445 446// More checking that arguments objects are handled correctly 447{ 448 // eslint-disable-next-line func-style 449 const returnArguments = function() { return arguments; }; 450 451 const someArgs = returnArguments('a'); 452 const sameArgs = returnArguments('a'); 453 const diffArgs = returnArguments('b'); 454 455 assertNotDeepOrStrict(someArgs, ['a']); 456 assertNotDeepOrStrict(someArgs, { '0': 'a' }); 457 assertNotDeepOrStrict(someArgs, diffArgs); 458 assertDeepAndStrictEqual(someArgs, sameArgs); 459} 460 461{ 462 const values = [ 463 123, 464 Infinity, 465 0, 466 null, 467 undefined, 468 false, 469 true, 470 {}, 471 [], 472 () => {}, 473 ]; 474 assertDeepAndStrictEqual(new Set(values), new Set(values)); 475 assertDeepAndStrictEqual(new Set(values), new Set(values.reverse())); 476 477 const mapValues = values.map((v) => [v, { a: 5 }]); 478 assertDeepAndStrictEqual(new Map(mapValues), new Map(mapValues)); 479 assertDeepAndStrictEqual(new Map(mapValues), new Map(mapValues.reverse())); 480} 481 482{ 483 const s1 = new Set(); 484 const s2 = new Set(); 485 s1.add(1); 486 s1.add(2); 487 s2.add(2); 488 s2.add(1); 489 assertDeepAndStrictEqual(s1, s2); 490} 491 492{ 493 const m1 = new Map(); 494 const m2 = new Map(); 495 const obj = { a: 5, b: 6 }; 496 m1.set(1, obj); 497 m1.set(2, 'hi'); 498 m1.set(3, [1, 2, 3]); 499 500 m2.set(2, 'hi'); // different order 501 m2.set(1, obj); 502 m2.set(3, [1, 2, 3]); // Deep equal, but not reference equal. 503 504 assertDeepAndStrictEqual(m1, m2); 505} 506 507{ 508 const m1 = new Map(); 509 const m2 = new Map(); 510 511 // m1 contains itself. 512 m1.set(1, m1); 513 m2.set(1, new Map()); 514 515 assertNotDeepOrStrict(m1, m2); 516} 517 518{ 519 const map1 = new Map([[1, 1]]); 520 const map2 = new Map([[1, '1']]); 521 assert.deepEqual(map1, map2); 522 assert.throws( 523 () => assert.deepStrictEqual(map1, map2), 524 { 525 code: 'ERR_ASSERTION', 526 message: `${defaultMsgStartFull}\n\n` + 527 " Map(1) {\n+ 1 => 1\n- 1 => '1'\n }" 528 } 529 ); 530} 531 532{ 533 // Two equivalent sets / maps with different key/values applied shouldn't be 534 // the same. This is a terrible idea to do in practice, but deepEqual should 535 // still check for it. 536 const s1 = new Set(); 537 const s2 = new Set(); 538 s1.x = 5; 539 assertNotDeepOrStrict(s1, s2); 540 541 const m1 = new Map(); 542 const m2 = new Map(); 543 m1.x = 5; 544 assertNotDeepOrStrict(m1, m2); 545} 546 547{ 548 // Circular references. 549 const s1 = new Set(); 550 s1.add(s1); 551 const s2 = new Set(); 552 s2.add(s2); 553 assertDeepAndStrictEqual(s1, s2); 554 555 const m1 = new Map(); 556 m1.set(2, m1); 557 const m2 = new Map(); 558 m2.set(2, m2); 559 assertDeepAndStrictEqual(m1, m2); 560 561 const m3 = new Map(); 562 m3.set(m3, 2); 563 const m4 = new Map(); 564 m4.set(m4, 2); 565 assertDeepAndStrictEqual(m3, m4); 566} 567 568// Handle sparse arrays. 569{ 570 /* eslint-disable no-sparse-arrays */ 571 assertDeepAndStrictEqual([1, , , 3], [1, , , 3]); 572 assertNotDeepOrStrict([1, , , 3], [1, , , 3, , , ]); 573 /* eslint-enable no-sparse-arrays */ 574 const a = new Array(3); 575 const b = new Array(3); 576 a[2] = true; 577 b[1] = true; 578 assertNotDeepOrStrict(a, b); 579 b[2] = true; 580 assertNotDeepOrStrict(a, b); 581 a[0] = true; 582 assertNotDeepOrStrict(a, b); 583} 584 585// Handle different error messages 586{ 587 const err1 = new Error('foo1'); 588 assertNotDeepOrStrict(err1, new Error('foo2'), assert.AssertionError); 589 assertNotDeepOrStrict(err1, new TypeError('foo1'), assert.AssertionError); 590 assertDeepAndStrictEqual(err1, new Error('foo1')); 591 assertNotDeepOrStrict(err1, {}, AssertionError); 592} 593 594// Handle NaN 595assertDeepAndStrictEqual(NaN, NaN); 596assertDeepAndStrictEqual({ a: NaN }, { a: NaN }); 597assertDeepAndStrictEqual([ 1, 2, NaN, 4 ], [ 1, 2, NaN, 4 ]); 598 599// Handle boxed primitives 600{ 601 const boxedString = new String('test'); 602 const boxedSymbol = Object(Symbol()); 603 604 const fakeBoxedSymbol = {}; 605 Object.setPrototypeOf(fakeBoxedSymbol, Symbol.prototype); 606 Object.defineProperty( 607 fakeBoxedSymbol, 608 Symbol.toStringTag, 609 { enumerable: false, value: 'Symbol' } 610 ); 611 612 assertNotDeepOrStrict(new Boolean(true), Object(false)); 613 assertNotDeepOrStrict(Object(true), new Number(1)); 614 assertNotDeepOrStrict(new Number(2), new Number(1)); 615 assertNotDeepOrStrict(boxedSymbol, Object(Symbol())); 616 assertNotDeepOrStrict(boxedSymbol, {}); 617 assertNotDeepOrStrict(boxedSymbol, fakeBoxedSymbol); 618 assertDeepAndStrictEqual(boxedSymbol, boxedSymbol); 619 assertDeepAndStrictEqual(Object(true), Object(true)); 620 assertDeepAndStrictEqual(Object(2), Object(2)); 621 assertDeepAndStrictEqual(boxedString, Object('test')); 622 boxedString.slow = true; 623 assertNotDeepOrStrict(boxedString, Object('test')); 624 boxedSymbol.slow = true; 625 assertNotDeepOrStrict(boxedSymbol, {}); 626 assertNotDeepOrStrict(boxedSymbol, fakeBoxedSymbol); 627} 628 629// Minus zero 630assertOnlyDeepEqual(0, -0); 631assertDeepAndStrictEqual(-0, -0); 632 633// Handle symbols (enumerable only) 634{ 635 const symbol1 = Symbol(); 636 const obj1 = { [symbol1]: 1 }; 637 const obj2 = { [symbol1]: 1 }; 638 const obj3 = { [Symbol()]: 1 }; 639 // Add a non enumerable symbol as well. It is going to be ignored! 640 Object.defineProperty(obj2, Symbol(), { value: 1 }); 641 assertOnlyDeepEqual(obj1, obj3); 642 assertDeepAndStrictEqual(obj1, obj2); 643 obj2[Symbol()] = true; 644 assertOnlyDeepEqual(obj1, obj2); 645 // TypedArrays have a fast path. Test for this as well. 646 const a = new Uint8Array(4); 647 const b = new Uint8Array(4); 648 a[symbol1] = true; 649 b[symbol1] = false; 650 assertOnlyDeepEqual(a, b); 651 b[symbol1] = true; 652 assertDeepAndStrictEqual(a, b); 653 // The same as TypedArrays is valid for boxed primitives 654 const boxedStringA = new String('test'); 655 const boxedStringB = new String('test'); 656 boxedStringA[symbol1] = true; 657 assertOnlyDeepEqual(boxedStringA, boxedStringB); 658 boxedStringA[symbol1] = true; 659 assertDeepAndStrictEqual(a, b); 660 // Loose equal arrays should not compare symbols. 661 const arr = [1]; 662 const arr2 = [1]; 663 arr[symbol1] = true; 664 assertOnlyDeepEqual(arr, arr2); 665 arr2[symbol1] = false; 666 assertOnlyDeepEqual(arr, arr2); 667} 668 669assert.throws( 670 () => assert.notDeepEqual(1, true), 671 { 672 message: /1\n\nshould not loosely deep-equal\n\ntrue/ 673 } 674); 675 676assert.throws( 677 () => assert.notDeepEqual(1, 1), 678 { 679 message: /Expected "actual" not to be loosely deep-equal to:\n\n1/ 680 } 681); 682 683assertDeepAndStrictEqual(new Date(2000, 3, 14), new Date(2000, 3, 14)); 684 685assert.throws(() => { assert.deepEqual(new Date(), new Date(2000, 3, 14)); }, 686 AssertionError, 687 'deepEqual(new Date(), new Date(2000, 3, 14))'); 688 689assert.throws( 690 () => { assert.notDeepEqual(new Date(2000, 3, 14), new Date(2000, 3, 14)); }, 691 AssertionError, 692 'notDeepEqual(new Date(2000, 3, 14), new Date(2000, 3, 14))' 693); 694 695assert.throws( 696 () => { assert.notDeepEqual('a'.repeat(1024), 'a'.repeat(1024)); }, 697 AssertionError, 698 'notDeepEqual("a".repeat(1024), "a".repeat(1024))' 699); 700 701assertNotDeepOrStrict(new Date(), new Date(2000, 3, 14)); 702 703assertDeepAndStrictEqual(/a/, /a/); 704assertDeepAndStrictEqual(/a/g, /a/g); 705assertDeepAndStrictEqual(/a/i, /a/i); 706assertDeepAndStrictEqual(/a/m, /a/m); 707assertDeepAndStrictEqual(/a/igm, /a/igm); 708assertNotDeepOrStrict(/ab/, /a/); 709assertNotDeepOrStrict(/a/g, /a/); 710assertNotDeepOrStrict(/a/i, /a/); 711assertNotDeepOrStrict(/a/m, /a/); 712assertNotDeepOrStrict(/a/igm, /a/im); 713 714{ 715 const re1 = /a/g; 716 re1.lastIndex = 3; 717 assert.notDeepEqual(re1, /a/g); 718} 719 720assert.deepEqual(4, '4'); 721assert.deepEqual(true, 1); 722assert.throws(() => assert.deepEqual(4, '5'), 723 AssertionError, 724 'deepEqual( 4, \'5\')'); 725 726// Having the same number of owned properties && the same set of keys. 727assert.deepEqual({ a: 4 }, { a: 4 }); 728assert.deepEqual({ a: 4, b: '2' }, { a: 4, b: '2' }); 729assert.deepEqual([4], ['4']); 730assert.throws( 731 () => assert.deepEqual({ a: 4 }, { a: 4, b: true }), AssertionError); 732assert.notDeepEqual(['a'], { 0: 'a' }); 733assert.deepEqual({ a: 4, b: '1' }, { b: '1', a: 4 }); 734const a1 = [1, 2, 3]; 735const a2 = [1, 2, 3]; 736a1.a = 'test'; 737a1.b = true; 738a2.b = true; 739a2.a = 'test'; 740assert.throws(() => assert.deepEqual(Object.keys(a1), Object.keys(a2)), 741 AssertionError); 742assertDeepAndStrictEqual(a1, a2); 743 744// Having an identical prototype property. 745const nbRoot = { 746 toString() { return `${this.first} ${this.last}`; } 747}; 748 749function nameBuilder(first, last) { 750 this.first = first; 751 this.last = last; 752 return this; 753} 754nameBuilder.prototype = nbRoot; 755 756function nameBuilder2(first, last) { 757 this.first = first; 758 this.last = last; 759 return this; 760} 761nameBuilder2.prototype = nbRoot; 762 763const nb1 = new nameBuilder('Ryan', 'Dahl'); 764let nb2 = new nameBuilder2('Ryan', 'Dahl'); 765 766assert.deepEqual(nb1, nb2); 767 768nameBuilder2.prototype = Object; 769nb2 = new nameBuilder2('Ryan', 'Dahl'); 770assert.deepEqual(nb1, nb2); 771 772// Primitives 773assertNotDeepOrStrict(null, {}); 774assertNotDeepOrStrict(undefined, {}); 775assertNotDeepOrStrict('a', ['a']); 776assertNotDeepOrStrict('a', { 0: 'a' }); 777assertNotDeepOrStrict(1, {}); 778assertNotDeepOrStrict(true, {}); 779assertNotDeepOrStrict(Symbol(), {}); 780assertNotDeepOrStrict(Symbol(), Symbol()); 781 782assertOnlyDeepEqual(4, '4'); 783assertOnlyDeepEqual(true, 1); 784 785{ 786 const s = Symbol(); 787 assertDeepAndStrictEqual(s, s); 788} 789 790// Primitive wrappers and object. 791assertNotDeepOrStrict(new String('a'), ['a']); 792assertNotDeepOrStrict(new String('a'), { 0: 'a' }); 793assertNotDeepOrStrict(new Number(1), {}); 794assertNotDeepOrStrict(new Boolean(true), {}); 795 796// Same number of keys but different key names. 797assertNotDeepOrStrict({ a: 1 }, { b: 1 }); 798 799assert.deepStrictEqual(new Date(2000, 3, 14), new Date(2000, 3, 14)); 800 801assert.throws( 802 () => assert.deepStrictEqual(new Date(), new Date(2000, 3, 14)), 803 AssertionError, 804 'deepStrictEqual(new Date(), new Date(2000, 3, 14))' 805); 806 807assert.throws( 808 () => assert.notDeepStrictEqual(new Date(2000, 3, 14), new Date(2000, 3, 14)), 809 { 810 name: 'AssertionError', 811 message: 'Expected "actual" not to be strictly deep-equal to:\n\n' + 812 util.inspect(new Date(2000, 3, 14)) 813 } 814); 815 816assert.notDeepStrictEqual(new Date(), new Date(2000, 3, 14)); 817 818assert.throws( 819 () => assert.deepStrictEqual(/ab/, /a/), 820 { 821 code: 'ERR_ASSERTION', 822 name: 'AssertionError', 823 message: `${defaultMsgStartFull}\n\n+ /ab/\n- /a/` 824 }); 825assert.throws( 826 () => assert.deepStrictEqual(/a/g, /a/), 827 { 828 code: 'ERR_ASSERTION', 829 name: 'AssertionError', 830 message: `${defaultMsgStartFull}\n\n+ /a/g\n- /a/` 831 }); 832assert.throws( 833 () => assert.deepStrictEqual(/a/i, /a/), 834 { 835 code: 'ERR_ASSERTION', 836 name: 'AssertionError', 837 message: `${defaultMsgStartFull}\n\n+ /a/i\n- /a/` 838 }); 839assert.throws( 840 () => assert.deepStrictEqual(/a/m, /a/), 841 { 842 code: 'ERR_ASSERTION', 843 name: 'AssertionError', 844 message: `${defaultMsgStartFull}\n\n+ /a/m\n- /a/` 845 }); 846assert.throws( 847 () => assert.deepStrictEqual(/aa/igm, /aa/im), 848 { 849 code: 'ERR_ASSERTION', 850 name: 'AssertionError', 851 message: `${defaultMsgStartFull}\n\n+ /aa/gim\n- /aa/im\n ^` 852 }); 853 854{ 855 const re1 = /a/; 856 re1.lastIndex = 3; 857 assert.notDeepStrictEqual(re1, /a/); 858} 859 860assert.throws( 861 // eslint-disable-next-line no-restricted-syntax 862 () => assert.deepStrictEqual(4, '4'), 863 { message: `${defaultMsgStart}\n4 !== '4'\n` } 864); 865 866assert.throws( 867 // eslint-disable-next-line no-restricted-syntax 868 () => assert.deepStrictEqual(true, 1), 869 { message: `${defaultMsgStart}\ntrue !== 1\n` } 870); 871 872// Having the same number of owned properties && the same set of keys. 873assert.deepStrictEqual({ a: 4 }, { a: 4 }); 874assert.deepStrictEqual({ a: 4, b: '2' }, { a: 4, b: '2' }); 875assert.throws(() => assert.deepStrictEqual([4], ['4']), 876 { 877 code: 'ERR_ASSERTION', 878 name: 'AssertionError', 879 message: `${defaultMsgStartFull}\n\n [\n+ 4\n- '4'\n ]` 880 }); 881assert.throws( 882 () => assert.deepStrictEqual({ a: 4 }, { a: 4, b: true }), 883 { 884 code: 'ERR_ASSERTION', 885 name: 'AssertionError', 886 message: `${defaultMsgStartFull}\n\n ` + 887 '{\n a: 4,\n- b: true\n }' 888 }); 889assert.throws( 890 () => assert.deepStrictEqual(['a'], { 0: 'a' }), 891 { 892 code: 'ERR_ASSERTION', 893 name: 'AssertionError', 894 message: `${defaultMsgStartFull}\n\n` + 895 "+ [\n+ 'a'\n+ ]\n- {\n- '0': 'a'\n- }" 896 }); 897 898/* eslint-enable */ 899 900assertDeepAndStrictEqual({ a: 4, b: '1' }, { b: '1', a: 4 }); 901 902assert.throws( 903 () => assert.deepStrictEqual([0, 1, 2, 'a', 'b'], [0, 1, 2, 'b', 'a']), 904 AssertionError); 905 906// Prototype check. 907function Constructor1(first, last) { 908 this.first = first; 909 this.last = last; 910} 911 912function Constructor2(first, last) { 913 this.first = first; 914 this.last = last; 915} 916 917const obj1 = new Constructor1('Ryan', 'Dahl'); 918let obj2 = new Constructor2('Ryan', 'Dahl'); 919 920assert.throws(() => assert.deepStrictEqual(obj1, obj2), AssertionError); 921 922Constructor2.prototype = Constructor1.prototype; 923obj2 = new Constructor2('Ryan', 'Dahl'); 924 925assertDeepAndStrictEqual(obj1, obj2); 926 927// Check extra properties on errors. 928{ 929 const a = new TypeError('foo'); 930 const b = new TypeError('foo'); 931 a.foo = 'bar'; 932 b.foo = 'baz.'; 933 934 assert.throws( 935 () => assert.throws( 936 () => assert.deepStrictEqual(a, b), 937 { 938 operator: 'throws', 939 message: `${defaultMsgStartFull}\n\n` + 940 ' [TypeError: foo] {\n+ foo: \'bar\'\n- foo: \'baz\'\n }', 941 } 942 ), 943 { 944 message: 'Expected values to be strictly deep-equal:\n' + 945 '+ actual - expected ... Lines skipped\n' + 946 '\n' + 947 ' Comparison {\n' + 948 " message: 'Expected values to be strictly deep-equal:\\n' +\n" + 949 '...\n' + 950 " ' [TypeError: foo] {\\n' +\n" + 951 " \"+ foo: 'bar'\\n\" +\n" + 952 "+ \"- foo: 'baz.'\\n\" +\n" + 953 "- \"- foo: 'baz'\\n\" +\n" + 954 " ' }',\n" + 955 "+ operator: 'deepStrictEqual'\n" + 956 "- operator: 'throws'\n" + 957 ' }' 958 } 959 ); 960} 961 962// Check proxies. 963{ 964 const arrProxy = new Proxy([1, 2], {}); 965 assert.deepStrictEqual(arrProxy, [1, 2]); 966 const tmp = util.inspect.defaultOptions; 967 util.inspect.defaultOptions = { showProxy: true }; 968 assert.throws( 969 () => assert.deepStrictEqual(arrProxy, [1, 2, 3]), 970 { message: `${defaultMsgStartFull}\n\n` + 971 ' [\n 1,\n 2,\n- 3\n ]' } 972 ); 973 util.inspect.defaultOptions = tmp; 974 975 const invalidTrap = new Proxy([1, 2, 3], { 976 ownKeys() { return []; } 977 }); 978 assert.throws( 979 () => assert.deepStrictEqual(invalidTrap, [1, 2, 3]), 980 { 981 name: 'TypeError', 982 message: "'ownKeys' on proxy: trap result did not include 'length'" 983 } 984 ); 985} 986 987// Strict equal with identical objects that are not identical 988// by reference and longer than 50 elements 989// E.g., assert.deepStrictEqual({ a: Symbol() }, { a: Symbol() }) 990{ 991 const a = {}; 992 const b = {}; 993 for (let i = 0; i < 55; i++) { 994 a[`symbol${i}`] = Symbol(); 995 b[`symbol${i}`] = Symbol(); 996 } 997 998 assert.throws( 999 () => assert.deepStrictEqual(a, b), 1000 { 1001 code: 'ERR_ASSERTION', 1002 name: 'AssertionError', 1003 message: /\.\.\./g 1004 } 1005 ); 1006} 1007 1008// Basic valueOf check. 1009{ 1010 const a = new String(1); 1011 a.valueOf = undefined; 1012 assertNotDeepOrStrict(a, new String(1)); 1013} 1014 1015// Basic array out of bounds check. 1016{ 1017 const arr = [1, 2, 3]; 1018 arr[2 ** 32] = true; 1019 assertNotDeepOrStrict(arr, [1, 2, 3]); 1020} 1021 1022assert.throws( 1023 () => assert.deepStrictEqual([1, 2, 3], [1, 2]), 1024 { 1025 code: 'ERR_ASSERTION', 1026 name: 'AssertionError', 1027 message: `${defaultMsgStartFull}\n\n` + 1028 ' [\n' + 1029 ' 1,\n' + 1030 ' 2,\n' + 1031 '+ 3\n' + 1032 ' ]' 1033 } 1034); 1035 1036// Verify that manipulating the `getTime()` function has no impact on the time 1037// verification. 1038{ 1039 const a = new Date('2000'); 1040 const b = new Date('2000'); 1041 Object.defineProperty(a, 'getTime', { 1042 value: () => 5 1043 }); 1044 assertDeepAndStrictEqual(a, b); 1045} 1046 1047// Verify that an array and the equivalent fake array object 1048// are correctly compared 1049{ 1050 const a = [1, 2, 3]; 1051 const o = { 1052 __proto__: Array.prototype, 1053 0: 1, 1054 1: 2, 1055 2: 3, 1056 length: 3, 1057 }; 1058 Object.defineProperty(o, 'length', { enumerable: false }); 1059 assertNotDeepOrStrict(o, a); 1060} 1061 1062// Verify that extra keys will be tested for when using fake arrays. 1063{ 1064 const a = { 1065 0: 1, 1066 1: 1, 1067 2: 'broken' 1068 }; 1069 Object.setPrototypeOf(a, Object.getPrototypeOf([])); 1070 Object.defineProperty(a, Symbol.toStringTag, { 1071 value: 'Array', 1072 }); 1073 Object.defineProperty(a, 'length', { 1074 value: 2 1075 }); 1076 assertNotDeepOrStrict(a, [1, 1]); 1077} 1078 1079// Verify that changed tags will still check for the error message. 1080{ 1081 const err = new Error('foo'); 1082 err[Symbol.toStringTag] = 'Foobar'; 1083 const err2 = new Error('bar'); 1084 err2[Symbol.toStringTag] = 'Foobar'; 1085 assertNotDeepOrStrict(err, err2, AssertionError); 1086} 1087 1088// Check for non-native errors. 1089{ 1090 const source = new Error('abc'); 1091 const err = Object.create( 1092 Object.getPrototypeOf(source), Object.getOwnPropertyDescriptors(source)); 1093 Object.defineProperty(err, 'message', { value: 'foo' }); 1094 const err2 = Object.create( 1095 Object.getPrototypeOf(source), Object.getOwnPropertyDescriptors(source)); 1096 Object.defineProperty(err2, 'message', { value: 'bar' }); 1097 err[Symbol.toStringTag] = 'Foo'; 1098 err2[Symbol.toStringTag] = 'Foo'; 1099 assert.notDeepStrictEqual(err, err2); 1100} 1101 1102// Verify that `valueOf` is not called for boxed primitives. 1103{ 1104 const a = new Number(5); 1105 const b = new Number(5); 1106 Object.defineProperty(a, 'valueOf', { 1107 value: () => { throw new Error('failed'); } 1108 }); 1109 Object.defineProperty(b, 'valueOf', { 1110 value: () => { throw new Error('failed'); } 1111 }); 1112 assertDeepAndStrictEqual(a, b); 1113} 1114 1115// Check getters. 1116{ 1117 const a = { 1118 get a() { return 5; } 1119 }; 1120 const b = { 1121 get a() { return 6; } 1122 }; 1123 assert.throws( 1124 () => assert.deepStrictEqual(a, b), 1125 { 1126 code: 'ERR_ASSERTION', 1127 name: 'AssertionError', 1128 message: /a: \[Getter: 5]\n- {3}a: \[Getter: 6]\n {2}/ 1129 } 1130 ); 1131 1132 // The descriptor is not compared. 1133 assertDeepAndStrictEqual(a, { a: 5 }); 1134} 1135 1136// Verify object types being identical on both sides. 1137{ 1138 let a = Buffer.from('test'); 1139 let b = Object.create( 1140 Object.getPrototypeOf(a), 1141 Object.getOwnPropertyDescriptors(a) 1142 ); 1143 Object.defineProperty(b, Symbol.toStringTag, { 1144 value: 'Uint8Array' 1145 }); 1146 assertNotDeepOrStrict(a, b); 1147 1148 a = new Uint8Array(10); 1149 b = new Int8Array(10); 1150 Object.defineProperty(b, Symbol.toStringTag, { 1151 value: 'Uint8Array' 1152 }); 1153 Object.setPrototypeOf(b, Uint8Array.prototype); 1154 assertNotDeepOrStrict(a, b); 1155 1156 a = [1, 2, 3]; 1157 b = { 0: 1, 1: 2, 2: 3 }; 1158 Object.setPrototypeOf(b, Array.prototype); 1159 Object.defineProperty(b, 'length', { value: 3, enumerable: false }); 1160 Object.defineProperty(b, Symbol.toStringTag, { 1161 value: 'Array' 1162 }); 1163 assertNotDeepOrStrict(a, b); 1164 1165 a = new Date(2000); 1166 b = Object.create( 1167 Object.getPrototypeOf(a), 1168 Object.getOwnPropertyDescriptors(a) 1169 ); 1170 Object.defineProperty(b, Symbol.toStringTag, { 1171 value: 'Date' 1172 }); 1173 assertNotDeepOrStrict(a, b); 1174 1175 a = /abc/g; 1176 b = Object.create( 1177 Object.getPrototypeOf(a), 1178 Object.getOwnPropertyDescriptors(a) 1179 ); 1180 Object.defineProperty(b, Symbol.toStringTag, { 1181 value: 'RegExp' 1182 }); 1183 assertNotDeepOrStrict(a, b); 1184 1185 a = []; 1186 b = /abc/; 1187 Object.setPrototypeOf(b, Array.prototype); 1188 Object.defineProperty(b, Symbol.toStringTag, { 1189 value: 'Array' 1190 }); 1191 assertNotDeepOrStrict(a, b); 1192 1193 a = Object.create(null); 1194 b = new RangeError('abc'); 1195 Object.defineProperty(a, Symbol.toStringTag, { 1196 value: 'Error' 1197 }); 1198 Object.setPrototypeOf(b, null); 1199 assertNotDeepOrStrict(a, b, assert.AssertionError); 1200} 1201 1202{ 1203 // Verify commutativity 1204 // Regression test for https://github.com/nodejs/node/issues/37710 1205 const a = { x: 1 }; 1206 const b = { y: 1 }; 1207 Object.defineProperty(b, 'x', { value: 1 }); 1208 1209 assertNotDeepOrStrict(a, b); 1210} 1211