11cb0ef41Sopenharmony_ci// META: global=window,worker
21cb0ef41Sopenharmony_ci// META: script=../resources/rs-utils.js
31cb0ef41Sopenharmony_ci// META: script=../resources/test-utils.js
41cb0ef41Sopenharmony_ci// META: script=../resources/recording-streams.js
51cb0ef41Sopenharmony_ci// META: script=../resources/rs-test-templates.js
61cb0ef41Sopenharmony_ci'use strict';
71cb0ef41Sopenharmony_ci
81cb0ef41Sopenharmony_citest(() => {
91cb0ef41Sopenharmony_ci
101cb0ef41Sopenharmony_ci  const rs = new ReadableStream({ type: 'bytes' });
111cb0ef41Sopenharmony_ci  const result = rs.tee();
121cb0ef41Sopenharmony_ci
131cb0ef41Sopenharmony_ci  assert_true(Array.isArray(result), 'return value should be an array');
141cb0ef41Sopenharmony_ci  assert_equals(result.length, 2, 'array should have length 2');
151cb0ef41Sopenharmony_ci  assert_equals(result[0].constructor, ReadableStream, '0th element should be a ReadableStream');
161cb0ef41Sopenharmony_ci  assert_equals(result[1].constructor, ReadableStream, '1st element should be a ReadableStream');
171cb0ef41Sopenharmony_ci
181cb0ef41Sopenharmony_ci}, 'ReadableStream teeing with byte source: rs.tee() returns an array of two ReadableStreams');
191cb0ef41Sopenharmony_ci
201cb0ef41Sopenharmony_cipromise_test(async t => {
211cb0ef41Sopenharmony_ci
221cb0ef41Sopenharmony_ci  const rs = new ReadableStream({
231cb0ef41Sopenharmony_ci    type: 'bytes',
241cb0ef41Sopenharmony_ci    start(c) {
251cb0ef41Sopenharmony_ci      c.enqueue(new Uint8Array([0x01]));
261cb0ef41Sopenharmony_ci      c.enqueue(new Uint8Array([0x02]));
271cb0ef41Sopenharmony_ci      c.close();
281cb0ef41Sopenharmony_ci    }
291cb0ef41Sopenharmony_ci  });
301cb0ef41Sopenharmony_ci
311cb0ef41Sopenharmony_ci  const [branch1, branch2] = rs.tee();
321cb0ef41Sopenharmony_ci  const reader1 = branch1.getReader({ mode: 'byob' });
331cb0ef41Sopenharmony_ci  const reader2 = branch2.getReader({ mode: 'byob' });
341cb0ef41Sopenharmony_ci
351cb0ef41Sopenharmony_ci  reader2.closed.then(t.unreached_func('branch2 should not be closed'));
361cb0ef41Sopenharmony_ci
371cb0ef41Sopenharmony_ci  {
381cb0ef41Sopenharmony_ci    const result = await reader1.read(new Uint8Array(1));
391cb0ef41Sopenharmony_ci    assert_equals(result.done, false, 'done');
401cb0ef41Sopenharmony_ci    assert_typed_array_equals(result.value, new Uint8Array([0x01]), 'value');
411cb0ef41Sopenharmony_ci  }
421cb0ef41Sopenharmony_ci
431cb0ef41Sopenharmony_ci  {
441cb0ef41Sopenharmony_ci    const result = await reader1.read(new Uint8Array(1));
451cb0ef41Sopenharmony_ci    assert_equals(result.done, false, 'done');
461cb0ef41Sopenharmony_ci    assert_typed_array_equals(result.value, new Uint8Array([0x02]), 'value');
471cb0ef41Sopenharmony_ci  }
481cb0ef41Sopenharmony_ci
491cb0ef41Sopenharmony_ci  {
501cb0ef41Sopenharmony_ci    const result = await reader1.read(new Uint8Array(1));
511cb0ef41Sopenharmony_ci    assert_equals(result.done, true, 'done');
521cb0ef41Sopenharmony_ci    assert_typed_array_equals(result.value, new Uint8Array([0]).subarray(0, 0), 'value');
531cb0ef41Sopenharmony_ci  }
541cb0ef41Sopenharmony_ci
551cb0ef41Sopenharmony_ci  {
561cb0ef41Sopenharmony_ci    const result = await reader2.read(new Uint8Array(1));
571cb0ef41Sopenharmony_ci    assert_equals(result.done, false, 'done');
581cb0ef41Sopenharmony_ci    assert_typed_array_equals(result.value, new Uint8Array([0x01]), 'value');
591cb0ef41Sopenharmony_ci  }
601cb0ef41Sopenharmony_ci
611cb0ef41Sopenharmony_ci  await reader1.closed;
621cb0ef41Sopenharmony_ci
631cb0ef41Sopenharmony_ci}, 'ReadableStream teeing with byte source: should be able to read one branch to the end without affecting the other');
641cb0ef41Sopenharmony_ci
651cb0ef41Sopenharmony_cipromise_test(async () => {
661cb0ef41Sopenharmony_ci
671cb0ef41Sopenharmony_ci  let pullCount = 0;
681cb0ef41Sopenharmony_ci  const enqueuedChunk = new Uint8Array([0x01]);
691cb0ef41Sopenharmony_ci  const rs = new ReadableStream({
701cb0ef41Sopenharmony_ci    type: 'bytes',
711cb0ef41Sopenharmony_ci    pull(c) {
721cb0ef41Sopenharmony_ci      ++pullCount;
731cb0ef41Sopenharmony_ci      if (pullCount === 1) {
741cb0ef41Sopenharmony_ci        c.enqueue(enqueuedChunk);
751cb0ef41Sopenharmony_ci      }
761cb0ef41Sopenharmony_ci    }
771cb0ef41Sopenharmony_ci  });
781cb0ef41Sopenharmony_ci
791cb0ef41Sopenharmony_ci  const [branch1, branch2] = rs.tee();
801cb0ef41Sopenharmony_ci  const reader1 = branch1.getReader();
811cb0ef41Sopenharmony_ci  const reader2 = branch2.getReader();
821cb0ef41Sopenharmony_ci
831cb0ef41Sopenharmony_ci  const [result1, result2] = await Promise.all([reader1.read(), reader2.read()]);
841cb0ef41Sopenharmony_ci  assert_equals(result1.done, false, 'reader1 done');
851cb0ef41Sopenharmony_ci  assert_equals(result2.done, false, 'reader2 done');
861cb0ef41Sopenharmony_ci
871cb0ef41Sopenharmony_ci  const view1 = result1.value;
881cb0ef41Sopenharmony_ci  const view2 = result2.value;
891cb0ef41Sopenharmony_ci  assert_typed_array_equals(view1, new Uint8Array([0x01]), 'reader1 value');
901cb0ef41Sopenharmony_ci  assert_typed_array_equals(view2, new Uint8Array([0x01]), 'reader2 value');
911cb0ef41Sopenharmony_ci
921cb0ef41Sopenharmony_ci  assert_not_equals(view1.buffer, view2.buffer, 'chunks should have different buffers');
931cb0ef41Sopenharmony_ci  assert_not_equals(enqueuedChunk.buffer, view1.buffer, 'enqueued chunk and branch1\'s chunk should have different buffers');
941cb0ef41Sopenharmony_ci  assert_not_equals(enqueuedChunk.buffer, view2.buffer, 'enqueued chunk and branch2\'s chunk should have different buffers');
951cb0ef41Sopenharmony_ci
961cb0ef41Sopenharmony_ci}, 'ReadableStream teeing with byte source: chunks should be cloned for each branch');
971cb0ef41Sopenharmony_ci
981cb0ef41Sopenharmony_cipromise_test(async () => {
991cb0ef41Sopenharmony_ci
1001cb0ef41Sopenharmony_ci  let pullCount = 0;
1011cb0ef41Sopenharmony_ci  const rs = new ReadableStream({
1021cb0ef41Sopenharmony_ci    type: 'bytes',
1031cb0ef41Sopenharmony_ci    pull(c) {
1041cb0ef41Sopenharmony_ci      ++pullCount;
1051cb0ef41Sopenharmony_ci      if (pullCount === 1) {
1061cb0ef41Sopenharmony_ci        c.byobRequest.view[0] = 0x01;
1071cb0ef41Sopenharmony_ci        c.byobRequest.respond(1);
1081cb0ef41Sopenharmony_ci      }
1091cb0ef41Sopenharmony_ci    }
1101cb0ef41Sopenharmony_ci  });
1111cb0ef41Sopenharmony_ci
1121cb0ef41Sopenharmony_ci  const [branch1, branch2] = rs.tee();
1131cb0ef41Sopenharmony_ci  const reader1 = branch1.getReader({ mode: 'byob' });
1141cb0ef41Sopenharmony_ci  const reader2 = branch2.getReader();
1151cb0ef41Sopenharmony_ci  const buffer = new Uint8Array([42, 42, 42]).buffer;
1161cb0ef41Sopenharmony_ci
1171cb0ef41Sopenharmony_ci  {
1181cb0ef41Sopenharmony_ci    const result = await reader1.read(new Uint8Array(buffer, 0, 1));
1191cb0ef41Sopenharmony_ci    assert_equals(result.done, false, 'done');
1201cb0ef41Sopenharmony_ci    assert_typed_array_equals(result.value, new Uint8Array([0x01, 42, 42]).subarray(0, 1), 'value');
1211cb0ef41Sopenharmony_ci  }
1221cb0ef41Sopenharmony_ci
1231cb0ef41Sopenharmony_ci  {
1241cb0ef41Sopenharmony_ci    const result = await reader2.read();
1251cb0ef41Sopenharmony_ci    assert_equals(result.done, false, 'done');
1261cb0ef41Sopenharmony_ci    assert_typed_array_equals(result.value, new Uint8Array([0x01]), 'value');
1271cb0ef41Sopenharmony_ci  }
1281cb0ef41Sopenharmony_ci
1291cb0ef41Sopenharmony_ci}, 'ReadableStream teeing with byte source: chunks for BYOB requests from branch 1 should be cloned to branch 2');
1301cb0ef41Sopenharmony_ci
1311cb0ef41Sopenharmony_cipromise_test(async t => {
1321cb0ef41Sopenharmony_ci
1331cb0ef41Sopenharmony_ci  const theError = { name: 'boo!' };
1341cb0ef41Sopenharmony_ci  const rs = new ReadableStream({
1351cb0ef41Sopenharmony_ci    type: 'bytes',
1361cb0ef41Sopenharmony_ci    start(c) {
1371cb0ef41Sopenharmony_ci      c.enqueue(new Uint8Array([0x01]));
1381cb0ef41Sopenharmony_ci      c.enqueue(new Uint8Array([0x02]));
1391cb0ef41Sopenharmony_ci    },
1401cb0ef41Sopenharmony_ci    pull() {
1411cb0ef41Sopenharmony_ci      throw theError;
1421cb0ef41Sopenharmony_ci    }
1431cb0ef41Sopenharmony_ci  });
1441cb0ef41Sopenharmony_ci
1451cb0ef41Sopenharmony_ci  const [branch1, branch2] = rs.tee();
1461cb0ef41Sopenharmony_ci  const reader1 = branch1.getReader({ mode: 'byob' });
1471cb0ef41Sopenharmony_ci  const reader2 = branch2.getReader({ mode: 'byob' });
1481cb0ef41Sopenharmony_ci
1491cb0ef41Sopenharmony_ci  {
1501cb0ef41Sopenharmony_ci    const result = await reader1.read(new Uint8Array(1));
1511cb0ef41Sopenharmony_ci    assert_equals(result.done, false, 'first read from branch1 should not be done');
1521cb0ef41Sopenharmony_ci    assert_typed_array_equals(result.value, new Uint8Array([0x01]), 'first read from branch1');
1531cb0ef41Sopenharmony_ci  }
1541cb0ef41Sopenharmony_ci
1551cb0ef41Sopenharmony_ci  {
1561cb0ef41Sopenharmony_ci    const result = await reader1.read(new Uint8Array(1));
1571cb0ef41Sopenharmony_ci    assert_equals(result.done, false, 'second read from branch1 should not be done');
1581cb0ef41Sopenharmony_ci    assert_typed_array_equals(result.value, new Uint8Array([0x02]), 'second read from branch1');
1591cb0ef41Sopenharmony_ci  }
1601cb0ef41Sopenharmony_ci
1611cb0ef41Sopenharmony_ci  await promise_rejects_exactly(t, theError, reader1.read(new Uint8Array(1)));
1621cb0ef41Sopenharmony_ci  await promise_rejects_exactly(t, theError, reader2.read(new Uint8Array(1)));
1631cb0ef41Sopenharmony_ci
1641cb0ef41Sopenharmony_ci  await Promise.all([
1651cb0ef41Sopenharmony_ci    promise_rejects_exactly(t, theError, reader1.closed),
1661cb0ef41Sopenharmony_ci    promise_rejects_exactly(t, theError, reader2.closed)
1671cb0ef41Sopenharmony_ci  ]);
1681cb0ef41Sopenharmony_ci
1691cb0ef41Sopenharmony_ci}, 'ReadableStream teeing with byte source: errors in the source should propagate to both branches');
1701cb0ef41Sopenharmony_ci
1711cb0ef41Sopenharmony_cipromise_test(async () => {
1721cb0ef41Sopenharmony_ci
1731cb0ef41Sopenharmony_ci  const rs = new ReadableStream({
1741cb0ef41Sopenharmony_ci    type: 'bytes',
1751cb0ef41Sopenharmony_ci    start(c) {
1761cb0ef41Sopenharmony_ci      c.enqueue(new Uint8Array([0x01]));
1771cb0ef41Sopenharmony_ci      c.enqueue(new Uint8Array([0x02]));
1781cb0ef41Sopenharmony_ci      c.close();
1791cb0ef41Sopenharmony_ci    }
1801cb0ef41Sopenharmony_ci  });
1811cb0ef41Sopenharmony_ci
1821cb0ef41Sopenharmony_ci  const [branch1, branch2] = rs.tee();
1831cb0ef41Sopenharmony_ci  branch1.cancel();
1841cb0ef41Sopenharmony_ci
1851cb0ef41Sopenharmony_ci  const [chunks1, chunks2] = await Promise.all([readableStreamToArray(branch1), readableStreamToArray(branch2)]);
1861cb0ef41Sopenharmony_ci  assert_array_equals(chunks1, [], 'branch1 should have no chunks');
1871cb0ef41Sopenharmony_ci  assert_equals(chunks2.length, 2, 'branch2 should have two chunks');
1881cb0ef41Sopenharmony_ci  assert_typed_array_equals(chunks2[0], new Uint8Array([0x01]), 'first chunk from branch2');
1891cb0ef41Sopenharmony_ci  assert_typed_array_equals(chunks2[1], new Uint8Array([0x02]), 'second chunk from branch2');
1901cb0ef41Sopenharmony_ci
1911cb0ef41Sopenharmony_ci}, 'ReadableStream teeing with byte source: canceling branch1 should not impact branch2');
1921cb0ef41Sopenharmony_ci
1931cb0ef41Sopenharmony_cipromise_test(async () => {
1941cb0ef41Sopenharmony_ci
1951cb0ef41Sopenharmony_ci  const rs = new ReadableStream({
1961cb0ef41Sopenharmony_ci    type: 'bytes',
1971cb0ef41Sopenharmony_ci    start(c) {
1981cb0ef41Sopenharmony_ci      c.enqueue(new Uint8Array([0x01]));
1991cb0ef41Sopenharmony_ci      c.enqueue(new Uint8Array([0x02]));
2001cb0ef41Sopenharmony_ci      c.close();
2011cb0ef41Sopenharmony_ci    }
2021cb0ef41Sopenharmony_ci  });
2031cb0ef41Sopenharmony_ci
2041cb0ef41Sopenharmony_ci  const [branch1, branch2] = rs.tee();
2051cb0ef41Sopenharmony_ci  branch2.cancel();
2061cb0ef41Sopenharmony_ci
2071cb0ef41Sopenharmony_ci  const [chunks1, chunks2] = await Promise.all([readableStreamToArray(branch1), readableStreamToArray(branch2)]);
2081cb0ef41Sopenharmony_ci  assert_equals(chunks1.length, 2, 'branch1 should have two chunks');
2091cb0ef41Sopenharmony_ci  assert_typed_array_equals(chunks1[0], new Uint8Array([0x01]), 'first chunk from branch1');
2101cb0ef41Sopenharmony_ci  assert_typed_array_equals(chunks1[1], new Uint8Array([0x02]), 'second chunk from branch1');
2111cb0ef41Sopenharmony_ci  assert_array_equals(chunks2, [], 'branch2 should have no chunks');
2121cb0ef41Sopenharmony_ci
2131cb0ef41Sopenharmony_ci}, 'ReadableStream teeing with byte source: canceling branch2 should not impact branch1');
2141cb0ef41Sopenharmony_ci
2151cb0ef41Sopenharmony_citemplatedRSTeeCancel('ReadableStream teeing with byte source', (extras) => {
2161cb0ef41Sopenharmony_ci  return new ReadableStream({ type: 'bytes', ...extras });
2171cb0ef41Sopenharmony_ci});
2181cb0ef41Sopenharmony_ci
2191cb0ef41Sopenharmony_cipromise_test(async () => {
2201cb0ef41Sopenharmony_ci
2211cb0ef41Sopenharmony_ci  let controller;
2221cb0ef41Sopenharmony_ci  const rs = new ReadableStream({
2231cb0ef41Sopenharmony_ci    type: 'bytes',
2241cb0ef41Sopenharmony_ci    start(c) {
2251cb0ef41Sopenharmony_ci      controller = c;
2261cb0ef41Sopenharmony_ci    }
2271cb0ef41Sopenharmony_ci  });
2281cb0ef41Sopenharmony_ci
2291cb0ef41Sopenharmony_ci  const [branch1, branch2] = rs.tee();
2301cb0ef41Sopenharmony_ci  const reader1 = branch1.getReader({ mode: 'byob' });
2311cb0ef41Sopenharmony_ci  const reader2 = branch2.getReader({ mode: 'byob' });
2321cb0ef41Sopenharmony_ci
2331cb0ef41Sopenharmony_ci  const promise = Promise.all([reader1.closed, reader2.closed]);
2341cb0ef41Sopenharmony_ci
2351cb0ef41Sopenharmony_ci  controller.close();
2361cb0ef41Sopenharmony_ci
2371cb0ef41Sopenharmony_ci  // The branches are created with HWM 0, so we need to read from at least one of them
2381cb0ef41Sopenharmony_ci  // to observe the stream becoming closed.
2391cb0ef41Sopenharmony_ci  const read1 = await reader1.read(new Uint8Array(1));
2401cb0ef41Sopenharmony_ci  assert_equals(read1.done, true, 'first read from branch1 should be done');
2411cb0ef41Sopenharmony_ci
2421cb0ef41Sopenharmony_ci  await promise;
2431cb0ef41Sopenharmony_ci
2441cb0ef41Sopenharmony_ci}, 'ReadableStream teeing with byte source: closing the original should close the branches');
2451cb0ef41Sopenharmony_ci
2461cb0ef41Sopenharmony_cipromise_test(async t => {
2471cb0ef41Sopenharmony_ci
2481cb0ef41Sopenharmony_ci  let controller;
2491cb0ef41Sopenharmony_ci  const rs = new ReadableStream({
2501cb0ef41Sopenharmony_ci    type: 'bytes',
2511cb0ef41Sopenharmony_ci    start(c) {
2521cb0ef41Sopenharmony_ci      controller = c;
2531cb0ef41Sopenharmony_ci    }
2541cb0ef41Sopenharmony_ci  });
2551cb0ef41Sopenharmony_ci
2561cb0ef41Sopenharmony_ci  const [branch1, branch2] = rs.tee();
2571cb0ef41Sopenharmony_ci  const reader1 = branch1.getReader({ mode: 'byob' });
2581cb0ef41Sopenharmony_ci  const reader2 = branch2.getReader({ mode: 'byob' });
2591cb0ef41Sopenharmony_ci
2601cb0ef41Sopenharmony_ci  const theError = { name: 'boo!' };
2611cb0ef41Sopenharmony_ci  const promise = Promise.all([
2621cb0ef41Sopenharmony_ci    promise_rejects_exactly(t, theError, reader1.closed),
2631cb0ef41Sopenharmony_ci    promise_rejects_exactly(t, theError, reader2.closed)
2641cb0ef41Sopenharmony_ci  ]);
2651cb0ef41Sopenharmony_ci
2661cb0ef41Sopenharmony_ci  controller.error(theError);
2671cb0ef41Sopenharmony_ci  await promise;
2681cb0ef41Sopenharmony_ci
2691cb0ef41Sopenharmony_ci}, 'ReadableStream teeing with byte source: erroring the original should immediately error the branches');
2701cb0ef41Sopenharmony_ci
2711cb0ef41Sopenharmony_cipromise_test(async t => {
2721cb0ef41Sopenharmony_ci
2731cb0ef41Sopenharmony_ci  let controller;
2741cb0ef41Sopenharmony_ci  const rs = new ReadableStream({
2751cb0ef41Sopenharmony_ci    type: 'bytes',
2761cb0ef41Sopenharmony_ci    start(c) {
2771cb0ef41Sopenharmony_ci      controller = c;
2781cb0ef41Sopenharmony_ci    }
2791cb0ef41Sopenharmony_ci  });
2801cb0ef41Sopenharmony_ci
2811cb0ef41Sopenharmony_ci  const [branch1, branch2] = rs.tee();
2821cb0ef41Sopenharmony_ci  const reader1 = branch1.getReader();
2831cb0ef41Sopenharmony_ci  const reader2 = branch2.getReader();
2841cb0ef41Sopenharmony_ci
2851cb0ef41Sopenharmony_ci  const theError = { name: 'boo!' };
2861cb0ef41Sopenharmony_ci  const promise = Promise.all([
2871cb0ef41Sopenharmony_ci    promise_rejects_exactly(t, theError, reader1.read()),
2881cb0ef41Sopenharmony_ci    promise_rejects_exactly(t, theError, reader2.read())
2891cb0ef41Sopenharmony_ci  ]);
2901cb0ef41Sopenharmony_ci
2911cb0ef41Sopenharmony_ci  controller.error(theError);
2921cb0ef41Sopenharmony_ci  await promise;
2931cb0ef41Sopenharmony_ci
2941cb0ef41Sopenharmony_ci}, 'ReadableStream teeing with byte source: erroring the original should error pending reads from default reader');
2951cb0ef41Sopenharmony_ci
2961cb0ef41Sopenharmony_cipromise_test(async t => {
2971cb0ef41Sopenharmony_ci
2981cb0ef41Sopenharmony_ci  let controller;
2991cb0ef41Sopenharmony_ci  const rs = new ReadableStream({
3001cb0ef41Sopenharmony_ci    type: 'bytes',
3011cb0ef41Sopenharmony_ci    start(c) {
3021cb0ef41Sopenharmony_ci      controller = c;
3031cb0ef41Sopenharmony_ci    }
3041cb0ef41Sopenharmony_ci  });
3051cb0ef41Sopenharmony_ci
3061cb0ef41Sopenharmony_ci  const [branch1, branch2] = rs.tee();
3071cb0ef41Sopenharmony_ci  const reader1 = branch1.getReader({ mode: 'byob' });
3081cb0ef41Sopenharmony_ci  const reader2 = branch2.getReader({ mode: 'byob' });
3091cb0ef41Sopenharmony_ci
3101cb0ef41Sopenharmony_ci  const theError = { name: 'boo!' };
3111cb0ef41Sopenharmony_ci  const promise = Promise.all([
3121cb0ef41Sopenharmony_ci    promise_rejects_exactly(t, theError, reader1.read(new Uint8Array(1))),
3131cb0ef41Sopenharmony_ci    promise_rejects_exactly(t, theError, reader2.read(new Uint8Array(1)))
3141cb0ef41Sopenharmony_ci  ]);
3151cb0ef41Sopenharmony_ci
3161cb0ef41Sopenharmony_ci  controller.error(theError);
3171cb0ef41Sopenharmony_ci  await promise;
3181cb0ef41Sopenharmony_ci
3191cb0ef41Sopenharmony_ci}, 'ReadableStream teeing with byte source: erroring the original should error pending reads from BYOB reader');
3201cb0ef41Sopenharmony_ci
3211cb0ef41Sopenharmony_cipromise_test(async () => {
3221cb0ef41Sopenharmony_ci
3231cb0ef41Sopenharmony_ci  let controller;
3241cb0ef41Sopenharmony_ci  const rs = new ReadableStream({
3251cb0ef41Sopenharmony_ci    type: 'bytes',
3261cb0ef41Sopenharmony_ci    start(c) {
3271cb0ef41Sopenharmony_ci      controller = c;
3281cb0ef41Sopenharmony_ci    }
3291cb0ef41Sopenharmony_ci  });
3301cb0ef41Sopenharmony_ci
3311cb0ef41Sopenharmony_ci  const [branch1, branch2] = rs.tee();
3321cb0ef41Sopenharmony_ci  const reader1 = branch1.getReader({ mode: 'byob' });
3331cb0ef41Sopenharmony_ci  const reader2 = branch2.getReader({ mode: 'byob' });
3341cb0ef41Sopenharmony_ci  const cancelPromise = reader2.cancel();
3351cb0ef41Sopenharmony_ci
3361cb0ef41Sopenharmony_ci  controller.enqueue(new Uint8Array([0x01]));
3371cb0ef41Sopenharmony_ci
3381cb0ef41Sopenharmony_ci  const read1 = await reader1.read(new Uint8Array(1));
3391cb0ef41Sopenharmony_ci  assert_equals(read1.done, false, 'first read() from branch1 should not be done');
3401cb0ef41Sopenharmony_ci  assert_typed_array_equals(read1.value, new Uint8Array([0x01]), 'first read() from branch1');
3411cb0ef41Sopenharmony_ci
3421cb0ef41Sopenharmony_ci  controller.close();
3431cb0ef41Sopenharmony_ci
3441cb0ef41Sopenharmony_ci  const read2 = await reader1.read(new Uint8Array(1));
3451cb0ef41Sopenharmony_ci  assert_equals(read2.done, true, 'second read() from branch1 should be done');
3461cb0ef41Sopenharmony_ci
3471cb0ef41Sopenharmony_ci  await Promise.all([
3481cb0ef41Sopenharmony_ci    reader1.closed,
3491cb0ef41Sopenharmony_ci    cancelPromise
3501cb0ef41Sopenharmony_ci  ]);
3511cb0ef41Sopenharmony_ci
3521cb0ef41Sopenharmony_ci}, 'ReadableStream teeing with byte source: canceling branch1 should finish when branch2 reads until end of stream');
3531cb0ef41Sopenharmony_ci
3541cb0ef41Sopenharmony_cipromise_test(async t => {
3551cb0ef41Sopenharmony_ci
3561cb0ef41Sopenharmony_ci  let controller;
3571cb0ef41Sopenharmony_ci  const theError = { name: 'boo!' };
3581cb0ef41Sopenharmony_ci  const rs = new ReadableStream({
3591cb0ef41Sopenharmony_ci    type: 'bytes',
3601cb0ef41Sopenharmony_ci    start(c) {
3611cb0ef41Sopenharmony_ci      controller = c;
3621cb0ef41Sopenharmony_ci    }
3631cb0ef41Sopenharmony_ci  });
3641cb0ef41Sopenharmony_ci
3651cb0ef41Sopenharmony_ci  const [branch1, branch2] = rs.tee();
3661cb0ef41Sopenharmony_ci  const reader1 = branch1.getReader({ mode: 'byob' });
3671cb0ef41Sopenharmony_ci  const reader2 = branch2.getReader({ mode: 'byob' });
3681cb0ef41Sopenharmony_ci  const cancelPromise = reader2.cancel();
3691cb0ef41Sopenharmony_ci
3701cb0ef41Sopenharmony_ci  controller.error(theError);
3711cb0ef41Sopenharmony_ci
3721cb0ef41Sopenharmony_ci  await Promise.all([
3731cb0ef41Sopenharmony_ci    promise_rejects_exactly(t, theError, reader1.read(new Uint8Array(1))),
3741cb0ef41Sopenharmony_ci    cancelPromise
3751cb0ef41Sopenharmony_ci  ]);
3761cb0ef41Sopenharmony_ci
3771cb0ef41Sopenharmony_ci}, 'ReadableStream teeing with byte source: canceling branch1 should finish when original stream errors');
3781cb0ef41Sopenharmony_ci
3791cb0ef41Sopenharmony_cipromise_test(async () => {
3801cb0ef41Sopenharmony_ci
3811cb0ef41Sopenharmony_ci  const rs = recordingReadableStream({ type: 'bytes' });
3821cb0ef41Sopenharmony_ci
3831cb0ef41Sopenharmony_ci  // Create two branches, each with a HWM of 0. This should result in no chunks being pulled.
3841cb0ef41Sopenharmony_ci  rs.tee();
3851cb0ef41Sopenharmony_ci
3861cb0ef41Sopenharmony_ci  await flushAsyncEvents();
3871cb0ef41Sopenharmony_ci  assert_array_equals(rs.events, [], 'pull should not be called');
3881cb0ef41Sopenharmony_ci
3891cb0ef41Sopenharmony_ci}, 'ReadableStream teeing with byte source: should not pull any chunks if no branches are reading');
3901cb0ef41Sopenharmony_ci
3911cb0ef41Sopenharmony_cipromise_test(async () => {
3921cb0ef41Sopenharmony_ci
3931cb0ef41Sopenharmony_ci  const rs = recordingReadableStream({
3941cb0ef41Sopenharmony_ci    type: 'bytes',
3951cb0ef41Sopenharmony_ci    pull(controller) {
3961cb0ef41Sopenharmony_ci      controller.enqueue(new Uint8Array([0x01]));
3971cb0ef41Sopenharmony_ci    }
3981cb0ef41Sopenharmony_ci  });
3991cb0ef41Sopenharmony_ci
4001cb0ef41Sopenharmony_ci  const [reader1, reader2] = rs.tee().map(branch => branch.getReader({ mode: 'byob' }));
4011cb0ef41Sopenharmony_ci  await Promise.all([
4021cb0ef41Sopenharmony_ci    reader1.read(new Uint8Array(1)),
4031cb0ef41Sopenharmony_ci    reader2.read(new Uint8Array(1))
4041cb0ef41Sopenharmony_ci  ]);
4051cb0ef41Sopenharmony_ci  assert_array_equals(rs.events, ['pull'], 'pull should be called once');
4061cb0ef41Sopenharmony_ci
4071cb0ef41Sopenharmony_ci}, 'ReadableStream teeing with byte source: should only pull enough to fill the emptiest queue');
4081cb0ef41Sopenharmony_ci
4091cb0ef41Sopenharmony_cipromise_test(async t => {
4101cb0ef41Sopenharmony_ci
4111cb0ef41Sopenharmony_ci  const rs = recordingReadableStream({ type: 'bytes' });
4121cb0ef41Sopenharmony_ci  const theError = { name: 'boo!' };
4131cb0ef41Sopenharmony_ci
4141cb0ef41Sopenharmony_ci  rs.controller.error(theError);
4151cb0ef41Sopenharmony_ci
4161cb0ef41Sopenharmony_ci  const [reader1, reader2] = rs.tee().map(branch => branch.getReader({ mode: 'byob' }));
4171cb0ef41Sopenharmony_ci
4181cb0ef41Sopenharmony_ci  await flushAsyncEvents();
4191cb0ef41Sopenharmony_ci  assert_array_equals(rs.events, [], 'pull should not be called');
4201cb0ef41Sopenharmony_ci
4211cb0ef41Sopenharmony_ci  await Promise.all([
4221cb0ef41Sopenharmony_ci    promise_rejects_exactly(t, theError, reader1.closed),
4231cb0ef41Sopenharmony_ci    promise_rejects_exactly(t, theError, reader2.closed)
4241cb0ef41Sopenharmony_ci  ]);
4251cb0ef41Sopenharmony_ci
4261cb0ef41Sopenharmony_ci}, 'ReadableStream teeing with byte source: should not pull when original is already errored');
4271cb0ef41Sopenharmony_ci
4281cb0ef41Sopenharmony_cifor (const branch of [1, 2]) {
4291cb0ef41Sopenharmony_ci  promise_test(async t => {
4301cb0ef41Sopenharmony_ci
4311cb0ef41Sopenharmony_ci    const rs = recordingReadableStream({ type: 'bytes' });
4321cb0ef41Sopenharmony_ci    const theError = { name: 'boo!' };
4331cb0ef41Sopenharmony_ci
4341cb0ef41Sopenharmony_ci    const [reader1, reader2] = rs.tee().map(branch => branch.getReader({ mode: 'byob' }));
4351cb0ef41Sopenharmony_ci
4361cb0ef41Sopenharmony_ci    await flushAsyncEvents();
4371cb0ef41Sopenharmony_ci    assert_array_equals(rs.events, [], 'pull should not be called');
4381cb0ef41Sopenharmony_ci
4391cb0ef41Sopenharmony_ci    const reader = (branch === 1) ? reader1 : reader2;
4401cb0ef41Sopenharmony_ci    const read1 = reader.read(new Uint8Array(1));
4411cb0ef41Sopenharmony_ci
4421cb0ef41Sopenharmony_ci    await flushAsyncEvents();
4431cb0ef41Sopenharmony_ci    assert_array_equals(rs.events, ['pull'], 'pull should be called once');
4441cb0ef41Sopenharmony_ci
4451cb0ef41Sopenharmony_ci    rs.controller.error(theError);
4461cb0ef41Sopenharmony_ci
4471cb0ef41Sopenharmony_ci    await Promise.all([
4481cb0ef41Sopenharmony_ci      promise_rejects_exactly(t, theError, read1),
4491cb0ef41Sopenharmony_ci      promise_rejects_exactly(t, theError, reader1.closed),
4501cb0ef41Sopenharmony_ci      promise_rejects_exactly(t, theError, reader2.closed)
4511cb0ef41Sopenharmony_ci    ]);
4521cb0ef41Sopenharmony_ci
4531cb0ef41Sopenharmony_ci    await flushAsyncEvents();
4541cb0ef41Sopenharmony_ci    assert_array_equals(rs.events, ['pull'], 'pull should be called once');
4551cb0ef41Sopenharmony_ci
4561cb0ef41Sopenharmony_ci  }, `ReadableStream teeing with byte source: stops pulling when original stream errors while branch ${branch} is reading`);
4571cb0ef41Sopenharmony_ci}
4581cb0ef41Sopenharmony_ci
4591cb0ef41Sopenharmony_cipromise_test(async t => {
4601cb0ef41Sopenharmony_ci
4611cb0ef41Sopenharmony_ci  const rs = recordingReadableStream({ type: 'bytes' });
4621cb0ef41Sopenharmony_ci  const theError = { name: 'boo!' };
4631cb0ef41Sopenharmony_ci
4641cb0ef41Sopenharmony_ci  const [reader1, reader2] = rs.tee().map(branch => branch.getReader({ mode: 'byob' }));
4651cb0ef41Sopenharmony_ci
4661cb0ef41Sopenharmony_ci  await flushAsyncEvents();
4671cb0ef41Sopenharmony_ci  assert_array_equals(rs.events, [], 'pull should not be called');
4681cb0ef41Sopenharmony_ci
4691cb0ef41Sopenharmony_ci  const read1 = reader1.read(new Uint8Array(1));
4701cb0ef41Sopenharmony_ci  const read2 = reader2.read(new Uint8Array(1));
4711cb0ef41Sopenharmony_ci
4721cb0ef41Sopenharmony_ci  await flushAsyncEvents();
4731cb0ef41Sopenharmony_ci  assert_array_equals(rs.events, ['pull'], 'pull should be called once');
4741cb0ef41Sopenharmony_ci
4751cb0ef41Sopenharmony_ci  rs.controller.error(theError);
4761cb0ef41Sopenharmony_ci
4771cb0ef41Sopenharmony_ci  await Promise.all([
4781cb0ef41Sopenharmony_ci    promise_rejects_exactly(t, theError, read1),
4791cb0ef41Sopenharmony_ci    promise_rejects_exactly(t, theError, read2),
4801cb0ef41Sopenharmony_ci    promise_rejects_exactly(t, theError, reader1.closed),
4811cb0ef41Sopenharmony_ci    promise_rejects_exactly(t, theError, reader2.closed)
4821cb0ef41Sopenharmony_ci  ]);
4831cb0ef41Sopenharmony_ci
4841cb0ef41Sopenharmony_ci  await flushAsyncEvents();
4851cb0ef41Sopenharmony_ci  assert_array_equals(rs.events, ['pull'], 'pull should be called once');
4861cb0ef41Sopenharmony_ci
4871cb0ef41Sopenharmony_ci}, 'ReadableStream teeing with byte source: stops pulling when original stream errors while both branches are reading');
4881cb0ef41Sopenharmony_ci
4891cb0ef41Sopenharmony_cipromise_test(async () => {
4901cb0ef41Sopenharmony_ci
4911cb0ef41Sopenharmony_ci  const rs = recordingReadableStream({ type: 'bytes' });
4921cb0ef41Sopenharmony_ci
4931cb0ef41Sopenharmony_ci  const [reader1, reader2] = rs.tee().map(branch => branch.getReader({ mode: 'byob' }));
4941cb0ef41Sopenharmony_ci
4951cb0ef41Sopenharmony_ci  const read1 = reader1.read(new Uint8Array([0x11]));
4961cb0ef41Sopenharmony_ci  const read2 = reader2.read(new Uint8Array([0x22]));
4971cb0ef41Sopenharmony_ci
4981cb0ef41Sopenharmony_ci  const cancel1 = reader1.cancel();
4991cb0ef41Sopenharmony_ci  await flushAsyncEvents();
5001cb0ef41Sopenharmony_ci  const cancel2 = reader2.cancel();
5011cb0ef41Sopenharmony_ci
5021cb0ef41Sopenharmony_ci  const result1 = await read1;
5031cb0ef41Sopenharmony_ci  assert_object_equals(result1, { value: undefined, done: true });
5041cb0ef41Sopenharmony_ci  const result2 = await read2;
5051cb0ef41Sopenharmony_ci  assert_object_equals(result2, { value: undefined, done: true });
5061cb0ef41Sopenharmony_ci
5071cb0ef41Sopenharmony_ci  await Promise.all([cancel1, cancel2]);
5081cb0ef41Sopenharmony_ci
5091cb0ef41Sopenharmony_ci}, 'ReadableStream teeing with byte source: canceling both branches in sequence with delay');
5101cb0ef41Sopenharmony_ci
5111cb0ef41Sopenharmony_cipromise_test(async t => {
5121cb0ef41Sopenharmony_ci
5131cb0ef41Sopenharmony_ci  const theError = { name: 'boo!' };
5141cb0ef41Sopenharmony_ci  const rs = new ReadableStream({
5151cb0ef41Sopenharmony_ci    type: 'bytes',
5161cb0ef41Sopenharmony_ci    cancel() {
5171cb0ef41Sopenharmony_ci      throw theError;
5181cb0ef41Sopenharmony_ci    }
5191cb0ef41Sopenharmony_ci  });
5201cb0ef41Sopenharmony_ci
5211cb0ef41Sopenharmony_ci  const [reader1, reader2] = rs.tee().map(branch => branch.getReader({ mode: 'byob' }));
5221cb0ef41Sopenharmony_ci
5231cb0ef41Sopenharmony_ci  const read1 = reader1.read(new Uint8Array([0x11]));
5241cb0ef41Sopenharmony_ci  const read2 = reader2.read(new Uint8Array([0x22]));
5251cb0ef41Sopenharmony_ci
5261cb0ef41Sopenharmony_ci  const cancel1 = reader1.cancel();
5271cb0ef41Sopenharmony_ci  await flushAsyncEvents();
5281cb0ef41Sopenharmony_ci  const cancel2 = reader2.cancel();
5291cb0ef41Sopenharmony_ci
5301cb0ef41Sopenharmony_ci  const result1 = await read1;
5311cb0ef41Sopenharmony_ci  assert_object_equals(result1, { value: undefined, done: true });
5321cb0ef41Sopenharmony_ci  const result2 = await read2;
5331cb0ef41Sopenharmony_ci  assert_object_equals(result2, { value: undefined, done: true });
5341cb0ef41Sopenharmony_ci
5351cb0ef41Sopenharmony_ci  await Promise.all([
5361cb0ef41Sopenharmony_ci    promise_rejects_exactly(t, theError, cancel1),
5371cb0ef41Sopenharmony_ci    promise_rejects_exactly(t, theError, cancel2)
5381cb0ef41Sopenharmony_ci  ]);
5391cb0ef41Sopenharmony_ci
5401cb0ef41Sopenharmony_ci}, 'ReadableStream teeing with byte source: failing to cancel when canceling both branches in sequence with delay');
5411cb0ef41Sopenharmony_ci
5421cb0ef41Sopenharmony_cipromise_test(async () => {
5431cb0ef41Sopenharmony_ci
5441cb0ef41Sopenharmony_ci  let cancelResolve;
5451cb0ef41Sopenharmony_ci  const cancelCalled = new Promise((resolve) => {
5461cb0ef41Sopenharmony_ci    cancelResolve = resolve;
5471cb0ef41Sopenharmony_ci  });
5481cb0ef41Sopenharmony_ci  const rs = recordingReadableStream({
5491cb0ef41Sopenharmony_ci    type: 'bytes',
5501cb0ef41Sopenharmony_ci    cancel() {
5511cb0ef41Sopenharmony_ci      cancelResolve();
5521cb0ef41Sopenharmony_ci    }
5531cb0ef41Sopenharmony_ci  });
5541cb0ef41Sopenharmony_ci
5551cb0ef41Sopenharmony_ci  const [reader1, reader2] = rs.tee().map(branch => branch.getReader({ mode: 'byob' }));
5561cb0ef41Sopenharmony_ci
5571cb0ef41Sopenharmony_ci  const read1 = reader1.read(new Uint8Array([0x11]));
5581cb0ef41Sopenharmony_ci  await flushAsyncEvents();
5591cb0ef41Sopenharmony_ci  const read2 = reader2.read(new Uint8Array([0x22]));
5601cb0ef41Sopenharmony_ci  await flushAsyncEvents();
5611cb0ef41Sopenharmony_ci
5621cb0ef41Sopenharmony_ci  // We are reading into branch1's buffer.
5631cb0ef41Sopenharmony_ci  const byobRequest1 = rs.controller.byobRequest;
5641cb0ef41Sopenharmony_ci  assert_not_equals(byobRequest1, null);
5651cb0ef41Sopenharmony_ci  assert_typed_array_equals(byobRequest1.view, new Uint8Array([0x11]), 'byobRequest1.view');
5661cb0ef41Sopenharmony_ci
5671cb0ef41Sopenharmony_ci  // Cancelling branch1 should not affect the BYOB request.
5681cb0ef41Sopenharmony_ci  const cancel1 = reader1.cancel();
5691cb0ef41Sopenharmony_ci  const result1 = await read1;
5701cb0ef41Sopenharmony_ci  assert_equals(result1.done, true);
5711cb0ef41Sopenharmony_ci  assert_equals(result1.value, undefined);
5721cb0ef41Sopenharmony_ci  await flushAsyncEvents();
5731cb0ef41Sopenharmony_ci  const byobRequest2 = rs.controller.byobRequest;
5741cb0ef41Sopenharmony_ci  assert_typed_array_equals(byobRequest2.view, new Uint8Array([0x11]), 'byobRequest2.view');
5751cb0ef41Sopenharmony_ci
5761cb0ef41Sopenharmony_ci  // Cancelling branch1 should invalidate the BYOB request.
5771cb0ef41Sopenharmony_ci  const cancel2 = reader2.cancel();
5781cb0ef41Sopenharmony_ci  await cancelCalled;
5791cb0ef41Sopenharmony_ci  const byobRequest3 = rs.controller.byobRequest;
5801cb0ef41Sopenharmony_ci  assert_equals(byobRequest3, null);
5811cb0ef41Sopenharmony_ci  const result2 = await read2;
5821cb0ef41Sopenharmony_ci  assert_equals(result2.done, true);
5831cb0ef41Sopenharmony_ci  assert_equals(result2.value, undefined);
5841cb0ef41Sopenharmony_ci
5851cb0ef41Sopenharmony_ci  await Promise.all([cancel1, cancel2]);
5861cb0ef41Sopenharmony_ci
5871cb0ef41Sopenharmony_ci}, 'ReadableStream teeing with byte source: read from branch1 and branch2, cancel branch1, cancel branch2');
5881cb0ef41Sopenharmony_ci
5891cb0ef41Sopenharmony_cipromise_test(async () => {
5901cb0ef41Sopenharmony_ci
5911cb0ef41Sopenharmony_ci  let cancelResolve;
5921cb0ef41Sopenharmony_ci  const cancelCalled = new Promise((resolve) => {
5931cb0ef41Sopenharmony_ci    cancelResolve = resolve;
5941cb0ef41Sopenharmony_ci  });
5951cb0ef41Sopenharmony_ci  const rs = recordingReadableStream({
5961cb0ef41Sopenharmony_ci    type: 'bytes',
5971cb0ef41Sopenharmony_ci    cancel() {
5981cb0ef41Sopenharmony_ci      cancelResolve();
5991cb0ef41Sopenharmony_ci    }
6001cb0ef41Sopenharmony_ci  });
6011cb0ef41Sopenharmony_ci
6021cb0ef41Sopenharmony_ci  const [reader1, reader2] = rs.tee().map(branch => branch.getReader({ mode: 'byob' }));
6031cb0ef41Sopenharmony_ci
6041cb0ef41Sopenharmony_ci  const read1 = reader1.read(new Uint8Array([0x11]));
6051cb0ef41Sopenharmony_ci  await flushAsyncEvents();
6061cb0ef41Sopenharmony_ci  const read2 = reader2.read(new Uint8Array([0x22]));
6071cb0ef41Sopenharmony_ci  await flushAsyncEvents();
6081cb0ef41Sopenharmony_ci
6091cb0ef41Sopenharmony_ci  // We are reading into branch1's buffer.
6101cb0ef41Sopenharmony_ci  const byobRequest1 = rs.controller.byobRequest;
6111cb0ef41Sopenharmony_ci  assert_not_equals(byobRequest1, null);
6121cb0ef41Sopenharmony_ci  assert_typed_array_equals(byobRequest1.view, new Uint8Array([0x11]), 'byobRequest1.view');
6131cb0ef41Sopenharmony_ci
6141cb0ef41Sopenharmony_ci  // Cancelling branch2 should not affect the BYOB request.
6151cb0ef41Sopenharmony_ci  const cancel2 = reader2.cancel();
6161cb0ef41Sopenharmony_ci  const result2 = await read2;
6171cb0ef41Sopenharmony_ci  assert_equals(result2.done, true);
6181cb0ef41Sopenharmony_ci  assert_equals(result2.value, undefined);
6191cb0ef41Sopenharmony_ci  await flushAsyncEvents();
6201cb0ef41Sopenharmony_ci  const byobRequest2 = rs.controller.byobRequest;
6211cb0ef41Sopenharmony_ci  assert_typed_array_equals(byobRequest2.view, new Uint8Array([0x11]), 'byobRequest2.view');
6221cb0ef41Sopenharmony_ci
6231cb0ef41Sopenharmony_ci  // Cancelling branch1 should invalidate the BYOB request.
6241cb0ef41Sopenharmony_ci  const cancel1 = reader1.cancel();
6251cb0ef41Sopenharmony_ci  await cancelCalled;
6261cb0ef41Sopenharmony_ci  const byobRequest3 = rs.controller.byobRequest;
6271cb0ef41Sopenharmony_ci  assert_equals(byobRequest3, null);
6281cb0ef41Sopenharmony_ci  const result1 = await read1;
6291cb0ef41Sopenharmony_ci  assert_equals(result1.done, true);
6301cb0ef41Sopenharmony_ci  assert_equals(result1.value, undefined);
6311cb0ef41Sopenharmony_ci
6321cb0ef41Sopenharmony_ci  await Promise.all([cancel1, cancel2]);
6331cb0ef41Sopenharmony_ci
6341cb0ef41Sopenharmony_ci}, 'ReadableStream teeing with byte source: read from branch1 and branch2, cancel branch2, cancel branch1');
6351cb0ef41Sopenharmony_ci
6361cb0ef41Sopenharmony_cipromise_test(async () => {
6371cb0ef41Sopenharmony_ci
6381cb0ef41Sopenharmony_ci  const rs = recordingReadableStream({ type: 'bytes' });
6391cb0ef41Sopenharmony_ci
6401cb0ef41Sopenharmony_ci  const [reader1, reader2] = rs.tee().map(branch => branch.getReader({ mode: 'byob' }));
6411cb0ef41Sopenharmony_ci
6421cb0ef41Sopenharmony_ci  const read1 = reader1.read(new Uint8Array([0x11]));
6431cb0ef41Sopenharmony_ci  await flushAsyncEvents();
6441cb0ef41Sopenharmony_ci  const read2 = reader2.read(new Uint8Array([0x22]));
6451cb0ef41Sopenharmony_ci  await flushAsyncEvents();
6461cb0ef41Sopenharmony_ci
6471cb0ef41Sopenharmony_ci  // We are reading into branch1's buffer.
6481cb0ef41Sopenharmony_ci  assert_typed_array_equals(rs.controller.byobRequest.view, new Uint8Array([0x11]), 'first byobRequest.view');
6491cb0ef41Sopenharmony_ci
6501cb0ef41Sopenharmony_ci  // Cancelling branch2 should not affect the BYOB request.
6511cb0ef41Sopenharmony_ci  reader2.cancel();
6521cb0ef41Sopenharmony_ci  const result2 = await read2;
6531cb0ef41Sopenharmony_ci  assert_equals(result2.done, true);
6541cb0ef41Sopenharmony_ci  assert_equals(result2.value, undefined);
6551cb0ef41Sopenharmony_ci  await flushAsyncEvents();
6561cb0ef41Sopenharmony_ci  assert_typed_array_equals(rs.controller.byobRequest.view, new Uint8Array([0x11]), 'second byobRequest.view');
6571cb0ef41Sopenharmony_ci
6581cb0ef41Sopenharmony_ci  // Respond to the BYOB request.
6591cb0ef41Sopenharmony_ci  rs.controller.byobRequest.view[0] = 0x33;
6601cb0ef41Sopenharmony_ci  rs.controller.byobRequest.respond(1);
6611cb0ef41Sopenharmony_ci
6621cb0ef41Sopenharmony_ci  // branch1 should receive the read chunk.
6631cb0ef41Sopenharmony_ci  const result1 = await read1;
6641cb0ef41Sopenharmony_ci  assert_equals(result1.done, false);
6651cb0ef41Sopenharmony_ci  assert_typed_array_equals(result1.value, new Uint8Array([0x33]), 'first read() from branch1');
6661cb0ef41Sopenharmony_ci
6671cb0ef41Sopenharmony_ci}, 'ReadableStream teeing with byte source: read from branch1 and branch2, cancel branch2, enqueue to branch1');
6681cb0ef41Sopenharmony_ci
6691cb0ef41Sopenharmony_cipromise_test(async () => {
6701cb0ef41Sopenharmony_ci
6711cb0ef41Sopenharmony_ci  const rs = recordingReadableStream({ type: 'bytes' });
6721cb0ef41Sopenharmony_ci
6731cb0ef41Sopenharmony_ci  const [reader1, reader2] = rs.tee().map(branch => branch.getReader({ mode: 'byob' }));
6741cb0ef41Sopenharmony_ci
6751cb0ef41Sopenharmony_ci  const read1 = reader1.read(new Uint8Array([0x11]));
6761cb0ef41Sopenharmony_ci  await flushAsyncEvents();
6771cb0ef41Sopenharmony_ci  const read2 = reader2.read(new Uint8Array([0x22]));
6781cb0ef41Sopenharmony_ci  await flushAsyncEvents();
6791cb0ef41Sopenharmony_ci
6801cb0ef41Sopenharmony_ci  // We are reading into branch1's buffer.
6811cb0ef41Sopenharmony_ci  assert_typed_array_equals(rs.controller.byobRequest.view, new Uint8Array([0x11]), 'first byobRequest.view');
6821cb0ef41Sopenharmony_ci
6831cb0ef41Sopenharmony_ci  // Cancelling branch1 should not affect the BYOB request.
6841cb0ef41Sopenharmony_ci  reader1.cancel();
6851cb0ef41Sopenharmony_ci  const result1 = await read1;
6861cb0ef41Sopenharmony_ci  assert_equals(result1.done, true);
6871cb0ef41Sopenharmony_ci  assert_equals(result1.value, undefined);
6881cb0ef41Sopenharmony_ci  await flushAsyncEvents();
6891cb0ef41Sopenharmony_ci  assert_typed_array_equals(rs.controller.byobRequest.view, new Uint8Array([0x11]), 'second byobRequest.view');
6901cb0ef41Sopenharmony_ci
6911cb0ef41Sopenharmony_ci  // Respond to the BYOB request.
6921cb0ef41Sopenharmony_ci  rs.controller.byobRequest.view[0] = 0x33;
6931cb0ef41Sopenharmony_ci  rs.controller.byobRequest.respond(1);
6941cb0ef41Sopenharmony_ci
6951cb0ef41Sopenharmony_ci  // branch2 should receive the read chunk.
6961cb0ef41Sopenharmony_ci  const result2 = await read2;
6971cb0ef41Sopenharmony_ci  assert_equals(result2.done, false);
6981cb0ef41Sopenharmony_ci  assert_typed_array_equals(result2.value, new Uint8Array([0x33]), 'first read() from branch2');
6991cb0ef41Sopenharmony_ci
7001cb0ef41Sopenharmony_ci}, 'ReadableStream teeing with byte source: read from branch1 and branch2, cancel branch1, respond to branch2');
7011cb0ef41Sopenharmony_ci
7021cb0ef41Sopenharmony_cipromise_test(async () => {
7031cb0ef41Sopenharmony_ci
7041cb0ef41Sopenharmony_ci  let pullCount = 0;
7051cb0ef41Sopenharmony_ci  const byobRequestDefined = [];
7061cb0ef41Sopenharmony_ci  const rs = new ReadableStream({
7071cb0ef41Sopenharmony_ci    type: 'bytes',
7081cb0ef41Sopenharmony_ci    pull(c) {
7091cb0ef41Sopenharmony_ci      ++pullCount;
7101cb0ef41Sopenharmony_ci      byobRequestDefined.push(c.byobRequest !== null);
7111cb0ef41Sopenharmony_ci      c.enqueue(new Uint8Array([pullCount]));
7121cb0ef41Sopenharmony_ci    }
7131cb0ef41Sopenharmony_ci  });
7141cb0ef41Sopenharmony_ci
7151cb0ef41Sopenharmony_ci  const [branch1, _] = rs.tee();
7161cb0ef41Sopenharmony_ci  const reader1 = branch1.getReader({ mode: 'byob' });
7171cb0ef41Sopenharmony_ci
7181cb0ef41Sopenharmony_ci  const result1 = await reader1.read(new Uint8Array([0x11]));
7191cb0ef41Sopenharmony_ci  assert_equals(result1.done, false, 'first read should not be done');
7201cb0ef41Sopenharmony_ci  assert_typed_array_equals(result1.value, new Uint8Array([0x1]), 'first read');
7211cb0ef41Sopenharmony_ci  assert_equals(pullCount, 1, 'pull() should be called once');
7221cb0ef41Sopenharmony_ci  assert_equals(byobRequestDefined[0], true, 'should have created a BYOB request for first read');
7231cb0ef41Sopenharmony_ci
7241cb0ef41Sopenharmony_ci  reader1.releaseLock();
7251cb0ef41Sopenharmony_ci  const reader2 = branch1.getReader();
7261cb0ef41Sopenharmony_ci
7271cb0ef41Sopenharmony_ci  const result2 = await reader2.read();
7281cb0ef41Sopenharmony_ci  assert_equals(result2.done, false, 'second read should not be done');
7291cb0ef41Sopenharmony_ci  assert_typed_array_equals(result2.value, new Uint8Array([0x2]), 'second read');
7301cb0ef41Sopenharmony_ci  assert_equals(pullCount, 2, 'pull() should be called twice');
7311cb0ef41Sopenharmony_ci  assert_equals(byobRequestDefined[1], false, 'should not have created a BYOB request for second read');
7321cb0ef41Sopenharmony_ci
7331cb0ef41Sopenharmony_ci}, 'ReadableStream teeing with byte source: pull with BYOB reader, then pull with default reader');
7341cb0ef41Sopenharmony_ci
7351cb0ef41Sopenharmony_cipromise_test(async () => {
7361cb0ef41Sopenharmony_ci
7371cb0ef41Sopenharmony_ci  let pullCount = 0;
7381cb0ef41Sopenharmony_ci  const byobRequestDefined = [];
7391cb0ef41Sopenharmony_ci  const rs = new ReadableStream({
7401cb0ef41Sopenharmony_ci    type: 'bytes',
7411cb0ef41Sopenharmony_ci    pull(c) {
7421cb0ef41Sopenharmony_ci      ++pullCount;
7431cb0ef41Sopenharmony_ci      byobRequestDefined.push(c.byobRequest !== null);
7441cb0ef41Sopenharmony_ci      c.enqueue(new Uint8Array([pullCount]));
7451cb0ef41Sopenharmony_ci    }
7461cb0ef41Sopenharmony_ci  });
7471cb0ef41Sopenharmony_ci
7481cb0ef41Sopenharmony_ci  const [branch1, _] = rs.tee();
7491cb0ef41Sopenharmony_ci  const reader1 = branch1.getReader();
7501cb0ef41Sopenharmony_ci
7511cb0ef41Sopenharmony_ci  const result1 = await reader1.read();
7521cb0ef41Sopenharmony_ci  assert_equals(result1.done, false, 'first read should not be done');
7531cb0ef41Sopenharmony_ci  assert_typed_array_equals(result1.value, new Uint8Array([0x1]), 'first read');
7541cb0ef41Sopenharmony_ci  assert_equals(pullCount, 1, 'pull() should be called once');
7551cb0ef41Sopenharmony_ci  assert_equals(byobRequestDefined[0], false, 'should not have created a BYOB request for first read');
7561cb0ef41Sopenharmony_ci
7571cb0ef41Sopenharmony_ci  reader1.releaseLock();
7581cb0ef41Sopenharmony_ci  const reader2 = branch1.getReader({ mode: 'byob' });
7591cb0ef41Sopenharmony_ci
7601cb0ef41Sopenharmony_ci  const result2 = await reader2.read(new Uint8Array([0x22]));
7611cb0ef41Sopenharmony_ci  assert_equals(result2.done, false, 'second read should not be done');
7621cb0ef41Sopenharmony_ci  assert_typed_array_equals(result2.value, new Uint8Array([0x2]), 'second read');
7631cb0ef41Sopenharmony_ci  assert_equals(pullCount, 2, 'pull() should be called twice');
7641cb0ef41Sopenharmony_ci  assert_equals(byobRequestDefined[1], true, 'should have created a BYOB request for second read');
7651cb0ef41Sopenharmony_ci
7661cb0ef41Sopenharmony_ci}, 'ReadableStream teeing with byte source: pull with default reader, then pull with BYOB reader');
7671cb0ef41Sopenharmony_ci
7681cb0ef41Sopenharmony_cipromise_test(async () => {
7691cb0ef41Sopenharmony_ci
7701cb0ef41Sopenharmony_ci  const rs = recordingReadableStream({
7711cb0ef41Sopenharmony_ci    type: 'bytes'
7721cb0ef41Sopenharmony_ci  });
7731cb0ef41Sopenharmony_ci  const [reader1, reader2] = rs.tee().map(branch => branch.getReader({ mode: 'byob' }));
7741cb0ef41Sopenharmony_ci
7751cb0ef41Sopenharmony_ci  // Wait for each branch's start() promise to resolve.
7761cb0ef41Sopenharmony_ci  await flushAsyncEvents();
7771cb0ef41Sopenharmony_ci
7781cb0ef41Sopenharmony_ci  const read2 = reader2.read(new Uint8Array([0x22]));
7791cb0ef41Sopenharmony_ci  const read1 = reader1.read(new Uint8Array([0x11]));
7801cb0ef41Sopenharmony_ci  await flushAsyncEvents();
7811cb0ef41Sopenharmony_ci
7821cb0ef41Sopenharmony_ci  // branch2 should provide the BYOB request.
7831cb0ef41Sopenharmony_ci  const byobRequest = rs.controller.byobRequest;
7841cb0ef41Sopenharmony_ci  assert_typed_array_equals(byobRequest.view, new Uint8Array([0x22]), 'first BYOB request');
7851cb0ef41Sopenharmony_ci  byobRequest.view[0] = 0x01;
7861cb0ef41Sopenharmony_ci  byobRequest.respond(1);
7871cb0ef41Sopenharmony_ci
7881cb0ef41Sopenharmony_ci  const result1 = await read1;
7891cb0ef41Sopenharmony_ci  assert_equals(result1.done, false, 'first read should not be done');
7901cb0ef41Sopenharmony_ci  assert_typed_array_equals(result1.value, new Uint8Array([0x1]), 'first read');
7911cb0ef41Sopenharmony_ci
7921cb0ef41Sopenharmony_ci  const result2 = await read2;
7931cb0ef41Sopenharmony_ci  assert_equals(result2.done, false, 'second read should not be done');
7941cb0ef41Sopenharmony_ci  assert_typed_array_equals(result2.value, new Uint8Array([0x1]), 'second read');
7951cb0ef41Sopenharmony_ci
7961cb0ef41Sopenharmony_ci}, 'ReadableStream teeing with byte source: read from branch2, then read from branch1');
7971cb0ef41Sopenharmony_ci
7981cb0ef41Sopenharmony_cipromise_test(async () => {
7991cb0ef41Sopenharmony_ci
8001cb0ef41Sopenharmony_ci  const rs = recordingReadableStream({ type: 'bytes' });
8011cb0ef41Sopenharmony_ci  const [branch1, branch2] = rs.tee();
8021cb0ef41Sopenharmony_ci  const reader1 = branch1.getReader();
8031cb0ef41Sopenharmony_ci  const reader2 = branch2.getReader({ mode: 'byob' });
8041cb0ef41Sopenharmony_ci  await flushAsyncEvents();
8051cb0ef41Sopenharmony_ci
8061cb0ef41Sopenharmony_ci  const read1 = reader1.read();
8071cb0ef41Sopenharmony_ci  const read2 = reader2.read(new Uint8Array([0x22]));
8081cb0ef41Sopenharmony_ci  await flushAsyncEvents();
8091cb0ef41Sopenharmony_ci
8101cb0ef41Sopenharmony_ci  // There should be no BYOB request.
8111cb0ef41Sopenharmony_ci  assert_equals(rs.controller.byobRequest, null, 'first BYOB request');
8121cb0ef41Sopenharmony_ci
8131cb0ef41Sopenharmony_ci  // Close the stream.
8141cb0ef41Sopenharmony_ci  rs.controller.close();
8151cb0ef41Sopenharmony_ci
8161cb0ef41Sopenharmony_ci  const result1 = await read1;
8171cb0ef41Sopenharmony_ci  assert_equals(result1.done, true, 'read from branch1 should be done');
8181cb0ef41Sopenharmony_ci  assert_equals(result1.value, undefined, 'read from branch1');
8191cb0ef41Sopenharmony_ci
8201cb0ef41Sopenharmony_ci  // branch2 should get its buffer back.
8211cb0ef41Sopenharmony_ci  const result2 = await read2;
8221cb0ef41Sopenharmony_ci  assert_equals(result2.done, true, 'read from branch2 should be done');
8231cb0ef41Sopenharmony_ci  assert_typed_array_equals(result2.value, new Uint8Array([0x22]).subarray(0, 0), 'read from branch2');
8241cb0ef41Sopenharmony_ci
8251cb0ef41Sopenharmony_ci}, 'ReadableStream teeing with byte source: read from branch1 with default reader, then close while branch2 has pending BYOB read');
8261cb0ef41Sopenharmony_ci
8271cb0ef41Sopenharmony_cipromise_test(async () => {
8281cb0ef41Sopenharmony_ci
8291cb0ef41Sopenharmony_ci  const rs = recordingReadableStream({ type: 'bytes' });
8301cb0ef41Sopenharmony_ci  const [branch1, branch2] = rs.tee();
8311cb0ef41Sopenharmony_ci  const reader1 = branch1.getReader({ mode: 'byob' });
8321cb0ef41Sopenharmony_ci  const reader2 = branch2.getReader();
8331cb0ef41Sopenharmony_ci  await flushAsyncEvents();
8341cb0ef41Sopenharmony_ci
8351cb0ef41Sopenharmony_ci  const read2 = reader2.read();
8361cb0ef41Sopenharmony_ci  const read1 = reader1.read(new Uint8Array([0x11]));
8371cb0ef41Sopenharmony_ci  await flushAsyncEvents();
8381cb0ef41Sopenharmony_ci
8391cb0ef41Sopenharmony_ci  // There should be no BYOB request.
8401cb0ef41Sopenharmony_ci  assert_equals(rs.controller.byobRequest, null, 'first BYOB request');
8411cb0ef41Sopenharmony_ci
8421cb0ef41Sopenharmony_ci  // Close the stream.
8431cb0ef41Sopenharmony_ci  rs.controller.close();
8441cb0ef41Sopenharmony_ci
8451cb0ef41Sopenharmony_ci  const result2 = await read2;
8461cb0ef41Sopenharmony_ci  assert_equals(result2.done, true, 'read from branch2 should be done');
8471cb0ef41Sopenharmony_ci  assert_equals(result2.value, undefined, 'read from branch2');
8481cb0ef41Sopenharmony_ci
8491cb0ef41Sopenharmony_ci  // branch1 should get its buffer back.
8501cb0ef41Sopenharmony_ci  const result1 = await read1;
8511cb0ef41Sopenharmony_ci  assert_equals(result1.done, true, 'read from branch1 should be done');
8521cb0ef41Sopenharmony_ci  assert_typed_array_equals(result1.value, new Uint8Array([0x11]).subarray(0, 0), 'read from branch1');
8531cb0ef41Sopenharmony_ci
8541cb0ef41Sopenharmony_ci}, 'ReadableStream teeing with byte source: read from branch2 with default reader, then close while branch1 has pending BYOB read');
8551cb0ef41Sopenharmony_ci
8561cb0ef41Sopenharmony_cipromise_test(async () => {
8571cb0ef41Sopenharmony_ci
8581cb0ef41Sopenharmony_ci  const rs = recordingReadableStream({ type: 'bytes' });
8591cb0ef41Sopenharmony_ci  const [reader1, reader2] = rs.tee().map(branch => branch.getReader({ mode: 'byob' }));
8601cb0ef41Sopenharmony_ci  await flushAsyncEvents();
8611cb0ef41Sopenharmony_ci
8621cb0ef41Sopenharmony_ci  const read1 = reader1.read(new Uint8Array([0x11]));
8631cb0ef41Sopenharmony_ci  const read2 = reader2.read(new Uint8Array([0x22]));
8641cb0ef41Sopenharmony_ci  await flushAsyncEvents();
8651cb0ef41Sopenharmony_ci
8661cb0ef41Sopenharmony_ci  // branch1 should provide the BYOB request.
8671cb0ef41Sopenharmony_ci  const byobRequest = rs.controller.byobRequest;
8681cb0ef41Sopenharmony_ci  assert_typed_array_equals(byobRequest.view, new Uint8Array([0x11]), 'first BYOB request');
8691cb0ef41Sopenharmony_ci
8701cb0ef41Sopenharmony_ci  // Close the stream.
8711cb0ef41Sopenharmony_ci  rs.controller.close();
8721cb0ef41Sopenharmony_ci  byobRequest.respond(0);
8731cb0ef41Sopenharmony_ci
8741cb0ef41Sopenharmony_ci  // Both branches should get their buffers back.
8751cb0ef41Sopenharmony_ci  const result1 = await read1;
8761cb0ef41Sopenharmony_ci  assert_equals(result1.done, true, 'first read should be done');
8771cb0ef41Sopenharmony_ci  assert_typed_array_equals(result1.value, new Uint8Array([0x11]).subarray(0, 0), 'first read');
8781cb0ef41Sopenharmony_ci
8791cb0ef41Sopenharmony_ci  const result2 = await read2;
8801cb0ef41Sopenharmony_ci  assert_equals(result2.done, true, 'second read should be done');
8811cb0ef41Sopenharmony_ci  assert_typed_array_equals(result2.value, new Uint8Array([0x22]).subarray(0, 0), 'second read');
8821cb0ef41Sopenharmony_ci
8831cb0ef41Sopenharmony_ci}, 'ReadableStream teeing with byte source: close when both branches have pending BYOB reads');
8841cb0ef41Sopenharmony_ci
8851cb0ef41Sopenharmony_cipromise_test(async () => {
8861cb0ef41Sopenharmony_ci
8871cb0ef41Sopenharmony_ci  const rs = recordingReadableStream({ type: 'bytes' });
8881cb0ef41Sopenharmony_ci
8891cb0ef41Sopenharmony_ci  const [reader1, reader2] = rs.tee().map(branch => branch.getReader());
8901cb0ef41Sopenharmony_ci  const branch1Reads = [reader1.read(), reader1.read()];
8911cb0ef41Sopenharmony_ci  const branch2Reads = [reader2.read(), reader2.read()];
8921cb0ef41Sopenharmony_ci
8931cb0ef41Sopenharmony_ci  await flushAsyncEvents();
8941cb0ef41Sopenharmony_ci  rs.controller.enqueue(new Uint8Array([0x11]));
8951cb0ef41Sopenharmony_ci  rs.controller.close();
8961cb0ef41Sopenharmony_ci
8971cb0ef41Sopenharmony_ci  const result1 = await branch1Reads[0];
8981cb0ef41Sopenharmony_ci  assert_equals(result1.done, false, 'first read() from branch1 should be not done');
8991cb0ef41Sopenharmony_ci  assert_typed_array_equals(result1.value, new Uint8Array([0x11]), 'first chunk from branch1 should be correct');
9001cb0ef41Sopenharmony_ci  const result2 = await branch2Reads[0];
9011cb0ef41Sopenharmony_ci  assert_equals(result2.done, false, 'first read() from branch2 should be not done');
9021cb0ef41Sopenharmony_ci  assert_typed_array_equals(result2.value, new Uint8Array([0x11]), 'first chunk from branch2 should be correct');
9031cb0ef41Sopenharmony_ci
9041cb0ef41Sopenharmony_ci  assert_object_equals(await branch1Reads[1], { value: undefined, done: true }, 'second read() from branch1 should be done');
9051cb0ef41Sopenharmony_ci  assert_object_equals(await branch2Reads[1], { value: undefined, done: true }, 'second read() from branch2 should be done');
9061cb0ef41Sopenharmony_ci
9071cb0ef41Sopenharmony_ci}, 'ReadableStream teeing with byte source: enqueue() and close() while both branches are pulling');
9081cb0ef41Sopenharmony_ci
9091cb0ef41Sopenharmony_cipromise_test(async () => {
9101cb0ef41Sopenharmony_ci
9111cb0ef41Sopenharmony_ci  const rs = recordingReadableStream({ type: 'bytes' });
9121cb0ef41Sopenharmony_ci
9131cb0ef41Sopenharmony_ci  const [reader1, reader2] = rs.tee().map(branch => branch.getReader({ mode: 'byob' }));
9141cb0ef41Sopenharmony_ci  const branch1Reads = [reader1.read(new Uint8Array(1)), reader1.read(new Uint8Array(1))];
9151cb0ef41Sopenharmony_ci  const branch2Reads = [reader2.read(new Uint8Array(1)), reader2.read(new Uint8Array(1))];
9161cb0ef41Sopenharmony_ci
9171cb0ef41Sopenharmony_ci  await flushAsyncEvents();
9181cb0ef41Sopenharmony_ci  rs.controller.byobRequest.view[0] = 0x11;
9191cb0ef41Sopenharmony_ci  rs.controller.byobRequest.respond(1);
9201cb0ef41Sopenharmony_ci  rs.controller.close();
9211cb0ef41Sopenharmony_ci
9221cb0ef41Sopenharmony_ci  const result1 = await branch1Reads[0];
9231cb0ef41Sopenharmony_ci  assert_equals(result1.done, false, 'first read() from branch1 should be not done');
9241cb0ef41Sopenharmony_ci  assert_typed_array_equals(result1.value, new Uint8Array([0x11]), 'first chunk from branch1 should be correct');
9251cb0ef41Sopenharmony_ci  const result2 = await branch2Reads[0];
9261cb0ef41Sopenharmony_ci  assert_equals(result2.done, false, 'first read() from branch2 should be not done');
9271cb0ef41Sopenharmony_ci  assert_typed_array_equals(result2.value, new Uint8Array([0x11]), 'first chunk from branch2 should be correct');
9281cb0ef41Sopenharmony_ci
9291cb0ef41Sopenharmony_ci  const result3 = await branch1Reads[1];
9301cb0ef41Sopenharmony_ci  assert_equals(result3.done, true, 'second read() from branch1 should be done');
9311cb0ef41Sopenharmony_ci  assert_typed_array_equals(result3.value, new Uint8Array([0]).subarray(0, 0), 'second chunk from branch1 should be correct');
9321cb0ef41Sopenharmony_ci  const result4 = await branch2Reads[1];
9331cb0ef41Sopenharmony_ci  assert_equals(result4.done, true, 'second read() from branch2 should be done');
9341cb0ef41Sopenharmony_ci  assert_typed_array_equals(result4.value, new Uint8Array([0]).subarray(0, 0), 'second chunk from branch2 should be correct');
9351cb0ef41Sopenharmony_ci
9361cb0ef41Sopenharmony_ci}, 'ReadableStream teeing with byte source: respond() and close() while both branches are pulling');
937