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

test: update Web Streams WPT #44234

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion test/fixtures/wpt/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Last update:
- interfaces: https://github.com/web-platform-tests/wpt/tree/fc086c82d5/interfaces
- performance-timeline: https://github.com/web-platform-tests/wpt/tree/17ebc3aea0/performance-timeline
- resources: https://github.com/web-platform-tests/wpt/tree/c5b428f15a/resources
- streams: https://github.com/web-platform-tests/wpt/tree/8f60d94439/streams
- streams: https://github.com/web-platform-tests/wpt/tree/9e5ef42bd3/streams
- url: https://github.com/web-platform-tests/wpt/tree/0e5b126cd0/url
- user-timing: https://github.com/web-platform-tests/wpt/tree/df24fb604e/user-timing
- wasm/jsapi: https://github.com/web-platform-tests/wpt/tree/d8dbe6990b/wasm/jsapi
Expand Down
2 changes: 2 additions & 0 deletions test/fixtures/wpt/streams/idlharness-shadowrealm.window.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// META: script=/resources/idlharness-shadowrealm.js
idl_test_shadowrealm(["streams"], ["dom"]);
175 changes: 104 additions & 71 deletions test/fixtures/wpt/streams/piping/abort.any.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// META: global=window,worker,jsshell
// META: global=window,worker
// META: script=../resources/recording-streams.js
// META: script=../resources/test-utils.js
'use strict';
Expand Down Expand Up @@ -53,29 +53,28 @@ promise_test(t => {
});
}, 'an aborted signal should cause the writable stream to reject with an AbortError');

promise_test(() => {
let error;
const rs = recordingReadableStream(errorOnPull, hwm0);
const ws = new WritableStream();
const abortController = new AbortController();
const signal = abortController.signal;
abortController.abort();
return rs.pipeTo(ws, { signal })
.catch(e => {
error = e;
})
.then(() => Promise.all([
rs.getReader().closed,
ws.getWriter().closed.catch(e => {
assert_equals(e, error, 'the writable should be errored with the same object');
})
]))
.then(() => {
for (const reason of [null, undefined, error1]) {
promise_test(async t => {
const rs = recordingReadableStream(errorOnPull, hwm0);
const ws = new WritableStream();
const abortController = new AbortController();
const signal = abortController.signal;
abortController.abort(reason);
const pipeToPromise = rs.pipeTo(ws, { signal });
if (reason !== undefined) {
await promise_rejects_exactly(t, reason, pipeToPromise, 'pipeTo rejects with abort reason');
} else {
await promise_rejects_dom(t, 'AbortError', pipeToPromise, 'pipeTo rejects with AbortError');
}
const error = await pipeToPromise.catch(e => e);
await rs.getReader().closed;
await promise_rejects_exactly(t, error, ws.getWriter().closed, 'the writable should be errored with the same object');
assert_equals(signal.reason, error, 'signal.reason should be error'),
assert_equals(rs.events.length, 2, 'cancel should have been called');
assert_equals(rs.events[0], 'cancel', 'first event should be cancel');
assert_equals(rs.events[1], error, 'the readable should be canceled with the same object');
});
}, 'all the AbortError objects should be the same object');
}, `(reason: '${reason}') all the error objects should be the same object`);
}

promise_test(t => {
const rs = recordingReadableStream(errorOnPull, hwm0);
Expand Down Expand Up @@ -115,61 +114,74 @@ promise_test(t => {
});
}, 'preventCancel and preventAbort should prevent canceling the readable and aborting the readable');

