Skip to content

Commit

Permalink
assert: renamed deepEqual/deepStrictEqual to partialDeepEqual/partial…
Browse files Browse the repository at this point in the history
…DeepStrictEqual
  • Loading branch information
puskin94 committed Sep 11, 2024
1 parent 0ee83d4 commit 3d52d4b
Show file tree
Hide file tree
Showing 3 changed files with 132 additions and 81 deletions.
66 changes: 33 additions & 33 deletions doc/api/assert.md
Original file line number Diff line number Diff line change
Expand Up @@ -2548,7 +2548,7 @@ assert.throws(throwingFirst, /Second$/);
Due to the confusing error-prone notation, avoid a string as the second
argument.

## `assert.deepMatch(actual, expected[, message])`
## `assert.partialDeepEqual(actual, expected[, message])`

<!-- YAML
added: REPLACEME
Expand All @@ -2558,54 +2558,54 @@ added: REPLACEME
* `expected` {any}
* `message` {string|Error}

[`assert.deepMatch()`][] evaluates the equivalence between the `actual` and `expected` parameters by
[`assert.partialDeepEqual()`][] evaluates the equivalence between the `actual` and `expected` parameters by
performing a deep comparison. This function ensures that all properties defined
in the `expected` parameter match those in the `actual` parameter in
both value and type, allowing type coercion. The main difference with [`assert.deepEqual()`][] is that
[`assert.deepMatch()`][] does not require all properties in the `actual` parameter to be present in the
[`assert.partialDeepEqual()`][] does not require all properties in the `actual` parameter to be present in the
`expected` parameter.

```mjs
import assert from 'node:assert';

assert.deepMatch({ a: 1, b: '2' }, { a: 1, b: 2 });
assert.partialDeepEqual({ a: 1, b: '2' }, { a: 1, b: 2 });
// OK

assert.deepMatch({ a: 1, b: '2', c: 3 }, { a: 1, b: 2 });
assert.partialDeepEqual({ a: 1, b: '2', c: 3 }, { a: 1, b: 2 });
// OK

assert.deepMatch({ a: { b: { c: '1' } } }, { a: { b: { c: 1 } } });
assert.partialDeepEqual({ a: { b: { c: '1' } } }, { a: { b: { c: 1 } } });
// OK

assert.deepMatch({ a: 1 }, { a: 1, b: 2 });
assert.partialDeepEqual({ a: 1 }, { a: 1, b: 2 });
// AssertionError

assert.deepMatch({ a: 1, b: true }, { a: 1, b: 'true' });
assert.partialDeepEqual({ a: 1, b: true }, { a: 1, b: 'true' });
// AssertionError

assert.deepMatch({ a: { b: 2 } }, { a: { b: 2, c: 3 } });
assert.partialDeepEqual({ a: { b: 2 } }, { a: { b: 2, c: 3 } });
// AssertionError
```

```cjs
const assert = require('node:assert');

assert.deepMatch({ a: 1, b: '2' }, { a: 1, b: 2 });
assert.partialDeepEqual({ a: 1, b: '2' }, { a: 1, b: 2 });
// OK

assert.deepMatch({ a: 1, b: '2', c: 3 }, { a: 1, b: 2 });
assert.partialDeepEqual({ a: 1, b: '2', c: 3 }, { a: 1, b: 2 });
// OK

assert.deepMatch({ a: { b: { c: '1' } } }, { a: { b: { c: 1 } } });
assert.partialDeepEqual({ a: { b: { c: '1' } } }, { a: { b: { c: 1 } } });
// OK

assert.deepMatch({ a: 1 }, { a: 1, b: 2 });
assert.partialDeepEqual({ a: 1 }, { a: 1, b: 2 });
// AssertionError: Expected key b

assert.deepMatch({ a: 1, b: true }, { a: 1, b: 'true' });
assert.partialDeepEqual({ a: 1, b: true }, { a: 1, b: 'true' });
// AssertionError

assert.deepMatch({ a: { b: 2, d: 4 } }, { a: { b: 2, c: 3 } });
assert.partialDeepEqual({ a: { b: 2, d: 4 } }, { a: { b: 2, c: 3 } });
// AssertionError: Expected key c
```

Expand All @@ -2615,7 +2615,7 @@ parameter is undefined, a default error message is assigned. If the `message`
parameter is an instance of an [`Error`][] then it will be thrown instead of the
`AssertionError`.

## `assert.deepMatchStrict(actual, expected[, message])`
## `assert.partialDeepStrictEqual(actual, expected[, message])`

<!-- YAML
added: REPLACEME
Expand All @@ -2625,53 +2625,53 @@ added: REPLACEME
* `expected` {any}
* `message` {string|Error}

