diff --git a/test/fixtures/wpt/README.md b/test/fixtures/wpt/README.md index 406e89b820e9f7..8336539a7d70d4 100644 --- a/test/fixtures/wpt/README.md +++ b/test/fixtures/wpt/README.md @@ -27,7 +27,7 @@ Last update: - performance-timeline: https://github.com/web-platform-tests/wpt/tree/94caab7038/performance-timeline - resource-timing: https://github.com/web-platform-tests/wpt/tree/22d38586d0/resource-timing - resources: https://github.com/web-platform-tests/wpt/tree/1e140d63ec/resources -- streams: https://github.com/web-platform-tests/wpt/tree/2bd26e124c/streams +- streams: https://github.com/web-platform-tests/wpt/tree/bc9dcbbf1a/streams - url: https://github.com/web-platform-tests/wpt/tree/67880a4eb8/url - user-timing: https://github.com/web-platform-tests/wpt/tree/5ae85bf826/user-timing - wasm/jsapi: https://github.com/web-platform-tests/wpt/tree/cde25e7e3c/wasm/jsapi diff --git a/test/fixtures/wpt/streams/idlharness-shadowrealm.window.js b/test/fixtures/wpt/streams/idlharness-shadowrealm.window.js deleted file mode 100644 index 099b2475ca7e87..00000000000000 --- a/test/fixtures/wpt/streams/idlharness-shadowrealm.window.js +++ /dev/null @@ -1,2 +0,0 @@ -// META: script=/resources/idlharness-shadowrealm.js -idl_test_shadowrealm(["streams"], ["dom"]); diff --git a/test/fixtures/wpt/streams/idlharness.any.js b/test/fixtures/wpt/streams/idlharness.any.js index 42a17da58c5ae3..0be03b2078f9bc 100644 --- a/test/fixtures/wpt/streams/idlharness.any.js +++ b/test/fixtures/wpt/streams/idlharness.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker +// META: global=window,worker,shadowrealm-in-window // META: script=/resources/WebIDLParser.js // META: script=/resources/idlharness.js // META: timeout=long diff --git a/test/fixtures/wpt/streams/readable-byte-streams/general.any.js b/test/fixtures/wpt/streams/readable-byte-streams/general.any.js index cdce2244c3c84b..4b0c73865f7cf9 100644 --- a/test/fixtures/wpt/streams/readable-byte-streams/general.any.js +++ b/test/fixtures/wpt/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/test/fixtures/wpt/streams/readable-byte-streams/patched-global.any.js b/test/fixtures/wpt/streams/readable-byte-streams/patched-global.any.js new file mode 100644 index 00000000000000..ce2e9e9993ae57 --- /dev/null +++ b/test/fixtures/wpt/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/test/fixtures/wpt/streams/readable-byte-streams/tee.any.js b/test/fixtures/wpt/streams/readable-byte-streams/tee.any.js index 7dd5ba3f3fb013..60d82b9cf6a1fd 100644 --- a/test/fixtures/wpt/streams/readable-byte-streams/tee.any.js +++ b/test/fixtures/wpt/streams/readable-byte-streams/tee.any.js @@ -934,3 +934,36 @@ promise_test(async () => { assert_typed_array_equals(result4.value, new Uint8Array([0]).subarray(0, 0), 'second chunk from branch2 should be correct'); }, 'ReadableStream teeing with byte source: respond() and close() while both branches are pulling'); + +promise_test(async t => { + let pullCount = 0; + const arrayBuffer = new Uint8Array([0x01, 0x02, 0x03]).buffer; + const enqueuedChunk = new Uint8Array(arrayBuffer, 2); + assert_equals(enqueuedChunk.length, 1); + assert_equals(enqueuedChunk.byteOffset, 2); + const rs = new ReadableStream({ + type: 'bytes', + pull(c) { + ++pullCount; + if (pullCount === 1) { + c.enqueue(enqueuedChunk); + } + } + }); + + const [branch1, branch2] = rs.tee(); + const reader1 = branch1.getReader(); + const reader2 = branch2.getReader(); + + const [result1, result2] = await Promise.all([reader1.read(), reader2.read()]); + assert_equals(result1.done, false, 'reader1 done'); + assert_equals(result2.done, false, 'reader2 done'); + + const view1 = result1.value; + const view2 = result2.value; + // The first stream has the transferred buffer, but the second stream has the + // cloned buffer. + const underlying = new Uint8Array([0x01, 0x02, 0x03]).buffer; + assert_typed_array_equals(view1, new Uint8Array(underlying, 2), 'reader1 value'); + assert_typed_array_equals(view2, new Uint8Array([0x03]), 'reader2 value'); +}, 'ReadableStream teeing with byte source: reading an array with a byte offset should clone correctly'); diff --git a/test/fixtures/wpt/streams/readable-streams/crashtests/from-cross-realm.https.html b/test/fixtures/wpt/streams/readable-streams/crashtests/from-cross-realm.https.html new file mode 100644 index 00000000000000..58a4371186ece7 --- /dev/null +++ b/test/fixtures/wpt/streams/readable-streams/crashtests/from-cross-realm.https.html @@ -0,0 +1,18 @@ + + + diff --git a/test/fixtures/wpt/streams/readable-streams/owning-type-video-frame.any.js b/test/fixtures/wpt/streams/readable-streams/owning-type-video-frame.any.js index b652f9c5fcb4b6..ec01fda0b3c737 100644 --- a/test/fixtures/wpt/streams/readable-streams/owning-type-video-frame.any.js +++ b/test/fixtures/wpt/streams/readable-streams/owning-type-video-frame.any.js @@ -1,4 +1,4 @@ -// META: global=window,worker,shadowrealm +// META: global=window,worker // META: script=../resources/test-utils.js // META: script=../resources/rs-utils.js 'use strict'; diff --git a/test/fixtures/wpt/streams/resources/rs-utils.js b/test/fixtures/wpt/streams/resources/rs-utils.js index f1a014275a2fbc..0f7742a5b3b190 100644 --- a/test/fixtures/wpt/streams/resources/rs-utils.js +++ b/test/fixtures/wpt/streams/resources/rs-utils.js @@ -1,5 +1,42 @@ 'use strict'; (function () { + // Fake setInterval-like functionality in environments that don't have it + class IntervalHandle { + constructor(callback, delayMs) { + this.callback = callback; + this.delayMs = delayMs; + this.cancelled = false; + Promise.resolve().then(() => this.check()); + } + + async check() { + while (true) { + await new Promise(resolve => step_timeout(resolve, this.delayMs)); + if (this.cancelled) { + return; + } + this.callback(); + } + } + + cancel() { + this.cancelled = true; + } + } + + let localSetInterval, localClearInterval; + if (typeof globalThis.setInterval !== "undefined" && + typeof globalThis.clearInterval !== "undefined") { + localSetInterval = globalThis.setInterval; + localClearInterval = globalThis.clearInterval; + } else { + localSetInterval = function setInterval(callback, delayMs) { + return new IntervalHandle(callback, delayMs); + } + localClearInterval = function clearInterval(handle) { + handle.cancel(); + } + } class RandomPushSource { constructor(toPush) { @@ -18,12 +55,12 @@ } if (!this.started) { - this._intervalHandle = setInterval(writeChunk, 2); + this._intervalHandle = localSetInterval(writeChunk, 2); this.started = true; } if (this.paused) { - this._intervalHandle = setInterval(writeChunk, 2); + this._intervalHandle = localSetInterval(writeChunk, 2); this.paused = false; } @@ -37,7 +74,7 @@ if (source.toPush > 0 && source.pushed > source.toPush) { if (source._intervalHandle) { - clearInterval(source._intervalHandle); + localClearInterval(source._intervalHandle); source._intervalHandle = undefined; } source.closed = true; @@ -55,7 +92,7 @@ if (this.started) { this.paused = true; - clearInterval(this._intervalHandle); + localClearInterval(this._intervalHandle); this._intervalHandle = undefined; } else { throw new Error('Can\'t pause reading an unstarted source.'); @@ -178,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; diff --git a/test/fixtures/wpt/streams/transferable/transfer-with-messageport.window.js b/test/fixtures/wpt/streams/transferable/transfer-with-messageport.window.js index 37f8c9df169607..3bfe634a6e153d 100644 --- a/test/fixtures/wpt/streams/transferable/transfer-with-messageport.window.js +++ b/test/fixtures/wpt/streams/transferable/transfer-with-messageport.window.js @@ -105,7 +105,7 @@ async function transferMessagePortWith(constructor) { await transferMessagePortWithOrder3(new constructor()); } -async function advancedTransferMesagePortWith(constructor) { +async function advancedTransferMessagePortWith(constructor) { await transferMessagePortWithOrder4(new constructor()); await transferMessagePortWithOrder5(new constructor()); await transferMessagePortWithOrder6(new constructor()); @@ -166,7 +166,7 @@ async function mixedTransferMessagePortWithOrder3() { ); } -async function mixedTransferMesagePortWith() { +async function mixedTransferMessagePortWith() { await mixedTransferMessagePortWithOrder1(); await mixedTransferMessagePortWithOrder2(); await mixedTransferMessagePortWithOrder3(); @@ -185,19 +185,19 @@ promise_test(async t => { }, "Transferring a MessagePort with a TransformStream should set `.ports`"); promise_test(async t => { - await transferMessagePortWith(ReadableStream); + await advancedTransferMessagePortWith(ReadableStream); }, "Transferring a MessagePort with a ReadableStream should set `.ports`, advanced"); promise_test(async t => { - await transferMessagePortWith(WritableStream); + await advancedTransferMessagePortWith(WritableStream); }, "Transferring a MessagePort with a WritableStream should set `.ports`, advanced"); promise_test(async t => { - await transferMessagePortWith(TransformStream); + await advancedTransferMessagePortWith(TransformStream); }, "Transferring a MessagePort with a TransformStream should set `.ports`, advanced"); promise_test(async t => { - await mixedTransferMesagePortWith(); + await mixedTransferMessagePortWith(); }, "Transferring a MessagePort with multiple streams should set `.ports`"); test(() => { diff --git a/test/fixtures/wpt/versions.json b/test/fixtures/wpt/versions.json index 55227b3be66e1b..a3e0dd60ed66ab 100644 --- a/test/fixtures/wpt/versions.json +++ b/test/fixtures/wpt/versions.json @@ -68,7 +68,7 @@ "path": "resources" }, "streams": { - "commit": "2bd26e124cf17b2f0a25c150794d640b07b2a870", + "commit": "bc9dcbbf1a4c2c741ef47f47d6ede6458f40c4a4", "path": "streams" }, "url": {