promise_test(t => {
const rs = new ReadableStream({
start(controller) {
controller.enqueue('a');
controller.enqueue('b');
controller.close();
}
});
const abortController = new AbortController();
const signal = abortController.signal;
const ws = recordingWritableStream({
write() {
abortController.abort();
for (const reason of [null, undefined, error1]) {
promise_test(async t => {
const rs = new ReadableStream({
start(controller) {
controller.enqueue('a');
controller.enqueue('b');
controller.close();
}
});
const abortController = new AbortController();
const signal = abortController.signal;
const ws = recordingWritableStream({
write() {
abortController.abort(reason);
}
});
const pipeToPromise = rs.pipeTo(ws, { signal });
if (reason !== undefined) {
await promise_rejects_exactly(t, reason, pipeToPromise, 'pipeTo rejects with abort reason');
} else {
await promise_rejects_dom(t, 'AbortError', pipeToPromise, 'pipeTo rejects with AbortError');
}
});
return promise_rejects_dom(t, 'AbortError', rs.pipeTo(ws, { signal }), 'pipeTo should reject')
.then(() => {
assert_equals(ws.events.length, 4, 'only chunk "a" should have been written');
assert_array_equals(ws.events.slice(0, 3), ['write', 'a', 'abort'], 'events should match');
assert_equals(ws.events[3].name, 'AbortError', 'abort reason should be an AbortError');
});
}, 'abort should prevent further reads');
const error = await pipeToPromise.catch(e => e);
assert_equals(signal.reason, error, 'signal.reason should be error');
assert_equals(ws.events.length, 4, 'only chunk "a" should have been written');
assert_array_equals(ws.events.slice(0, 3), ['write', 'a', 'abort'], 'events should match');
assert_equals(ws.events[3], error, 'abort reason should be error');
}, `(reason: '${reason}') abort should prevent further reads`);
}

promise_test(t => {
let readController;
const rs = new ReadableStream({
start(c) {
readController = c;
c.enqueue('a');
c.enqueue('b');
}
});
const abortController = new AbortController();
const signal = abortController.signal;
let resolveWrite;
const writePromise = new Promise(resolve => {
resolveWrite = resolve;
});
const ws = recordingWritableStream({
write() {
return writePromise;
for (const reason of [null, undefined, error1]) {
promise_test(async t => {
let readController;
const rs = new ReadableStream({
start(c) {
readController = c;
c.enqueue('a');
c.enqueue('b');
}
});
const abortController = new AbortController();
const signal = abortController.signal;
let resolveWrite;
const writePromise = new Promise(resolve => {
resolveWrite = resolve;
});
const ws = recordingWritableStream({
write() {
return writePromise;
}
}, new CountQueuingStrategy({ highWaterMark: Infinity }));
const pipeToPromise = rs.pipeTo(ws, { signal });
await delay(0);
await abortController.abort(reason);
await readController.close(); // Make sure the test terminates when signal is not implemented.
await resolveWrite();
if (reason !== undefined) {
await promise_rejects_exactly(t, reason, pipeToPromise, 'pipeTo rejects with abort reason');
} else {
await promise_rejects_dom(t, 'AbortError', pipeToPromise, 'pipeTo rejects with AbortError');
}
}, new CountQueuingStrategy({ highWaterMark: Infinity }));
const pipeToPromise = rs.pipeTo(ws, { signal });
return delay(0).then(() => {
abortController.abort();
readController.close(); // Make sure the test terminates when signal is not implemented.
resolveWrite();
return promise_rejects_dom(t, 'AbortError', pipeToPromise, 'pipeTo should reject');
}).then(() => {
const error = await pipeToPromise.catch(e => e);
assert_equals(signal.reason, error, 'signal.reason should be error');
assert_equals(ws.events.length, 6, 'chunks "a" and "b" should have been written');
assert_array_equals(ws.events.slice(0, 5), ['write', 'a', 'write', 'b', 'abort'], 'events should match');
assert_equals(ws.events[5].name, 'AbortError', 'abort reason should be an AbortError');
});
}, 'all pending writes should complete on abort');
assert_equals(ws.events[5], error, 'abort reason should be error');
}, `(reason: '${reason}') all pending writes should complete on abort`);
}

promise_test(t => {
const rs = new ReadableStream({
Expand Down Expand Up @@ -373,3 +385,24 @@ promise_test(t => {
assert_array_equals(rs.events, ['pull'], 'cancel should not have been called');
});
}, 'abort should do nothing after the writable is errored');

promise_test(async t => {
const rs = new ReadableStream({
pull(c) {
c.enqueue(new Uint8Array([]));
},
type: "bytes",
});
const ws = new WritableStream();
const [first, second] = rs.tee();

let aborted = false;
first.pipeTo(ws, { signal: AbortSignal.abort() }).catch(() => {
aborted = true;
});
await delay(0);
assert_true(!aborted, "pipeTo should not resolve yet");
await second.cancel();
await delay(0);
assert_true(aborted, "pipeTo should be aborted now");
}, "pipeTo on a teed readable byte stream should only be aborted when both branches are aborted");
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// META: global=window,worker,jsshell
// META: global=window,worker
// META: script=../resources/recording-streams.js
'use strict';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// META: global=window,worker,jsshell
// META: global=window,worker
// META: script=../resources/test-utils.js
// META: script=../resources/recording-streams.js
'use strict';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// META: global=window,worker,jsshell
// META: global=window,worker
// META: script=../resources/test-utils.js
// META: script=../resources/recording-streams.js
'use strict';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// META: global=window,worker,jsshell
// META: global=window,worker
// META: script=../resources/test-utils.js
// META: script=../resources/recording-streams.js
'use strict';
Expand Down
2 changes: 1 addition & 1 deletion test/fixtures/wpt/streams/piping/flow-control.any.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// META: global=window,worker,jsshell
// META: global=window,worker
// META: script=../resources/test-utils.js
// META: script=../resources/rs-utils.js
// META: script=../resources/recording-streams.js
Expand Down
2 changes: 1 addition & 1 deletion test/fixtures/wpt/streams/piping/general.any.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// META: global=window,worker,jsshell
// META: global=window,worker
// META: script=../resources/test-utils.js
// META: script=../resources/recording-streams.js
'use strict';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// META: global=window,worker,jsshell
// META: global=window,worker
// META: script=../resources/test-utils.js
// META: script=../resources/recording-streams.js
'use strict';
Expand Down
65 changes: 64 additions & 1 deletion test/fixtures/wpt/streams/piping/pipe-through.any.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// META: global=window,worker,jsshell
// META: global=window,worker
// META: script=../resources/rs-utils.js
// META: script=../resources/test-utils.js
// META: script=../resources/recording-streams.js
Expand Down Expand Up @@ -266,3 +266,66 @@ test(() => {
}
}), 'pipeThrough should throw');
}, 'pipeThrough() should throw if an option getter grabs a writer');

