From bc9dcbbf1a4c2c741ef47f47d6ede6458f40c4a4 Mon Sep 17 00:00:00 2001 From: Mattias Buelens <649348+MattiasBuelens@users.noreply.github.com> Date: Wed, 27 Nov 2024 05:32:38 +0100 Subject: [PATCH] Streams: test whether patched `then()` sees correct `byobRequest` See https://github.com/whatwg/streams/pull/1326 for context. This also updates the `transferArrayBufferView` test utility to be synchronous, which slightly changes the timings of some tests in `streams/readable-byte-streams/general.any.js`. --- streams/readable-byte-streams/general.any.js | 8 +-- .../patched-global.any.js | 54 +++++++++++++++++++ streams/resources/rs-utils.js | 10 +--- 3 files changed, 59 insertions(+), 13 deletions(-) create mode 100644 streams/readable-byte-streams/patched-global.any.js diff --git a/streams/readable-byte-streams/general.any.js b/streams/readable-byte-streams/general.any.js index cdce2244c3c84b..4b0c73865f7cf9 100644 --- a/streams/readable-byte-streams/general.any.js +++ b/streams/readable-byte-streams/general.any.js @@ -870,11 +870,11 @@ promise_test(() => { start(c) { controller = c; }, - async pull() { + pull() { byobRequestDefined.push(controller.byobRequest !== null); const initialByobRequest = controller.byobRequest; - const transferredView = await transferArrayBufferView(controller.byobRequest.view); + const transferredView = transferArrayBufferView(controller.byobRequest.view); transferredView[0] = 0x01; controller.byobRequest.respondWithNewView(transferredView); @@ -2288,7 +2288,7 @@ promise_test(async t => { await pullCalledPromise; // Transfer the original BYOB request's buffer, and respond with a new view on that buffer - const transferredView = await transferArrayBufferView(controller.byobRequest.view); + const transferredView = transferArrayBufferView(controller.byobRequest.view); const newView = transferredView.subarray(0, 1); newView[0] = 42; @@ -2328,7 +2328,7 @@ promise_test(async t => { await pullCalledPromise; // Transfer the original BYOB request's buffer, and respond with an empty view on that buffer - const transferredView = await transferArrayBufferView(controller.byobRequest.view); + const transferredView = transferArrayBufferView(controller.byobRequest.view); const newView = transferredView.subarray(0, 0); controller.close(); diff --git a/streams/readable-byte-streams/patched-global.any.js b/streams/readable-byte-streams/patched-global.any.js new file mode 100644 index 00000000000000..ce2e9e9993ae57 --- /dev/null +++ b/streams/readable-byte-streams/patched-global.any.js @@ -0,0 +1,54 @@ +// META: global=window,worker,shadowrealm +// META: script=../resources/test-utils.js +'use strict'; + +// Tests which patch the global environment are kept separate to avoid +// interfering with other tests. + +promise_test(async (t) => { + let controller; + const rs = new ReadableStream({ + type: 'bytes', + start(c) { + controller = c; + } + }); + const reader = rs.getReader({mode: 'byob'}); + + const length = 0x4000; + const buffer = new ArrayBuffer(length); + const bigArray = new BigUint64Array(buffer, length - 8, 1); + + const read1 = reader.read(new Uint8Array(new ArrayBuffer(0x100))); + const read2 = reader.read(bigArray); + + let flag = false; + Object.defineProperty(Object.prototype, 'then', { + get: t.step_func(() => { + if (!flag) { + flag = true; + assert_equals(controller.byobRequest, null, 'byobRequest should be null after filling both views'); + } + }), + configurable: true + }); + t.add_cleanup(() => { + delete Object.prototype.then; + }); + + controller.enqueue(new Uint8Array(0x110).fill(0x42)); + assert_true(flag, 'patched then() should be called'); + + // The first read() is filled entirely with 0x100 bytes + const result1 = await read1; + assert_false(result1.done, 'result1.done'); + assert_typed_array_equals(result1.value, new Uint8Array(0x100).fill(0x42), 'result1.value'); + + // The second read() is filled with the remaining 0x10 bytes + const result2 = await read2; + assert_false(result2.done, 'result2.done'); + assert_equals(result2.value.constructor, BigUint64Array, 'result2.value constructor'); + assert_equals(result2.value.byteOffset, length - 8, 'result2.value byteOffset'); + assert_equals(result2.value.length, 1, 'result2.value length'); + assert_array_equals([...result2.value], [0x42424242_42424242n], 'result2.value contents'); +}, 'Patched then() sees byobRequest after filling all pending pull-into descriptors'); diff --git a/streams/resources/rs-utils.js b/streams/resources/rs-utils.js index f52dd6197b7d5d..0f7742a5b3b190 100644 --- a/streams/resources/rs-utils.js +++ b/streams/resources/rs-utils.js @@ -215,15 +215,7 @@ } function transferArrayBufferView(view) { - const noopByteStream = new ReadableStream({ - type: 'bytes', - pull(c) { - c.byobRequest.respond(c.byobRequest.view.byteLength); - c.close(); - } - }); - const reader = noopByteStream.getReader({ mode: 'byob' }); - return reader.read(view).then((result) => result.value); + return structuredClone(view, { transfer: [view.buffer] }); } self.RandomPushSource = RandomPushSource;