Skip to content

Commit 26396a9

Browse files
committed
Readable-byte suite: per-test map of the WPT general.any.js failures
1 parent 803ac37 commit 26396a9

4 files changed

Lines changed: 139 additions & 0 deletions

File tree

src/tests/streams/readable-byte/AGENTS.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,31 @@ bridge drives to consume TypeScript streams (conduit basics in the
5959
identity suite's draining-reader.js). No such global exists under the
6060
C++ implementation; `draining-reader.js` asserts both sides.
6161

62+
## WPT map: readable-byte-streams/general.any.js expectedFailures
63+
64+
The 34 C++ expectedFailures in that WPT file (see
65+
src/wpt/streams-test.ts), each mapped to the suite pin that owns the
66+
divergence root. "Family" means the WPT test fails for the same root a
67+
named suite test pins directly, differing only in incidental asserts.
68+
69+
| WPT test (abbreviated) | Root | Suite pin |
70+
| --- | --- | --- |
71+
| start() throws an exception | ctor captures sync start throws (ledger #4) | `syncStartThrow` |
72+
| Automatic pull() after start() / after read() / after read(view) | proactive pull (ledger #3) | `pullCountShape` |
73+
| autoAllocateChunkSize | auto-allocated byobRequest on default reads (ledger #5) | `byobRequestOnDefaultRead` |
74+
| Respond to pull() by enqueue() asynchronously / multiple pull() by separate enqueue() / read() twice then enqueue() twice / Push source without pull signal / enqueue()+getReader()+read() | pull-count and coalescing family (ledger #3, #17) | `pullCountShape`, `byteDesiredSizeAccounting` |
75+
| constructor rejects size with type "bytes" | ledger #1 | `sizeStrategyForBytes` |
76+
| cancel() with partially filled pending pull() | done-shape family + partial discard | `cancelWithPartiallyFilledPull` (direct) |
77+
| getReader(), read(view), then cancel() | pull runs before cancel under C++ | `readViewThenCancelOrdering` (direct) |
78+
| enqueue() with Uint16Array then read() / 3 byte + 2-element Uint16Array | mismatched view/enqueue granularity | `readableStreamBytesMismatchedSizes`, `byobUint16Array` |
79+
| read(view) Uint32Array filled by multiple enqueue() | partial fills across enqueues | `byobUint32Array`, `byobPartialRespondMisalignsFillOffset` |
80+
| enqueue(), read(view) partially, then read() | remainder to a default read | `partialViewThenDefaultRead` (direct; PARITY) |
81+
| read(view) Uint16 on close()-d with 1 byte / errored if close()-d before fulfilling read(view) | close-with-partial (ledger #7) | `closeWithPartiallyFilledView` |
82+
| Throwing in pull ignored if errored / pull throw errors stream | pull-throw shapes | `pullThrowIgnoredIfErrored`, `pullThrowErrorsStream` |
83+
| enqueue() discards auto-allocated BYOB request | request invalidation | `enqueueDiscardsByobRequest` |
84+
| releaseLock()+second-reader ×9 (respond / respond(1) Uint16 / respond(3) / respondWithNewView / autoAllocate ×3 / Uint16 respond(1) chains ×2) | the release-relock cluster (ledger #9, #10) | `release-relock.js` (whole module) |
85+
| Multiple read(view): close() and respond() / big enqueue() / multiple enqueue() | multi-pending-read delivery | `readableStreamMultiplePendingReads` |
86+
6287
## Compatibility flags
6388

6489
| Flag | Pinned in main cells | Other cells |

src/tests/streams/readable-byte/byob-reader.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,3 +507,34 @@ export const byobreaderRegression = {
507507
ok(done);
508508
},
509509
};
510+
511+
// A BYOB read consumes part of an enqueued chunk; a later DEFAULT read
512+
// picks up the remainder (WPT 'enqueue(), read(view) partially, then
513+
// read()'). PARITY: [1,2] to the view, then Uint8Array [3] to the
514+
// default reader.
515+
export const partialViewThenDefaultRead = {
516+
async test() {
517+
const rs = new ReadableStream({
518+
type: 'bytes',
519+
start(c) {
520+
c.enqueue(new Uint8Array([1, 2, 3]));
521+
},
522+
});
523+
const byob = rs.getReader({ mode: 'byob' });
524+
const first = await byob.read(new Uint8Array(2));
525+
byob.releaseLock();
526+
const dflt = rs.getReader();
527+
const second = await Promise.race([
528+
dflt
529+
.read()
530+
.then(
531+
(r) =>
532+
`second:done=${r.done},type=${r.value?.constructor?.name},bytes=[${r.value ? Array.from(r.value) : ''}]`
533+
),
534+
scheduler.wait(200).then(() => 'second:pending'),
535+
]);
536+
strictEqual(first.done, false);
537+
strictEqual(Array.from(first.value).join(','), '1,2');
538+
strictEqual(second, 'second:done=false,type=Uint8Array,bytes=[3]');
539+
},
540+
};

src/tests/streams/readable-byte/controller.js

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,3 +195,83 @@ export const controllerType = {
195195
strictEqual(c instanceof ReadableByteStreamController, true);
196196
},
197197
};
198+
199+
// cancel() while a partially filled pull-into is pending (WPT
200+
// 'cancel() with partially filled pending pull() request'): the read
201+
// resolves done with the partial bytes DISCARDED on both sides —
202+
// DIVERGENCE only in the done shape (C++ an empty view, TypeScript
203+
// undefined; the done-read family). The cancel hook gets the reason
204+
// and the cancel fulfills on both.
205+
export const cancelWithPartiallyFilledPull = {
206+
async test() {
207+
const events = [];
208+
let controller;
209+
const rs = new ReadableStream({
210+
type: 'bytes',
211+
start(c) {
212+
controller = c;
213+
},
214+
cancel(reason) {
215+
events.push(`cancel:${reason}`);
216+
},
217+
});
218+
const reader = rs.getReader({ mode: 'byob' });
219+
const readP = reader.read(new Uint16Array(1)); // wants 2 bytes
220+
controller.enqueue(new Uint8Array([0x11])); // partial: 1 byte
221+
await scheduler.wait(1);
222+
const cancelP = reader.cancel('why');
223+
const read = await Promise.race([
224+
readP.then(
225+
(r) =>
226+
`read:done=${r.done},len=${r.value ? r.value.byteLength : 'undef'}`,
227+
(e) => `read-rejected:${e.name}`
228+
),
229+
scheduler.wait(200).then(() => 'read:pending'),
230+
]);
231+
const cancel = await Promise.race([
232+
cancelP.then(
233+
() => 'cancel:fulfilled',
234+
(e) => `cancel-rejected:${e.name}`
235+
),
236+
scheduler.wait(200).then(() => 'cancel:pending'),
237+
]);
238+
strictEqual(
239+
read,
240+
usingTsImpl ? 'read:done=true,len=undef' : 'read:done=true,len=0'
241+
);
242+
strictEqual(cancel, 'cancel:fulfilled');
243+
strictEqual(events.join(','), 'cancel:why');
244+
},
245+
};
246+
247+
// read(view) then immediate cancel() (WPT 'getReader(), read(view),
248+
// then cancel()'): DIVERGENCE — C++ pulls proactively on the read, so
249+
// pull runs BEFORE the cancel hook; TypeScript never pulls (spec: the
250+
// cancel wins). The read resolves done on both.
251+
export const readViewThenCancelOrdering = {
252+
async test() {
253+
const events = [];
254+
const rs = new ReadableStream({
255+
type: 'bytes',
256+
pull() {
257+
events.push('pull');
258+
},
259+
cancel(reason) {
260+
events.push(`cancel:${reason}`);
261+
},
262+
});
263+
const reader = rs.getReader({ mode: 'byob' });
264+
const readP = reader.read(new Uint8Array(4));
265+
const cancelP = reader.cancel('stop');
266+
await Promise.all([
267+
readP.then((r) => events.push(`read:done=${r.done}`)),
268+
cancelP,
269+
]);
270+
strictEqual(
271+
events.join(','),
272+
usingTsImpl
273+
? 'cancel:stop,read:done=true'
274+
: 'pull,cancel:stop,read:done=true'
275+
);
276+
},
277+
};

src/tests/streams/readable-byte/main.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ export {
5252
readDetachesCallerBuffer,
5353
closeWithPendingUnfilledByobRead,
5454
controllerType,
55+
cancelWithPartiallyFilledPull,
56+
readViewThenCancelOrdering,
5557
} from 'controller';
5658

5759
export {
@@ -69,6 +71,7 @@ export {
6971
readableStreamBytesEnqueueSubarray,
7072
readableStreamMultiplePendingReads,
7173
byobreaderRegression,
74+
partialViewThenDefaultRead,
7275
} from 'byob-reader';
7376

7477
export {

0 commit comments

Comments
 (0)