tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

read-min.any.js (29919B)


      1 // META: global=window,worker,shadowrealm
      2 // META: script=../resources/rs-utils.js
      3 // META: script=../resources/test-utils.js
      4 'use strict';
      5 
      6 // View buffers are detached after pull() returns, so record the information at the time that pull() was called.
      7 function extractViewInfo(view) {
      8  return {
      9    constructor: view.constructor,
     10    bufferByteLength: view.buffer.byteLength,
     11    byteOffset: view.byteOffset,
     12    byteLength: view.byteLength
     13  };
     14 }
     15 
     16 promise_test(async t => {
     17  const rs = new ReadableStream({
     18    type: 'bytes',
     19    pull: t.unreached_func('pull() should not be called'),
     20  });
     21  const reader = rs.getReader({ mode: 'byob' });
     22  await promise_rejects_js(t, TypeError, reader.read(new Uint8Array(1), { min: 0 }));
     23 }, 'ReadableStream with byte source: read({ min }) rejects if min is 0');
     24 
     25 promise_test(async t => {
     26  const rs = new ReadableStream({
     27    type: 'bytes',
     28    pull: t.unreached_func('pull() should not be called'),
     29  });
     30  const reader = rs.getReader({ mode: 'byob' });
     31  await promise_rejects_js(t, TypeError, reader.read(new Uint8Array(1), { min: -1 }));
     32 }, 'ReadableStream with byte source: read({ min }) rejects if min is negative');
     33 
     34 promise_test(async t => {
     35  const rs = new ReadableStream({
     36    type: 'bytes',
     37    pull: t.unreached_func('pull() should not be called'),
     38  });
     39  const reader = rs.getReader({ mode: 'byob' });
     40  await promise_rejects_js(t, RangeError, reader.read(new Uint8Array(1), { min: 2 }));
     41 }, 'ReadableStream with byte source: read({ min }) rejects if min is larger than view\'s length (Uint8Array)');
     42 
     43 promise_test(async t => {
     44  const rs = new ReadableStream({
     45    type: 'bytes',
     46    pull: t.unreached_func('pull() should not be called'),
     47  });
     48  const reader = rs.getReader({ mode: 'byob' });
     49  await promise_rejects_js(t, RangeError, reader.read(new Uint16Array(1), { min: 2 }));
     50 }, 'ReadableStream with byte source: read({ min }) rejects if min is larger than view\'s length (Uint16Array)');
     51 
     52 promise_test(async t => {
     53  const rs = new ReadableStream({
     54    type: 'bytes',
     55    pull: t.unreached_func('pull() should not be called'),
     56  });
     57  const reader = rs.getReader({ mode: 'byob' });
     58  await promise_rejects_js(t, RangeError, reader.read(new DataView(new ArrayBuffer(1)), { min: 2 }));
     59 }, 'ReadableStream with byte source: read({ min }) rejects if min is larger than view\'s length (DataView)');
     60 
     61 promise_test(async t => {
     62  let pullCount = 0;
     63  const byobRequests = [];
     64  const rs = new ReadableStream({
     65    type: 'bytes',
     66    pull: t.step_func((c) => {
     67      const byobRequest = c.byobRequest;
     68      const view = byobRequest.view;
     69      byobRequests[pullCount] = {
     70        nonNull: byobRequest !== null,
     71        viewNonNull: view !== null,
     72        viewInfo: extractViewInfo(view)
     73      };
     74      if (pullCount === 0) {
     75        view[0] = 0x01;
     76        view[1] = 0x02;
     77        byobRequest.respond(2);
     78      } else if (pullCount === 1) {
     79        view[0] = 0x03;
     80        byobRequest.respond(1);
     81      } else if (pullCount === 2) {
     82        view[0] = 0x04;
     83        byobRequest.respond(1);
     84      }
     85      ++pullCount;
     86    })
     87  });
     88  const reader = rs.getReader({ mode: 'byob' });
     89  const read1 = reader.read(new Uint8Array(3), { min: 3 });
     90  const read2 = reader.read(new Uint8Array(1));
     91 
     92  const result1 = await read1;
     93  assert_false(result1.done, 'first result should not be done');
     94  assert_typed_array_equals(result1.value, new Uint8Array([0x01, 0x02, 0x03]), 'first result value');
     95 
     96  const result2 = await read2;
     97  assert_false(result2.done, 'second result should not be done');
     98  assert_typed_array_equals(result2.value, new Uint8Array([0x04]), 'second result value');
     99 
    100  assert_equals(pullCount, 3, 'pull() must have been called 3 times');
    101 
    102  {
    103    const byobRequest = byobRequests[0];
    104    assert_true(byobRequest.nonNull, 'first byobRequest must not be null');
    105    assert_true(byobRequest.viewNonNull, 'first byobRequest.view must not be null');
    106    const viewInfo = byobRequest.viewInfo;
    107    assert_equals(viewInfo.constructor, Uint8Array, 'first view.constructor should be Uint8Array');
    108    assert_equals(viewInfo.bufferByteLength, 3, 'first view.buffer.byteLength should be 3');
    109    assert_equals(viewInfo.byteOffset, 0, 'first view.byteOffset should be 0');
    110    assert_equals(viewInfo.byteLength, 3, 'first view.byteLength should be 3');
    111  }
    112 
    113  {
    114    const byobRequest = byobRequests[1];
    115    assert_true(byobRequest.nonNull, 'second byobRequest must not be null');
    116    assert_true(byobRequest.viewNonNull, 'second byobRequest.view must not be null');
    117    const viewInfo = byobRequest.viewInfo;
    118    assert_equals(viewInfo.constructor, Uint8Array, 'second view.constructor should be Uint8Array');
    119    assert_equals(viewInfo.bufferByteLength, 3, 'second view.buffer.byteLength should be 3');
    120    assert_equals(viewInfo.byteOffset, 2, 'second view.byteOffset should be 2');
    121    assert_equals(viewInfo.byteLength, 1, 'second view.byteLength should be 1');
    122  }
    123 
    124  {
    125    const byobRequest = byobRequests[2];
    126    assert_true(byobRequest.nonNull, 'third byobRequest must not be null');
    127    assert_true(byobRequest.viewNonNull, 'third byobRequest.view must not be null');
    128    const viewInfo = byobRequest.viewInfo;
    129    assert_equals(viewInfo.constructor, Uint8Array, 'third view.constructor should be Uint8Array');
    130    assert_equals(viewInfo.bufferByteLength, 1, 'third view.buffer.byteLength should be 1');
    131    assert_equals(viewInfo.byteOffset, 0, 'third view.byteOffset should be 0');
    132    assert_equals(viewInfo.byteLength, 1, 'third view.byteLength should be 1');
    133  }
    134 
    135 }, 'ReadableStream with byte source: read({ min }), then read()');
    136 
    137 promise_test(async t => {
    138  let pullCount = 0;
    139  const byobRequests = [];
    140  const rs = new ReadableStream({
    141    type: 'bytes',
    142    pull: t.step_func((c) => {
    143      const byobRequest = c.byobRequest;
    144      const view = byobRequest.view;
    145      byobRequests[pullCount] = {
    146        nonNull: byobRequest !== null,
    147        viewNonNull: view !== null,
    148        viewInfo: extractViewInfo(view)
    149      };
    150      if (pullCount === 0) {
    151        view[0] = 0x01;
    152        view[1] = 0x02;
    153        byobRequest.respond(2);
    154      } else if (pullCount === 1) {
    155        view[0] = 0x03;
    156        byobRequest.respond(1);
    157      }
    158      ++pullCount;
    159    })
    160  });
    161  const reader = rs.getReader({ mode: 'byob' });
    162 
    163  const result = await reader.read(new DataView(new ArrayBuffer(3)), { min: 3 });
    164  assert_false(result.done, 'result should not be done');
    165  assert_equals(result.value.constructor, DataView, 'result.value must be a DataView');
    166  assert_equals(result.value.byteOffset, 0, 'result.value.byteOffset');
    167  assert_equals(result.value.byteLength, 3, 'result.value.byteLength');
    168  assert_equals(result.value.buffer.byteLength, 3, 'result.value.buffer.byteLength');
    169  assert_array_equals([...new Uint8Array(result.value.buffer)], [0x01, 0x02, 0x03], `result.value.buffer contents`);
    170 
    171  assert_equals(pullCount, 2, 'pull() must have been called 2 times');
    172 
    173  {
    174    const byobRequest = byobRequests[0];
    175    assert_true(byobRequest.nonNull, 'first byobRequest must not be null');
    176    assert_true(byobRequest.viewNonNull, 'first byobRequest.view must not be null');
    177    const viewInfo = byobRequest.viewInfo;
    178    assert_equals(viewInfo.constructor, Uint8Array, 'first view.constructor should be Uint8Array');
    179    assert_equals(viewInfo.bufferByteLength, 3, 'first view.buffer.byteLength should be 3');
    180    assert_equals(viewInfo.byteOffset, 0, 'first view.byteOffset should be 0');
    181    assert_equals(viewInfo.byteLength, 3, 'first view.byteLength should be 3');
    182  }
    183 
    184  {
    185    const byobRequest = byobRequests[1];
    186    assert_true(byobRequest.nonNull, 'second byobRequest must not be null');
    187    assert_true(byobRequest.viewNonNull, 'second byobRequest.view must not be null');
    188    const viewInfo = byobRequest.viewInfo;
    189    assert_equals(viewInfo.constructor, Uint8Array, 'second view.constructor should be Uint8Array');
    190    assert_equals(viewInfo.bufferByteLength, 3, 'second view.buffer.byteLength should be 3');
    191    assert_equals(viewInfo.byteOffset, 2, 'second view.byteOffset should be 2');
    192    assert_equals(viewInfo.byteLength, 1, 'second view.byteLength should be 1');
    193  }
    194 
    195 }, 'ReadableStream with byte source: read({ min }) with a DataView');
    196 
    197 promise_test(async t => {
    198  let pullCount = 0;
    199  const byobRequests = [];
    200  const rs = new ReadableStream({
    201    type: 'bytes',
    202    start: t.step_func((c) => {
    203      c.enqueue(new Uint8Array([0x01]));
    204    }),
    205    pull: t.step_func((c) => {
    206      const byobRequest = c.byobRequest;
    207      const view = byobRequest.view;
    208      byobRequests[pullCount] = {
    209        nonNull: byobRequest !== null,
    210        viewNonNull: view !== null,
    211        viewInfo: extractViewInfo(view)
    212      };
    213      if (pullCount === 0) {
    214        view[0] = 0x02;
    215        view[1] = 0x03;
    216        byobRequest.respond(2);
    217      }
    218      ++pullCount;
    219    })
    220  });
    221  const reader = rs.getReader({ mode: 'byob' });
    222 
    223  const result = await reader.read(new Uint8Array(3), { min: 3 });
    224  assert_false(result.done, 'first result should not be done');
    225  assert_typed_array_equals(result.value, new Uint8Array([0x01, 0x02, 0x03]), 'first result value');
    226 
    227  assert_equals(pullCount, 1, 'pull() must have only been called once');
    228 
    229  const byobRequest = byobRequests[0];
    230  assert_true(byobRequest.nonNull, 'first byobRequest must not be null');
    231  assert_true(byobRequest.viewNonNull, 'first byobRequest.view must not be null');
    232  const viewInfo = byobRequest.viewInfo;
    233  assert_equals(viewInfo.constructor, Uint8Array, 'first view.constructor should be Uint8Array');
    234  assert_equals(viewInfo.bufferByteLength, 3, 'first view.buffer.byteLength should be 3');
    235  assert_equals(viewInfo.byteOffset, 1, 'first view.byteOffset should be 1');
    236  assert_equals(viewInfo.byteLength, 2, 'first view.byteLength should be 2');
    237 
    238 }, 'ReadableStream with byte source: enqueue(), then read({ min })');
    239 
    240 promise_test(async t => {
    241  let pullCount = 0;
    242  const byobRequests = [];
    243  const rs = new ReadableStream({
    244    type: 'bytes',
    245    pull: t.step_func((c) => {
    246      const byobRequest = c.byobRequest;
    247      const view = byobRequest.view;
    248      byobRequests[pullCount] = {
    249        nonNull: byobRequest !== null,
    250        viewNonNull: view !== null,
    251        viewInfo: extractViewInfo(view)
    252      };
    253      if (pullCount === 0) {
    254        c.enqueue(new Uint8Array([0x01, 0x02]));
    255      } else if (pullCount === 1) {
    256        c.enqueue(new Uint8Array([0x03]));
    257      }
    258      ++pullCount;
    259    })
    260  });
    261  const reader = rs.getReader({ mode: 'byob' });
    262 
    263  const result = await reader.read(new Uint8Array(3), { min: 3 });
    264  assert_false(result.done, 'first result should not be done');
    265  assert_typed_array_equals(result.value, new Uint8Array([0x01, 0x02, 0x03]), 'first result value');
    266 
    267  assert_equals(pullCount, 2, 'pull() must have been called 2 times');
    268 
    269  {
    270    const byobRequest = byobRequests[0];
    271    assert_true(byobRequest.nonNull, 'first byobRequest must not be null');
    272    assert_true(byobRequest.viewNonNull, 'first byobRequest.view must not be null');
    273    const viewInfo = byobRequest.viewInfo;
    274    assert_equals(viewInfo.constructor, Uint8Array, 'first view.constructor should be Uint8Array');
    275    assert_equals(viewInfo.bufferByteLength, 3, 'first view.buffer.byteLength should be 3');
    276    assert_equals(viewInfo.byteOffset, 0, 'first view.byteOffset should be 0');
    277    assert_equals(viewInfo.byteLength, 3, 'first view.byteLength should be 3');
    278  }
    279 
    280  {
    281    const byobRequest = byobRequests[1];
    282    assert_true(byobRequest.nonNull, 'second byobRequest must not be null');
    283    assert_true(byobRequest.viewNonNull, 'second byobRequest.view must not be null');
    284    const viewInfo = byobRequest.viewInfo;
    285    assert_equals(viewInfo.constructor, Uint8Array, 'second view.constructor should be Uint8Array');
    286    assert_equals(viewInfo.bufferByteLength, 3, 'second view.buffer.byteLength should be 3');
    287    assert_equals(viewInfo.byteOffset, 2, 'second view.byteOffset should be 2');
    288    assert_equals(viewInfo.byteLength, 1, 'second view.byteLength should be 1');
    289  }
    290 
    291 }, 'ReadableStream with byte source: read({ min: 3 }) on a 3-byte Uint8Array, then multiple enqueue() up to 3 bytes');
    292 
    293 promise_test(async t => {
    294  let pullCount = 0;
    295  const byobRequests = [];
    296  const rs = new ReadableStream({
    297    type: 'bytes',
    298    pull: t.step_func((c) => {
    299      const byobRequest = c.byobRequest;
    300      const view = byobRequest.view;
    301      byobRequests[pullCount] = {
    302        nonNull: byobRequest !== null,
    303        viewNonNull: view !== null,
    304        viewInfo: extractViewInfo(view)
    305      };
    306      if (pullCount === 0) {
    307        c.enqueue(new Uint8Array([0x01, 0x02]));
    308      } else if (pullCount === 1) {
    309        c.enqueue(new Uint8Array([0x03]));
    310      }
    311      ++pullCount;
    312    })
    313  });
    314  const reader = rs.getReader({ mode: 'byob' });
    315 
    316  const result = await reader.read(new Uint8Array(5), { min: 3 });
    317  assert_false(result.done, 'first result should not be done');
    318  assert_typed_array_equals(result.value, new Uint8Array([0x01, 0x02, 0x03, 0, 0]).subarray(0, 3), 'first result value');
    319 
    320  assert_equals(pullCount, 2, 'pull() must have been called 2 times');
    321 
    322  {
    323    const byobRequest = byobRequests[0];
    324    assert_true(byobRequest.nonNull, 'first byobRequest must not be null');
    325    assert_true(byobRequest.viewNonNull, 'first byobRequest.view must not be null');
    326    const viewInfo = byobRequest.viewInfo;
    327    assert_equals(viewInfo.constructor, Uint8Array, 'first view.constructor should be Uint8Array');
    328    assert_equals(viewInfo.bufferByteLength, 5, 'first view.buffer.byteLength should be 5');
    329    assert_equals(viewInfo.byteOffset, 0, 'first view.byteOffset should be 0');
    330    assert_equals(viewInfo.byteLength, 5, 'first view.byteLength should be 5');
    331  }
    332 
    333  {
    334    const byobRequest = byobRequests[1];
    335    assert_true(byobRequest.nonNull, 'second byobRequest must not be null');
    336    assert_true(byobRequest.viewNonNull, 'second byobRequest.view must not be null');
    337    const viewInfo = byobRequest.viewInfo;
    338    assert_equals(viewInfo.constructor, Uint8Array, 'second view.constructor should be Uint8Array');
    339    assert_equals(viewInfo.bufferByteLength, 5, 'second view.buffer.byteLength should be 5');
    340    assert_equals(viewInfo.byteOffset, 2, 'second view.byteOffset should be 2');
    341    assert_equals(viewInfo.byteLength, 3, 'second view.byteLength should be 3');
    342  }
    343 
    344 }, 'ReadableStream with byte source: read({ min: 3 }) on a 5-byte Uint8Array, then multiple enqueue() up to 3 bytes');
    345 
    346 promise_test(async t => {
    347  let pullCount = 0;
    348  const byobRequests = [];
    349  const rs = new ReadableStream({
    350    type: 'bytes',
    351    pull: t.step_func((c) => {
    352      const byobRequest = c.byobRequest;
    353      const view = byobRequest.view;
    354      byobRequests[pullCount] = {
    355        nonNull: byobRequest !== null,
    356        viewNonNull: view !== null,
    357        viewInfo: extractViewInfo(view)
    358      };
    359      if (pullCount === 0) {
    360        c.enqueue(new Uint8Array([0x01, 0x02]));
    361      } else if (pullCount === 1) {
    362        c.enqueue(new Uint8Array([0x03, 0x04]));
    363      }
    364      ++pullCount;
    365    })
    366  });
    367  const reader = rs.getReader({ mode: 'byob' });
    368 
    369  const result = await reader.read(new Uint8Array(5), { min: 3 });
    370  assert_false(result.done, 'first result should not be done');
    371  assert_typed_array_equals(result.value, new Uint8Array([0x01, 0x02, 0x03, 0x04, 0]).subarray(0, 4), 'first result value');
    372 
    373  assert_equals(pullCount, 2, 'pull() must have been called 2 times');
    374 
    375  {
    376    const byobRequest = byobRequests[0];
    377    assert_true(byobRequest.nonNull, 'first byobRequest must not be null');
    378    assert_true(byobRequest.viewNonNull, 'first byobRequest.view must not be null');
    379    const viewInfo = byobRequest.viewInfo;
    380    assert_equals(viewInfo.constructor, Uint8Array, 'first view.constructor should be Uint8Array');
    381    assert_equals(viewInfo.bufferByteLength, 5, 'first view.buffer.byteLength should be 5');
    382    assert_equals(viewInfo.byteOffset, 0, 'first view.byteOffset should be 0');
    383    assert_equals(viewInfo.byteLength, 5, 'first view.byteLength should be 5');
    384  }
    385 
    386  {
    387    const byobRequest = byobRequests[1];
    388    assert_true(byobRequest.nonNull, 'second byobRequest must not be null');
    389    assert_true(byobRequest.viewNonNull, 'second byobRequest.view must not be null');
    390    const viewInfo = byobRequest.viewInfo;
    391    assert_equals(viewInfo.constructor, Uint8Array, 'second view.constructor should be Uint8Array');
    392    assert_equals(viewInfo.bufferByteLength, 5, 'second view.buffer.byteLength should be 5');
    393    assert_equals(viewInfo.byteOffset, 2, 'second view.byteOffset should be 2');
    394    assert_equals(viewInfo.byteLength, 3, 'second view.byteLength should be 3');
    395  }
    396 
    397 }, 'ReadableStream with byte source: read({ min: 3 }) on a 5-byte Uint8Array, then multiple enqueue() up to 4 bytes');
    398 
    399 promise_test(async t => {
    400  const stream = new ReadableStream({
    401    start(c) {
    402      const view = new Uint8Array(16);
    403      view[0] = 0x01;
    404      view[8] = 0x02;
    405      c.enqueue(view);
    406    },
    407    pull: t.unreached_func('pull() should not be called'),
    408    type: 'bytes'
    409  });
    410 
    411  const byobReader = stream.getReader({ mode: 'byob' });
    412  const result1 = await byobReader.read(new Uint8Array(8), { min: 8 });
    413  assert_false(result1.done, 'result1.done');
    414 
    415  const view1 = result1.value;
    416  assert_equals(view1.constructor, Uint8Array, 'result1.value.constructor');
    417  assert_equals(view1.buffer.byteLength, 8, 'result1.value.buffer.byteLength');
    418  assert_equals(view1.byteOffset, 0, 'result1.value.byteOffset');
    419  assert_equals(view1.byteLength, 8, 'result1.value.byteLength');
    420  assert_equals(view1[0], 0x01, 'result1.value[0]');
    421 
    422  byobReader.releaseLock();
    423 
    424  const reader = stream.getReader();
    425  const result2 = await reader.read();
    426  assert_false(result2.done, 'result2.done');
    427 
    428  const view2 = result2.value;
    429  assert_equals(view2.constructor, Uint8Array, 'result2.value.constructor');
    430  assert_equals(view2.buffer.byteLength, 16, 'result2.value.buffer.byteLength');
    431  assert_equals(view2.byteOffset, 8, 'result2.value.byteOffset');
    432  assert_equals(view2.byteLength, 8, 'result2.value.byteLength');
    433  assert_equals(view2[0], 0x02, 'result2.value[0]');
    434 }, 'ReadableStream with byte source: enqueue(), read({ min }) partially, then read()');
    435 
    436 promise_test(async () => {
    437  let pullCount = 0;
    438  const byobRequestDefined = [];
    439  let byobRequestViewDefined;
    440 
    441  const stream = new ReadableStream({
    442    async pull(c) {
    443      byobRequestDefined.push(c.byobRequest !== null);
    444      const initialByobRequest = c.byobRequest;
    445 
    446      const transferredView = await transferArrayBufferView(c.byobRequest.view);
    447      transferredView[0] = 0x01;
    448      c.byobRequest.respondWithNewView(transferredView);
    449 
    450      byobRequestDefined.push(c.byobRequest !== null);
    451      byobRequestViewDefined = initialByobRequest.view !== null;
    452 
    453      ++pullCount;
    454    },
    455    type: 'bytes'
    456  });
    457 
    458  const reader = stream.getReader({ mode: 'byob' });
    459  const result = await reader.read(new Uint8Array(1), { min: 1 });
    460  assert_false(result.done, 'result.done');
    461  assert_equals(result.value.byteLength, 1, 'result.value.byteLength');
    462  assert_equals(result.value[0], 0x01, 'result.value[0]');
    463  assert_equals(pullCount, 1, 'pull() should be called only once');
    464  assert_true(byobRequestDefined[0], 'byobRequest must not be null before respondWithNewView()');
    465  assert_false(byobRequestDefined[1], 'byobRequest must be null after respondWithNewView()');
    466  assert_false(byobRequestViewDefined, 'view of initial byobRequest must be null after respondWithNewView()');
    467 }, 'ReadableStream with byte source: read({ min }), then respondWithNewView() with a transferred ArrayBuffer');
    468 
    469 promise_test(async t => {
    470  const stream = new ReadableStream({
    471    start(c) {
    472      c.close();
    473    },
    474    pull: t.unreached_func('pull() should not be called'),
    475    type: 'bytes'
    476  });
    477 
    478  const reader = stream.getReader({ mode: 'byob' });
    479 
    480  const result = await reader.read(new Uint8Array([0x01]), { min: 1 });
    481  assert_true(result.done, 'result.done');
    482  assert_typed_array_equals(result.value, new Uint8Array([0x01]).subarray(0, 0), 'result.value');
    483 
    484  await reader.closed;
    485 }, 'ReadableStream with byte source: read({ min }) on a closed stream');
    486 
    487 promise_test(async t => {
    488  let pullCount = 0;
    489  const rs = new ReadableStream({
    490    type: 'bytes',
    491    pull: t.step_func((c) => {
    492      if (pullCount === 0) {
    493        c.byobRequest.view[0] = 0x01;
    494        c.byobRequest.respond(1);
    495      } else if (pullCount === 1) {
    496        c.close();
    497        c.byobRequest.respond(0);
    498      }
    499      ++pullCount;
    500    })
    501  });
    502  const reader = rs.getReader({ mode: 'byob' });
    503 
    504  const result = await reader.read(new Uint8Array(3), { min: 3 });
    505  assert_true(result.done, 'result.done');
    506  assert_typed_array_equals(result.value, new Uint8Array([0x01, 0, 0]).subarray(0, 1), 'result.value');
    507 
    508  assert_equals(pullCount, 2, 'pull() must have been called 2 times');
    509 
    510  await reader.closed;
    511 }, 'ReadableStream with byte source: read({ min }) when closed before view is filled');
    512 
    513 promise_test(async t => {
    514  let pullCount = 0;
    515  const rs = new ReadableStream({
    516    type: 'bytes',
    517    pull: t.step_func((c) => {
    518      if (pullCount === 0) {
    519        c.byobRequest.view[0] = 0x01;
    520        c.byobRequest.view[1] = 0x02;
    521        c.byobRequest.respond(2);
    522      } else if (pullCount === 1) {
    523        c.byobRequest.view[0] = 0x03;
    524        c.byobRequest.respond(1);
    525        c.close();
    526      }
    527      ++pullCount;
    528    })
    529  });
    530  const reader = rs.getReader({ mode: 'byob' });
    531 
    532  const result = await reader.read(new Uint8Array(3), { min: 3 });
    533  assert_false(result.done, 'result.done');
    534  assert_typed_array_equals(result.value, new Uint8Array([0x01, 0x02, 0x03]), 'result.value');
    535 
    536  assert_equals(pullCount, 2, 'pull() must have been called 2 times');
    537 
    538  await reader.closed;
    539 }, 'ReadableStream with byte source: read({ min }) when closed immediately after view is filled');
    540 
    541 promise_test(async t => {
    542  const error1 = new Error('error1');
    543  const stream = new ReadableStream({
    544    start(c) {
    545      c.error(error1);
    546    },
    547    pull: t.unreached_func('pull() should not be called'),
    548    type: 'bytes'
    549  });
    550 
    551  const reader = stream.getReader({ mode: 'byob' });
    552  const read = reader.read(new Uint8Array(1), { min: 1 });
    553 
    554  await Promise.all([
    555    promise_rejects_exactly(t, error1, read, 'read() must fail'),
    556    promise_rejects_exactly(t, error1, reader.closed, 'closed must fail')
    557  ]);
    558 }, 'ReadableStream with byte source: read({ min }) on an errored stream');
    559 
    560 promise_test(async t => {
    561  const error1 = new Error('error1');
    562  let controller;
    563  const stream = new ReadableStream({
    564    start(c) {
    565      controller = c;
    566    },
    567    type: 'bytes'
    568  });
    569 
    570  const reader = stream.getReader({ mode: 'byob' });
    571  const read = reader.read(new Uint8Array(1), { min: 1 });
    572 
    573  controller.error(error1);
    574 
    575  await Promise.all([
    576    promise_rejects_exactly(t, error1, read, 'read() must fail'),
    577    promise_rejects_exactly(t, error1, reader.closed, 'closed must fail')
    578  ]);
    579 }, 'ReadableStream with byte source: read({ min }), then error()');
    580 
    581 promise_test(t => {
    582  let cancelCount = 0;
    583  let reason;
    584 
    585  const passedReason = new TypeError('foo');
    586 
    587  const stream = new ReadableStream({
    588    pull: t.unreached_func('pull() should not be called'),
    589    cancel(r) {
    590      if (cancelCount === 0) {
    591        reason = r;
    592      }
    593 
    594      ++cancelCount;
    595 
    596      return 'bar';
    597    },
    598    type: 'bytes'
    599  });
    600 
    601  const reader = stream.getReader({ mode: 'byob' });
    602 
    603  const readPromise = reader.read(new Uint8Array(1), { min: 1 }).then(result => {
    604    assert_true(result.done, 'result.done');
    605    assert_equals(result.value, undefined, 'result.value');
    606  });
    607 
    608  const cancelPromise = reader.cancel(passedReason).then(result => {
    609    assert_equals(result, undefined, 'cancel() return value should be fulfilled with undefined');
    610    assert_equals(cancelCount, 1, 'cancel() should be called only once');
    611    assert_equals(reason, passedReason, 'reason should equal the passed reason');
    612  });
    613 
    614  return Promise.all([readPromise, cancelPromise]);
    615 }, 'ReadableStream with byte source: getReader(), read({ min }), then cancel()');
    616 
    617 promise_test(async t => {
    618  let pullCount = 0;
    619  let byobRequest;
    620  const viewInfos = [];
    621  const rs = new ReadableStream({
    622    type: 'bytes',
    623    pull: t.step_func((c) => {
    624      byobRequest = c.byobRequest;
    625 
    626      viewInfos.push(extractViewInfo(c.byobRequest.view));
    627      c.byobRequest.view[0] = 0x01;
    628      c.byobRequest.respond(1);
    629      viewInfos.push(extractViewInfo(c.byobRequest.view));
    630 
    631      ++pullCount;
    632    })
    633  });
    634 
    635  await Promise.resolve();
    636  assert_equals(pullCount, 0, 'pull() must not have been called yet');
    637 
    638  const reader = rs.getReader({ mode: 'byob' });
    639  const read = reader.read(new Uint8Array(3), { min: 3 });
    640  assert_equals(pullCount, 1, 'pull() must have been called once');
    641  assert_not_equals(byobRequest, null, 'byobRequest should not be null');
    642  assert_equals(viewInfos[0].byteLength, 3, 'byteLength before respond() should be 3');
    643  assert_equals(viewInfos[1].byteLength, 2, 'byteLength after respond() should be 2');
    644 
    645  reader.cancel().catch(t.unreached_func('cancel() should not reject'));
    646 
    647  const result = await read;
    648  assert_true(result.done, 'result.done');
    649  assert_equals(result.value, undefined, 'result.value');
    650 
    651  assert_equals(pullCount, 1, 'pull() must only be called once');
    652 
    653  await reader.closed;
    654 }, 'ReadableStream with byte source: cancel() with partially filled pending read({ min }) request');
    655 
    656 promise_test(async () => {
    657  let pullCalled = false;
    658 
    659  const stream = new ReadableStream({
    660    start(c) {
    661      const view = new Uint8Array(16);
    662      view[7] = 0x01;
    663      view[15] = 0x02;
    664      c.enqueue(view);
    665    },
    666    pull() {
    667      pullCalled = true;
    668    },
    669    type: 'bytes'
    670  });
    671 
    672  const reader = stream.getReader({ mode: 'byob' });
    673 
    674  const result1 = await reader.read(new Uint8Array(8), { min: 8 });
    675  assert_false(result1.done, 'result1.done');
    676 
    677  const view1 = result1.value;
    678  assert_equals(view1.byteOffset, 0, 'result1.value.byteOffset');
    679  assert_equals(view1.byteLength, 8, 'result1.value.byteLength');
    680  assert_equals(view1[7], 0x01, 'result1.value[7]');
    681 
    682  const result2 = await reader.read(new Uint8Array(8), { min: 8 });
    683  assert_false(pullCalled, 'pull() must not have been called');
    684  assert_false(result2.done, 'result2.done');
    685 
    686  const view2 = result2.value;
    687  assert_equals(view2.byteOffset, 0, 'result2.value.byteOffset');
    688  assert_equals(view2.byteLength, 8, 'result2.value.byteLength');
    689  assert_equals(view2[7], 0x02, 'result2.value[7]');
    690 }, 'ReadableStream with byte source: enqueue(), then read({ min }) with smaller views');
    691 
    692 promise_test(async t => {
    693  const stream = new ReadableStream({
    694    start(c) {
    695      c.enqueue(new Uint8Array([0xaa, 0xbb, 0xcc]));
    696      c.close();
    697    },
    698    pull: t.unreached_func('pull() should not be called'),
    699    type: 'bytes'
    700  });
    701 
    702  const reader = stream.getReader({ mode: 'byob' });
    703 
    704  await promise_rejects_js(t, TypeError, reader.read(new Uint16Array(2), { min: 2 }), 'read() must fail');
    705  await promise_rejects_js(t, TypeError, reader.closed, 'reader.closed should reject');
    706 }, 'ReadableStream with byte source: 3 byte enqueue(), then close(), then read({ min }) with 2-element Uint16Array must fail');
    707 
    708 promise_test(async t => {
    709  let controller;
    710  const stream = new ReadableStream({
    711    start(c) {
    712      controller = c;
    713    },
    714    pull: t.unreached_func('pull() should not be called'),
    715    type: 'bytes'
    716  });
    717 
    718  const reader = stream.getReader({ mode: 'byob' });
    719  const readPromise = reader.read(new Uint16Array(2), { min: 2 });
    720 
    721  controller.enqueue(new Uint8Array([0xaa, 0xbb, 0xcc]));
    722  assert_throws_js(TypeError, () => controller.close(), 'controller.close() must throw');
    723 
    724  await promise_rejects_js(t, TypeError, readPromise, 'read() must fail');
    725  await promise_rejects_js(t, TypeError, reader.closed, 'reader.closed must reject');
    726 }, 'ReadableStream with byte source: read({ min }) with 2-element Uint16Array, then 3 byte enqueue(), then close() must fail');
    727 
    728 promise_test(async t => {
    729  let pullCount = 0;
    730  let controller;
    731  const rs = new ReadableStream({
    732    type: 'bytes',
    733    start: t.step_func((c) => {
    734      controller = c;
    735    }),
    736    pull: t.step_func((c) => {
    737      ++pullCount;
    738    })
    739  });
    740 
    741  const [reader1, reader2] = rs.tee().map(branch => branch.getReader({ mode: 'byob' }));
    742 
    743  await Promise.resolve();
    744  assert_equals(pullCount, 0, 'pull() must not have been called yet');
    745 
    746  const read1 = reader1.read(new Uint8Array(3), { min: 3 });
    747  const read2 = reader2.read(new Uint8Array(1));
    748 
    749  assert_equals(pullCount, 1, 'pull() must have been called once');
    750  const byobRequest1 = controller.byobRequest;
    751  assert_equals(byobRequest1.view.byteLength, 3, 'first byobRequest.view.byteLength should be 3');
    752  byobRequest1.view[0] = 0x01;
    753  byobRequest1.respond(1);
    754 
    755  const result2 = await read2;
    756  assert_false(result2.done, 'branch2 first read() should not be done');
    757  assert_typed_array_equals(result2.value, new Uint8Array([0x01]), 'branch2 first read() value');
    758 
    759  assert_equals(pullCount, 2, 'pull() must have been called 2 times');
    760  const byobRequest2 = controller.byobRequest;
    761  assert_equals(byobRequest2.view.byteLength, 2, 'second byobRequest.view.byteLength should be 2');
    762  byobRequest2.view[0] = 0x02;
    763  byobRequest2.view[1] = 0x03;
    764  byobRequest2.respond(2);
    765 
    766  const result1 = await read1;
    767  assert_false(result1.done, 'branch1 read() should not be done');
    768  assert_typed_array_equals(result1.value, new Uint8Array([0x01, 0x02, 0x03]), 'branch1 read() value');
    769 
    770  const result3 = await reader2.read(new Uint8Array(2));
    771  assert_equals(pullCount, 2, 'pull() must only be called 2 times');
    772  assert_false(result3.done, 'branch2 second read() should not be done');
    773  assert_typed_array_equals(result3.value, new Uint8Array([0x02, 0x03]), 'branch2 second read() value');
    774 }, 'ReadableStream with byte source: tee() with read({ min }) from branch1 and read() from branch2');