Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

assert: partialDeepStrictEqual now handles comparisons of ArrayBuffers, SharedArrayBuffers and Int16Arrays #56098

Conversation

puskin94
Copy link
Contributor

@puskin94 puskin94 commented Dec 1, 2024

Fixes: #56097

Added handling for ArrayBuffers, SharedArrayBuffers and Int16Arrays , which were not properly considered in the new method assert.partialDeepStrictEqual .
This PR should move the feature one step closer to a stable version

@nodejs-github-bot nodejs-github-bot added assert Issues and PRs related to the assert subsystem. needs-ci PRs that need a full CI run. labels Dec 1, 2024
@puskin94 puskin94 force-pushed the partial-deep-strict-equal-array-buffer-int-16-array branch from 248bb46 to a5f1059 Compare December 1, 2024 14:16
@puskin94 puskin94 marked this pull request as draft December 1, 2024 14:21
@puskin94 puskin94 force-pushed the partial-deep-strict-equal-array-buffer-int-16-array branch from a5f1059 to bbca465 Compare December 1, 2024 14:55
@puskin94 puskin94 marked this pull request as ready for review December 1, 2024 14:57
@puskin94 puskin94 marked this pull request as draft December 1, 2024 15:56
Copy link

codecov bot commented Dec 1, 2024

Codecov Report

Attention: Patch coverage is 97.20670% with 5 lines in your changes missing coverage. Please review.

Project coverage is 88.01%. Comparing base (3f9c6c0) to head (b4ba259).
Report is 51 commits behind head on main.

Files with missing lines Patch % Lines
lib/assert.js 97.20% 4 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #56098      +/-   ##
==========================================
+ Coverage   87.99%   88.01%   +0.01%     
==========================================
  Files         656      656              
  Lines      189000   189234     +234     
  Branches    35992    36030      +38     
==========================================
+ Hits       166308   166550     +242     
- Misses      15851    15853       +2     
+ Partials     6841     6831      -10     
Files with missing lines Coverage Δ
lib/assert.js 99.10% <97.20%> (+0.09%) ⬆️

... and 54 files with indirect coverage changes

@puskin94 puskin94 force-pushed the partial-deep-strict-equal-array-buffer-int-16-array branch from bbca465 to 710b5cd Compare December 1, 2024 16:21
@puskin94 puskin94 marked this pull request as ready for review December 1, 2024 16:22
@puskin94 puskin94 force-pushed the partial-deep-strict-equal-array-buffer-int-16-array branch from 710b5cd to 2cc5ee6 Compare December 1, 2024 17:43
@aduh95
Copy link
Contributor

aduh95 commented Dec 1, 2024

The commit message doesn't fit our guidelines, the word just after the subsystem should be a verb in infinitive form.