test(() => {
const rs = new ReadableStream();
const readable = new ReadableStream();
const writable = new WritableStream();
rs.pipeThrough({readable, writable}, null);
}, 'pipeThrough() should not throw if option is null');

test(() => {
const rs = new ReadableStream();
const readable = new ReadableStream();
const writable = new WritableStream();
rs.pipeThrough({readable, writable}, {signal:undefined});
}, 'pipeThrough() should not throw if signal is undefined');

function tryPipeThrough(pair, options)
{
const rs = new ReadableStream();
if (!pair)
pair = {readable:new ReadableStream(), writable:new WritableStream()};
try {
rs.pipeThrough(pair, options)
} catch (e) {
return e;
}
}

test(() => {
let result = tryPipeThrough({
get readable() {
return new ReadableStream();
},
get writable() {
throw "writable threw";
}
}, { });
assert_equals(result, "writable threw");

result = tryPipeThrough({
get readable() {
throw "readable threw";
},
get writable() {
throw "writable threw";
}
}, { });
assert_equals(result, "readable threw");

result = tryPipeThrough({
get readable() {
throw "readable threw";
},
get writable() {
throw "writable threw";
}
}, {
get preventAbort() {
throw "preventAbort threw";
}
});
assert_equals(result, "readable threw");

}, 'pipeThrough() should throw if readable/writable getters throw');
2 changes: 1 addition & 1 deletion test/fixtures/wpt/streams/piping/then-interception.any.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// META: global=window,worker,jsshell
// META: global=window,worker
// META: script=../resources/test-utils.js
// META: script=../resources/recording-streams.js
'use strict';
Expand Down
2 changes: 1 addition & 1 deletion test/fixtures/wpt/streams/piping/throwing-options.any.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// META: global=window,worker,jsshell
// META: global=window,worker
'use strict';

class ThrowingOptions {
Expand Down
2 changes: 1 addition & 1 deletion test/fixtures/wpt/streams/piping/transform-streams.any.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// META: global=window,worker,jsshell
// META: global=window,worker
'use strict';

promise_test(() => {
Expand Down
17 changes: 16 additions & 1 deletion test/fixtures/wpt/streams/queuing-strategies.any.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// META: global=window,worker,jsshell
// META: global=window,worker
'use strict';

const highWaterMarkConversions = new Map([
Expand Down Expand Up @@ -75,8 +75,23 @@ for (const QueuingStrategy of [CountQueuingStrategy, ByteLengthQueuingStrategy])
assert_equals(sc.size(), 2, 'size() on the subclass should override the parent');
assert_true(sc.subClassMethod(), 'subClassMethod() should work');
}, `${QueuingStrategy.name}: subclassing should work correctly`);

test(() => {
const size = new QueuingStrategy({ highWaterMark: 5 }).size;
assert_false('prototype' in size);
}, `${QueuingStrategy.name}: size should not have a prototype property`);
}

test(() => {
const size = new CountQueuingStrategy({ highWaterMark: 5 }).size;
assert_throws_js(TypeError, () => new size());
}, `CountQueuingStrategy: size should not be a constructor`);

test(() => {
const size = new ByteLengthQueuingStrategy({ highWaterMark: 5 }).size;
assert_throws_js(TypeError, () => new size({ byteLength: 1024 }));
}, `ByteLengthQueuingStrategy: size should not be a constructor`);

test(() => {
const size = (new CountQueuingStrategy({ highWaterMark: 5 })).size;
assert_equals(size.length, 0);
Expand Down
Loading