[`assert.deepMatchStrict()`][] Assesses the equivalence between the `actual` and `expected` parameters through a
[`assert.partialDeepStrictEqual()`][] Assesses the equivalence between the `actual` and `expected` parameters through a
deep comparison, ensuring that all properties in the `expected` parameter are
present in the `actual` parameter with equivalent values, not allowing type coercion.
The main difference with [`assert.deepStrictEqual()`][] is that [`assert.deepMatchStrict()`][] does not require all
properties in the `actual` parameter to be present in the `expected` parameter.
The main difference with [`assert.deepStrictEqual()`][] is that [`assert.partialDeepStrictEqual()`][] does not require
all properties in the `actual` parameter to be present in the `expected` parameter.

```mjs
import assert from 'node:assert';

assert.deepMatchStrict({ a: 1, b: 2 }, { a: 1, b: 2 });
assert.partialDeepStrictEqual({ a: 1, b: 2 }, { a: 1, b: 2 });
// OK

assert.deepMatchStrict({ a: { b: { c: 1 } } }, { a: { b: { c: 1 } } });
assert.partialDeepStrictEqual({ a: { b: { c: 1 } } }, { a: { b: { c: 1 } } });
// OK

assert.deepMatchStrict({ a: 1, b: 2, c: 3 }, { a: 1, b: 2 });
assert.partialDeepStrictEqual({ a: 1, b: 2, c: 3 }, { a: 1, b: 2 });
// OK

assert.deepMatchStrict({ a: 1 }, { a: 1, b: 2 });
assert.partialDeepStrictEqual({ a: 1 }, { a: 1, b: 2 });
// AssertionError

assert.deepMatchStrict({ a: 1, b: '2' }, { a: 1, b: 2 });
assert.partialDeepStrictEqual({ a: 1, b: '2' }, { a: 1, b: 2 });
// AssertionError

assert.deepMatchStrict({ a: { b: 2 } }, { a: { b: '2' } });
assert.partialDeepStrictEqual({ a: { b: 2 } }, { a: { b: '2' } });
// AssertionError
```

```cjs
const assert = require('node:assert');

assert.deepMatchStrict({ a: 1, b: 2 }, { a: 1, b: 2 });
assert.partialDeepStrictEqual({ a: 1, b: 2 }, { a: 1, b: 2 });
// OK

assert.deepMatchStrict({ a: { b: { c: 1 } } }, { a: { b: { c: 1 } } });
assert.partialDeepStrictEqual({ a: { b: { c: 1 } } }, { a: { b: { c: 1 } } });
// OK

assert.deepMatchStrict({ a: 1, b: 2, c: 3 }, { a: 1, b: 2 });
assert.partialDeepStrictEqual({ a: 1, b: 2, c: 3 }, { a: 1, b: 2 });
// OK

assert.deepMatchStrict({ a: 1 }, { a: 1, b: 2 });
assert.partialDeepStrictEqual({ a: 1 }, { a: 1, b: 2 });
// AssertionError

assert.deepMatchStrict({ a: 1, b: '2' }, { a: 1, b: 2 });
assert.partialDeepStrictEqual({ a: 1, b: '2' }, { a: 1, b: 2 });
// AssertionError

assert.deepMatchStrict({ a: { b: 2 } }, { a: { b: '2' } });
assert.partialDeepStrictEqual({ a: { b: 2 } }, { a: { b: '2' } });
// AssertionError
```

