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 {\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 assertDeepAndStrictEqual([1, , , 3], [1, , , 3]); 571 assertNotDeepOrStrict([1, , , 3], [1, , , 3, , , ]); 572 const a = new Array(3); 573 const b = new Array(3); 574 a[2] = true; 575 b[1] = true; 576 assertNotDeepOrStrict(a, b); 577 b[2] = true; 578 assertNotDeepOrStrict(a, b); 579 a[0] = true; 580 assertNotDeepOrStrict(a, b); 581} 582 583// Handle different error messages 584{ 585 const err1 = new Error('foo1'); 586 assertNotDeepOrStrict(err1, new Error('foo2'), assert.AssertionError); 587 assertNotDeepOrStrict(err1, new TypeError('foo1'), assert.AssertionError); 588 assertDeepAndStrictEqual(err1, new Error('foo1')); 589 assertNotDeepOrStrict(err1, {}, AssertionError); 590} 591 592// Handle NaN 593assert.notDeepEqual(NaN, NaN); 594assert.deepStrictEqual(NaN, NaN); 595assert.deepStrictEqual({ a: NaN }, { a: NaN }); 596assert.deepStrictEqual([ 1, 2, NaN, 4 ], [ 1, 2, NaN, 4 ]); 597 598// Handle boxed primitives 599{ 600 const boxedString = new String('test'); 601 const boxedSymbol = Object(Symbol()); 602 603 const fakeBoxedSymbol = {}; 604 Object.setPrototypeOf(fakeBoxedSymbol, Symbol.prototype); 605 Object.defineProperty( 606 fakeBoxedSymbol, 607 Symbol.toStringTag, 608 { enumerable: false, value: 'Symbol' } 609 ); 610 611 assertNotDeepOrStrict(new Boolean(true), Object(false)); 612 assertNotDeepOrStrict(Object(true), new Number(1)); 613 assertNotDeepOrStrict(new Number(2), new Number(1)); 614 assertNotDeepOrStrict(boxedSymbol, Object(Symbol())); 615 assertNotDeepOrStrict(boxedSymbol, {}); 616 assertNotDeepOrStrict(boxedSymbol, fakeBoxedSymbol); 617 assertDeepAndStrictEqual(boxedSymbol, boxedSymbol); 618 assertDeepAndStrictEqual(Object(true), Object(true)); 619 assertDeepAndStrictEqual(Object(2), Object(2)); 620 assertDeepAndStrictEqual(boxedString, Object('test')); 621 boxedString.slow = true; 622 assertNotDeepOrStrict(boxedString, Object('test')); 623 boxedSymbol.slow = true; 624 assertNotDeepOrStrict(boxedSymbol, {}); 625 assertNotDeepOrStrict(boxedSymbol, fakeBoxedSymbol); 626} 627 628// Minus zero 629assertOnlyDeepEqual(0, -0); 630assertDeepAndStrictEqual(-0, -0); 631 632// Handle symbols (enumerable only) 633{ 634 const symbol1 = Symbol(); 635 const obj1 = { [symbol1]: 1 }; 636 const obj2 = { [symbol1]: 1 }; 637 const obj3 = { [Symbol()]: 1 }; 638 // Add a non enumerable symbol as well. It is going to be ignored! 639 Object.defineProperty(obj2, Symbol(), { value: 1 }); 640 assertOnlyDeepEqual(obj1, obj3); 641 assertDeepAndStrictEqual(obj1, obj2); 642 obj2[Symbol()] = true; 643 assertOnlyDeepEqual(obj1, obj2); 644 // TypedArrays have a fast path. Test for this as well. 645 const a = new Uint8Array(4); 646 const b = new Uint8Array(4); 647 a[symbol1] = true; 648 b[symbol1] = false; 649 assertOnlyDeepEqual(a, b); 650 b[symbol1] = true; 651 assertDeepAndStrictEqual(a, b); 652 // The same as TypedArrays is valid for boxed primitives 653 const boxedStringA = new String('test'); 654 const boxedStringB = new String('test'); 655 boxedStringA[symbol1] = true; 656 assertOnlyDeepEqual(boxedStringA, boxedStringB); 657 boxedStringA[symbol1] = true; 658 assertDeepAndStrictEqual(a, b); 659 // Loose equal arrays should not compare symbols. 660 const arr = [1]; 661 const arr2 = [1]; 662 arr[symbol1] = true; 663 assertOnlyDeepEqual(arr, arr2); 664 arr2[symbol1] = false; 665 assertOnlyDeepEqual(arr, arr2); 666} 667 668assert.throws( 669 () => assert.notDeepEqual(1, true), 670 { 671 message: /1\n\nshould not loosely deep-equal\n\ntrue/ 672 } 673); 674 675assert.throws( 676 () => assert.notDeepEqual(1, 1), 677 { 678 message: /Expected "actual" not to be loosely deep-equal to:\n\n1/ 679 } 680); 681 682assertDeepAndStrictEqual(new Date(2000, 3, 14), new Date(2000, 3, 14)); 683 684assert.throws(() => { assert.deepEqual(new Date(), new Date(2000, 3, 14)); }, 685 AssertionError, 686 'deepEqual(new Date(), new Date(2000, 3, 14))'); 687 688assert.throws( 689 () => { assert.notDeepEqual(new Date(2000, 3, 14), new Date(2000, 3, 14)); }, 690 AssertionError, 691 'notDeepEqual(new Date(2000, 3, 14), new Date(2000, 3, 14))' 692); 693 694assert.throws( 695 () => { assert.notDeepEqual('a'.repeat(1024), 'a'.repeat(1024)); }, 696 AssertionError, 697 'notDeepEqual("a".repeat(1024), "a".repeat(1024))' 698); 699 700assertNotDeepOrStrict(new Date(), new Date(2000, 3, 14)); 701 702assertDeepAndStrictEqual(/a/, /a/); 703assertDeepAndStrictEqual(/a/g, /a/g); 704assertDeepAndStrictEqual(/a/i, /a/i); 705assertDeepAndStrictEqual(/a/m, /a/m); 706assertDeepAndStrictEqual(/a/igm, /a/igm); 707assertNotDeepOrStrict(/ab/, /a/); 708assertNotDeepOrStrict(/a/g, /a/); 709assertNotDeepOrStrict(/a/i, /a/); 710assertNotDeepOrStrict(/a/m, /a/); 711assertNotDeepOrStrict(/a/igm, /a/im); 712 713{ 714 const re1 = /a/g; 715 re1.lastIndex = 3; 716 assert.deepEqual(re1, /a/g); 717} 718 719assert.deepEqual(4, '4'); 720assert.deepEqual(true, 1); 721assert.throws(() => assert.deepEqual(4, '5'), 722 AssertionError, 723 'deepEqual( 4, \'5\')'); 724 725// Having the same number of owned properties && the same set of keys. 726assert.deepEqual({ a: 4 }, { a: 4 }); 727assert.deepEqual({ a: 4, b: '2' }, { a: 4, b: '2' }); 728assert.deepEqual([4], ['4']); 729assert.throws( 730 () => assert.deepEqual({ a: 4 }, { a: 4, b: true }), AssertionError); 731assert.notDeepEqual(['a'], { 0: 'a' }); 732assert.deepEqual({ a: 4, b: '1' }, { b: '1', a: 4 }); 733const a1 = [1, 2, 3]; 734const a2 = [1, 2, 3]; 735a1.a = 'test'; 736a1.b = true; 737a2.b = true; 738a2.a = 'test'; 739assert.throws(() => assert.deepEqual(Object.keys(a1), Object.keys(a2)), 740 AssertionError); 741assertDeepAndStrictEqual(a1, a2); 742 743// Having an identical prototype property. 744const nbRoot = { 745 toString() { return `${this.first} ${this.last}`; } 746}; 747 748function nameBuilder(first, last) { 749 this.first = first; 750 this.last = last; 751 return this; 752} 753nameBuilder.prototype = nbRoot; 754 755function nameBuilder2(first, last) { 756 this.first = first; 757 this.last = last; 758 return this; 759} 760nameBuilder2.prototype = nbRoot; 761 762const nb1 = new nameBuilder('Ryan', 'Dahl'); 763let nb2 = new nameBuilder2('Ryan', 'Dahl'); 764 765assert.deepEqual(nb1, nb2); 766 767nameBuilder2.prototype = Object; 768nb2 = new nameBuilder2('Ryan', 'Dahl'); 769assert.deepEqual(nb1, nb2); 770 771// Primitives 772assertNotDeepOrStrict(null, {}); 773assertNotDeepOrStrict(undefined, {}); 774assertNotDeepOrStrict('a', ['a']); 775assertNotDeepOrStrict('a', { 0: 'a' }); 776assertNotDeepOrStrict(1, {}); 777assertNotDeepOrStrict(true, {}); 778assertNotDeepOrStrict(Symbol(), {}); 779assertNotDeepOrStrict(Symbol(), Symbol()); 780 781assertOnlyDeepEqual(4, '4'); 782assertOnlyDeepEqual(true, 1); 783 784{ 785 const s = Symbol(); 786 assertDeepAndStrictEqual(s, s); 787} 788 789// Primitive wrappers and object. 790assertNotDeepOrStrict(new String('a'), ['a']); 791assertNotDeepOrStrict(new String('a'), { 0: 'a' }); 792assertNotDeepOrStrict(new Number(1), {}); 793assertNotDeepOrStrict(new Boolean(true), {}); 794 795// Same number of keys but different key names. 796assertNotDeepOrStrict({ a: 1 }, { b: 1 }); 797 798assert.deepStrictEqual(new Date(2000, 3, 14), new Date(2000, 3, 14)); 799 800assert.throws( 801 () => assert.deepStrictEqual(new Date(), new Date(2000, 3, 14)), 802 AssertionError, 803 'deepStrictEqual(new Date(), new Date(2000, 3, 14))' 804); 805 806assert.throws( 807 () => assert.notDeepStrictEqual(new Date(2000, 3, 14), new Date(2000, 3, 14)), 808 { 809 name: 'AssertionError', 810 message: 'Expected "actual" not to be strictly deep-equal to:\n\n' + 811 util.inspect(new Date(2000, 3, 14)) 812 } 813); 814 815assert.notDeepStrictEqual(new Date(), new Date(2000, 3, 14)); 816 817assert.throws( 818 () => assert.deepStrictEqual(/ab/, /a/), 819 { 820 code: 'ERR_ASSERTION', 821 name: 'AssertionError', 822 message: `${defaultMsgStartFull}\n\n+ /ab/\n- /a/` 823 }); 824assert.throws( 825 () => assert.deepStrictEqual(/a/g, /a/), 826 { 827 code: 'ERR_ASSERTION', 828 name: 'AssertionError', 829 message: `${defaultMsgStartFull}\n\n+ /a/g\n- /a/` 830 }); 831assert.throws( 832 () => assert.deepStrictEqual(/a/i, /a/), 833 { 834 code: 'ERR_ASSERTION', 835 name: 'AssertionError', 836 message: `${defaultMsgStartFull}\n\n+ /a/i\n- /a/` 837 }); 838assert.throws( 839 () => assert.deepStrictEqual(/a/m, /a/), 840 { 841 code: 'ERR_ASSERTION', 842 name: 'AssertionError', 843 message: `${defaultMsgStartFull}\n\n+ /a/m\n- /a/` 844 }); 845assert.throws( 846 () => assert.deepStrictEqual(/aa/igm, /aa/im), 847 { 848 code: 'ERR_ASSERTION', 849 name: 'AssertionError', 850 message: `${defaultMsgStartFull}\n\n+ /aa/gim\n- /aa/im\n ^` 851 }); 852 853{ 854 const re1 = /a/; 855 re1.lastIndex = 3; 856 assert.deepStrictEqual(re1, /a/); 857} 858 859assert.throws( 860 () => assert.deepStrictEqual(4, '4'), 861 { message: `${defaultMsgStart}\n4 !== '4'\n` } 862); 863 864assert.throws( 865 () => assert.deepStrictEqual(true, 1), 866 { message: `${defaultMsgStart}\ntrue !== 1\n` } 867); 868 869// Having the same number of owned properties && the same set of keys. 870assert.deepStrictEqual({ a: 4 }, { a: 4 }); 871assert.deepStrictEqual({ a: 4, b: '2' }, { a: 4, b: '2' }); 872assert.throws(() => assert.deepStrictEqual([4], ['4']), 873 { 874 code: 'ERR_ASSERTION', 875 name: 'AssertionError', 876 message: `${defaultMsgStartFull}\n\n [\n+ 4\n- '4'\n ]` 877 }); 878assert.throws( 879 () => assert.deepStrictEqual({ a: 4 }, { a: 4, b: true }), 880 { 881 code: 'ERR_ASSERTION', 882 name: 'AssertionError', 883 message: `${defaultMsgStartFull}\n\n ` + 884 '{\n a: 4,\n- b: true\n }' 885 }); 886assert.throws( 887 () => assert.deepStrictEqual(['a'], { 0: 'a' }), 888 { 889 code: 'ERR_ASSERTION', 890 name: 'AssertionError', 891 message: `${defaultMsgStartFull}\n\n` + 892 "+ [\n+ 'a'\n+ ]\n- {\n- '0': 'a'\n- }" 893 }); 894 895/* eslint-enable */ 896 897assertDeepAndStrictEqual({ a: 4, b: '1' }, { b: '1', a: 4 }); 898 899assert.throws( 900 () => assert.deepStrictEqual([0, 1, 2, 'a', 'b'], [0, 1, 2, 'b', 'a']), 901 AssertionError); 902 903// Prototype check. 904function Constructor1(first, last) { 905 this.first = first; 906 this.last = last; 907} 908 909function Constructor2(first, last) { 910 this.first = first; 911 this.last = last; 912} 913 914const obj1 = new Constructor1('Ryan', 'Dahl'); 915let obj2 = new Constructor2('Ryan', 'Dahl'); 916 917assert.throws(() => assert.deepStrictEqual(obj1, obj2), AssertionError); 918 919Constructor2.prototype = Constructor1.prototype; 920obj2 = new Constructor2('Ryan', 'Dahl'); 921 922assertDeepAndStrictEqual(obj1, obj2); 923 924// Check extra properties on errors. 925{ 926 const a = new TypeError('foo'); 927 const b = new TypeError('foo'); 928 a.foo = 'bar'; 929 b.foo = 'baz.'; 930 931 assert.throws( 932 () => assert.throws( 933 () => assert.deepStrictEqual(a, b), 934 { 935 operator: 'throws', 936 message: `${defaultMsgStartFull}\n\n` + 937 ' [TypeError: foo] {\n+ foo: \'bar\'\n- foo: \'baz\'\n }', 938 } 939 ), 940 { 941 message: 'Expected values to be strictly deep-equal:\n' + 942 '+ actual - expected ... Lines skipped\n' + 943 '\n' + 944 ' Comparison {\n' + 945 " message: 'Expected values to be strictly deep-equal:\\n' +\n" + 946 '...\n' + 947 " ' [TypeError: foo] {\\n' +\n" + 948 " \"+ foo: 'bar'\\n\" +\n" + 949 "+ \"- foo: 'baz.'\\n\" +\n" + 950 "- \"- foo: 'baz'\\n\" +\n" + 951 " ' }',\n" + 952 "+ operator: 'deepStrictEqual'\n" + 953 "- operator: 'throws'\n" + 954 ' }' 955 } 956 ); 957} 958 959// Check proxies. 960{ 961 const arrProxy = new Proxy([1, 2], {}); 962 assert.deepStrictEqual(arrProxy, [1, 2]); 963 const tmp = util.inspect.defaultOptions; 964 util.inspect.defaultOptions = { showProxy: true }; 965 assert.throws( 966 () => assert.deepStrictEqual(arrProxy, [1, 2, 3]), 967 { message: `${defaultMsgStartFull}\n\n` + 968 ' [\n 1,\n 2,\n- 3\n ]' } 969 ); 970 util.inspect.defaultOptions = tmp; 971 972 const invalidTrap = new Proxy([1, 2, 3], { 973 ownKeys() { return []; } 974 }); 975 assert.throws( 976 () => assert.deepStrictEqual(invalidTrap, [1, 2, 3]), 977 { 978 name: 'TypeError', 979 message: "'ownKeys' on proxy: trap result did not include 'length'" 980 } 981 ); 982} 983 984// Strict equal with identical objects that are not identical 985// by reference and longer than 50 elements 986// E.g., assert.deepStrictEqual({ a: Symbol() }, { a: Symbol() }) 987{ 988 const a = {}; 989 const b = {}; 990 for (let i = 0; i < 55; i++) { 991 a[`symbol${i}`] = Symbol(); 992 b[`symbol${i}`] = Symbol(); 993 } 994 995 assert.throws( 996 () => assert.deepStrictEqual(a, b), 997 { 998 code: 'ERR_ASSERTION', 999 name: 'AssertionError', 1000 message: /\.\.\./g 1001 } 1002 ); 1003} 1004 1005// Basic valueOf check. 1006{ 1007 const a = new String(1); 1008 a.valueOf = undefined; 1009 assertNotDeepOrStrict(a, new String(1)); 1010} 1011 1012// Basic array out of bounds check. 1013{ 1014 const arr = [1, 2, 3]; 1015 arr[2 ** 32] = true; 1016 assertNotDeepOrStrict(arr, [1, 2, 3]); 1017} 1018 1019assert.throws( 1020 () => assert.deepStrictEqual([1, 2, 3], [1, 2]), 1021 { 1022 code: 'ERR_ASSERTION', 1023 name: 'AssertionError', 1024 message: `${defaultMsgStartFull}\n\n` + 1025 ' [\n' + 1026 ' 1,\n' + 1027 ' 2,\n' + 1028 '+ 3\n' + 1029 ' ]' 1030 } 1031); 1032 1033// Verify that manipulating the `getTime()` function has no impact on the time 1034// verification. 1035{ 1036 const a = new Date('2000'); 1037 const b = new Date('2000'); 1038 Object.defineProperty(a, 'getTime', { 1039 value: () => 5 1040 }); 1041 assertDeepAndStrictEqual(a, b); 1042} 1043 1044// Verify that an array and the equivalent fake array object 1045// are correctly compared 1046{ 1047 const a = [1, 2, 3]; 1048 const o = { 1049 __proto__: Array.prototype, 1050 0: 1, 1051 1: 2, 1052 2: 3, 1053 length: 3, 1054 }; 1055 Object.defineProperty(o, 'length', { enumerable: false }); 1056 assertNotDeepOrStrict(o, a); 1057} 1058 1059// Verify that extra keys will be tested for when using fake arrays. 1060{ 1061 const a = { 1062 0: 1, 1063 1: 1, 1064 2: 'broken' 1065 }; 1066 Object.setPrototypeOf(a, Object.getPrototypeOf([])); 1067 Object.defineProperty(a, Symbol.toStringTag, { 1068 value: 'Array', 1069 }); 1070 Object.defineProperty(a, 'length', { 1071 value: 2 1072 }); 1073 assertNotDeepOrStrict(a, [1, 1]); 1074} 1075 1076// Verify that changed tags will still check for the error message. 1077{ 1078 const err = new Error('foo'); 1079 err[Symbol.toStringTag] = 'Foobar'; 1080 const err2 = new Error('bar'); 1081 err2[Symbol.toStringTag] = 'Foobar'; 1082 assertNotDeepOrStrict(err, err2, AssertionError); 1083} 1084 1085// Check for non-native errors. 1086{ 1087 const source = new Error('abc'); 1088 const err = Object.create( 1089 Object.getPrototypeOf(source), Object.getOwnPropertyDescriptors(source)); 1090 Object.defineProperty(err, 'message', { value: 'foo' }); 1091 const err2 = Object.create( 1092 Object.getPrototypeOf(source), Object.getOwnPropertyDescriptors(source)); 1093 Object.defineProperty(err2, 'message', { value: 'bar' }); 1094 err[Symbol.toStringTag] = 'Foo'; 1095 err2[Symbol.toStringTag] = 'Foo'; 1096 assert.notDeepStrictEqual(err, err2); 1097} 1098 1099// Verify that `valueOf` is not called for boxed primitives. 1100{ 1101 const a = new Number(5); 1102 const b = new Number(5); 1103 Object.defineProperty(a, 'valueOf', { 1104 value: () => { throw new Error('failed'); } 1105 }); 1106 Object.defineProperty(b, 'valueOf', { 1107 value: () => { throw new Error('failed'); } 1108 }); 1109 assertDeepAndStrictEqual(a, b); 1110} 1111 1112// Check getters. 1113{ 1114 const a = { 1115 get a() { return 5; } 1116 }; 1117 const b = { 1118 get a() { return 6; } 1119 }; 1120 assert.throws( 1121 () => assert.deepStrictEqual(a, b), 1122 { 1123 code: 'ERR_ASSERTION', 1124 name: 'AssertionError', 1125 message: /a: \[Getter: 5]\n- a: \[Getter: 6]\n / 1126 } 1127 ); 1128 1129 // The descriptor is not compared. 1130 assertDeepAndStrictEqual(a, { a: 5 }); 1131} 1132 1133// Verify object types being identical on both sides. 1134{ 1135 let a = Buffer.from('test'); 1136 let b = Object.create( 1137 Object.getPrototypeOf(a), 1138 Object.getOwnPropertyDescriptors(a) 1139 ); 1140 Object.defineProperty(b, Symbol.toStringTag, { 1141 value: 'Uint8Array' 1142 }); 1143 assertNotDeepOrStrict(a, b); 1144 1145 a = new Uint8Array(10); 1146 b = new Int8Array(10); 1147 Object.defineProperty(b, Symbol.toStringTag, { 1148 value: 'Uint8Array' 1149 }); 1150 Object.setPrototypeOf(b, Uint8Array.prototype); 1151 assertNotDeepOrStrict(a, b); 1152 1153 a = [1, 2, 3]; 1154 b = { 0: 1, 1: 2, 2: 3 }; 1155 Object.setPrototypeOf(b, Array.prototype); 1156 Object.defineProperty(b, 'length', { value: 3, enumerable: false }); 1157 Object.defineProperty(b, Symbol.toStringTag, { 1158 value: 'Array' 1159 }); 1160 assertNotDeepOrStrict(a, b); 1161 1162 a = new Date(2000); 1163 b = Object.create( 1164 Object.getPrototypeOf(a), 1165 Object.getOwnPropertyDescriptors(a) 1166 ); 1167 Object.defineProperty(b, Symbol.toStringTag, { 1168 value: 'Date' 1169 }); 1170 assertNotDeepOrStrict(a, b); 1171 1172 a = /abc/g; 1173 b = Object.create( 1174 Object.getPrototypeOf(a), 1175 Object.getOwnPropertyDescriptors(a) 1176 ); 1177 Object.defineProperty(b, Symbol.toStringTag, { 1178 value: 'RegExp' 1179 }); 1180 assertNotDeepOrStrict(a, b); 1181 1182 a = []; 1183 b = /abc/; 1184 Object.setPrototypeOf(b, Array.prototype); 1185 Object.defineProperty(b, Symbol.toStringTag, { 1186 value: 'Array' 1187 }); 1188 assertNotDeepOrStrict(a, b); 1189 1190 a = Object.create(null); 1191 b = new RangeError('abc'); 1192 Object.defineProperty(a, Symbol.toStringTag, { 1193 value: 'Error' 1194 }); 1195 Object.setPrototypeOf(b, null); 1196 assertNotDeepOrStrict(a, b, assert.AssertionError); 1197} 1198