8000
We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
There was an error while loading. Please reload this page.
1 parent c5b1cf4 commit 4c13d8eCopy full SHA for 4c13d8e
lib/assert.js
@@ -21,35 +21,44 @@
21
'use strict';
22
23
const {
24
+ ArrayBufferIsView,
25
+ ArrayBufferPrototypeGetByteLength,
26
ArrayFrom,
27
ArrayIsArray,
28
ArrayPrototypeIndexOf,
29
ArrayPrototypeJoin,
30
ArrayPrototypePush,
31
ArrayPrototypeSlice,
32
+ DataViewPrototypeGetBuffer,
33
+ DataViewPrototypeGetByteLength,
34
+ DataViewPrototypeGetByteOffset,
35
Error,
36
FunctionPrototypeCall,
- MapPrototypeDelete,
37
MapPrototypeGet,
38
+ MapPrototypeGetSize,
39
MapPrototypeHas,
- MapPrototypeSet,
40
NumberIsNaN,
41
ObjectAssign,
42
ObjectIs,
43
ObjectKeys,
44
ObjectPrototypeIsPrototypeOf,
45
+ ObjectPrototypeToString,
46
ReflectApply,
47
ReflectHas,
48
ReflectOwnKeys,
49
RegExpPrototypeExec,
50
+ SafeArrayIterator,
51
SafeMap,
52
SafeSet,
53
SafeWeakSet,
54
+ SetPrototypeGetSize,
55
String,
56
StringPrototypeIndexOf,
57
StringPrototypeSlice,
58
StringPrototypeSplit,
59
SymbolIterator,
60
+ TypedArrayPrototypeGetLength,
61
+ Uint8Array,
62
} = primordials;
63
64
@@ -65,6 +74,8 @@ const AssertionError = require('internal/assert/assertion_error');
65
74
const { inspect } = require('internal/util/inspect');
66
75
const { Buffer } = require('buffer');
67
76
77
+ isArrayBuffer,
78
+ isDataView,
68
79
isKeyObject,
69
80
isPromise,
70
81
isRegExp,
@@ -73,6 +84,8 @@ const {
73
84
isDate,
85
isWeakSet,
86
isWeakMap,
87
+ isSharedArrayBuffer,
88
+ isAnyArrayBuffer,
89
} = require('internal/util/types');
90
const { isError, deprecate, emitExperimentalWarning } = require('internal/util');
91
const { innerOk } = require('internal/assert/utils');
@@ -369,9 +382,161 @@ function isSpecial(obj) {
369
382
}
370
383
371
384
const typesToCallDeepStrictEqualWith = [
372
- isKeyObject, isWeakSet, isWeakMap, Buffer.isBuffer,
385
+ isKeyObject, isWeakSet, isWeakMap, Buffer.isBuffer, isSharedArrayBuffer,
373
386
];
374
387
< 9E88 div class="diff-text-inner">
388
+function compareMaps(actual, expected, comparedObjects) {
389
+ if (MapPrototypeGetSize(actual) !== MapPrototypeGetSize(expected)) {
390
+ return false;
391
+ }
392
+ const safeIterator = FunctionPrototypeCall(SafeMap.prototype[SymbolIterator], actual);
393
+
394
+ comparedObjects ??= new SafeWeakSet();
395
396
+ for (const { 0: key, 1: val } of safeIterator) {
397
+ if (!MapPrototypeHas(expected, key)) {
398
399
400
+ if (!compareBranch(val, MapPrototypeGet(expected, key), comparedObjects)) {
401
402
403
404
+ return true;
405
+}
406
407
+function partiallyCompareArrayBuffersOrViews(actual, expected) {
408
+ let actualView, expectedView, expectedViewLength;
409
410
+ if (!ArrayBufferIsView(actual)) {
411
+ let actualViewLength;
412
413
+ if (isArrayBuffer(actual) && isArrayBuffer(expected)) {
414
+ actualViewLength = ArrayBufferPrototypeGetByteLength(actual);
415
+ expectedViewLength = ArrayBufferPrototypeGetByteLength(expected);
416
+ } else if (isSharedArrayBuffer(actual) && isSharedArrayBuffer(expected)) {
417
+ actualViewLength = actual.byteLength;
418
+ expectedViewLength = expected.byteLength;
419
+ } else {
420
+ // Cannot compare ArrayBuffers with SharedArrayBuffers
421
422
423
424
+ if (expectedViewLength > actualViewLength) {
425
426
427
+ actualView = new Uint8Array(actual);
428
+ expectedView = new Uint8Array(expected);
429
430
+ } else if (isDataView(actual)) {
431
+ if (!isDataView(expected)) {
432
433
434
+ const actualByteLength = DataViewPrototypeGetByteLength(actual);
435
+ expectedViewLength = DataViewPrototypeGetByteLength(expected);
436
+ if (expectedViewLength > actualByteLength) {
437
438
439
440
+ actualView = new Uint8Array(
441
+ DataViewPrototypeGetBuffer(actual),
442
+ DataViewPrototypeGetByteOffset(actual),
443
+ actualByteLength,
444
+ );
445
+ expectedView = new Uint8Array(
446
+ DataViewPrototypeGetBuffer(expected),
447
+ DataViewPrototypeGetByteOffset(expected),
448
+ expectedViewLength,
449
450
451
+ if (ObjectPrototypeToString(actual) !== ObjectPrototypeToString(expected)) {
452
453
454
+ actualView = actual;
455
+ expectedView = expected;
456
+ expectedViewLength = TypedArrayPrototypeGetLength(expected);
457
458
+ if (expectedViewLength > TypedArrayPrototypeGetLength(actual)) {
459
460
461
462
463
+ for (let i = 0; i < expectedViewLength; i++) {
464
+ if (actualView[i] !== expectedView[i]) {
465
466
467
468
469
470
471
472
+function partiallyCompareSets(actual, expected, comparedObjects) {
473
+ if (SetPrototypeGetSize(expected) > SetPrototypeGetSize(actual)) {
474
+ return false; // `expected` can't be a subset if it has more elements
475
476
477
+ if (isDeepEqual === undefined) lazyLoadComparison();
478
479
+ const actualArray = ArrayFrom(FunctionPrototypeCall(SafeSet.prototype[SymbolIterator], actual));
480
+ const expectedIterator = FunctionPrototypeCall(SafeSet.prototype[SymbolIterator], expected);
481
+ const usedIndices = new SafeSet();
482
483
+ expectedIteration: for (const expectedItem of expectedIterator) {
484
+ for (let actualIdx = 0; actualIdx < actualArray.length; actualIdx++) {
485
+ if (!usedIndices.has(actualIdx) && isDeepStrictEqual(actualArray[actualIdx], expectedItem)) {
486
+ usedIndices.add(actualIdx);
487
+ continue expectedIteration;
488
489
490
491
492
493
494
495
496
+function partiallyCompareArrays(actual, expected, comparedObjects) {
497
+ if (expected.length > actual.length) {
498
499
500
501
502
503
+ // Create a map to count occurrences of each element in the expected array
504
+ const expectedCounts = new SafeMap();
505
+ for (const expectedItem of expected) {
506
+ let found = false;
507
+ for (const { 0: key, 1: count } of expectedCounts) {
508
+ if (isDeepStrictEqual(key, expectedItem)) {
509
+ expectedCounts.set(key, count + 1);
510
+ found = true;
511
+ break;
512
513
514
+ if (!found) {
515
+ expectedCounts.set(expectedItem, 1);
516
517
518
519
+ const safeActual = new SafeArrayIterator(actual);
520
521
+ // Create a map to count occurrences of relevant elements in the actual array
522
+ for (const actualItem of safeActual) {
523
524
+ if (isDeepStrictEqual(key, actualItem)) {
525
+ if (count === 1) {
526
+ expectedCounts.delete(key);
527
528
+ expectedCounts.set(key, count - 1);
529
530
531
532
533
534
535
+ const { size } = expectedCounts;
536
+ expectedCounts.clear();
537
+ return size === 0;
538
539
375
540
/**
376
541
* Compares two objects or values recursively to check if they are equal.
377
542
* @param {any} actual - The actual value to compare.
@@ -388,22 +553,16 @@ function compareBranch(
553
) {
554
// Check for Map object equality
555
if (isMap(actual) && isMap(expected)) {
- if (actual.size !== expected.size) {
- return false;
- }
- const safeIterator = FunctionPrototypeCall(SafeMap.prototype[SymbolIterator], actual);
-
- comparedObjects ??= new SafeWeakSet();
556
+ return compareMaps(actual, expected, comparedObjects);
557
558
- for (const { 0: key, 1: val } of safeIterator) {
- if (!MapPrototypeHas(expected, key)) {
- if (!compareBranch(val, MapPrototypeGet(expected, key), comparedObjects)) {
- return true;
559
+ if (
560
+ ArrayBufferIsView(actual) ||
561
+ isAnyArrayBuffer(actual) ||
562
+ ArrayBufferIsView(expected) ||
563
+ isAnyArrayBuffer(expected)
564
+ ) {
565
+ return partiallyCompareArrayBuffersOrViews(actual, expected);
566
567
568
for (const type of typesToCallDeepStrictEqualWith) {
@@ -415,68 +574,12 @@ function compareBranch(
574
575
// Check for Set object equality
576
if (isSet(actual) && isSet(expected)) {
- if (expected.size > actual.size) {
- return false; // `expected` can't be a subset if it has more elements
- if (isDeepEqual === undefined) lazyLoadComparison();
- const actualArray = ArrayFrom(FunctionPrototypeCall(SafeSet.prototype[SymbolIterator], actual));
- const expectedIterator = FunctionPrototypeCall(SafeSet.prototype[SymbolIterator], expected);
- const usedIndices = new SafeSet();
- expectedIteration: for (const expectedItem of expectedIterator) {
- for (let actualIdx = 0; actualIdx < actualArray.length; actualIdx++) {
- if (!usedIndices.has(actualIdx) && isDeepStrictEqual(actualArray[actualIdx], expectedItem)) {
- usedIndices.add(actualIdx);
- continue expectedIteration;
577
+ return partiallyCompareSets(actual, expected, comparedObjects);
578
579
580
// Check if expected array is a subset of actual array
581
if (ArrayIsArray(actual) && ArrayIsArray(expected)) {
- if (expected.length > actual.length) {
- // Create a map to count occurrences of each element in the expected array
- const expectedCounts = new SafeMap();
- for (const expectedItem of expected) {
- let found = false;
- for (const { 0: key, 1: count } of expectedCounts) {
- if (isDeepStrictEqual(key, expectedItem)) {
- MapPrototypeSet(expectedCounts, key, count + 1);
- found = true;
- break;
- if (!found) {
- MapPrototypeSet(expectedCounts, expectedItem, 1);
- // Create a map to count occurrences of relevant elements in the actual array
- for (const actualItem of actual) {
- if (isDeepStrictEqual(key, actualItem)) {
- if (count === 1) {
- MapPrototypeDelete(expectedCounts, key);
- } else {
- MapPrototypeSet(expectedCounts, key, count - 1);
- return !expectedCounts.size;
582
+ return partiallyCompareArrays(actual, expected, comparedObjects);
583
584
585
// Comparison done when at least one of the values is not an object