Expand Down Expand Up @@ -2803,8 +2803,6 @@ parameter is an instance of an [`Error`][] then it will be thrown instead of the
[`WeakMap`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap
[`WeakSet`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakSet
[`assert.deepEqual()`]: #assertdeepequalactual-expected-message
[`assert.deepMatch()`]: #assertdeepmatchactual-expected-message
[`assert.deepMatchStrict()`]: #assertdeepmatchstrictactual-expected-message
[`assert.deepStrictEqual()`]: #assertdeepstrictequalactual-expected-message
[`assert.doesNotThrow()`]: #assertdoesnotthrowfn-error-message
[`assert.equal()`]: #assertequalactual-expected-message
Expand All @@ -2815,6 +2813,8 @@ parameter is an instance of an [`Error`][] then it will be thrown instead of the
[`assert.notEqual()`]: #assertnotequalactual-expected-message
[`assert.notStrictEqual()`]: #assertnotstrictequalactual-expected-message
[`assert.ok()`]: #assertokvalue-message
[`assert.partialDeepEqual()`]: #assertpartialDeepEqualactual-expected-message
[`assert.partialDeepStrictEqual()`]: #assertpartialDeepstrictEqualactual-expected-message
[`assert.strictEqual()`]: #assertstrictequalactual-expected-message
[`assert.throws()`]: #assertthrowsfn-error-message
[`getColorDepth()`]: tty.md#writestreamgetcolordepthenv
Expand Down
52 changes: 35 additions & 17 deletions lib/assert.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,15 @@
'use strict';

const {
ArrayFrom,
ArrayIsArray,
ArrayPrototypeEvery,
ArrayPrototypeIndexOf,
ArrayPrototypeJoin,
ArrayPrototypePush,
ArrayPrototypeShift,
ArrayPrototypeSlice,
ArrayPrototypeSome,
Error,
ErrorCaptureStackTrace,
FunctionPrototypeBind,
Expand Down Expand Up @@ -636,7 +639,7 @@ function assertIncludes(actual, expected, loose) {
return StringPrototypeIncludes(actual, expected);
}

return expected.every((item) => actual.some((actualItem) => {
return ArrayPrototypeEvery(expected, (item) => ArrayPrototypeSome(actual, (actualItem) => {
// eslint-disable-next-line eqeqeq
return loose ? actualItem == item : actualItem === item;
}));
Expand Down Expand Up @@ -668,7 +671,11 @@ function compareBranch(
return false;
}
const safeIterator = FunctionPrototypeCall(SafeMap.prototype[SymbolIterator], actual);
for (const { 0: key, 1: val } of safeIterator) {
const safeIteratorArray = ArrayFrom(safeIterator);

for (let i = 0; i < safeIteratorArray.length; i++) {
const { 0: key, 1: val } = safeIteratorArray[i];

if (!MapPrototypeHas(expected, key)) {
return false;
}
Expand All @@ -685,8 +692,10 @@ function compareBranch(
return false;
}
const safeIterator = FunctionPrototypeCall(SafeSet.prototype[SymbolIterator], actual);
for (const item of safeIterator) {
if (!SetPrototypeHas(expected, item)) {
const safeIteratorArray = ArrayFrom(safeIterator);

for (let i = 0; i < safeIteratorArray.length; i++) {
if (!SetPrototypeHas(expected, safeIteratorArray[i])) {
return false;
}
}
Expand All @@ -706,16 +715,11 @@ function compareBranch(
return loose ? isDeepEqual(actual, expected) : isDeepStrictEqual(actual, expected);
}

// Check if actual and expected are null or not objects
if (actual == null || expected == null) {
return false;
}

// Use Reflect.ownKeys() instead of Object.keys() to include symbol properties
const keysExpected = ReflectOwnKeys(expected);

// Handle circular references
if (comparedObjects.has(actual)) {
if (SetPrototypeHas(comparedObjects, actual)) {
return true;
}
comparedObjects.add(actual);
Expand All @@ -742,7 +746,7 @@ function compareBranch(
* @param {string | Error} [message]
* @returns {void}
*/
assert.deepMatchStrict = function deepMatchStrict(
assert.partialDeepStrictEqual = function partialDeepStrictEqual(
actual,
expected,
message,
Expand All @@ -756,8 +760,8 @@ assert.deepMatchStrict = function deepMatchStrict(
actual,
expected,
message,
operator: 'deepMatchStrict',
stackStartFn: deepMatchStrict,
operator: 'partialDeepStrictEqual',
stackStartFn: partialDeepStrictEqual,
});
}
};
Expand All @@ -769,7 +773,7 @@ assert.deepMatchStrict = function deepMatchStrict(
* @param {string | Error} [message]
* @returns {void}
*/
assert.deepMatch = function deepMatch(actual, expected, message) {
assert.partialDeepEqual = function partialDeepEqual(actual, expected, message) {
if (arguments.length < 2) {
throw new ERR_MISSING_ARGS('actual', 'expected');
}
Expand All @@ -779,12 +783,22 @@ assert.deepMatch = function deepMatch(actual, expected, message) {
actual,
expected,
message,
operator: 'deepMatch',
stackStartFn: deepMatch,
operator: 'partialDeepEqual',
stackStartFn: partialDeepEqual,
});
}
};

function throwIfInvalidIncludesParams(actual, expected) {
if (typeof actual !== 'string' && !ArrayIsArray(actual)) {
throw new ERR_INVALID_ARG_TYPE('actual', ['string', 'Array'], actual);
}

if (typeof expected !== 'string' && !ArrayIsArray(expected)) {
throw new ERR_INVALID_ARG_TYPE('expected', ['string', 'Array'], expected);
}
}

/**
* The inclusion assertion test between two arrays or strings
* @param {Array | string} actual
Expand All @@ -797,6 +811,8 @@ assert.includes = function includes(actual, expected, message) {
throw new ERR_MISSING_ARGS('actual', 'expected');
}

throwIfInvalidIncludesParams(actual, expected);

if (!assertIncludes(actual, expected, true)) {
innerFail({
actual,
Expand All @@ -821,6 +837,8 @@ assert.includesStrict = function includesStrict(actual, expected, message) {
throw new ERR_MISSING_ARGS('actual', 'expected');
}

throwIfInvalidIncludesParams(actual, expected);

if (!assertIncludes(actual, expected, false)) {
innerFail({
actual,
Expand Down Expand Up @@ -1298,7 +1316,7 @@ assert.strict = ObjectAssign(strict, assert, {
deepEqual: assert.deepStrictEqual,
notEqual: assert.notStrictEqual,
notDeepEqual: assert.notDeepStrictEqual,
deepMatch: assert.deepMatchStrict,
partialDeepEqual: assert.partialDeepStrictEqual,
includes: assert.includesStrict,
});

Expand Down
Loading

0 comments on commit 3d52d4b

Please sign in to comment.