1// META: global=window,worker
2// META: script=../resources/rs-utils.js
3// META: script=../resources/test-utils.js
4'use strict';
5
6const error1 = new Error('error1');
7error1.name = 'error1';
8
9test(() => {
10  assert_throws_js(TypeError, () => new ReadableStream().getReader({ mode: 'byob' }));
11}, 'getReader({mode: "byob"}) throws on non-bytes streams');
12
13
14test(() => {
15  // Constructing ReadableStream with an empty underlying byte source object as parameter shouldn't throw.
16  new ReadableStream({ type: 'bytes' }).getReader({ mode: 'byob' });
17  // Constructor must perform ToString(type).
18  new ReadableStream({ type: { toString() {return 'bytes';} } })
19    .getReader({ mode: 'byob' });
20  new ReadableStream({ type: { toString: null, valueOf() {return 'bytes';} } })
21    .getReader({ mode: 'byob' });
22}, 'ReadableStream with byte source can be constructed with no errors');
23
24test(() => {
25  const ReadableStreamBYOBReader = new ReadableStream({ type: 'bytes' }).getReader({ mode: 'byob' }).constructor;
26  const rs = new ReadableStream({ type: 'bytes' });
27
28  let reader = rs.getReader({ mode: { toString() { return 'byob'; } } });
29  assert_true(reader instanceof ReadableStreamBYOBReader, 'must give a BYOB reader');
30  reader.releaseLock();
31
32  reader = rs.getReader({ mode: { toString: null, valueOf() {return 'byob';} } });
33  assert_true(reader instanceof ReadableStreamBYOBReader, 'must give a BYOB reader');
34  reader.releaseLock();
35
36  reader = rs.getReader({ mode: 'byob', notmode: 'ignored' });
37  assert_true(reader instanceof ReadableStreamBYOBReader, 'must give a BYOB reader');
38}, 'getReader({mode}) must perform ToString()');
39
40promise_test(() => {
41  let startCalled = false;
42  let startCalledBeforePull = false;
43  let desiredSize;
44  let controller;
45
46  let resolveTestPromise;
47  const testPromise = new Promise(resolve => {
48    resolveTestPromise = resolve;
49  });
50
51  new ReadableStream({
52    start(c) {
53      controller = c;
54      startCalled = true;
55    },
56    pull() {
57      startCalledBeforePull = startCalled;
58      desiredSize = controller.desiredSize;
59      resolveTestPromise();
60    },
61    type: 'bytes'
62  }, {
63    highWaterMark: 256
64  });
65
66  return testPromise.then(() => {
67    assert_true(startCalledBeforePull, 'start should be called before pull');
68    assert_equals(desiredSize, 256, 'desiredSize should equal highWaterMark');
69  });
70
71}, 'ReadableStream with byte source: Construct and expect start and pull being called');
72
73promise_test(() => {
74  let pullCount = 0;
75  let checkedNoPull = false;
76
77  let resolveTestPromise;
78  const testPromise = new Promise(resolve => {
79    resolveTestPromise = resolve;
80  });
81  let resolveStartPromise;
82
83  new ReadableStream({
84    start() {
85      return new Promise(resolve => {
86        resolveStartPromise = resolve;
87      });
88    },
89    pull() {
90      if (checkedNoPull) {
91        resolveTestPromise();
92      }
93
94      ++pullCount;
95    },
96    type: 'bytes'
97  }, {
98    highWaterMark: 256
99  });
100
101  Promise.resolve().then(() => {
102    assert_equals(pullCount, 0);
103    checkedNoPull = true;
104    resolveStartPromise();
105  });
106
107  return testPromise;
108
109}, 'ReadableStream with byte source: No automatic pull call if start doesn\'t finish');
110
111test(() => {
112  assert_throws_js(Error, () => new ReadableStream({ start() { throw new Error(); }, type:'bytes' }),
113      'start() can throw an exception with type: bytes');
114}, 'ReadableStream with byte source: start() throws an exception');
115
116promise_test(t => {
117  new ReadableStream({
118    pull: t.unreached_func('pull() should not be called'),
119    type: 'bytes'
120  }, {
121    highWaterMark: 0
122  });
123
124  return Promise.resolve();
125}, 'ReadableStream with byte source: Construct with highWaterMark of 0');
126
127test(() => {
128  new ReadableStream({
129    start(c) {
130      assert_equals(c.desiredSize, 10, 'desiredSize must start at the highWaterMark');
131      c.close();
132      assert_equals(c.desiredSize, 0, 'after closing, desiredSize must be 0');
133    },
134    type: 'bytes'
135  }, {
136    highWaterMark: 10
137  });
138}, 'ReadableStream with byte source: desiredSize when closed');
139
140test(() => {
141  new ReadableStream({
142    start(c) {
143      assert_equals(c.desiredSize, 10, 'desiredSize must start at the highWaterMark');
144      c.error();
145      assert_equals(c.desiredSize, null, 'after erroring, desiredSize must be null');
146    },
147    type: 'bytes'
148  }, {
149    highWaterMark: 10
150  });
151}, 'ReadableStream with byte source: desiredSize when errored');
152
153promise_test(t => {
154  const stream = new ReadableStream({
155    type: 'bytes'
156  });
157
158  const reader = stream.getReader();
159  reader.releaseLock();
160
161  return promise_rejects_js(t, TypeError, reader.closed, 'closed must reject');
162}, 'ReadableStream with byte source: getReader(), then releaseLock()');
163
164promise_test(t => {
165  const stream = new ReadableStream({
166    type: 'bytes'
167  });
168
169  const reader = stream.getReader({ mode: 'byob' });
170  reader.releaseLock();
171
172  return promise_rejects_js(t, TypeError, reader.closed, 'closed must reject');
173}, 'ReadableStream with byte source: getReader() with mode set to byob, then releaseLock()');
174
175promise_test(t => {
176  const stream = new ReadableStream({
177    start(c) {
178      c.close();
179    },
180    pull: t.unreached_func('pull() should not be called'),
181    type: 'bytes'
182  });
183
184  const reader = stream.getReader();
185
186  return reader.closed.then(() => {
187    assert_throws_js(TypeError, () => stream.getReader(), 'getReader() must throw');
188  });
189}, 'ReadableStream with byte source: Test that closing a stream does not release a reader automatically');
190
191promise_test(t => {
192  const stream = new ReadableStream({
193    start(c) {
194      c.close();
195    },
196    pull: t.unreached_func('pull() should not be called'),
197    type: 'bytes'
198  });
199
200  const reader = stream.getReader({ mode: 'byob' });
201
202  return reader.closed.then(() => {
203    assert_throws_js(TypeError, () => stream.getReader({ mode: 'byob' }), 'getReader() must throw');
204  });
205}, 'ReadableStream with byte source: Test that closing a stream does not release a BYOB reader automatically');
206
207promise_test(t => {
208  const stream = new ReadableStream({
209    start(c) {
210      c.error(error1);
211    },
212    pull: t.unreached_func('pull() should not be called'),
213    type: 'bytes'
214  });
215
216  const reader = stream.getReader();
217
218  return promise_rejects_exactly(t, error1, reader.closed, 'closed must reject').then(() => {
219    assert_throws_js(TypeError, () => stream.getReader(), 'getReader() must throw');
220  });
221}, 'ReadableStream with byte source: Test that erroring a stream does not release a reader automatically');
222
223promise_test(t => {
224  const stream = new ReadableStream({
225    start(c) {
226      c.error(error1);
227    },
228    pull: t.unreached_func('pull() should not be called'),
229    type: 'bytes'
230  });
231
232  const reader = stream.getReader({ mode: 'byob' });
233
234  return promise_rejects_exactly(t, error1, reader.closed, 'closed must reject').then(() => {
235    assert_throws_js(TypeError, () => stream.getReader({ mode: 'byob' }), 'getReader() must throw');
236  });
237}, 'ReadableStream with byte source: Test that erroring a stream does not release a BYOB reader automatically');
238
239promise_test(async t => {
240  const stream = new ReadableStream({
241    type: 'bytes'
242  });
243
244  const reader = stream.getReader();
245  const read = reader.read();
246  reader.releaseLock();
247  await promise_rejects_js(t, TypeError, read, 'pending read must reject');
248}, 'ReadableStream with byte source: releaseLock() on ReadableStreamDefaultReader must reject pending read()');
249
250promise_test(async t => {
251  const stream = new ReadableStream({
252    type: 'bytes'
253  });
254
255  const reader = stream.getReader({ mode: 'byob' });
256  const read = reader.read(new Uint8Array(1));
257  reader.releaseLock();
258  await promise_rejects_js(t, TypeError, read, 'pending read must reject');
259}, 'ReadableStream with byte source: releaseLock() on ReadableStreamBYOBReader must reject pending read()');
260
261promise_test(() => {
262  let pullCount = 0;
263
264  const stream = new ReadableStream({
265    pull() {
266      ++pullCount;
267    },
268    type: 'bytes'
269  }, {
270    highWaterMark: 8
271  });
272
273  stream.getReader();
274
275  assert_equals(pullCount, 0, 'No pull as start() just finished and is not yet reflected to the state of the stream');
276
277  return Promise.resolve().then(() => {
278    assert_equals(pullCount, 1, 'pull must be invoked');
279  });
280}, 'ReadableStream with byte source: Automatic pull() after start()');
281
282promise_test(() => {
283  let pullCount = 0;
284
285  const stream = new ReadableStream({
286    pull() {
287      ++pullCount;
288    },
289    type: 'bytes'
290  }, {
291    highWaterMark: 0
292  });
293
294  const reader = stream.getReader();
295  reader.read();
296
297  assert_equals(pullCount, 0, 'No pull as start() just finished and is not yet reflected to the state of the stream');
298
299  return Promise.resolve().then(() => {
300    assert_equals(pullCount, 1, 'pull must be invoked');
301  });
302}, 'ReadableStream with byte source: Automatic pull() after start() and read()');
303
304// View buffers are detached after pull() returns, so record the information at the time that pull() was called.
305function extractViewInfo(view) {
306  return {
307    constructor: view.constructor,
308    bufferByteLength: view.buffer.byteLength,
309    byteOffset: view.byteOffset,
310    byteLength: view.byteLength
311  };
312}
313
314promise_test(() => {
315  let pullCount = 0;
316  let controller;
317  const byobRequests = [];
318
319  const stream = new ReadableStream({
320    start(c) {
321      controller = c;
322    },
323    pull() {
324      const byobRequest = controller.byobRequest;
325      const view = byobRequest.view;
326      byobRequests[pullCount] = {
327        nonNull: byobRequest !== null,
328        viewNonNull: view !== null,
329        viewInfo: extractViewInfo(view)
330      };
331      if (pullCount === 0) {
332        view[0] = 0x01;
333        byobRequest.respond(1);
334      } else if (pullCount === 1) {
335        view[0] = 0x02;
336        view[1] = 0x03;
337        byobRequest.respond(2);
338      }
339
340      ++pullCount;
341    },
342    type: 'bytes',
343    autoAllocateChunkSize: 16
344  }, {
345    highWaterMark: 0
346  });
347
348  const reader = stream.getReader();
349  const p0 = reader.read();
350  const p1 = reader.read();
351
352  assert_equals(pullCount, 0, 'No pull() as start() just finished and is not yet reflected to the state of the stream');
353
354  return Promise.resolve().then(() => {
355    assert_equals(pullCount, 1, 'pull() must have been invoked once');
356    const byobRequest = byobRequests[0];
357    assert_true(byobRequest.nonNull, 'first byobRequest must not be null');
358    assert_true(byobRequest.viewNonNull, 'first byobRequest.view must not be null');
359    const viewInfo = byobRequest.viewInfo;
360    assert_equals(viewInfo.constructor, Uint8Array, 'first view.constructor should be Uint8Array');
361    assert_equals(viewInfo.bufferByteLength, 16, 'first view.buffer.byteLength should be 16');
362    assert_equals(viewInfo.byteOffset, 0, 'first view.byteOffset should be 0');
363    assert_equals(viewInfo.byteLength, 16, 'first view.byteLength should be 16');
364
365    return p0;
366  }).then(result => {
367    assert_equals(pullCount, 2, 'pull() must have been invoked twice');
368    const value = result.value;
369    assert_not_equals(value, undefined, 'first read should have a value');
370    assert_equals(value.constructor, Uint8Array, 'first value should be a Uint8Array');
371    assert_equals(value.buffer.byteLength, 16, 'first value.buffer.byteLength should be 16');
372    assert_equals(value.byteOffset, 0, 'first value.byteOffset should be 0');
373    assert_equals(value.byteLength, 1, 'first value.byteLength should be 1');
374    assert_equals(value[0], 0x01, 'first value[0] should be 0x01');
375    const byobRequest = byobRequests[1];
376    assert_true(byobRequest.nonNull, 'second byobRequest must not be null');
377    assert_true(byobRequest.viewNonNull, 'second byobRequest.view must not be null');
378    const viewInfo = byobRequest.viewInfo;
379    assert_equals(viewInfo.constructor, Uint8Array, 'second view.constructor should be Uint8Array');
380    assert_equals(viewInfo.bufferByteLength, 16, 'second view.buffer.byteLength should be 16');
381    assert_equals(viewInfo.byteOffset, 0, 'second view.byteOffset should be 0');
382    assert_equals(viewInfo.byteLength, 16, 'second view.byteLength should be 16');
383
384    return p1;
385  }).then(result => {
386    assert_equals(pullCount, 2, 'pull() should only be invoked twice');
387    const value = result.value;
388    assert_not_equals(value, undefined, 'second read should have a value');
389    assert_equals(value.constructor, Uint8Array, 'second value should be a Uint8Array');
390    assert_equals(value.buffer.byteLength, 16, 'second value.buffer.byteLength should be 16');
391    assert_equals(value.byteOffset, 0, 'second value.byteOffset should be 0');
392    assert_equals(value.byteLength, 2, 'second value.byteLength should be 2');
393    assert_equals(value[0], 0x02, 'second value[0] should be 0x02');
394    assert_equals(value[1], 0x03, 'second value[1] should be 0x03');
395  });
396}, 'ReadableStream with byte source: autoAllocateChunkSize');
397
398promise_test(() => {
399  let pullCount = 0;
400  let controller;
401  const byobRequests = [];
402
403  const stream = new ReadableStream({
404    start(c) {
405      controller = c;
406    },
407    pull() {
408      const byobRequest = controller.byobRequest;
409      const view = byobRequest.view;
410      byobRequests[pullCount] = {
411        nonNull: byobRequest !== null,
412        viewNonNull: view !== null,
413        viewInfo: extractViewInfo(view)
414      };
415      if (pullCount === 0) {
416        view[0] = 0x01;
417        byobRequest.respond(1);
418      } else if (pullCount === 1) {
419        view[0] = 0x02;
420        view[1] = 0x03;
421        byobRequest.respond(2);
422      }
423
424      ++pullCount;
425    },
426    type: 'bytes',
427    autoAllocateChunkSize: 16
428  }, {
429    highWaterMark: 0
430  });
431
432  const reader = stream.getReader();
433  return reader.read().then(result => {
434    const value = result.value;
435    assert_not_equals(value, undefined, 'first read should have a value');
436    assert_equals(value.constructor, Uint8Array, 'first value should be a Uint8Array');
437    assert_equals(value.buffer.byteLength, 16, 'first value.buffer.byteLength should be 16');
438    assert_equals(value.byteOffset, 0, 'first value.byteOffset should be 0');
439    assert_equals(value.byteLength, 1, 'first value.byteLength should be 1');
440    assert_equals(value[0], 0x01, 'first value[0] should be 0x01');
441    const byobRequest = byobRequests[0];
442    assert_true(byobRequest.nonNull, 'first byobRequest must not be null');
443    assert_true(byobRequest.viewNonNull, 'first byobRequest.view must not be null');
444    const viewInfo = byobRequest.viewInfo;
445    assert_equals(viewInfo.constructor, Uint8Array, 'first view.constructor should be Uint8Array');
446    assert_equals(viewInfo.bufferByteLength, 16, 'first view.buffer.byteLength should be 16');
447    assert_equals(viewInfo.byteOffset, 0, 'first view.byteOffset should be 0');
448    assert_equals(viewInfo.byteLength, 16, 'first view.byteLength should be 16');
449
450    reader.releaseLock();
451    const byobReader = stream.getReader({ mode: 'byob' });
452    return byobReader.read(new Uint8Array(32));
453  }).then(result => {
454    const value = result.value;
455    assert_not_equals(value, undefined, 'second read should have a value');
456    assert_equals(value.constructor, Uint8Array, 'second value should be a Uint8Array');
457    assert_equals(value.buffer.byteLength, 32, 'second value.buffer.byteLength should be 32');
458    assert_equals(value.byteOffset, 0, 'second value.byteOffset should be 0');
459    assert_equals(value.byteLength, 2, 'second value.byteLength should be 2');
460    assert_equals(value[0], 0x02, 'second value[0] should be 0x02');
461    assert_equals(value[1], 0x03, 'second value[1] should be 0x03');
462    const byobRequest = byobRequests[1];
463    assert_true(byobRequest.nonNull, 'second byobRequest must not be null');
464    assert_true(byobRequest.viewNonNull, 'second byobRequest.view must not be null');
465    const viewInfo = byobRequest.viewInfo;
466    assert_equals(viewInfo.constructor, Uint8Array, 'second view.constructor should be Uint8Array');
467    assert_equals(viewInfo.bufferByteLength, 32, 'second view.buffer.byteLength should be 32');
468    assert_equals(viewInfo.byteOffset, 0, 'second view.byteOffset should be 0');
469    assert_equals(viewInfo.byteLength, 32, 'second view.byteLength should be 32');
470    assert_equals(pullCount, 2, 'pullCount should be 2');
471  });
472}, 'ReadableStream with byte source: Mix of auto allocate and BYOB');
473
474promise_test(() => {
475  let pullCount = 0;
476
477  const stream = new ReadableStream({
478    pull() {
479      ++pullCount;
480    },
481    type: 'bytes'
482  }, {
483    highWaterMark: 0
484  });
485
486  const reader = stream.getReader();
487  reader.read(new Uint8Array(8));
488
489  assert_equals(pullCount, 0, 'No pull as start() just finished and is not yet reflected to the state of the stream');
490
491  return Promise.resolve().then(() => {
492    assert_equals(pullCount, 1, 'pull must be invoked');
493  });
494}, 'ReadableStream with byte source: Automatic pull() after start() and read(view)');
495
496promise_test(() => {
497  let pullCount = 0;
498
499  let controller;
500  let desiredSizeInStart;
501  let desiredSizeInPull;
502
503  const stream = new ReadableStream({
504    start(c) {
505      c.enqueue(new Uint8Array(16));
506      desiredSizeInStart = c.desiredSize;
507      controller = c;
508    },
509    pull() {
510      ++pullCount;
511
512      if (pullCount === 1) {
513        desiredSizeInPull = controller.desiredSize;
514      }
515    },
516    type: 'bytes'
517  }, {
518    highWaterMark: 8
519  });
520
521  return Promise.resolve().then(() => {
522    assert_equals(pullCount, 0, 'No pull as the queue was filled by start()');
523    assert_equals(desiredSizeInStart, -8, 'desiredSize after enqueue() in start()');
524
525    const reader = stream.getReader();
526
527    const promise = reader.read();
528    assert_equals(pullCount, 1, 'The first pull() should be made on read()');
529    assert_equals(desiredSizeInPull, 8, 'desiredSize in pull()');
530
531    return promise.then(result => {
532      assert_false(result.done, 'result.done');
533
534      const view = result.value;
535      assert_equals(view.constructor, Uint8Array, 'view.constructor');
536      assert_equals(view.buffer.byteLength, 16, 'view.buffer');
537      assert_equals(view.byteOffset, 0, 'view.byteOffset');
538      assert_equals(view.byteLength, 16, 'view.byteLength');
539    });
540  });
541}, 'ReadableStream with byte source: enqueue(), getReader(), then read()');
542
543promise_test(() => {
544  let controller;
545
546  const stream = new ReadableStream({
547    start(c) {
548      controller = c;
549    },
550    type: 'bytes'
551  });
552
553  const reader = stream.getReader();
554
555  const promise = reader.read().then(result => {
556    assert_false(result.done);
557
558    const view = result.value;
559    assert_equals(view.constructor, Uint8Array);
560    assert_equals(view.buffer.byteLength, 1);
561    assert_equals(view.byteOffset, 0);
562    assert_equals(view.byteLength, 1);
563  });
564
565  controller.enqueue(new Uint8Array(1));
566
567  return promise;
568}, 'ReadableStream with byte source: Push source that doesn\'t understand pull signal');
569
570test(() => {
571  assert_throws_js(TypeError, () => new ReadableStream({
572    pull: 'foo',
573    type: 'bytes'
574  }), 'constructor should throw');
575}, 'ReadableStream with byte source: pull() function is not callable');
576
577promise_test(() => {
578  const stream = new ReadableStream({
579    start(c) {
580      c.enqueue(new Uint16Array(16));
581    },
582    type: 'bytes'
583  });
584
585  const reader = stream.getReader();
586
587  return reader.read().then(result => {
588    assert_false(result.done);
589
590    const view = result.value;
591    assert_equals(view.constructor, Uint8Array);
592    assert_equals(view.buffer.byteLength, 32);
593    assert_equals(view.byteOffset, 0);
594    assert_equals(view.byteLength, 32);
595  });
596}, 'ReadableStream with byte source: enqueue() with Uint16Array, getReader(), then read()');
597
598promise_test(t => {
599  const stream = new ReadableStream({
600    start(c) {
601      const view = new Uint8Array(16);
602      view[0] = 0x01;
603      view[8] = 0x02;
604      c.enqueue(view);
605    },
606    pull: t.unreached_func('pull() should not be called'),
607    type: 'bytes'
608  });
609
610  const byobReader = stream.getReader({ mode: 'byob' });
611
612  return byobReader.read(new Uint8Array(8)).then(result => {
613    assert_false(result.done, 'done');
614
615    const view = result.value;
616    assert_equals(view.constructor, Uint8Array, 'value.constructor');
617    assert_equals(view.buffer.byteLength, 8, 'value.buffer.byteLength');
618    assert_equals(view.byteOffset, 0, 'value.byteOffset');
619    assert_equals(view.byteLength, 8, 'value.byteLength');
620    assert_equals(view[0], 0x01);
621
622    byobReader.releaseLock();
623
624    const reader = stream.getReader();
625
626    return reader.read();
627  }).then(result => {
628    assert_false(result.done, 'done');
629
630    const view = result.value;
631    assert_equals(view.constructor, Uint8Array, 'value.constructor');
632    assert_equals(view.buffer.byteLength, 16, 'value.buffer.byteLength');
633    assert_equals(view.byteOffset, 8, 'value.byteOffset');
634    assert_equals(view.byteLength, 8, 'value.byteLength');
635    assert_equals(view[0], 0x02);
636  });
637}, 'ReadableStream with byte source: enqueue(), read(view) partially, then read()');
638
639promise_test(t => {
640  let controller;
641
642  const stream = new ReadableStream({
643    start(c) {
644      controller = c;
645    },
646    pull: t.unreached_func('pull() should not be called'),
647    type: 'bytes'
648  });
649
650  const reader = stream.getReader();
651
652  controller.enqueue(new Uint8Array(16));
653  controller.close();
654
655  return reader.read().then(result => {
656    assert_false(result.done, 'done');
657
658    const view = result.value;
659    assert_equals(view.byteOffset, 0, 'byteOffset');
660    assert_equals(view.byteLength, 16, 'byteLength');
661
662    return reader.read();
663  }).then(result => {
664    assert_true(result.done, 'done');
665    assert_equals(result.value, undefined, 'value');
666  });
667}, 'ReadableStream with byte source: getReader(), enqueue(), close(), then read()');
668
669promise_test(t => {
670  const stream = new ReadableStream({
671    start(c) {
672      c.enqueue(new Uint8Array(16));
673      c.close();
674    },
675    pull: t.unreached_func('pull() should not be called'),
676    type: 'bytes'
677  });
678
679  const reader = stream.getReader();
680
681  return reader.read().then(result => {
682    assert_false(result.done, 'done');
683
684    const view = result.value;
685    assert_equals(view.byteOffset, 0, 'byteOffset');
686    assert_equals(view.byteLength, 16, 'byteLength');
687
688    return reader.read();
689  }).then(result => {
690    assert_true(result.done, 'done');
691    assert_equals(result.value, undefined, 'value');
692  });
693}, 'ReadableStream with byte source: enqueue(), close(), getReader(), then read()');
694
695promise_test(() => {
696  let controller;
697  let byobRequest;
698
699  const stream = new ReadableStream({
700    start(c) {
701      controller = c;
702    },
703    pull() {
704      controller.enqueue(new Uint8Array(16));
705      byobRequest = controller.byobRequest;
706    },
707    type: 'bytes'
708  });
709
710  const reader = stream.getReader();
711
712  return reader.read().then(result => {
713    assert_false(result.done, 'done');
714    assert_equals(result.value.byteLength, 16, 'byteLength');
715    assert_equals(byobRequest, null, 'byobRequest must be null');
716  });
717}, 'ReadableStream with byte source: Respond to pull() by enqueue()');
718
719promise_test(() => {
720  let pullCount = 0;
721
722  let controller;
723  let byobRequest;
724  const desiredSizes = [];
725
726  const stream = new ReadableStream({
727    start(c) {
728      controller = c;
729    },
730    pull() {
731      byobRequest = controller.byobRequest;
732      desiredSizes.push(controller.desiredSize);
733      controller.enqueue(new Uint8Array(1));
734      desiredSizes.push(controller.desiredSize);
735      controller.enqueue(new Uint8Array(1));
736      desiredSizes.push(controller.desiredSize);
737
738      ++pullCount;
739    },
740    type: 'bytes'
741  }, {
742    highWaterMark: 0
743  });
744
745  const reader = stream.getReader();
746
747  const p0 = reader.read();
748  const p1 = reader.read();
749  const p2 = reader.read();
750
751  // Respond to the first pull call.
752  controller.enqueue(new Uint8Array(1));
753
754  assert_equals(pullCount, 0, 'pullCount after the enqueue() outside pull');
755
756  return Promise.all([p0, p1, p2]).then(result => {
757    assert_equals(pullCount, 1, 'pullCount after completion of all read()s');
758
759    assert_equals(result[0].done, false, 'result[0].done');
760    assert_equals(result[0].value.byteLength, 1, 'result[0].value.byteLength');
761    assert_equals(result[1].done, false, 'result[1].done');
762    assert_equals(result[1].value.byteLength, 1, 'result[1].value.byteLength');
763    assert_equals(result[2].done, false, 'result[2].done');
764    assert_equals(result[2].value.byteLength, 1, 'result[2].value.byteLength');
765    assert_equals(byobRequest, null, 'byobRequest should be null');
766    assert_equals(desiredSizes[0], 0, 'desiredSize on pull should be 0');
767    assert_equals(desiredSizes[1], 0, 'desiredSize after 1st enqueue() should be 0');
768    assert_equals(desiredSizes[2], 0, 'desiredSize after 2nd enqueue() should be 0');
769    assert_equals(pullCount, 1, 'pull() should only be called once');
770  });
771}, 'ReadableStream with byte source: Respond to pull() by enqueue() asynchronously');
772
773promise_test(() => {
774  let pullCount = 0;
775
776  let byobRequest;
777  const desiredSizes = [];
778
779  const stream = new ReadableStream({
780    pull(c) {
781      byobRequest = c.byobRequest;
782      desiredSizes.push(c.desiredSize);
783
784      if (pullCount < 3) {
785        c.enqueue(new Uint8Array(1));
786      } else {
787        c.close();
788      }
789
790      ++pullCount;
791    },
792    type: 'bytes'
793  }, {
794    highWaterMark: 256
795  });
796
797  const reader = stream.getReader();
798
799  const p0 = reader.read();
800  const p1 = reader.read();
801  const p2 = reader.read();
802
803  assert_equals(pullCount, 0, 'No pull as start() just finished and is not yet reflected to the state of the stream');
804
805  return Promise.all([p0, p1, p2]).then(result => {
806    assert_equals(pullCount, 4, 'pullCount after completion of all read()s');
807
808    assert_equals(result[0].done, false, 'result[0].done');
809    assert_equals(result[0].value.byteLength, 1, 'result[0].value.byteLength');
810    assert_equals(result[1].done, false, 'result[1].done');
811    assert_equals(result[1].value.byteLength, 1, 'result[1].value.byteLength');
812    assert_equals(result[2].done, false, 'result[2].done');
813    assert_equals(result[2].value.byteLength, 1, 'result[2].value.byteLength');
814    assert_equals(byobRequest, null, 'byobRequest should be null');
815    assert_equals(desiredSizes[0], 256, 'desiredSize on pull should be 256');
816    assert_equals(desiredSizes[1], 256, 'desiredSize after 1st enqueue() should be 256');
817    assert_equals(desiredSizes[2], 256, 'desiredSize after 2nd enqueue() should be 256');
818    assert_equals(desiredSizes[3], 256, 'desiredSize after 3rd enqueue() should be 256');
819  });
820}, 'ReadableStream with byte source: Respond to multiple pull() by separate enqueue()');
821
822promise_test(() => {
823  let controller;
824
825  let pullCount = 0;
826  const byobRequestDefined = [];
827  let byobRequestViewDefined;
828
829  const stream = new ReadableStream({
830    start(c) {
831      controller = c;
832    },
833    pull() {
834      byobRequestDefined.push(controller.byobRequest !== null);
835      const initialByobRequest = controller.byobRequest;
836
837      const view = controller.byobRequest.view;
838      view[0] = 0x01;
839      controller.byobRequest.respond(1);
840
841      byobRequestDefined.push(controller.byobRequest !== null);
842      byobRequestViewDefined = initialByobRequest.view !== null;
843
844      ++pullCount;
845    },
846    type: 'bytes'
847  });
848
849  const reader = stream.getReader({ mode: 'byob' });
850
851  return reader.read(new Uint8Array(1)).then(result => {
852    assert_false(result.done, 'result.done');
853    assert_equals(result.value.byteLength, 1, 'result.value.byteLength');
854    assert_equals(result.value[0], 0x01, 'result.value[0]');
855    assert_equals(pullCount, 1, 'pull() should be called only once');
856    assert_true(byobRequestDefined[0], 'byobRequest must not be null before respond()');
857    assert_false(byobRequestDefined[1], 'byobRequest must be null after respond()');
858    assert_false(byobRequestViewDefined, 'view of initial byobRequest must be null after respond()');
859  });
860}, 'ReadableStream with byte source: read(view), then respond()');
861
862promise_test(() => {
863  let controller;
864
865  let pullCount = 0;
866  const byobRequestDefined = [];
867  let byobRequestViewDefined;
868
869  const stream = new ReadableStream({
870    start(c) {
871      controller = c;
872    },
873    async pull() {
874      byobRequestDefined.push(controller.byobRequest !== null);
875      const initialByobRequest = controller.byobRequest;
876
877      const transferredView = await transferArrayBufferView(controller.byobRequest.view);
878      transferredView[0] = 0x01;
879      controller.byobRequest.respondWithNewView(transferredView);
880
881      byobRequestDefined.push(controller.byobRequest !== null);
882      byobRequestViewDefined = initialByobRequest.view !== null;
883
884      ++pullCount;
885    },
886    type: 'bytes'
887  });
888
889  const reader = stream.getReader({ mode: 'byob' });
890
891  return reader.read(new Uint8Array(1)).then(result => {
892    assert_false(result.done, 'result.done');
893    assert_equals(result.value.byteLength, 1, 'result.value.byteLength');
894    assert_equals(result.value[0], 0x01, 'result.value[0]');
895    assert_equals(pullCount, 1, 'pull() should be called only once');
896    assert_true(byobRequestDefined[0], 'byobRequest must not be null before respondWithNewView()');
897    assert_false(byobRequestDefined[1], 'byobRequest must be null after respondWithNewView()');
898    assert_false(byobRequestViewDefined, 'view of initial byobRequest must be null after respondWithNewView()');
899  });
900}, 'ReadableStream with byte source: read(view), then respondWithNewView() with a transferred ArrayBuffer');
901
902promise_test(() => {
903  let controller;
904  let byobRequestWasDefined;
905  let incorrectRespondException;
906
907  const stream = new ReadableStream({
908    start(c) {
909      controller = c;
910    },
911    pull() {
912      byobRequestWasDefined = controller.byobRequest !== null;
913
914      try {
915        controller.byobRequest.respond(2);
916      } catch (e) {
917        incorrectRespondException = e;
918      }
919
920      controller.byobRequest.respond(1);
921    },
922    type: 'bytes'
923  });
924
925  const reader = stream.getReader({ mode: 'byob' });
926
927  return reader.read(new Uint8Array(1)).then(() => {
928    assert_true(byobRequestWasDefined, 'byobRequest should be non-null');
929    assert_not_equals(incorrectRespondException, undefined, 'respond() must throw');
930    assert_equals(incorrectRespondException.name, 'RangeError', 'respond() must throw a RangeError');
931  });
932}, 'ReadableStream with byte source: read(view), then respond() with too big value');
933
934promise_test(() => {
935  let pullCount = 0;
936
937  let controller;
938  let byobRequest;
939  let viewInfo;
940
941  const stream = new ReadableStream({
942    start(c) {
943      controller = c;
944    },
945    pull() {
946      ++pullCount;
947
948      byobRequest = controller.byobRequest;
949      const view = byobRequest.view;
950      viewInfo = extractViewInfo(view);
951
952      view[0] = 0x01;
953      view[1] = 0x02;
954      view[2] = 0x03;
955
956      controller.byobRequest.respond(3);
957    },
958    type: 'bytes'
959  });
960
961  const reader = stream.getReader({ mode: 'byob' });
962
963  return reader.read(new Uint16Array(2)).then(result => {
964    assert_equals(pullCount, 1);
965
966    assert_false(result.done, 'done');
967
968    const view = result.value;
969    assert_equals(view.byteOffset, 0, 'byteOffset');
970    assert_equals(view.byteLength, 2, 'byteLength');
971
972    const dataView = new DataView(view.buffer, view.byteOffset, view.byteLength);
973    assert_equals(dataView.getUint16(0), 0x0102);
974
975    return reader.read(new Uint8Array(1));
976  }).then(result => {
977    assert_equals(pullCount, 1);
978    assert_not_equals(byobRequest, null, 'byobRequest must not be null');
979    assert_equals(viewInfo.constructor, Uint8Array, 'view.constructor should be Uint8Array');
980    assert_equals(viewInfo.bufferByteLength, 4, 'view.buffer.byteLength should be 4');
981    assert_equals(viewInfo.byteOffset, 0, 'view.byteOffset should be 0');
982    assert_equals(viewInfo.byteLength, 4, 'view.byteLength should be 4');
983
984    assert_false(result.done, 'done');
985
986    const view = result.value;
987    assert_equals(view.byteOffset, 0, 'byteOffset');
988    assert_equals(view.byteLength, 1, 'byteLength');
989
990    assert_equals(view[0], 0x03);
991  });
992}, 'ReadableStream with byte source: respond(3) to read(view) with 2 element Uint16Array enqueues the 1 byte ' +
993   'remainder');
994
995promise_test(t => {
996  const stream = new ReadableStream({
997    start(controller) {
998      const view = new Uint8Array(16);
999      view[15] = 0x01;
1000      controller.enqueue(view);
1001    },
1002    pull: t.unreached_func('pull() should not be called'),
1003    type: 'bytes'
1004  });
1005
1006  const reader = stream.getReader({ mode: 'byob' });
1007
1008  return reader.read(new Uint8Array(16)).then(result => {
1009    assert_false(result.done);
1010
1011    const view = result.value;
1012    assert_equals(view.byteOffset, 0);
1013    assert_equals(view.byteLength, 16);
1014    assert_equals(view[15], 0x01);
1015  });
1016}, 'ReadableStream with byte source: enqueue(), getReader(), then read(view)');
1017
1018promise_test(t => {
1019  let cancelCount = 0;
1020  let reason;
1021
1022  const passedReason = new TypeError('foo');
1023
1024  const stream = new ReadableStream({
1025    start(c) {
1026      c.enqueue(new Uint8Array(16));
1027    },
1028    pull: t.unreached_func('pull() should not be called'),
1029    cancel(r) {
1030      if (cancelCount === 0) {
1031        reason = r;
1032      }
1033
1034      ++cancelCount;
1035    },
1036    type: 'bytes'
1037  });
1038
1039  const reader = stream.getReader();
1040
1041  return reader.cancel(passedReason).then(result => {
1042    assert_equals(result, undefined);
1043    assert_equals(cancelCount, 1);
1044    assert_equals(reason, passedReason, 'reason should equal the passed reason');
1045  });
1046}, 'ReadableStream with byte source: enqueue(), getReader(), then cancel() (mode = not BYOB)');
1047
1048promise_test(t => {
1049  let cancelCount = 0;
1050  let reason;
1051
1052  const passedReason = new TypeError('foo');
1053
1054  const stream = new ReadableStream({
1055    start(c) {
1056      c.enqueue(new Uint8Array(16));
1057    },
1058    pull: t.unreached_func('pull() should not be called'),
1059    cancel(r) {
1060      if (cancelCount === 0) {
1061        reason = r;
1062      }
1063
1064      ++cancelCount;
1065    },
1066    type: 'bytes'
1067  });
1068
1069  const reader = stream.getReader({ mode: 'byob' });
1070
1071  return reader.cancel(passedReason).then(result => {
1072    assert_equals(result, undefined);
1073    assert_equals(cancelCount, 1);
1074    assert_equals(reason, passedReason, 'reason should equal the passed reason');
1075  });
1076}, 'ReadableStream with byte source: enqueue(), getReader(), then cancel() (mode = BYOB)');
1077
1078promise_test(t => {
1079  let cancelCount = 0;
1080  let reason;
1081
1082  const passedReason = new TypeError('foo');
1083
1084  let controller;
1085
1086  const stream = new ReadableStream({
1087    start(c) {
1088      controller = c;
1089    },
1090    pull: t.unreached_func('pull() should not be called'),
1091    cancel(r) {
1092      if (cancelCount === 0) {
1093        reason = r;
1094      }
1095
1096      ++cancelCount;
1097
1098      return 'bar';
1099    },
1100    type: 'bytes'
1101  });
1102
1103  const reader = stream.getReader({ mode: 'byob' });
1104
1105  const readPromise = reader.read(new Uint8Array(1)).then(result => {
1106    assert_true(result.done, 'result.done');
1107    assert_equals(result.value, undefined, 'result.value');
1108  });
1109
1110  const cancelPromise = reader.cancel(passedReason).then(result => {
1111    assert_equals(result, undefined, 'cancel() return value should be fulfilled with undefined');
1112    assert_equals(cancelCount, 1, 'cancel() should be called only once');
1113    assert_equals(reason, passedReason, 'reason should equal the passed reason');
1114  });
1115
1116  return Promise.all([readPromise, cancelPromise]);
1117}, 'ReadableStream with byte source: getReader(), read(view), then cancel()');
1118
1119promise_test(() => {
1120  let pullCount = 0;
1121
1122  let controller;
1123  let byobRequest;
1124  const viewInfos = [];
1125
1126  const stream = new ReadableStream({
1127    start(c) {
1128      controller = c;
1129    },
1130    pull() {
1131      byobRequest = controller.byobRequest;
1132
1133      viewInfos.push(extractViewInfo(controller.byobRequest.view));
1134      controller.enqueue(new Uint8Array(1));
1135      viewInfos.push(extractViewInfo(controller.byobRequest.view));
1136
1137      ++pullCount;
1138    },
1139    type: 'bytes'
1140  });
1141
1142  return Promise.resolve().then(() => {
1143    assert_equals(pullCount, 0, 'No pull() as no read(view) yet');
1144
1145    const reader = stream.getReader({ mode: 'byob' });
1146
1147    const promise = reader.read(new Uint16Array(1)).then(result => {
1148      assert_true(result.done, 'result.done');
1149      assert_equals(result.value, undefined, 'result.value');
1150    });
1151
1152    assert_equals(pullCount, 1, '1 pull() should have been made in response to partial fill by enqueue()');
1153    assert_not_equals(byobRequest, null, 'byobRequest should not be null');
1154    assert_equals(viewInfos[0].byteLength, 2, 'byteLength before enqueue() should be 2');
1155    assert_equals(viewInfos[1].byteLength, 1, 'byteLength after enqueue() should be 1');
1156
1157    reader.cancel();
1158
1159    assert_equals(pullCount, 1, 'pull() should only be called once');
1160    return promise;
1161  });
1162}, 'ReadableStream with byte source: cancel() with partially filled pending pull() request');
1163
1164promise_test(() => {
1165  let controller;
1166  let pullCalled = false;
1167
1168  const stream = new ReadableStream({
1169    start(c) {
1170      const view = new Uint8Array(8);
1171      view[7] = 0x01;
1172      c.enqueue(view);
1173
1174      controller = c;
1175    },
1176    pull() {
1177      pullCalled = true;
1178    },
1179    type: 'bytes'
1180  });
1181
1182  const reader = stream.getReader({ mode: 'byob' });
1183
1184  const buffer = new ArrayBuffer(16);
1185
1186  return reader.read(new Uint8Array(buffer, 8, 8)).then(result => {
1187    assert_false(result.done);
1188
1189    assert_false(pullCalled, 'pull() must not have been called');
1190
1191    const view = result.value;
1192    assert_equals(view.constructor, Uint8Array);
1193    assert_equals(view.buffer.byteLength, 16);
1194    assert_equals(view.byteOffset, 8);
1195    assert_equals(view.byteLength, 8);
1196    assert_equals(view[7], 0x01);
1197  });
1198}, 'ReadableStream with byte source: enqueue(), getReader(), then read(view) where view.buffer is not fully ' +
1199   'covered by view');
1200
1201promise_test(() => {
1202  let controller;
1203  let pullCalled = false;
1204
1205  const stream = new ReadableStream({
1206    start(c) {
1207      let view;
1208
1209      view = new Uint8Array(16);
1210      view[15] = 123;
1211      c.enqueue(view);
1212
1213      view = new Uint8Array(8);
1214      view[7] = 111;
1215      c.enqueue(view);
1216
1217      controller = c;
1218    },
1219    pull() {
1220      pullCalled = true;
1221    },
1222    type: 'bytes'
1223  });
1224
1225  const reader = stream.getReader({ mode: 'byob' });
1226
1227  return reader.read(new Uint8Array(24)).then(result => {
1228    assert_false(result.done, 'done');
1229
1230    assert_false(pullCalled, 'pull() must not have been called');
1231
1232    const view = result.value;
1233    assert_equals(view.byteOffset, 0, 'byteOffset');
1234    assert_equals(view.byteLength, 24, 'byteLength');
1235    assert_equals(view[15], 123, 'Contents are set from the first chunk');
1236    assert_equals(view[23], 111, 'Contents are set from the second chunk');
1237  });
1238}, 'ReadableStream with byte source: Multiple enqueue(), getReader(), then read(view)');
1239
1240promise_test(() => {
1241  let pullCalled = false;
1242
1243  const stream = new ReadableStream({
1244    start(c) {
1245      const view = new Uint8Array(16);
1246      view[15] = 0x01;
1247      c.enqueue(view);
1248    },
1249    pull() {
1250      pullCalled = true;
1251    },
1252    type: 'bytes'
1253  });
1254
1255  const reader = stream.getReader({ mode: 'byob' });
1256
1257  return reader.read(new Uint8Array(24)).then(result => {
1258    assert_false(result.done);
1259
1260    assert_false(pullCalled, 'pull() must not have been called');
1261
1262    const view = result.value;
1263    assert_equals(view.byteOffset, 0);
1264    assert_equals(view.byteLength, 16);
1265    assert_equals(view[15], 0x01);
1266  });
1267}, 'ReadableStream with byte source: enqueue(), getReader(), then read(view) with a bigger view');
1268
1269promise_test(() => {
1270  let pullCalled = false;
1271
1272  const stream = new ReadableStream({
1273    start(c) {
1274      const view = new Uint8Array(16);
1275      view[7] = 0x01;
1276      view[15] = 0x02;
1277      c.enqueue(view);
1278    },
1279    pull() {
1280      pullCalled = true;
1281    },
1282    type: 'bytes'
1283  });
1284
1285  const reader = stream.getReader({ mode: 'byob' });
1286
1287  return reader.read(new Uint8Array(8)).then(result => {
1288    assert_false(result.done, 'done');
1289
1290    const view = result.value;
1291    assert_equals(view.byteOffset, 0);
1292    assert_equals(view.byteLength, 8);
1293    assert_equals(view[7], 0x01);
1294
1295    return reader.read(new Uint8Array(8));
1296  }).then(result => {
1297    assert_false(result.done, 'done');
1298
1299    assert_false(pullCalled, 'pull() must not have been called');
1300
1301    const view = result.value;
1302    assert_equals(view.byteOffset, 0);
1303    assert_equals(view.byteLength, 8);
1304    assert_equals(view[7], 0x02);
1305  });
1306}, 'ReadableStream with byte source: enqueue(), getReader(), then read(view) with smaller views');
1307
1308promise_test(() => {
1309  let controller;
1310  let viewInfo;
1311
1312  const stream = new ReadableStream({
1313    start(c) {
1314      const view = new Uint8Array(1);
1315      view[0] = 0xff;
1316      c.enqueue(view);
1317
1318      controller = c;
1319    },
1320    pull() {
1321      if (controller.byobRequest === null) {
1322        return;
1323      }
1324
1325      const view = controller.byobRequest.view;
1326      viewInfo = extractViewInfo(view);
1327
1328      view[0] = 0xaa;
1329      controller.byobRequest.respond(1);
1330    },
1331    type: 'bytes'
1332  });
1333
1334  const reader = stream.getReader({ mode: 'byob' });
1335
1336  return reader.read(new Uint16Array(1)).then(result => {
1337    assert_false(result.done);
1338
1339    const view = result.value;
1340    assert_equals(view.byteOffset, 0);
1341    assert_equals(view.byteLength, 2);
1342
1343    const dataView = new DataView(view.buffer, view.byteOffset, view.byteLength);
1344    assert_equals(dataView.getUint16(0), 0xffaa);
1345
1346    assert_equals(viewInfo.constructor, Uint8Array, 'view.constructor should be Uint8Array');
1347    assert_equals(viewInfo.bufferByteLength, 2, 'view.buffer.byteLength should be 2');
1348    assert_equals(viewInfo.byteOffset, 1, 'view.byteOffset should be 1');
1349    assert_equals(viewInfo.byteLength, 1, 'view.byteLength should be 1');
1350  });
1351}, 'ReadableStream with byte source: enqueue() 1 byte, getReader(), then read(view) with Uint16Array');
1352
1353promise_test(() => {
1354  let pullCount = 0;
1355
1356  let controller;
1357  let byobRequest;
1358  let viewInfo;
1359  let desiredSize;
1360
1361  const stream = new ReadableStream({
1362    start(c) {
1363      const view = new Uint8Array(3);
1364      view[0] = 0x01;
1365      view[2] = 0x02;
1366      c.enqueue(view);
1367
1368      controller = c;
1369    },
1370    pull() {
1371      byobRequest = controller.byobRequest;
1372
1373      const view = controller.byobRequest.view;
1374
1375      viewInfo = extractViewInfo(view);
1376
1377      view[0] = 0x03;
1378      controller.byobRequest.respond(1);
1379
1380      desiredSize = controller.desiredSize;
1381
1382      ++pullCount;
1383    },
1384    type: 'bytes'
1385  });
1386
1387  // Wait for completion of the start method to be reflected.
1388  return Promise.resolve().then(() => {
1389    const reader = stream.getReader({ mode: 'byob' });
1390
1391    const promise = reader.read(new Uint16Array(2)).then(result => {
1392      assert_false(result.done, 'done');
1393
1394      const view = result.value;
1395      assert_equals(view.constructor, Uint16Array, 'constructor');
1396      assert_equals(view.buffer.byteLength, 4, 'buffer.byteLength');
1397      assert_equals(view.byteOffset, 0, 'byteOffset');
1398      assert_equals(view.byteLength, 2, 'byteLength');
1399
1400      const dataView = new DataView(view.buffer, view.byteOffset, view.byteLength);
1401      assert_equals(dataView.getUint16(0), 0x0100, 'contents are set');
1402
1403      const p = reader.read(new Uint16Array(1));
1404
1405      assert_equals(pullCount, 1);
1406
1407      return p;
1408    }).then(result => {
1409      assert_false(result.done, 'done');
1410
1411      const view = result.value;
1412      assert_equals(view.buffer.byteLength, 2, 'buffer.byteLength');
1413      assert_equals(view.byteOffset, 0, 'byteOffset');
1414      assert_equals(view.byteLength, 2, 'byteLength');
1415
1416      const dataView = new DataView(view.buffer, view.byteOffset, view.byteLength);
1417      assert_equals(dataView.getUint16(0), 0x0203, 'contents are set');
1418
1419      assert_not_equals(byobRequest, null, 'byobRequest must not be null');
1420      assert_equals(viewInfo.constructor, Uint8Array, 'view.constructor should be Uint8Array');
1421      assert_equals(viewInfo.bufferByteLength, 2, 'view.buffer.byteLength should be 2');
1422      assert_equals(viewInfo.byteOffset, 1, 'view.byteOffset should be 1');
1423      assert_equals(viewInfo.byteLength, 1, 'view.byteLength should be 1');
1424      assert_equals(desiredSize, 0, 'desiredSize should be zero');
1425    });
1426
1427    assert_equals(pullCount, 0);
1428
1429    return promise;
1430  });
1431}, 'ReadableStream with byte source: enqueue() 3 byte, getReader(), then read(view) with 2-element Uint16Array');
1432
1433promise_test(t => {
1434  const stream = new ReadableStream({
1435    start(c) {
1436      const view = new Uint8Array(1);
1437      view[0] = 0xff;
1438      c.enqueue(view);
1439      c.close();
1440    },
1441    pull: t.unreached_func('pull() should not be called'),
1442    type: 'bytes'
1443  });
1444
1445  const reader = stream.getReader({ mode: 'byob' });
1446
1447
1448  return promise_rejects_js(t, TypeError, reader.read(new Uint16Array(1)), 'read(view) must fail')
1449      .then(() => promise_rejects_js(t, TypeError, reader.closed, 'reader.closed should reject'));
1450}, 'ReadableStream with byte source: read(view) with Uint16Array on close()-d stream with 1 byte enqueue()-d must ' +
1451   'fail');
1452
1453promise_test(t => {
1454  let controller;
1455
1456  const stream = new ReadableStream({
1457    start(c) {
1458      const view = new Uint8Array(1);
1459      view[0] = 0xff;
1460      c.enqueue(view);
1461
1462      controller = c;
1463    },
1464    pull: t.unreached_func('pull() should not be called'),
1465    type: 'bytes'
1466  });
1467
1468  const reader = stream.getReader({ mode: 'byob' });
1469
1470  const readPromise = reader.read(new Uint16Array(1));
1471
1472  assert_throws_js(TypeError, () => controller.close(), 'controller.close() must throw');
1473
1474  return promise_rejects_js(t, TypeError, readPromise, 'read(view) must fail')
1475      .then(() => promise_rejects_js(t, TypeError, reader.closed, 'reader.closed must reject'));
1476}, 'ReadableStream with byte source: A stream must be errored if close()-d before fulfilling read(view) with ' +
1477   'Uint16Array');
1478
1479test(() => {
1480  let controller;
1481
1482  new ReadableStream({
1483    start(c) {
1484      controller = c;
1485    },
1486    type: 'bytes'
1487  });
1488
1489  // Enqueue a chunk so that the stream doesn't get closed. This is to check duplicate close() calls are rejected
1490  // even if the stream has not yet entered the closed state.
1491  const view = new Uint8Array(1);
1492  controller.enqueue(view);
1493  controller.close();
1494
1495  assert_throws_js(TypeError, () => controller.close(), 'controller.close() must throw');
1496}, 'ReadableStream with byte source: Throw if close()-ed more than once');
1497
1498test(() => {
1499  let controller;
1500
1501  new ReadableStream({
1502    start(c) {
1503      controller = c;
1504    },
1505    type: 'bytes'
1506  });
1507
1508  // Enqueue a chunk so that the stream doesn't get closed. This is to check enqueue() after close() is  rejected
1509  // even if the stream has not yet entered the closed state.
1510  const view = new Uint8Array(1);
1511  controller.enqueue(view);
1512  controller.close();
1513
1514  assert_throws_js(TypeError, () => controller.enqueue(view), 'controller.close() must throw');
1515}, 'ReadableStream with byte source: Throw on enqueue() after close()');
1516
1517promise_test(() => {
1518  let controller;
1519  let byobRequest;
1520  let viewInfo;
1521
1522  const stream = new ReadableStream({
1523    start(c) {
1524      controller = c;
1525    },
1526    pull() {
1527      byobRequest = controller.byobRequest;
1528      const view = controller.byobRequest.view;
1529      viewInfo = extractViewInfo(view);
1530
1531      view[15] = 0x01;
1532      controller.byobRequest.respond(16);
1533      controller.close();
1534    },
1535    type: 'bytes'
1536  });
1537
1538  const reader = stream.getReader({ mode: 'byob' });
1539
1540  return reader.read(new Uint8Array(16)).then(result => {
1541    assert_false(result.done);
1542
1543    const view = result.value;
1544    assert_equals(view.byteOffset, 0);
1545    assert_equals(view.byteLength, 16);
1546    assert_equals(view[15], 0x01);
1547
1548    return reader.read(new Uint8Array(16));
1549  }).then(result => {
1550    assert_true(result.done);
1551
1552    const view = result.value;
1553    assert_equals(view.byteOffset, 0);
1554    assert_equals(view.byteLength, 0);
1555
1556    assert_not_equals(byobRequest, null, 'byobRequest must not be null');
1557    assert_equals(viewInfo.constructor, Uint8Array, 'view.constructor should be Uint8Array');
1558    assert_equals(viewInfo.bufferByteLength, 16, 'view.buffer.byteLength should be 16');
1559    assert_equals(viewInfo.byteOffset, 0, 'view.byteOffset should be 0');
1560    assert_equals(viewInfo.byteLength, 16, 'view.byteLength should be 16');
1561  });
1562}, 'ReadableStream with byte source: read(view), then respond() and close() in pull()');
1563
1564promise_test(() => {
1565  let pullCount = 0;
1566
1567  let controller;
1568  const viewInfos = [];
1569  const viewInfosAfterRespond = [];
1570
1571  const stream = new ReadableStream({
1572    start(c) {
1573      controller = c;
1574    },
1575    pull() {
1576      if (controller.byobRequest === null) {
1577        return;
1578      }
1579
1580      for (let i = 0; i < 4; ++i) {
1581        const view = controller.byobRequest.view;
1582        viewInfos.push(extractViewInfo(view));
1583
1584        view[0] = 0x01;
1585        controller.byobRequest.respond(1);
1586        viewInfosAfterRespond.push(extractViewInfo(view));
1587      }
1588
1589      ++pullCount;
1590    },
1591    type: 'bytes'
1592  });
1593
1594  const reader = stream.getReader({ mode: 'byob' });
1595
1596  return reader.read(new Uint32Array(1)).then(result => {
1597    assert_false(result.done, 'result.done');
1598
1599    const view = result.value;
1600    assert_equals(view.byteOffset, 0, 'result.value.byteOffset');
1601    assert_equals(view.byteLength, 4, 'result.value.byteLength');
1602    assert_equals(view[0], 0x01010101, 'result.value[0]');
1603
1604    assert_equals(pullCount, 1, 'pull() should only be called once');
1605
1606    for (let i = 0; i < 4; ++i) {
1607      assert_equals(viewInfos[i].constructor, Uint8Array, 'view.constructor should be Uint8Array');
1608      assert_equals(viewInfos[i].bufferByteLength, 4, 'view.buffer.byteLength should be 4');
1609
1610      assert_equals(viewInfos[i].byteOffset, i, 'view.byteOffset should be i');
1611      assert_equals(viewInfos[i].byteLength, 4 - i, 'view.byteLength should be 4 - i');
1612
1613      assert_equals(viewInfosAfterRespond[i].bufferByteLength, 0, 'view.buffer should be transferred after respond()');
1614    }
1615  });
1616}, 'ReadableStream with byte source: read(view) with Uint32Array, then fill it by multiple respond() calls');
1617
1618promise_test(() => {
1619  let pullCount = 0;
1620
1621  let controller;
1622  const viewInfos = [];
1623  const viewInfosAfterEnqueue = [];
1624
1625  const stream = new ReadableStream({
1626    start(c) {
1627      controller = c;
1628    },
1629    pull() {
1630      if (controller.byobRequest === null) {
1631        return;
1632      }
1633
1634      for (let i = 0; i < 4; ++i) {
1635        const view = controller.byobRequest.view;
1636        viewInfos.push(extractViewInfo(view));
1637
1638        controller.enqueue(new Uint8Array([0x01]));
1639        viewInfosAfterEnqueue.push(extractViewInfo(view));
1640      }
1641
1642      ++pullCount;
1643    },
1644    type: 'bytes'
1645  });
1646
1647  const reader = stream.getReader({ mode: 'byob' });
1648
1649  return reader.read(new Uint32Array(1)).then(result => {
1650    assert_false(result.done, 'result.done');
1651
1652    const view = result.value;
1653    assert_equals(view.byteOffset, 0, 'result.value.byteOffset');
1654    assert_equals(view.byteLength, 4, 'result.value.byteLength');
1655    assert_equals(view[0], 0x01010101, 'result.value[0]');
1656
1657    assert_equals(pullCount, 1, 'pull() should only be called once');
1658
1659    for (let i = 0; i < 4; ++i) {
1660      assert_equals(viewInfos[i].constructor, Uint8Array, 'view.constructor should be Uint8Array');
1661      assert_equals(viewInfos[i].bufferByteLength, 4, 'view.buffer.byteLength should be 4');
1662
1663      assert_equals(viewInfos[i].byteOffset, i, 'view.byteOffset should be i');
1664      assert_equals(viewInfos[i].byteLength, 4 - i, 'view.byteLength should be 4 - i');
1665
1666      assert_equals(viewInfosAfterEnqueue[i].bufferByteLength, 0, 'view.buffer should be transferred after enqueue()');
1667    }
1668  });
1669}, 'ReadableStream with byte source: read(view) with Uint32Array, then fill it by multiple enqueue() calls');
1670
1671promise_test(() => {
1672  let pullCount = 0;
1673
1674  let controller;
1675  let byobRequest;
1676
1677  const stream = new ReadableStream({
1678    start(c) {
1679      controller = c;
1680    },
1681    pull() {
1682      byobRequest = controller.byobRequest;
1683
1684      ++pullCount;
1685    },
1686    type: 'bytes'
1687  });
1688
1689  const reader = stream.getReader();
1690
1691  const p0 = reader.read().then(result => {
1692    assert_equals(pullCount, 1);
1693
1694    controller.enqueue(new Uint8Array(2));
1695
1696    // Since the queue has data no less than HWM, no more pull.
1697    assert_equals(pullCount, 1);
1698
1699    assert_false(result.done);
1700
1701    const view = result.value;
1702    assert_equals(view.constructor, Uint8Array);
1703    assert_equals(view.buffer.byteLength, 1);
1704    assert_equals(view.byteOffset, 0);
1705    assert_equals(view.byteLength, 1);
1706  });
1707
1708  assert_equals(pullCount, 0, 'No pull should have been made since the startPromise has not yet been handled');
1709
1710  const p1 = reader.read().then(result => {
1711    assert_equals(pullCount, 1);
1712
1713    assert_false(result.done);
1714
1715    const view = result.value;
1716    assert_equals(view.constructor, Uint8Array);
1717    assert_equals(view.buffer.byteLength, 2);
1718    assert_equals(view.byteOffset, 0);
1719    assert_equals(view.byteLength, 2);
1720
1721    assert_equals(byobRequest, null, 'byobRequest must be null');
1722  });
1723
1724  assert_equals(pullCount, 0, 'No pull should have been made since the startPromise has not yet been handled');
1725
1726  controller.enqueue(new Uint8Array(1));
1727
1728  assert_equals(pullCount, 0, 'No pull should have been made since the startPromise has not yet been handled');
1729
1730  return Promise.all([p0, p1]);
1731}, 'ReadableStream with byte source: read() twice, then enqueue() twice');
1732
1733promise_test(t => {
1734  let controller;
1735
1736  const stream = new ReadableStream({
1737    start(c) {
1738      controller = c;
1739    },
1740    pull: t.unreached_func('pull() should not be called'),
1741    type: 'bytes'
1742  });
1743
1744  const reader = stream.getReader({ mode: 'byob' });
1745
1746  const p0 = reader.read(new Uint8Array(16)).then(result => {
1747    assert_true(result.done, '1st read: done');
1748
1749    const view = result.value;
1750    assert_equals(view.buffer.byteLength, 16, '1st read: buffer.byteLength');
1751    assert_equals(view.byteOffset, 0, '1st read: byteOffset');
1752    assert_equals(view.byteLength, 0, '1st read: byteLength');
1753  });
1754
1755  const p1 = reader.read(new Uint8Array(32)).then(result => {
1756    assert_true(result.done, '2nd read: done');
1757
1758    const view = result.value;
1759    assert_equals(view.buffer.byteLength, 32, '2nd read: buffer.byteLength');
1760    assert_equals(view.byteOffset, 0, '2nd read: byteOffset');
1761    assert_equals(view.byteLength, 0, '2nd read: byteLength');
1762  });
1763
1764  controller.close();
1765  controller.byobRequest.respond(0);
1766
1767  return Promise.all([p0, p1]);
1768}, 'ReadableStream with byte source: Multiple read(view), close() and respond()');
1769
1770promise_test(t => {
1771  let controller;
1772
1773  const stream = new ReadableStream({
1774    start(c) {
1775      controller = c;
1776    },
1777    pull: t.unreached_func('pull() should not be called'),
1778    type: 'bytes'
1779  });
1780
1781  const reader = stream.getReader({ mode: 'byob' });
1782
1783  const p0 = reader.read(new Uint8Array(16)).then(result => {
1784    assert_false(result.done, '1st read: done');
1785
1786    const view = result.value;
1787    assert_equals(view.buffer.byteLength, 16, '1st read: buffer.byteLength');
1788    assert_equals(view.byteOffset, 0, '1st read: byteOffset');
1789    assert_equals(view.byteLength, 16, '1st read: byteLength');
1790  });
1791
1792  const p1 = reader.read(new Uint8Array(16)).then(result => {
1793    assert_false(result.done, '2nd read: done');
1794
1795    const view = result.value;
1796    assert_equals(view.buffer.byteLength, 16, '2nd read: buffer.byteLength');
1797    assert_equals(view.byteOffset, 0, '2nd read: byteOffset');
1798    assert_equals(view.byteLength, 8, '2nd read: byteLength');
1799  });
1800
1801  controller.enqueue(new Uint8Array(24));
1802
1803  return Promise.all([p0, p1]);
1804}, 'ReadableStream with byte source: Multiple read(view), big enqueue()');
1805
1806promise_test(t => {
1807  let controller;
1808
1809  const stream = new ReadableStream({
1810    start(c) {
1811      controller = c;
1812    },
1813    pull: t.unreached_func('pull() should not be called'),
1814    type: 'bytes'
1815  });
1816
1817  const reader = stream.getReader({ mode: 'byob' });
1818
1819  let bytesRead = 0;
1820
1821  function pump() {
1822    return reader.read(new Uint8Array(7)).then(result => {
1823      if (result.done) {
1824        assert_equals(bytesRead, 1024);
1825        return undefined;
1826      }
1827
1828      bytesRead += result.value.byteLength;
1829
1830      return pump();
1831    });
1832  }
1833  const promise = pump();
1834
1835  controller.enqueue(new Uint8Array(512));
1836  controller.enqueue(new Uint8Array(512));
1837  controller.close();
1838
1839  return promise;
1840}, 'ReadableStream with byte source: Multiple read(view) and multiple enqueue()');
1841
1842promise_test(t => {
1843  let pullCalled = false;
1844  const stream = new ReadableStream({
1845    pull(controller) {
1846      pullCalled = true;
1847    },
1848    type: 'bytes'
1849  });
1850
1851  const reader = stream.getReader({ mode: 'byob' });
1852
1853  return promise_rejects_js(t, TypeError, reader.read(), 'read() must fail')
1854      .then(() => assert_false(pullCalled, 'pull() must not have been called'));
1855}, 'ReadableStream with byte source: read(view) with passing undefined as view must fail');
1856
1857promise_test(t => {
1858  const stream = new ReadableStream({
1859    type: 'bytes'
1860  });
1861
1862  const reader = stream.getReader({ mode: 'byob' });
1863
1864  return promise_rejects_js(t, TypeError, reader.read({}), 'read(view) must fail');
1865}, 'ReadableStream with byte source: read(view) with passing an empty object as view must fail');
1866
1867promise_test(t => {
1868  const stream = new ReadableStream({
1869    type: 'bytes'
1870  });
1871
1872  const reader = stream.getReader({ mode: 'byob' });
1873
1874  return promise_rejects_js(t, TypeError,
1875                         reader.read({ buffer: new ArrayBuffer(10), byteOffset: 0, byteLength: 10 }),
1876                         'read(view) must fail');
1877}, 'ReadableStream with byte source: Even read(view) with passing ArrayBufferView like object as view must fail');
1878
1879promise_test(t => {
1880  const stream = new ReadableStream({
1881    start(c) {
1882      c.error(error1);
1883    },
1884    pull: t.unreached_func('pull() should not be called'),
1885    type: 'bytes'
1886  });
1887
1888  const reader = stream.getReader();
1889
1890  return promise_rejects_exactly(t, error1, reader.read(), 'read() must fail');
1891}, 'ReadableStream with byte source: read() on an errored stream');
1892
1893promise_test(t => {
1894  let controller;
1895
1896  const stream = new ReadableStream({
1897    start(c) {
1898      controller = c;
1899    },
1900    type: 'bytes'
1901  });
1902
1903  const reader = stream.getReader();
1904
1905  const promise = promise_rejects_exactly(t, error1, reader.read(), 'read() must fail');
1906
1907  controller.error(error1);
1908
1909  return promise;
1910}, 'ReadableStream with byte source: read(), then error()');
1911
1912promise_test(t => {
1913  const stream = new ReadableStream({
1914    start(c) {
1915      c.error(error1);
1916    },
1917    pull: t.unreached_func('pull() should not be called'),
1918    type: 'bytes'
1919  });
1920
1921  const reader = stream.getReader({ mode: 'byob' });
1922
1923  return promise_rejects_exactly(t, error1, reader.read(new Uint8Array(1)), 'read() must fail');
1924}, 'ReadableStream with byte source: read(view) on an errored stream');
1925
1926promise_test(t => {
1927  let controller;
1928
1929  const stream = new ReadableStream({
1930    start(c) {
1931      controller = c;
1932    },
1933    type: 'bytes'
1934  });
1935
1936  const reader = stream.getReader({ mode: 'byob' });
1937
1938  const promise = promise_rejects_exactly(t, error1, reader.read(new Uint8Array(1)), 'read() must fail');
1939
1940  controller.error(error1);
1941
1942  return promise;
1943}, 'ReadableStream with byte source: read(view), then error()');
1944
1945promise_test(t => {
1946  let controller;
1947  let byobRequest;
1948
1949  const testError = new TypeError('foo');
1950
1951  const stream = new ReadableStream({
1952    start(c) {
1953      controller = c;
1954    },
1955    pull() {
1956      byobRequest = controller.byobRequest;
1957      throw testError;
1958    },
1959    type: 'bytes'
1960  });
1961
1962  const reader = stream.getReader();
1963
1964  const promise = promise_rejects_exactly(t, testError, reader.read(), 'read() must fail');
1965  return promise_rejects_exactly(t, testError, promise.then(() => reader.closed))
1966      .then(() => assert_equals(byobRequest, null, 'byobRequest must be null'));
1967}, 'ReadableStream with byte source: Throwing in pull function must error the stream');
1968
1969promise_test(t => {
1970  let byobRequest;
1971
1972  const stream = new ReadableStream({
1973    pull(controller) {
1974      byobRequest = controller.byobRequest;
1975      controller.error(error1);
1976      throw new TypeError('foo');
1977    },
1978    type: 'bytes'
1979  });
1980
1981  const reader = stream.getReader();
1982
1983  return promise_rejects_exactly(t, error1, reader.read(), 'read() must fail')
1984      .then(() => promise_rejects_exactly(t, error1, reader.closed, 'closed must fail'))
1985      .then(() => assert_equals(byobRequest, null, 'byobRequest must be null'));
1986}, 'ReadableStream with byte source: Throwing in pull in response to read() must be ignored if the stream is ' +
1987   'errored in it');
1988
1989promise_test(t => {
1990  let byobRequest;
1991
1992  const testError = new TypeError('foo');
1993
1994  const stream = new ReadableStream({
1995    pull(controller) {
1996      byobRequest = controller.byobRequest;
1997      throw testError;
1998    },
1999    type: 'bytes'
2000  });
2001
2002  const reader = stream.getReader({ mode: 'byob' });
2003
2004  return promise_rejects_exactly(t, testError, reader.read(new Uint8Array(1)), 'read(view) must fail')
2005      .then(() => promise_rejects_exactly(t, testError, reader.closed, 'reader.closed must reject'))
2006      .then(() => assert_not_equals(byobRequest, null, 'byobRequest must not be null'));
2007}, 'ReadableStream with byte source: Throwing in pull in response to read(view) function must error the stream');
2008
2009promise_test(t => {
2010  let byobRequest;
2011
2012  const stream = new ReadableStream({
2013    pull(controller) {
2014      byobRequest = controller.byobRequest;
2015      controller.error(error1);
2016      throw new TypeError('foo');
2017    },
2018    type: 'bytes'
2019  });
2020
2021  const reader = stream.getReader({ mode: 'byob' });
2022
2023  return promise_rejects_exactly(t, error1, reader.read(new Uint8Array(1)), 'read(view) must fail')
2024      .then(() => promise_rejects_exactly(t, error1, reader.closed, 'closed must fail'))
2025      .then(() => assert_not_equals(byobRequest, null, 'byobRequest must not be null'));
2026}, 'ReadableStream with byte source: Throwing in pull in response to read(view) must be ignored if the stream is ' +
2027   'errored in it');
2028
2029promise_test(() => {
2030  let byobRequest;
2031  const rs = new ReadableStream({
2032    pull(controller) {
2033      byobRequest = controller.byobRequest;
2034      byobRequest.respond(4);
2035    },
2036    type: 'bytes'
2037  });
2038  const reader = rs.getReader({ mode: 'byob' });
2039  const view = new Uint8Array(16);
2040  return reader.read(view).then(() => {
2041    assert_throws_js(TypeError, () => byobRequest.respond(4), 'respond() should throw a TypeError');
2042  });
2043}, 'calling respond() twice on the same byobRequest should throw');
2044
2045promise_test(() => {
2046  let byobRequest;
2047  const newView = () => new Uint8Array(16);
2048  const rs = new ReadableStream({
2049    pull(controller) {
2050      byobRequest = controller.byobRequest;
2051      byobRequest.respondWithNewView(newView());
2052    },
2053    type: 'bytes'
2054  });
2055  const reader = rs.getReader({ mode: 'byob' });
2056  return reader.read(newView()).then(() => {
2057    assert_throws_js(TypeError, () => byobRequest.respondWithNewView(newView()),
2058                     'respondWithNewView() should throw a TypeError');
2059  });
2060}, 'calling respondWithNewView() twice on the same byobRequest should throw');
2061
2062promise_test(() => {
2063  let controller;
2064  let byobRequest;
2065  let resolvePullCalledPromise;
2066  const pullCalledPromise = new Promise(resolve => {
2067    resolvePullCalledPromise = resolve;
2068  });
2069  let resolvePull;
2070  const rs = new ReadableStream({
2071    start(c) {
2072      controller = c;
2073    },
2074    pull(c) {
2075      byobRequest = c.byobRequest;
2076      resolvePullCalledPromise();
2077      return new Promise(resolve => {
2078        resolvePull = resolve;
2079      });
2080    },
2081    type: 'bytes'
2082  });
2083  const reader = rs.getReader({ mode: 'byob' });
2084  const readPromise = reader.read(new Uint8Array(16));
2085  return pullCalledPromise.then(() => {
2086    controller.close();
2087    byobRequest.respond(0);
2088    resolvePull();
2089    return readPromise.then(() => {
2090      assert_throws_js(TypeError, () => byobRequest.respond(0), 'respond() should throw');
2091    });
2092  });
2093}, 'calling respond(0) twice on the same byobRequest should throw even when closed');
2094
2095promise_test(() => {
2096  let controller;
2097  let byobRequest;
2098  let resolvePullCalledPromise;
2099  const pullCalledPromise = new Promise(resolve => {
2100    resolvePullCalledPromise = resolve;
2101  });
2102  let resolvePull;
2103  const rs = new ReadableStream({
2104    start(c) {
2105      controller = c;
2106    },
2107    pull(c) {
2108      byobRequest = c.byobRequest;
2109      resolvePullCalledPromise();
2110      return new Promise(resolve => {
2111        resolvePull = resolve;
2112      });
2113    },
2114    type: 'bytes'
2115  });
2116  const reader = rs.getReader({ mode: 'byob' });
2117  const readPromise = reader.read(new Uint8Array(16));
2118  return pullCalledPromise.then(() => {
2119    const cancelPromise = reader.cancel('meh');
2120    assert_throws_js(TypeError, () => byobRequest.respond(0), 'respond() should throw');
2121    resolvePull();
2122    return Promise.all([readPromise, cancelPromise]);
2123  });
2124}, 'calling respond() should throw when canceled');
2125
2126promise_test(async t => {
2127  let resolvePullCalledPromise;
2128  const pullCalledPromise = new Promise(resolve => {
2129    resolvePullCalledPromise = resolve;
2130  });
2131  let resolvePull;
2132  const rs = new ReadableStream({
2133    pull() {
2134      resolvePullCalledPromise();
2135      return new Promise(resolve => {
2136        resolvePull = resolve;
2137      });
2138    },
2139    type: 'bytes'
2140  });
2141  const reader = rs.getReader({ mode: 'byob' });
2142  const read = reader.read(new Uint8Array(16));
2143  await pullCalledPromise;
2144  resolvePull();
2145  await delay(0);
2146  reader.releaseLock();
2147  await promise_rejects_js(t, TypeError, read, 'pending read should reject');
2148}, 'pull() resolving should not resolve read()');
2149
2150promise_test(() => {
2151  // Tests https://github.com/whatwg/streams/issues/686
2152
2153  let controller;
2154  const rs = new ReadableStream({
2155    autoAllocateChunkSize: 128,
2156    start(c) {
2157      controller = c;
2158    },
2159    type: 'bytes'
2160  });
2161
2162  const readPromise = rs.getReader().read();
2163
2164  const br = controller.byobRequest;
2165  controller.close();
2166
2167  br.respond(0);
2168
2169  return readPromise;
2170}, 'ReadableStream with byte source: default reader + autoAllocateChunkSize + byobRequest interaction');
2171
2172test(() => {
2173  assert_throws_js(TypeError, () => new ReadableStream({ autoAllocateChunkSize: 0, type: 'bytes' }),
2174      'controller cannot be setup with autoAllocateChunkSize = 0');
2175}, 'ReadableStream with byte source: autoAllocateChunkSize cannot be 0');
2176
2177test(() => {
2178  const ReadableStreamBYOBReader = new ReadableStream({ type: 'bytes' }).getReader({ mode: 'byob' }).constructor;
2179  const stream = new ReadableStream({ type: 'bytes' });
2180  new ReadableStreamBYOBReader(stream);
2181}, 'ReadableStreamBYOBReader can be constructed directly');
2182
2183test(() => {
2184  const ReadableStreamBYOBReader = new ReadableStream({ type: 'bytes' }).getReader({ mode: 'byob' }).constructor;
2185  assert_throws_js(TypeError, () => new ReadableStreamBYOBReader({}), 'constructor must throw');
2186}, 'ReadableStreamBYOBReader constructor requires a ReadableStream argument');
2187
2188test(() => {
2189  const ReadableStreamBYOBReader = new ReadableStream({ type: 'bytes' }).getReader({ mode: 'byob' }).constructor;
2190  const stream = new ReadableStream({ type: 'bytes' });
2191  stream.getReader();
2192  assert_throws_js(TypeError, () => new ReadableStreamBYOBReader(stream), 'constructor must throw');
2193}, 'ReadableStreamBYOBReader constructor requires an unlocked ReadableStream');
2194
2195test(() => {
2196  const ReadableStreamBYOBReader = new ReadableStream({ type: 'bytes' }).getReader({ mode: 'byob' }).constructor;
2197  const stream = new ReadableStream();
2198  assert_throws_js(TypeError, () => new ReadableStreamBYOBReader(stream), 'constructor must throw');
2199}, 'ReadableStreamBYOBReader constructor requires a ReadableStream with type "bytes"');
2200
2201test(() => {
2202  assert_throws_js(RangeError, () => new ReadableStream({ type: 'bytes' }, {
2203    size() {
2204      return 1;
2205    }
2206  }), 'constructor should throw for size function');
2207
2208  assert_throws_js(RangeError,
2209                   () => new ReadableStream({ type: 'bytes' }, new CountQueuingStrategy({ highWaterMark: 1 })),
2210                   'constructor should throw when strategy is CountQueuingStrategy');
2211
2212  assert_throws_js(RangeError,
2213                   () => new ReadableStream({ type: 'bytes' }, new ByteLengthQueuingStrategy({ highWaterMark: 512 })),
2214                   'constructor should throw when strategy is ByteLengthQueuingStrategy');
2215
2216  class HasSizeMethod {
2217    size() {}
2218 }
2219
2220  assert_throws_js(RangeError, () => new ReadableStream({ type: 'bytes' }, new HasSizeMethod()),
2221                   'constructor should throw when size on the prototype chain');
2222}, 'ReadableStream constructor should not accept a strategy with a size defined if type is "bytes"');
2223
2224promise_test(async t => {
2225  const stream = new ReadableStream({
2226    pull: t.step_func(c => {
2227      const view = new Uint8Array(c.byobRequest.view.buffer, 0, 1);
2228      view[0] = 1;
2229
2230      c.byobRequest.respondWithNewView(view);
2231    }),
2232    type: 'bytes'
2233  });
2234  const reader = stream.getReader({ mode: 'byob' });
2235
2236  const result = await reader.read(new Uint8Array([4, 5, 6]));
2237  assert_false(result.done, 'result.done');
2238
2239  const view = result.value;
2240  assert_equals(view.byteOffset, 0, 'result.value.byteOffset');
2241  assert_equals(view.byteLength, 1, 'result.value.byteLength');
2242  assert_equals(view[0], 1, 'result.value[0]');
2243  assert_equals(view.buffer.byteLength, 3, 'result.value.buffer.byteLength');
2244  assert_array_equals([...new Uint8Array(view.buffer)], [1, 5, 6], 'result.value.buffer');
2245}, 'ReadableStream with byte source: respondWithNewView() with a smaller view');
2246
2247promise_test(async t => {
2248  const stream = new ReadableStream({
2249    pull: t.step_func(c => {
2250      const view = new Uint8Array(c.byobRequest.view.buffer, 0, 0);
2251
2252      c.close();
2253
2254      c.byobRequest.respondWithNewView(view);
2255    }),
2256    type: 'bytes'
2257  });
2258  const reader = stream.getReader({ mode: 'byob' });
2259
2260  const result = await reader.read(new Uint8Array([4, 5, 6]));
2261  assert_true(result.done, 'result.done');
2262
2263  const view = result.value;
2264  assert_equals(view.byteOffset, 0, 'result.value.byteOffset');
2265  assert_equals(view.byteLength, 0, 'result.value.byteLength');
2266  assert_equals(view.buffer.byteLength, 3, 'result.value.buffer.byteLength');
2267  assert_array_equals([...new Uint8Array(view.buffer)], [4, 5, 6], 'result.value.buffer');
2268}, 'ReadableStream with byte source: respondWithNewView() with a zero-length view (in the closed state)');
2269
2270promise_test(async t => {
2271  let controller;
2272  let resolvePullCalledPromise;
2273  const pullCalledPromise = new Promise(resolve => {
2274    resolvePullCalledPromise = resolve;
2275  });
2276  const stream = new ReadableStream({
2277    start: t.step_func((c) => {
2278      controller = c;
2279    }),
2280    pull: t.step_func(() => {
2281      resolvePullCalledPromise();
2282    }),
2283    type: 'bytes'
2284  });
2285
2286  const reader = stream.getReader({ mode: 'byob' });
2287  const readPromise = reader.read(new Uint8Array([4, 5, 6]));
2288  await pullCalledPromise;
2289
2290  // Transfer the original BYOB request's buffer, and respond with a new view on that buffer
2291  const transferredView = await transferArrayBufferView(controller.byobRequest.view);
2292  const newView = transferredView.subarray(0, 1);
2293  newView[0] = 42;
2294
2295  controller.byobRequest.respondWithNewView(newView);
2296
2297  const result = await readPromise;
2298  assert_false(result.done, 'result.done');
2299
2300  const view = result.value;
2301  assert_equals(view.byteOffset, 0, 'result.value.byteOffset');
2302  assert_equals(view.byteLength, 1, 'result.value.byteLength');
2303  assert_equals(view[0], 42, 'result.value[0]');
2304  assert_equals(view.buffer.byteLength, 3, 'result.value.buffer.byteLength');
2305  assert_array_equals([...new Uint8Array(view.buffer)], [42, 5, 6], 'result.value.buffer');
2306
2307}, 'ReadableStream with byte source: respondWithNewView() with a transferred non-zero-length view ' +
2308   '(in the readable state)');
2309
2310promise_test(async t => {
2311  let controller;
2312  let resolvePullCalledPromise;
2313  const pullCalledPromise = new Promise(resolve => {
2314    resolvePullCalledPromise = resolve;
2315  });
2316  const stream = new ReadableStream({
2317    start: t.step_func((c) => {
2318      controller = c;
2319    }),
2320    pull: t.step_func(() => {
2321      resolvePullCalledPromise();
2322    }),
2323    type: 'bytes'
2324  });
2325
2326  const reader = stream.getReader({ mode: 'byob' });
2327  const readPromise = reader.read(new Uint8Array([4, 5, 6]));
2328  await pullCalledPromise;
2329
2330  // Transfer the original BYOB request's buffer, and respond with an empty view on that buffer
2331  const transferredView = await transferArrayBufferView(controller.byobRequest.view);
2332  const newView = transferredView.subarray(0, 0);
2333
2334  controller.close();
2335  controller.byobRequest.respondWithNewView(newView);
2336
2337  const result = await readPromise;
2338  assert_true(result.done, 'result.done');
2339
2340  const view = result.value;
2341  assert_equals(view.byteOffset, 0, 'result.value.byteOffset');
2342  assert_equals(view.byteLength, 0, 'result.value.byteLength');
2343  assert_equals(view.buffer.byteLength, 3, 'result.value.buffer.byteLength');
2344  assert_array_equals([...new Uint8Array(view.buffer)], [4, 5, 6], 'result.value.buffer');
2345
2346}, 'ReadableStream with byte source: respondWithNewView() with a transferred zero-length view ' +
2347   '(in the closed state)');
2348
2349promise_test(async t => {
2350  let controller;
2351  let pullCount = 0;
2352  const rs = new ReadableStream({
2353    type: 'bytes',
2354    autoAllocateChunkSize: 10,
2355    start: t.step_func((c) => {
2356      controller = c;
2357    }),
2358    pull: t.step_func(() => {
2359      ++pullCount;
2360    })
2361  });
2362
2363  await flushAsyncEvents();
2364  assert_equals(pullCount, 0, 'pull() must not have been invoked yet');
2365
2366  const reader1 = rs.getReader();
2367  const read1 = reader1.read();
2368  assert_equals(pullCount, 1, 'pull() must have been invoked once');
2369  const byobRequest1 = controller.byobRequest;
2370  assert_equals(byobRequest1.view.byteLength, 10, 'first byobRequest.view.byteLength');
2371
2372  // enqueue() must discard the auto-allocated BYOB request
2373  controller.enqueue(new Uint8Array([1, 2, 3]));
2374  assert_equals(byobRequest1.view, null, 'first byobRequest must be invalidated after enqueue()');
2375
2376  const result1 = await read1;
2377  assert_false(result1.done, 'first result.done');
2378  const view1 = result1.value;
2379  assert_equals(view1.byteOffset, 0, 'first result.value.byteOffset');
2380  assert_equals(view1.byteLength, 3, 'first result.value.byteLength');
2381  assert_array_equals([...new Uint8Array(view1.buffer)], [1, 2, 3], 'first result.value.buffer');
2382
2383  reader1.releaseLock();
2384
2385  // read(view) should work after discarding the auto-allocated BYOB request
2386  const reader2 = rs.getReader({ mode: 'byob' });
2387  const read2 = reader2.read(new Uint8Array([4, 5, 6]));
2388  assert_equals(pullCount, 2, 'pull() must have been invoked twice');
2389  const byobRequest2 = controller.byobRequest;
2390  assert_equals(byobRequest2.view.byteOffset, 0, 'second byobRequest.view.byteOffset');
2391  assert_equals(byobRequest2.view.byteLength, 3, 'second byobRequest.view.byteLength');
2392  assert_array_equals([...new Uint8Array(byobRequest2.view.buffer)], [4, 5, 6], 'second byobRequest.view.buffer');
2393
2394  byobRequest2.respond(3);
2395  assert_equals(byobRequest2.view, null, 'second byobRequest must be invalidated after respond()');
2396
2397  const result2 = await read2;
2398  assert_false(result2.done, 'second result.done');
2399  const view2 = result2.value;
2400  assert_equals(view2.byteOffset, 0, 'second result.value.byteOffset');
2401  assert_equals(view2.byteLength, 3, 'second result.value.byteLength');
2402  assert_array_equals([...new Uint8Array(view2.buffer)], [4, 5, 6], 'second result.value.buffer');
2403
2404  reader2.releaseLock();
2405  assert_equals(pullCount, 2, 'pull() must only have been invoked twice');
2406}, 'ReadableStream with byte source: enqueue() discards auto-allocated BYOB request');
2407
2408promise_test(async t => {
2409  let controller;
2410  const rs = new ReadableStream({
2411    type: 'bytes',
2412    start: t.step_func((c) => {
2413      controller = c;
2414    })
2415  });
2416  await flushAsyncEvents();
2417
2418  const reader1 = rs.getReader({ mode: 'byob' });
2419  const read1 = reader1.read(new Uint8Array([1, 2, 3]));
2420  const byobRequest1 = controller.byobRequest;
2421  assert_not_equals(byobRequest1, null, 'first byobRequest should exist');
2422  assert_typed_array_equals(byobRequest1.view, new Uint8Array([1, 2, 3]), 'first byobRequest.view');
2423
2424  // releaseLock() should reject the pending read, but *not* invalidate the BYOB request
2425  reader1.releaseLock();
2426  const reader2 = rs.getReader({ mode: 'byob' });
2427  const read2 = reader2.read(new Uint8Array([4, 5, 6]));
2428  assert_not_equals(controller.byobRequest, null, 'byobRequest should not be invalidated after releaseLock()');
2429  assert_equals(controller.byobRequest, byobRequest1, 'byobRequest should be unchanged');
2430  assert_array_equals([...new Uint8Array(byobRequest1.view.buffer)], [1, 2, 3], 'byobRequest.view.buffer should be unchanged');
2431  await promise_rejects_js(t, TypeError, read1, 'pending read must reject after releaseLock()');
2432
2433  // respond() should fulfill the *second* read() request
2434  byobRequest1.view[0] = 11;
2435  byobRequest1.respond(1);
2436  const byobRequest2 = controller.byobRequest;
2437  assert_equals(byobRequest2, null, 'byobRequest should be null after respond()');
2438
2439  const result2 = await read2;
2440  assert_false(result2.done, 'second result.done');
2441  assert_typed_array_equals(result2.value, new Uint8Array([11, 5, 6]).subarray(0, 1), 'second result.value');
2442
2443}, 'ReadableStream with byte source: releaseLock() with pending read(view), read(view) on second reader, respond()');
2444
2445promise_test(async t => {
2446  let controller;
2447  const rs = new ReadableStream({
2448    type: 'bytes',
2449    start: t.step_func((c) => {
2450      controller = c;
2451    })
2452  });
2453  await flushAsyncEvents();
2454
2455  const reader1 = rs.getReader({ mode: 'byob' });
2456  const read1 = reader1.read(new Uint8Array([1, 2, 3]));
2457  const byobRequest1 = controller.byobRequest;
2458  assert_not_equals(byobRequest1, null, 'first byobRequest should exist');
2459  assert_typed_array_equals(byobRequest1.view, new Uint8Array([1, 2, 3]), 'first byobRequest.view');
2460
2461  // releaseLock() should reject the pending read, but *not* invalidate the BYOB request
2462  reader1.releaseLock();
2463  const reader2 = rs.getReader({ mode: 'byob' });
2464  const read2 = reader2.read(new Uint16Array(1));
2465  assert_not_equals(controller.byobRequest, null, 'byobRequest should not be invalidated after releaseLock()');
2466  assert_equals(controller.byobRequest, byobRequest1, 'byobRequest should be unchanged');
2467  assert_array_equals([...new Uint8Array(byobRequest1.view.buffer)], [1, 2, 3], 'byobRequest.view.buffer should be unchanged');
2468  await promise_rejects_js(t, TypeError, read1, 'pending read must reject after releaseLock()');
2469
2470  // respond(1) should partially fill the second read(), but not yet fulfill it
2471  byobRequest1.view[0] = 0x11;
2472  byobRequest1.respond(1);
2473
2474  // second BYOB request should use remaining buffer from the second read()
2475  const byobRequest2 = controller.byobRequest;
2476  assert_not_equals(byobRequest2, null, 'second byobRequest should exist');
2477  assert_typed_array_equals(byobRequest2.view, new Uint8Array([0x11, 0]).subarray(1, 2), 'second byobRequest.view');
2478
2479  // second respond(1) should fill the read request and fulfill it
2480  byobRequest2.view[0] = 0x22;
2481  byobRequest2.respond(1);
2482  const result2 = await read2;
2483  assert_false(result2.done, 'second result.done');
2484  const view2 = result2.value;
2485  assert_equals(view2.byteOffset, 0, 'second result.value.byteOffset');
2486  assert_equals(view2.byteLength, 2, 'second result.value.byteLength');
2487  const dataView2 = new DataView(view2.buffer, view2.byteOffset, view2.byteLength);
2488  assert_equals(dataView2.getUint16(0), 0x1122, 'second result.value[0]');
2489
2490}, 'ReadableStream with byte source: releaseLock() with pending read(view), read(view) on second reader with ' +
2491   '1 element Uint16Array, respond(1)');
2492
2493promise_test(async t => {
2494  let controller;
2495  const rs = new ReadableStream({
2496    type: 'bytes',
2497    start: t.step_func((c) => {
2498      controller = c;
2499    })
2500  });
2501  await flushAsyncEvents();
2502
2503  const reader1 = rs.getReader({ mode: 'byob' });
2504  const read1 = reader1.read(new Uint8Array([1, 2, 3]));
2505  const byobRequest1 = controller.byobRequest;
2506  assert_not_equals(byobRequest1, null, 'first byobRequest should exist');
2507  assert_typed_array_equals(byobRequest1.view, new Uint8Array([1, 2, 3]), 'first byobRequest.view');
2508
2509  // releaseLock() should reject the pending read, but *not* invalidate the BYOB request
2510  reader1.releaseLock();
2511  const reader2 = rs.getReader({ mode: 'byob' });
2512  const read2 = reader2.read(new Uint8Array([4, 5]));
2513  assert_not_equals(controller.byobRequest, null, 'byobRequest should not be invalidated after releaseLock()');
2514  assert_equals(controller.byobRequest, byobRequest1, 'byobRequest should be unchanged');
2515  assert_array_equals([...new Uint8Array(byobRequest1.view.buffer)], [1, 2, 3], 'byobRequest.view.buffer should be unchanged');
2516  await promise_rejects_js(t, TypeError, read1, 'pending read must reject after releaseLock()');
2517
2518  // respond(3) should fulfill the second read(), and put 1 remaining byte in the queue
2519  byobRequest1.view[0] = 6;
2520  byobRequest1.view[1] = 7;
2521  byobRequest1.view[2] = 8;
2522  byobRequest1.respond(3);
2523  const byobRequest2 = controller.byobRequest;
2524  assert_equals(byobRequest2, null, 'byobRequest should be null after respond()');
2525
2526  const result2 = await read2;
2527  assert_false(result2.done, 'second result.done');
2528  assert_typed_array_equals(result2.value, new Uint8Array([6, 7]), 'second result.value');
2529
2530  // third read() should fulfill with the remaining byte
2531  const result3 = await reader2.read(new Uint8Array([0, 0, 0]));
2532  assert_false(result3.done, 'third result.done');
2533  assert_typed_array_equals(result3.value, new Uint8Array([8, 0, 0]).subarray(0, 1), 'third result.value');
2534
2535}, 'ReadableStream with byte source: releaseLock() with pending read(view), read(view) on second reader with ' +
2536   '2 element Uint8Array, respond(3)');
2537
2538promise_test(async t => {
2539  let controller;
2540  const rs = new ReadableStream({
2541    type: 'bytes',
2542    start: t.step_func((c) => {
2543      controller = c;
2544    })
2545  });
2546  await flushAsyncEvents();
2547
2548  const reader1 = rs.getReader({ mode: 'byob' });
2549  const read1 = reader1.read(new Uint8Array([1, 2, 3]));
2550  const byobRequest1 = controller.byobRequest;
2551  assert_not_equals(byobRequest1, null, 'first byobRequest should exist');
2552  assert_typed_array_equals(byobRequest1.view, new Uint8Array([1, 2, 3]), 'first byobRequest.view');
2553
2554  // releaseLock() should reject the pending read, but *not* invalidate the BYOB request
2555  reader1.releaseLock();
2556  const reader2 = rs.getReader({ mode: 'byob' });
2557  const read2 = reader2.read(new Uint8Array([4, 5, 6]));
2558  assert_not_equals(controller.byobRequest, null, 'byobRequest should not be invalidated after releaseLock()');
2559  await promise_rejects_js(t, TypeError, read1, 'pending read must reject after releaseLock()');
2560
2561  // respondWithNewView() should fulfill the *second* read() request
2562  byobRequest1.view[0] = 11;
2563  byobRequest1.view[1] = 12;
2564  byobRequest1.respondWithNewView(byobRequest1.view.subarray(0, 2));
2565  const byobRequest2 = controller.byobRequest;
2566  assert_equals(byobRequest2, null, 'byobRequest should be null after respondWithNewView()');
2567
2568  const result2 = await read2;
2569  assert_false(result2.done, 'second result.done');
2570  assert_typed_array_equals(result2.value, new Uint8Array([11, 12, 6]).subarray(0, 2), 'second result.value');
2571
2572}, 'ReadableStream with byte source: releaseLock() with pending read(view), read(view) on second reader, respondWithNewView()');
2573
2574promise_test(async t => {
2575  let controller;
2576  const rs = new ReadableStream({
2577    type: 'bytes',
2578    start: t.step_func((c) => {
2579      controller = c;
2580    })
2581  });
2582  await flushAsyncEvents();
2583
2584  const reader1 = rs.getReader({ mode: 'byob' });
2585  const read1 = reader1.read(new Uint8Array([1, 2, 3]));
2586  const byobRequest1 = controller.byobRequest;
2587  assert_not_equals(byobRequest1, null, 'first byobRequest should exist');
2588  assert_typed_array_equals(byobRequest1.view, new Uint8Array([1, 2, 3]), 'first byobRequest.view');
2589
2590  // releaseLock() should reject the pending read, but *not* invalidate the BYOB request
2591  reader1.releaseLock();
2592  const reader2 = rs.getReader({ mode: 'byob' });
2593  const read2 = reader2.read(new Uint8Array([4, 5, 6]));
2594  assert_not_equals(controller.byobRequest, null, 'byobRequest should not be invalidated after releaseLock()');
2595  await promise_rejects_js(t, TypeError, read1, 'pending read must reject after releaseLock()');
2596
2597  // enqueue() should fulfill the *second* read() request
2598  controller.enqueue(new Uint8Array([11, 12]));
2599  const byobRequest2 = controller.byobRequest;
2600  assert_equals(byobRequest2, null, 'byobRequest should be null after enqueue()');
2601
2602  const result2 = await read2;
2603  assert_false(result2.done, 'second result.done');
2604  assert_typed_array_equals(result2.value, new Uint8Array([11, 12, 6]).subarray(0, 2), 'second result.value');
2605
2606}, 'ReadableStream with byte source: releaseLock() with pending read(view), read(view) on second reader, enqueue()');
2607
2608promise_test(async t => {
2609  let controller;
2610  const rs = new ReadableStream({
2611    type: 'bytes',
2612    start: t.step_func((c) => {
2613      controller = c;
2614    })
2615  });
2616  await flushAsyncEvents();
2617
2618  const reader1 = rs.getReader({ mode: 'byob' });
2619  const read1 = reader1.read(new Uint8Array([1, 2, 3]));
2620  const byobRequest1 = controller.byobRequest;
2621  assert_not_equals(byobRequest1, null, 'first byobRequest should exist');
2622  assert_typed_array_equals(byobRequest1.view, new Uint8Array([1, 2, 3]), 'first byobRequest.view');
2623
2624  // releaseLock() should reject the pending read, but *not* invalidate the BYOB request
2625  reader1.releaseLock();
2626  const reader2 = rs.getReader({ mode: 'byob' });
2627  const read2 = reader2.read(new Uint8Array([4, 5, 6]));
2628  assert_not_equals(controller.byobRequest, null, 'byobRequest should not be invalidated after releaseLock()');
2629  await promise_rejects_js(t, TypeError, read1, 'pending read must reject after releaseLock()');
2630
2631  // close() followed by respond(0) should fulfill the second read()
2632  controller.close();
2633  byobRequest1.respond(0);
2634  const byobRequest2 = controller.byobRequest;
2635  assert_equals(byobRequest2, null, 'byobRequest should be null after respond()');
2636
2637  const result2 = await read2;
2638  assert_true(result2.done, 'second result.done');
2639  assert_typed_array_equals(result2.value, new Uint8Array([4, 5, 6]).subarray(0, 0), 'second result.value');
2640}, 'ReadableStream with byte source: releaseLock() with pending read(view), read(view) on second reader, ' +
2641   'close(), respond(0)');
2642
2643promise_test(async t => {
2644  let controller;
2645  const rs = new ReadableStream({
2646    type: 'bytes',
2647    autoAllocateChunkSize: 4,
2648    start: t.step_func((c) => {
2649      controller = c;
2650    })
2651  });
2652  await flushAsyncEvents();
2653
2654  const reader1 = rs.getReader();
2655  const read1 = reader1.read();
2656  const byobRequest1 = controller.byobRequest;
2657  assert_not_equals(byobRequest1, null, 'first byobRequest should exist');
2658  assert_typed_array_equals(byobRequest1.view, new Uint8Array(4), 'first byobRequest.view');
2659
2660  // releaseLock() should reject the pending read, but *not* invalidate the BYOB request
2661  reader1.releaseLock();
2662  const reader2 = rs.getReader();
2663  const read2 = reader2.read();
2664  assert_not_equals(controller.byobRequest, null, 'byobRequest should not be invalidated after releaseLock()');
2665  await promise_rejects_js(t, TypeError, read1, 'pending read must reject after releaseLock()');
2666
2667  // respond() should fulfill the *second* read() request
2668  byobRequest1.view[0] = 11;
2669  byobRequest1.respond(1);
2670  const byobRequest2 = controller.byobRequest;
2671  assert_equals(byobRequest2, null, 'byobRequest should be null after respond()');
2672
2673  const result2 = await read2;
2674  assert_false(result2.done, 'second result.done');
2675  assert_typed_array_equals(result2.value, new Uint8Array([11, 0, 0, 0]).subarray(0, 1), 'second result.value');
2676
2677}, 'ReadableStream with byte source: autoAllocateChunkSize, releaseLock() with pending read(), read() on second reader, respond()');
2678
2679promise_test(async t => {
2680  let controller;
2681  const rs = new ReadableStream({
2682    type: 'bytes',
2683    autoAllocateChunkSize: 4,
2684    start: t.step_func((c) => {
2685      controller = c;
2686    })
2687  });
2688  await flushAsyncEvents();
2689
2690  const reader1 = rs.getReader();
2691  const read1 = reader1.read();
2692  const byobRequest1 = controller.byobRequest;
2693  assert_not_equals(byobRequest1, null, 'first byobRequest should exist');
2694  assert_typed_array_equals(byobRequest1.view, new Uint8Array(4), 'first byobRequest.view');
2695
2696  // releaseLock() should reject the pending read, but *not* invalidate the BYOB request
2697  reader1.releaseLock();
2698  const reader2 = rs.getReader();
2699  const read2 = reader2.read();
2700  assert_not_equals(controller.byobRequest, null, 'byobRequest should not be invalidated after releaseLock()');
2701  await promise_rejects_js(t, TypeError, read1, 'pending read must reject after releaseLock()');
2702
2703  // enqueue() should fulfill the *second* read() request
2704  controller.enqueue(new Uint8Array([11]));
2705  const byobRequest2 = controller.byobRequest;
2706  assert_equals(byobRequest2, null, 'byobRequest should be null after enqueue()');
2707
2708  const result2 = await read2;
2709  assert_false(result2.done, 'second result.done');
2710  assert_typed_array_equals(result2.value, new Uint8Array([11]), 'second result.value');
2711
2712}, 'ReadableStream with byte source: autoAllocateChunkSize, releaseLock() with pending read(), read() on second reader, enqueue()');
2713
2714promise_test(async t => {
2715  let controller;
2716  const rs = new ReadableStream({
2717    type: 'bytes',
2718    autoAllocateChunkSize: 4,
2719    start: t.step_func((c) => {
2720      controller = c;
2721    })
2722  });
2723  await flushAsyncEvents();
2724
2725  const reader1 = rs.getReader();
2726  const read1 = reader1.read();
2727  const byobRequest1 = controller.byobRequest;
2728  assert_not_equals(byobRequest1, null, 'first byobRequest should exist');
2729  assert_typed_array_equals(byobRequest1.view, new Uint8Array(4), 'first byobRequest.view');
2730
2731  // releaseLock() should reject the pending read, but *not* invalidate the BYOB request
2732  reader1.releaseLock();
2733  const reader2 = rs.getReader({ mode: 'byob' });
2734  const read2 = reader2.read(new Uint8Array([4, 5, 6]));
2735  assert_not_equals(controller.byobRequest, null, 'byobRequest should not be invalidated after releaseLock()');
2736  await promise_rejects_js(t, TypeError, read1, 'pending read must reject after releaseLock()');
2737
2738  // respond() should fulfill the *second* read() request
2739  byobRequest1.view[0] = 11;
2740  byobRequest1.respond(1);
2741  const byobRequest2 = controller.byobRequest;
2742  assert_equals(byobRequest2, null, 'byobRequest should be null after respond()');
2743
2744  const result2 = await read2;
2745  assert_false(result2.done, 'second result.done');
2746  assert_typed_array_equals(result2.value, new Uint8Array([11, 5, 6]).subarray(0, 1), 'second result.value');
2747
2748}, 'ReadableStream with byte source: autoAllocateChunkSize, releaseLock() with pending read(), read(view) on second reader, respond()');
2749
2750promise_test(async t => {
2751  let controller;
2752  const rs = new ReadableStream({
2753    type: 'bytes',
2754    autoAllocateChunkSize: 4,
2755    start: t.step_func((c) => {
2756      controller = c;
2757    })
2758  });
2759  await flushAsyncEvents();
2760
2761  const reader1 = rs.getReader();
2762  const read1 = reader1.read();
2763  const byobRequest1 = controller.byobRequest;
2764  assert_not_equals(byobRequest1, null, 'first byobRequest should exist');
2765  assert_typed_array_equals(byobRequest1.view, new Uint8Array(4), 'first byobRequest.view');
2766
2767  // releaseLock() should reject the pending read, but *not* invalidate the BYOB request
2768  reader1.releaseLock();
2769  const reader2 = rs.getReader({ mode: 'byob' });
2770  const read2 = reader2.read(new Uint8Array([4, 5, 6]));
2771  assert_not_equals(controller.byobRequest, null, 'byobRequest should not be invalidated after releaseLock()');
2772  await promise_rejects_js(t, TypeError, read1, 'pending read must reject after releaseLock()');
2773
2774  // enqueue() should fulfill the *second* read() request
2775  controller.enqueue(new Uint8Array([11]));
2776  const byobRequest2 = controller.byobRequest;
2777  assert_equals(byobRequest2, null, 'byobRequest should be null after enqueue()');
2778
2779  const result2 = await read2;
2780  assert_false(result2.done, 'second result.done');
2781  assert_typed_array_equals(result2.value, new Uint8Array([11, 5, 6]).subarray(0, 1), 'second result.value');
2782
2783}, 'ReadableStream with byte source: autoAllocateChunkSize, releaseLock() with pending read(), read(view) on second reader, enqueue()');
2784
2785promise_test(async t => {
2786  let controller;
2787  const rs = new ReadableStream({
2788    type: 'bytes',
2789    start: t.step_func((c) => {
2790      controller = c;
2791    })
2792  });
2793  await flushAsyncEvents();
2794
2795  const reader1 = rs.getReader({ mode: 'byob' });
2796  const read1 = reader1.read(new Uint16Array(1));
2797  const byobRequest1 = controller.byobRequest;
2798  assert_not_equals(byobRequest1, null, 'first byobRequest should exist');
2799  assert_typed_array_equals(byobRequest1.view, new Uint8Array([0, 0]), 'first byobRequest.view');
2800
2801  // respond(1) should partially fill the first read(), but not yet fulfill it
2802  byobRequest1.view[0] = 0x11;
2803  byobRequest1.respond(1);
2804  const byobRequest2 = controller.byobRequest;
2805  assert_not_equals(byobRequest2, null, 'second byobRequest should exist');
2806  assert_typed_array_equals(byobRequest2.view, new Uint8Array([0x11, 0]).subarray(1, 2), 'second byobRequest.view');
2807
2808  // releaseLock() should reject the pending read, but *not* invalidate the BYOB request
2809  reader1.releaseLock();
2810  const reader2 = rs.getReader({ mode: 'byob' });
2811  const read2 = reader2.read(new Uint16Array(1));
2812  assert_not_equals(controller.byobRequest, null, 'byobRequest should not be invalidated after releaseLock()');
2813  assert_equals(controller.byobRequest, byobRequest2, 'byobRequest should be unchanged');
2814  assert_typed_array_equals(byobRequest2.view, new Uint8Array([0x11, 0]).subarray(1, 2), 'byobRequest.view should be unchanged');
2815  await promise_rejects_js(t, TypeError, read1, 'pending read must reject after releaseLock()');
2816
2817  // second respond(1) should fill the read request and fulfill it
2818  byobRequest2.view[0] = 0x22;
2819  byobRequest2.respond(1);
2820  assert_equals(controller.byobRequest, null, 'byobRequest should be invalidated after second respond()');
2821
2822  const result2 = await read2;
2823  assert_false(result2.done, 'second result.done');
2824  const view2 = result2.value;
2825  assert_equals(view2.byteOffset, 0, 'second result.value.byteOffset');
2826  assert_equals(view2.byteLength, 2, 'second result.value.byteLength');
2827  const dataView2 = new DataView(view2.buffer, view2.byteOffset, view2.byteLength);
2828  assert_equals(dataView2.getUint16(0), 0x1122, 'second result.value[0]');
2829
2830}, 'ReadableStream with byte source: read(view) with 1 element Uint16Array, respond(1), releaseLock(), read(view) on ' +
2831   'second reader with 1 element Uint16Array, respond(1)');
2832
2833promise_test(async t => {
2834  let controller;
2835  const rs = new ReadableStream({
2836    type: 'bytes',
2837    start: t.step_func((c) => {
2838      controller = c;
2839    })
2840  });
2841  await flushAsyncEvents();
2842
2843  const reader1 = rs.getReader({ mode: 'byob' });
2844  const read1 = reader1.read(new Uint16Array(1));
2845  const byobRequest1 = controller.byobRequest;
2846  assert_not_equals(byobRequest1, null, 'first byobRequest should exist');
2847  assert_typed_array_equals(byobRequest1.view, new Uint8Array([0, 0]), 'first byobRequest.view');
2848
2849  // respond(1) should partially fill the first read(), but not yet fulfill it
2850  byobRequest1.view[0] = 0x11;
2851  byobRequest1.respond(1);
2852  const byobRequest2 = controller.byobRequest;
2853  assert_not_equals(byobRequest2, null, 'second byobRequest should exist');
2854  assert_typed_array_equals(byobRequest2.view, new Uint8Array([0x11, 0]).subarray(1, 2), 'second byobRequest.view');
2855
2856  // releaseLock() should reject the pending read, but *not* invalidate the BYOB request
2857  reader1.releaseLock();
2858  const reader2 = rs.getReader();
2859  const read2 = reader2.read();
2860  assert_not_equals(controller.byobRequest, null, 'byobRequest should not be invalidated after releaseLock()');
2861  assert_equals(controller.byobRequest, byobRequest2, 'byobRequest should be unchanged');
2862  assert_typed_array_equals(byobRequest2.view, new Uint8Array([0x11, 0]).subarray(1, 2), 'byobRequest.view should be unchanged');
2863  await promise_rejects_js(t, TypeError, read1, 'pending read must reject after releaseLock()');
2864
2865  // enqueue() should fulfill the read request and put remaining byte in the queue
2866  controller.enqueue(new Uint8Array([0x22]));
2867  assert_equals(controller.byobRequest, null, 'byobRequest should be invalidated after second respond()');
2868
2869  const result2 = await read2;
2870  assert_false(result2.done, 'second result.done');
2871  assert_typed_array_equals(result2.value, new Uint8Array([0x11]), 'second result.value');
2872
2873  const result3 = await reader2.read();
2874  assert_false(result3.done, 'third result.done');
2875  assert_typed_array_equals(result3.value, new Uint8Array([0x22]), 'third result.value');
2876
2877}, 'ReadableStream with byte source: read(view) with 1 element Uint16Array, respond(1), releaseLock(), read() on ' +
2878   'second reader, enqueue()');
2879
2880promise_test(async t => {
2881  // Tests https://github.com/nodejs/node/issues/41886
2882  const stream = new ReadableStream({
2883    type: 'bytes',
2884    autoAllocateChunkSize: 10,
2885    pull: t.step_func((c) => {
2886      const newView = new Uint8Array(c.byobRequest.view.buffer, 0, 3);
2887      newView.set([20, 21, 22]);
2888      c.byobRequest.respondWithNewView(newView);
2889    })
2890  });
2891
2892  const reader = stream.getReader();
2893  const result = await reader.read();
2894  assert_false(result.done, 'result.done');
2895
2896  const view = result.value;
2897  assert_equals(view.byteOffset, 0, 'result.value.byteOffset');
2898  assert_equals(view.byteLength, 3, 'result.value.byteLength');
2899  assert_equals(view.buffer.byteLength, 10, 'result.value.buffer.byteLength');
2900  assert_array_equals([...new Uint8Array(view)], [20, 21, 22], 'result.value');
2901}, 'ReadableStream with byte source: autoAllocateChunkSize, read(), respondWithNewView()');
2902