lib/assert.js Show resolved Hide resolved
lib/assert.js Outdated
return true;
if (
(ArrayBufferIsView(actual) && ArrayBufferIsView(expected)) ||
(actual instanceof ArrayBuffer && expected instanceof ArrayBuffer)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's not use instanceof, it doesn't work with values coming from other realms. Instead, let's use isArrayBuffer from internal/util/types

lib/assert.js Outdated
Comment on lines 400 to 412
const actualView = ArrayBufferIsView(actual) ? actual : new Uint8Array(actual);
const expectedView = ArrayBufferIsView(expected) ? expected : new Uint8Array(expected);

if (ObjectPrototypeToString(actualView) !== ObjectPrototypeToString(expectedView)) {
return false;
}

// Compare the lengths of the views (not just byte length, but actual element count)
if (expectedView.length > actualView.length) {
return false;
}

for (let i = 0; i < expectedView.length; i++) {
Copy link
Contributor

@aduh95 aduh95 Dec 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It feels quite arbitrary to consider that comparing an ArrayBuffer and a Uint8Array would be accepted, but not any other class. I think we would benefit from separating the different cases more, and we can also avoid calling some getters.

Suggested change
const actualView = ArrayBufferIsView(actual) ? actual : new Uint8Array(actual);
const expectedView = ArrayBufferIsView(expected) ? expected : new Uint8Array(expected);
if (ObjectPrototypeToString(actualView) !== ObjectPrototypeToString(expectedView)) {
return false;
}
// Compare the lengths of the views (not just byte length, but actual element count)
if (expectedView.length > actualView.length) {
return false;
}
for (let i = 0; i < expectedView.length; i++) {
let actualView, expectedView, expectedViewLength;
if (!ArrayBufferIsView(actual)) {
if (ArrayBufferIsView(expected)) return false;
expectedViewLength = ArrayBufferPrototypeGetByteLength(expected)
if (ArrayBufferPrototypeGetByteLength(actual) > expectedViewLength) return false;
actualView = new Uint8Array(actual);
expectedView = new Uin8Array(expected);
} else if (isDataView(actual)) {
if (!isDataView(expected)) return false;
const actualByteLength = DataViewPrototypeGetByteLength(actual);
expectedViewLength = DataViewPrototypeGetByteLength(expected)
if (actualByteLength > expectedViewLength) return false;
actualView = new Unit8Array(
DataViewPrototypeGetBuffer(actual),
DataViewPrototypeGetByteOffset(actual),
actualByteLength,
);
expectedView = new Unit8Array(
DataViewPrototypeGetBuffer(expected),
DataViewPrototypeGetByteOffset(expected),
expectedViewLength,
);
} else {
if (ObjectPrototypeToString(actual) !== ObjectPrototypeToString(expected)) return false;
actualView = actual;
expectedView = expected;
expectedViewLength = TypedArrayPrototypeGetLength(expected);
if (TypedArrayPrototypeGetLength(actual) > expectedViewLength) return false;
}
for (let i = 0; i < expectedViewLength; i++) {

@puskin94 puskin94 force-pushed the partial-deep-strict-equal-array-buffer-int-16-array branch 2 times, most recently from ca5e271 to 937f877 Compare December 2, 2024 08:21
lib/assert.js Show resolved Hide resolved
lib/assert.js Show resolved Hide resolved
@puskin94 puskin94 force-pushed the partial-deep-strict-equal-array-buffer-int-16-array branch 2 times, most recently from 14557cc to c912e20 Compare December 3, 2024 18:41
lib/assert.js Outdated
Comment on lines 546 to 547
(ArrayBufferIsView(actual) && ArrayBufferIsView(expected)) ||
(isArrayBuffer(actual) && isArrayBuffer(expected))
Copy link
Contributor

@aduh95 aduh95 Dec 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we want || here to catch all use of binary data?

Suggested change
(ArrayBufferIsView(actual) && ArrayBufferIsView(expected)) ||
(isArrayBuffer(actual) && isArrayBuffer(expected))
ArrayBufferIsView(actual) || ArrayBufferIsView(expected)) ||
isArrayBuffer(actual) || isArrayBuffer(expected)

Also, we may want to include SharedArrayBuffer (or is there a reason to treat those differently from regular ArrayBuffer?)

Suggested change
(ArrayBufferIsView(actual) && ArrayBufferIsView(expected)) ||
(isArrayBuffer(actual) && isArrayBuffer(expected))
ArrayBufferIsView(actual) || ArrayBufferIsView(expected)) ||
isAnyArrayBuffer(actual) || isAnyArrayBuffer(expected)

@puskin94 puskin94 force-pushed the partial-deep-strict-equal-array-buffer-int-16-array branch from c912e20 to 2e53fae Compare December 4, 2024 13:56
lib/assert.js Outdated
Comment on lines 555 to 563
ArrayBufferIsView(actual) ||
ArrayBufferIsView(expected) ||
isAnyArrayBuffer(actual) ||
isAnyArrayBuffer(expected)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can optimize the happy path here

Suggested change
ArrayBufferIsView(actual) ||
ArrayBufferIsView(expected) ||
isAnyArrayBuffer(actual) ||
isAnyArrayBuffer(expected)
ArrayBufferIsView(actual) || isAnyArrayBuffer(actual) ||
ArrayBufferIsView(expected) || isAnyArrayBuffer(expected)

Comment on lines +102 to +107
assert.throws(
makeBlock(assert.partialDeepStrictEqual, arrayPair[0], arrayPair[1]),
assert.AssertionError
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a pair of [new ArrayBuffer(3), new SharedArrayBuffer(3)] and [new SharedArrayBuffer(2), new ArrayBuffer(2)] please?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all the relevant tests have been added to test-assert-objects.js, including the ones you just mentioned. But I can add them here too if you want

@puskin94 puskin94 force-pushed the partial-deep-strict-equal-array-buffer-int-16-array branch from 2e53fae to b079afc Compare December 4, 2024 16:39
Comment on lines +412 to +422
if (isArrayBuffer(actual) && isArrayBuffer(expected)) {
actualViewLength = ArrayBufferPrototypeGetByteLength(actual);
expectedViewLength = ArrayBufferPrototypeGetByteLength(expected);
} else if (isSharedArrayBuffer(actual) && isSharedArrayBuffer(expected)) {
actualViewLength = actual.byteLength;
expectedViewLength = expected.byteLength;
} else {
// Cannot compare ArrayBuffers with SharedArrayBuffers
return false;
}
Copy link
Contributor

@aduh95 aduh95 Dec 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need to compute the value twice

    const isActualSharedArrayBuffer = isSharedArrayBuffer(actual);

    if (isActualSharedArrayBuffer !== isSharedArrayBuffer(expected)) return false;
    
    if (isActualSharedArrayBuffer) {
      // SharedArrayBuffer is not available in primordials because it can be
      // disabled with --no-harmony-sharedarraybuffer CLI flag.
      actualViewLength = actual.byteLength;
      expectedViewLength = expected.byteLength;
    } else {
      // If it is a BufferView and not a SharedArrayBuffer, it has to be an ArrayBuffer.
      actualViewLength = ArrayBufferPrototypeGetByteLength(actual);
      expectedViewLength = ArrayBufferPrototypeGetByteLength(expected);
    }

Copy link
Contributor

@aduh95 aduh95 Dec 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hum actually we do want to validate that expected is indeed a BufferView

Suggested change
if (isArrayBuffer(actual) && isArrayBuffer(expected)) {
actualViewLength = ArrayBufferPrototypeGetByteLength(actual);
expectedViewLength = ArrayBufferPrototypeGetByteLength(expected);
} else if (isSharedArrayBuffer(actual) && isSharedArrayBuffer(expected)) {
actualViewLength = actual.byteLength;
expectedViewLength = expected.byteLength;
} else {
// Cannot compare ArrayBuffers with SharedArrayBuffers
return false;
}
const isActualSharedArrayBuffer = isSharedArrayBuffer(actual);
if (!isActualSharedArrayBuffer && isArrayBuffer(expected)) {
actualViewLength = ArrayBufferPrototypeGetByteLength(actual);
expectedViewLength = ArrayBufferPrototypeGetByteLength(expected);
} else if (isActualSharedArrayBuffer && isSharedArrayBuffer(expected)) {
// SharedArrayBuffer is not available in primordials because it can be
// disabled with --no-harmony-sharedarraybuffer CLI flag.
actualViewLength = actual.byteLength;
expectedViewLength = expected.byteLength;
} else {
// Cannot compare ArrayBuffers with SharedArrayBuffers
return false;
}

Not sure if it actually matters for a performance PoV, feel free to ignore

@aduh95 aduh95 added author ready PRs that have at least one approval, no pending requests for changes, and a CI started. request-ci Add this label to start a Jenkins CI on a PR. labels Dec 4, 2024
lib/assert.js Outdated Show resolved Hide resolved
lib/assert.js Outdated Show resolved Hide resolved
lib/assert.js Outdated Show resolved Hide resolved
lib/assert.js Outdated Show resolved Hide resolved
lib/assert.js Outdated Show resolved Hide resolved
lib/assert.js Outdated Show resolved Hide resolved
lib/assert.js Outdated Show resolved Hide resolved
lib/assert.js Outdated Show resolved Hide resolved
@puskin94 puskin94 force-pushed the partial-deep-strict-equal-array-buffer-int-16-array branch 2 times, most recently from 6ac1f1a to f94b76b Compare December 7, 2024 09:41
lib/assert.js Outdated Show resolved Hide resolved
lib/assert.js Outdated Show resolved Hide resolved
@puskin94 puskin94 force-pushed the partial-deep-strict-equal-array-buffer-int-16-array branch from f94b76b to b4ba259 Compare December 7, 2024 10:01
@aduh95 aduh95 added the request-ci Add this label to start a Jenkins CI on a PR. label Dec 7, 2024
@github-actions github-actions bot removed the request-ci Add this label to start a Jenkins CI on a PR. label Dec 7, 2024
@nodejs-github-bot
Copy link
Collaborator

@nodejs-github-bot
Copy link
Collaborator

@aduh95 aduh95 added the commit-queue Add this label to land a pull request using GitHub Actions. label Dec 7, 2024
@nodejs-github-bot nodejs-github-bot added commit-queue-failed An error occurred while landing this pull request using GitHub Actions. and removed commit-queue Add this label to land a pull request using GitHub Actions. labels Dec 7, 2024
@nodejs-github-bot
Copy link
Collaborator

Commit Queue failed
- Loading data for nodejs/node/pull/56098
✔  Done loading data for nodejs/node/pull/56098
----------------------------------- PR info ------------------------------------
Title      assert: partialDeepStrictEqual now handles comparisons of ArrayBuffers, SharedArrayBuffers and Int16Arrays (#56098)
   ⚠  Could not retrieve the email or name of the PR author's from user's GitHub profile!
Branch     puskin94:partial-deep-strict-equal-array-buffer-int-16-array -> nodejs:main
Labels     assert, author ready, needs-ci
Commits    1
 - assert: make partialDeepStrictEqual work with ArrayBuffers
Committers 1
 - Giovanni <[email protected]>
PR-URL: https://github.com/nodejs/node/pull/56098
Fixes: https://github.com/nodejs/node/issues/56097
Reviewed-By: Antoine du Hamel <[email protected]>
------------------------------ Generated metadata ------------------------------
PR-URL: https://github.com/nodejs/node/pull/56098
Fixes: https://github.com/nodejs/node/issues/56097
Reviewed-By: Antoine du Hamel <[email protected]>
--------------------------------------------------------------------------------
   ℹ  This PR was created on Sun, 01 Dec 2024 14:13:09 GMT
   ✔  Approvals: 1
   ✔  - Antoine du Hamel (@aduh95) (TSC): https://github.com/nodejs/node/pull/56098#pullrequestreview-2486472658
   ✘  This PR needs to wait 14 more hours to land (or 0 hours if there is one more approval)
   ✔  Last GitHub CI successful
   ℹ  Last Full PR CI on 2024-12-07T18:10:47Z: https://ci.nodejs.org/job/node-test-pull-request/63927/
- Querying data for job/node-test-pull-request/63927/
   ✔  Last Jenkins CI successful
--------------------------------------------------------------------------------
   ✔  Aborted `git node land` session in /home/runner/work/node/node/.ncu
https://github.com/nodejs/node/actions/runs/12216903231

@aduh95 aduh95 added commit-queue Add this label to land a pull request using GitHub Actions. and removed commit-queue-failed An error occurred while landing this pull request using GitHub Actions. labels Dec 8, 2024
@nodejs-github-bot nodejs-github-bot removed the commit-queue Add this label to land a pull request using GitHub Actions. label Dec 8, 2024
@nodejs-github-bot nodejs-github-bot merged commit dbfcbe3 into nodejs:main Dec 8, 2024
67 checks passed
@nodejs-github-bot
Copy link
Collaborator

Landed in dbfcbe3

aduh95 pushed a commit that referenced this pull request Dec 10, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
assert Issues and PRs related to the assert subsystem. author ready PRs that have at least one approval, no pending requests for changes, and a CI started. needs-ci PRs that need a full CI run.
Projects
None yet
4 participants