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();
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: rs.tee() returns an array of two ReadableStreams');
191cb0ef41Sopenharmony_ci
201cb0ef41Sopenharmony_cipromise_test(t => {
211cb0ef41Sopenharmony_ci
221cb0ef41Sopenharmony_ci  const rs = new ReadableStream({
231cb0ef41Sopenharmony_ci    start(c) {
241cb0ef41Sopenharmony_ci      c.enqueue('a');
251cb0ef41Sopenharmony_ci      c.enqueue('b');
261cb0ef41Sopenharmony_ci      c.close();
271cb0ef41Sopenharmony_ci    }
281cb0ef41Sopenharmony_ci  });
291cb0ef41Sopenharmony_ci
301cb0ef41Sopenharmony_ci  const branch = rs.tee();
311cb0ef41Sopenharmony_ci  const branch1 = branch[0];
321cb0ef41Sopenharmony_ci  const branch2 = branch[1];
331cb0ef41Sopenharmony_ci  const reader1 = branch1.getReader();
341cb0ef41Sopenharmony_ci  const reader2 = branch2.getReader();
351cb0ef41Sopenharmony_ci
361cb0ef41Sopenharmony_ci  reader2.closed.then(t.unreached_func('branch2 should not be closed'));
371cb0ef41Sopenharmony_ci
381cb0ef41Sopenharmony_ci  return Promise.all([
391cb0ef41Sopenharmony_ci    reader1.closed,
401cb0ef41Sopenharmony_ci    reader1.read().then(r => {
411cb0ef41Sopenharmony_ci      assert_object_equals(r, { value: 'a', done: false }, 'first chunk from branch1 should be correct');
421cb0ef41Sopenharmony_ci    }),
431cb0ef41Sopenharmony_ci    reader1.read().then(r => {
441cb0ef41Sopenharmony_ci      assert_object_equals(r, { value: 'b', done: false }, 'second chunk from branch1 should be correct');
451cb0ef41Sopenharmony_ci    }),
461cb0ef41Sopenharmony_ci    reader1.read().then(r => {
471cb0ef41Sopenharmony_ci      assert_object_equals(r, { value: undefined, done: true }, 'third read() from branch1 should be done');
481cb0ef41Sopenharmony_ci    }),
491cb0ef41Sopenharmony_ci    reader2.read().then(r => {
501cb0ef41Sopenharmony_ci      assert_object_equals(r, { value: 'a', done: false }, 'first chunk from branch2 should be correct');
511cb0ef41Sopenharmony_ci    })
521cb0ef41Sopenharmony_ci  ]);
531cb0ef41Sopenharmony_ci
541cb0ef41Sopenharmony_ci}, 'ReadableStream teeing: should be able to read one branch to the end without affecting the other');
551cb0ef41Sopenharmony_ci
561cb0ef41Sopenharmony_cipromise_test(() => {
571cb0ef41Sopenharmony_ci
581cb0ef41Sopenharmony_ci  const theObject = { the: 'test object' };
591cb0ef41Sopenharmony_ci  const rs = new ReadableStream({
601cb0ef41Sopenharmony_ci    start(c) {
611cb0ef41Sopenharmony_ci      c.enqueue(theObject);
621cb0ef41Sopenharmony_ci    }
631cb0ef41Sopenharmony_ci  });
641cb0ef41Sopenharmony_ci
651cb0ef41Sopenharmony_ci  const branch = rs.tee();
661cb0ef41Sopenharmony_ci  const branch1 = branch[0];
671cb0ef41Sopenharmony_ci  const branch2 = branch[1];
681cb0ef41Sopenharmony_ci  const reader1 = branch1.getReader();
691cb0ef41Sopenharmony_ci  const reader2 = branch2.getReader();
701cb0ef41Sopenharmony_ci
711cb0ef41Sopenharmony_ci  return Promise.all([reader1.read(), reader2.read()]).then(values => {
721cb0ef41Sopenharmony_ci    assert_object_equals(values[0], values[1], 'the values should be equal');
731cb0ef41Sopenharmony_ci  });
741cb0ef41Sopenharmony_ci
751cb0ef41Sopenharmony_ci}, 'ReadableStream teeing: values should be equal across each branch');
761cb0ef41Sopenharmony_ci
771cb0ef41Sopenharmony_cipromise_test(t => {
781cb0ef41Sopenharmony_ci
791cb0ef41Sopenharmony_ci  const theError = { name: 'boo!' };
801cb0ef41Sopenharmony_ci  const rs = new ReadableStream({
811cb0ef41Sopenharmony_ci    start(c) {
821cb0ef41Sopenharmony_ci      c.enqueue('a');
831cb0ef41Sopenharmony_ci      c.enqueue('b');
841cb0ef41Sopenharmony_ci    },
851cb0ef41Sopenharmony_ci    pull() {
861cb0ef41Sopenharmony_ci      throw theError;
871cb0ef41Sopenharmony_ci    }
881cb0ef41Sopenharmony_ci  });
891cb0ef41Sopenharmony_ci
901cb0ef41Sopenharmony_ci  const branches = rs.tee();
911cb0ef41Sopenharmony_ci  const reader1 = branches[0].getReader();
921cb0ef41Sopenharmony_ci  const reader2 = branches[1].getReader();
931cb0ef41Sopenharmony_ci
941cb0ef41Sopenharmony_ci  reader1.label = 'reader1';
951cb0ef41Sopenharmony_ci  reader2.label = 'reader2';
961cb0ef41Sopenharmony_ci
971cb0ef41Sopenharmony_ci  return Promise.all([
981cb0ef41Sopenharmony_ci    promise_rejects_exactly(t, theError, reader1.closed),
991cb0ef41Sopenharmony_ci    promise_rejects_exactly(t, theError, reader2.closed),
1001cb0ef41Sopenharmony_ci    reader1.read().then(r => {
1011cb0ef41Sopenharmony_ci      assert_object_equals(r, { value: 'a', done: false }, 'should be able to read the first chunk in branch1');
1021cb0ef41Sopenharmony_ci    }),
1031cb0ef41Sopenharmony_ci    reader1.read().then(r => {
1041cb0ef41Sopenharmony_ci      assert_object_equals(r, { value: 'b', done: false }, 'should be able to read the second chunk in branch1');
1051cb0ef41Sopenharmony_ci
1061cb0ef41Sopenharmony_ci      return promise_rejects_exactly(t, theError, reader2.read());
1071cb0ef41Sopenharmony_ci    })
1081cb0ef41Sopenharmony_ci    .then(() => promise_rejects_exactly(t, theError, reader1.read()))
1091cb0ef41Sopenharmony_ci  ]);
1101cb0ef41Sopenharmony_ci
1111cb0ef41Sopenharmony_ci}, 'ReadableStream teeing: errors in the source should propagate to both branches');
1121cb0ef41Sopenharmony_ci
1131cb0ef41Sopenharmony_cipromise_test(() => {
1141cb0ef41Sopenharmony_ci
1151cb0ef41Sopenharmony_ci  const rs = new ReadableStream({
1161cb0ef41Sopenharmony_ci    start(c) {
1171cb0ef41Sopenharmony_ci      c.enqueue('a');
1181cb0ef41Sopenharmony_ci      c.enqueue('b');
1191cb0ef41Sopenharmony_ci      c.close();
1201cb0ef41Sopenharmony_ci    }
1211cb0ef41Sopenharmony_ci  });
1221cb0ef41Sopenharmony_ci
1231cb0ef41Sopenharmony_ci  const branches = rs.tee();
1241cb0ef41Sopenharmony_ci  const branch1 = branches[0];
1251cb0ef41Sopenharmony_ci  const branch2 = branches[1];
1261cb0ef41Sopenharmony_ci  branch1.cancel();
1271cb0ef41Sopenharmony_ci
1281cb0ef41Sopenharmony_ci  return Promise.all([
1291cb0ef41Sopenharmony_ci    readableStreamToArray(branch1).then(chunks => {
1301cb0ef41Sopenharmony_ci      assert_array_equals(chunks, [], 'branch1 should have no chunks');
1311cb0ef41Sopenharmony_ci    }),
1321cb0ef41Sopenharmony_ci    readableStreamToArray(branch2).then(chunks => {
1331cb0ef41Sopenharmony_ci      assert_array_equals(chunks, ['a', 'b'], 'branch2 should have two chunks');
1341cb0ef41Sopenharmony_ci    })
1351cb0ef41Sopenharmony_ci  ]);
1361cb0ef41Sopenharmony_ci
1371cb0ef41Sopenharmony_ci}, 'ReadableStream teeing: canceling branch1 should not impact branch2');
1381cb0ef41Sopenharmony_ci
1391cb0ef41Sopenharmony_cipromise_test(() => {
1401cb0ef41Sopenharmony_ci
1411cb0ef41Sopenharmony_ci  const rs = new ReadableStream({
1421cb0ef41Sopenharmony_ci    start(c) {
1431cb0ef41Sopenharmony_ci      c.enqueue('a');
1441cb0ef41Sopenharmony_ci      c.enqueue('b');
1451cb0ef41Sopenharmony_ci      c.close();
1461cb0ef41Sopenharmony_ci    }
1471cb0ef41Sopenharmony_ci  });
1481cb0ef41Sopenharmony_ci
1491cb0ef41Sopenharmony_ci  const branches = rs.tee();
1501cb0ef41Sopenharmony_ci  const branch1 = branches[0];
1511cb0ef41Sopenharmony_ci  const branch2 = branches[1];
1521cb0ef41Sopenharmony_ci  branch2.cancel();
1531cb0ef41Sopenharmony_ci
1541cb0ef41Sopenharmony_ci  return Promise.all([
1551cb0ef41Sopenharmony_ci    readableStreamToArray(branch1).then(chunks => {
1561cb0ef41Sopenharmony_ci      assert_array_equals(chunks, ['a', 'b'], 'branch1 should have two chunks');
1571cb0ef41Sopenharmony_ci    }),
1581cb0ef41Sopenharmony_ci    readableStreamToArray(branch2).then(chunks => {
1591cb0ef41Sopenharmony_ci      assert_array_equals(chunks, [], 'branch2 should have no chunks');
1601cb0ef41Sopenharmony_ci    })
1611cb0ef41Sopenharmony_ci  ]);
1621cb0ef41Sopenharmony_ci
1631cb0ef41Sopenharmony_ci}, 'ReadableStream teeing: canceling branch2 should not impact branch1');
1641cb0ef41Sopenharmony_ci
1651cb0ef41Sopenharmony_citemplatedRSTeeCancel('ReadableStream teeing', (extras) => {
1661cb0ef41Sopenharmony_ci  return new ReadableStream({ ...extras });
1671cb0ef41Sopenharmony_ci});
1681cb0ef41Sopenharmony_ci
1691cb0ef41Sopenharmony_cipromise_test(t => {
1701cb0ef41Sopenharmony_ci
1711cb0ef41Sopenharmony_ci  let controller;
1721cb0ef41Sopenharmony_ci  const stream = new ReadableStream({ start(c) { controller = c; } });
1731cb0ef41Sopenharmony_ci  const [branch1, branch2] = stream.tee();
1741cb0ef41Sopenharmony_ci
1751cb0ef41Sopenharmony_ci  const error = new Error();
1761cb0ef41Sopenharmony_ci  error.name = 'distinctive';
1771cb0ef41Sopenharmony_ci
1781cb0ef41Sopenharmony_ci  // Ensure neither branch is waiting in ReadableStreamDefaultReaderRead().
1791cb0ef41Sopenharmony_ci  controller.enqueue();
1801cb0ef41Sopenharmony_ci  controller.enqueue();
1811cb0ef41Sopenharmony_ci
1821cb0ef41Sopenharmony_ci  return delay(0).then(() => {
1831cb0ef41Sopenharmony_ci    // This error will have to be detected via [[closedPromise]].
1841cb0ef41Sopenharmony_ci    controller.error(error);
1851cb0ef41Sopenharmony_ci
1861cb0ef41Sopenharmony_ci    const reader1 = branch1.getReader();
1871cb0ef41Sopenharmony_ci    const reader2 = branch2.getReader();
1881cb0ef41Sopenharmony_ci
1891cb0ef41Sopenharmony_ci    return Promise.all([
1901cb0ef41Sopenharmony_ci      promise_rejects_exactly(t, error, reader1.closed, 'reader1.closed should reject'),
1911cb0ef41Sopenharmony_ci      promise_rejects_exactly(t, error, reader2.closed, 'reader2.closed should reject')
1921cb0ef41Sopenharmony_ci    ]);
1931cb0ef41Sopenharmony_ci  });
1941cb0ef41Sopenharmony_ci
1951cb0ef41Sopenharmony_ci}, 'ReadableStream teeing: erroring a teed stream should error both branches');
1961cb0ef41Sopenharmony_ci
1971cb0ef41Sopenharmony_cipromise_test(() => {
1981cb0ef41Sopenharmony_ci
1991cb0ef41Sopenharmony_ci  let controller;
2001cb0ef41Sopenharmony_ci  const rs = new ReadableStream({
2011cb0ef41Sopenharmony_ci    start(c) {
2021cb0ef41Sopenharmony_ci      controller = c;
2031cb0ef41Sopenharmony_ci    }
2041cb0ef41Sopenharmony_ci  });
2051cb0ef41Sopenharmony_ci
2061cb0ef41Sopenharmony_ci  const branches = rs.tee();
2071cb0ef41Sopenharmony_ci  const reader1 = branches[0].getReader();
2081cb0ef41Sopenharmony_ci  const reader2 = branches[1].getReader();
2091cb0ef41Sopenharmony_ci
2101cb0ef41Sopenharmony_ci  const promise = Promise.all([reader1.closed, reader2.closed]);
2111cb0ef41Sopenharmony_ci
2121cb0ef41Sopenharmony_ci  controller.close();
2131cb0ef41Sopenharmony_ci  return promise;
2141cb0ef41Sopenharmony_ci
2151cb0ef41Sopenharmony_ci}, 'ReadableStream teeing: closing the original should immediately close the branches');
2161cb0ef41Sopenharmony_ci
2171cb0ef41Sopenharmony_cipromise_test(t => {
2181cb0ef41Sopenharmony_ci
2191cb0ef41Sopenharmony_ci  let controller;
2201cb0ef41Sopenharmony_ci  const rs = new ReadableStream({
2211cb0ef41Sopenharmony_ci    start(c) {
2221cb0ef41Sopenharmony_ci      controller = c;
2231cb0ef41Sopenharmony_ci    }
2241cb0ef41Sopenharmony_ci  });
2251cb0ef41Sopenharmony_ci
2261cb0ef41Sopenharmony_ci  const branches = rs.tee();
2271cb0ef41Sopenharmony_ci  const reader1 = branches[0].getReader();
2281cb0ef41Sopenharmony_ci  const reader2 = branches[1].getReader();
2291cb0ef41Sopenharmony_ci
2301cb0ef41Sopenharmony_ci  const theError = { name: 'boo!' };
2311cb0ef41Sopenharmony_ci  const promise = Promise.all([
2321cb0ef41Sopenharmony_ci    promise_rejects_exactly(t, theError, reader1.closed),
2331cb0ef41Sopenharmony_ci    promise_rejects_exactly(t, theError, reader2.closed)
2341cb0ef41Sopenharmony_ci  ]);
2351cb0ef41Sopenharmony_ci
2361cb0ef41Sopenharmony_ci  controller.error(theError);
2371cb0ef41Sopenharmony_ci  return promise;
2381cb0ef41Sopenharmony_ci
2391cb0ef41Sopenharmony_ci}, 'ReadableStream teeing: erroring the original should immediately error the branches');
2401cb0ef41Sopenharmony_ci
2411cb0ef41Sopenharmony_cipromise_test(async t => {
2421cb0ef41Sopenharmony_ci
2431cb0ef41Sopenharmony_ci  let controller;
2441cb0ef41Sopenharmony_ci  const rs = new ReadableStream({
2451cb0ef41Sopenharmony_ci    start(c) {
2461cb0ef41Sopenharmony_ci      controller = c;
2471cb0ef41Sopenharmony_ci    }
2481cb0ef41Sopenharmony_ci  });
2491cb0ef41Sopenharmony_ci
2501cb0ef41Sopenharmony_ci  const [reader1, reader2] = rs.tee().map(branch => branch.getReader());
2511cb0ef41Sopenharmony_ci  const cancelPromise = reader2.cancel();
2521cb0ef41Sopenharmony_ci
2531cb0ef41Sopenharmony_ci  controller.enqueue('a');
2541cb0ef41Sopenharmony_ci
2551cb0ef41Sopenharmony_ci  const read1 = await reader1.read();
2561cb0ef41Sopenharmony_ci  assert_object_equals(read1, { value: 'a', done: false }, 'first read() from branch1 should fulfill with the chunk');
2571cb0ef41Sopenharmony_ci
2581cb0ef41Sopenharmony_ci  controller.close();
2591cb0ef41Sopenharmony_ci
2601cb0ef41Sopenharmony_ci  const read2 = await reader1.read();
2611cb0ef41Sopenharmony_ci  assert_object_equals(read2, { value: undefined, done: true }, 'second read() from branch1 should be done');
2621cb0ef41Sopenharmony_ci
2631cb0ef41Sopenharmony_ci  await Promise.all([
2641cb0ef41Sopenharmony_ci    reader1.closed,
2651cb0ef41Sopenharmony_ci    cancelPromise
2661cb0ef41Sopenharmony_ci  ]);
2671cb0ef41Sopenharmony_ci
2681cb0ef41Sopenharmony_ci}, 'ReadableStream teeing: canceling branch1 should finish when branch2 reads until end of stream');
2691cb0ef41Sopenharmony_ci
2701cb0ef41Sopenharmony_cipromise_test(async t => {
2711cb0ef41Sopenharmony_ci
2721cb0ef41Sopenharmony_ci  let controller;
2731cb0ef41Sopenharmony_ci  const theError = { name: 'boo!' };
2741cb0ef41Sopenharmony_ci  const rs = new ReadableStream({
2751cb0ef41Sopenharmony_ci    start(c) {
2761cb0ef41Sopenharmony_ci      controller = c;
2771cb0ef41Sopenharmony_ci    }
2781cb0ef41Sopenharmony_ci  });
2791cb0ef41Sopenharmony_ci
2801cb0ef41Sopenharmony_ci  const [reader1, reader2] = rs.tee().map(branch => branch.getReader());
2811cb0ef41Sopenharmony_ci  const cancelPromise = reader2.cancel();
2821cb0ef41Sopenharmony_ci
2831cb0ef41Sopenharmony_ci  controller.error(theError);
2841cb0ef41Sopenharmony_ci
2851cb0ef41Sopenharmony_ci  await Promise.all([
2861cb0ef41Sopenharmony_ci    promise_rejects_exactly(t, theError, reader1.read()),
2871cb0ef41Sopenharmony_ci    cancelPromise
2881cb0ef41Sopenharmony_ci  ]);
2891cb0ef41Sopenharmony_ci
2901cb0ef41Sopenharmony_ci}, 'ReadableStream teeing: canceling branch1 should finish when original stream errors');
2911cb0ef41Sopenharmony_ci
2921cb0ef41Sopenharmony_cipromise_test(async () => {
2931cb0ef41Sopenharmony_ci
2941cb0ef41Sopenharmony_ci  const rs = new ReadableStream({});
2951cb0ef41Sopenharmony_ci
2961cb0ef41Sopenharmony_ci  const [branch1, branch2] = rs.tee();
2971cb0ef41Sopenharmony_ci
2981cb0ef41Sopenharmony_ci  const cancel1 = branch1.cancel();
2991cb0ef41Sopenharmony_ci  await flushAsyncEvents();
3001cb0ef41Sopenharmony_ci  const cancel2 = branch2.cancel();
3011cb0ef41Sopenharmony_ci
3021cb0ef41Sopenharmony_ci  await Promise.all([cancel1, cancel2]);
3031cb0ef41Sopenharmony_ci
3041cb0ef41Sopenharmony_ci}, 'ReadableStream teeing: canceling both branches in sequence with delay');
3051cb0ef41Sopenharmony_ci
3061cb0ef41Sopenharmony_cipromise_test(async t => {
3071cb0ef41Sopenharmony_ci
3081cb0ef41Sopenharmony_ci  const theError = { name: 'boo!' };
3091cb0ef41Sopenharmony_ci  const rs = new ReadableStream({
3101cb0ef41Sopenharmony_ci    cancel() {
3111cb0ef41Sopenharmony_ci      throw theError;
3121cb0ef41Sopenharmony_ci    }
3131cb0ef41Sopenharmony_ci  });
3141cb0ef41Sopenharmony_ci
3151cb0ef41Sopenharmony_ci  const [branch1, branch2] = rs.tee();
3161cb0ef41Sopenharmony_ci
3171cb0ef41Sopenharmony_ci  const cancel1 = branch1.cancel();
3181cb0ef41Sopenharmony_ci  await flushAsyncEvents();
3191cb0ef41Sopenharmony_ci  const cancel2 = branch2.cancel();
3201cb0ef41Sopenharmony_ci
3211cb0ef41Sopenharmony_ci  await Promise.all([
3221cb0ef41Sopenharmony_ci    promise_rejects_exactly(t, theError, cancel1),
3231cb0ef41Sopenharmony_ci    promise_rejects_exactly(t, theError, cancel2)
3241cb0ef41Sopenharmony_ci  ]);
3251cb0ef41Sopenharmony_ci
3261cb0ef41Sopenharmony_ci}, 'ReadableStream teeing: failing to cancel when canceling both branches in sequence with delay');
3271cb0ef41Sopenharmony_ci
3281cb0ef41Sopenharmony_citest(t => {
3291cb0ef41Sopenharmony_ci
3301cb0ef41Sopenharmony_ci  // Copy original global.
3311cb0ef41Sopenharmony_ci  const oldReadableStream = ReadableStream;
3321cb0ef41Sopenharmony_ci  const getReader = ReadableStream.prototype.getReader;
3331cb0ef41Sopenharmony_ci
3341cb0ef41Sopenharmony_ci  const origRS = new ReadableStream();
3351cb0ef41Sopenharmony_ci
3361cb0ef41Sopenharmony_ci  // Replace the global ReadableStream constructor with one that doesn't work.
3371cb0ef41Sopenharmony_ci  ReadableStream = function() {
3381cb0ef41Sopenharmony_ci    throw new Error('global ReadableStream constructor called');
3391cb0ef41Sopenharmony_ci  };
3401cb0ef41Sopenharmony_ci  t.add_cleanup(() => {
3411cb0ef41Sopenharmony_ci    ReadableStream = oldReadableStream;
3421cb0ef41Sopenharmony_ci  });
3431cb0ef41Sopenharmony_ci
3441cb0ef41Sopenharmony_ci  // This will probably fail if the global ReadableStream constructor was used.
3451cb0ef41Sopenharmony_ci  const [rs1, rs2] = origRS.tee();
3461cb0ef41Sopenharmony_ci
3471cb0ef41Sopenharmony_ci  // These will definitely fail if the global ReadableStream constructor was used.
3481cb0ef41Sopenharmony_ci  assert_not_equals(getReader.call(rs1), undefined, 'getReader should work on rs1');
3491cb0ef41Sopenharmony_ci  assert_not_equals(getReader.call(rs2), undefined, 'getReader should work on rs2');
3501cb0ef41Sopenharmony_ci
3511cb0ef41Sopenharmony_ci}, 'ReadableStreamTee should not use a modified ReadableStream constructor from the global object');
3521cb0ef41Sopenharmony_ci
3531cb0ef41Sopenharmony_cipromise_test(t => {
3541cb0ef41Sopenharmony_ci
3551cb0ef41Sopenharmony_ci  const rs = recordingReadableStream({}, { highWaterMark: 0 });
3561cb0ef41Sopenharmony_ci
3571cb0ef41Sopenharmony_ci  // Create two branches, each with a HWM of 1. This should result in one
3581cb0ef41Sopenharmony_ci  // chunk being pulled, not two.
3591cb0ef41Sopenharmony_ci  rs.tee();
3601cb0ef41Sopenharmony_ci  return flushAsyncEvents().then(() => {
3611cb0ef41Sopenharmony_ci    assert_array_equals(rs.events, ['pull'], 'pull should only be called once');
3621cb0ef41Sopenharmony_ci  });
3631cb0ef41Sopenharmony_ci
3641cb0ef41Sopenharmony_ci}, 'ReadableStreamTee should not pull more chunks than can fit in the branch queue');
3651cb0ef41Sopenharmony_ci
3661cb0ef41Sopenharmony_cipromise_test(t => {
3671cb0ef41Sopenharmony_ci
3681cb0ef41Sopenharmony_ci  const rs = recordingReadableStream({
3691cb0ef41Sopenharmony_ci    pull(controller) {
3701cb0ef41Sopenharmony_ci      controller.enqueue('a');
3711cb0ef41Sopenharmony_ci    }
3721cb0ef41Sopenharmony_ci  }, { highWaterMark: 0 });
3731cb0ef41Sopenharmony_ci
3741cb0ef41Sopenharmony_ci  const [reader1, reader2] = rs.tee().map(branch => branch.getReader());
3751cb0ef41Sopenharmony_ci  return Promise.all([reader1.read(), reader2.read()])
3761cb0ef41Sopenharmony_ci      .then(() => {
3771cb0ef41Sopenharmony_ci    assert_array_equals(rs.events, ['pull', 'pull'], 'pull should be called twice');
3781cb0ef41Sopenharmony_ci  });
3791cb0ef41Sopenharmony_ci
3801cb0ef41Sopenharmony_ci}, 'ReadableStreamTee should only pull enough to fill the emptiest queue');
3811cb0ef41Sopenharmony_ci
3821cb0ef41Sopenharmony_cipromise_test(t => {
3831cb0ef41Sopenharmony_ci
3841cb0ef41Sopenharmony_ci  const rs = recordingReadableStream({}, { highWaterMark: 0 });
3851cb0ef41Sopenharmony_ci  const theError = { name: 'boo!' };
3861cb0ef41Sopenharmony_ci
3871cb0ef41Sopenharmony_ci  rs.controller.error(theError);
3881cb0ef41Sopenharmony_ci
3891cb0ef41Sopenharmony_ci  const [reader1, reader2] = rs.tee().map(branch => branch.getReader());
3901cb0ef41Sopenharmony_ci
3911cb0ef41Sopenharmony_ci  return flushAsyncEvents().then(() => {
3921cb0ef41Sopenharmony_ci    assert_array_equals(rs.events, [], 'pull should not be called');
3931cb0ef41Sopenharmony_ci
3941cb0ef41Sopenharmony_ci    return Promise.all([
3951cb0ef41Sopenharmony_ci      promise_rejects_exactly(t, theError, reader1.closed),
3961cb0ef41Sopenharmony_ci      promise_rejects_exactly(t, theError, reader2.closed)
3971cb0ef41Sopenharmony_ci    ]);
3981cb0ef41Sopenharmony_ci  });
3991cb0ef41Sopenharmony_ci
4001cb0ef41Sopenharmony_ci}, 'ReadableStreamTee should not pull when original is already errored');
4011cb0ef41Sopenharmony_ci
4021cb0ef41Sopenharmony_cifor (const branch of [1, 2]) {
4031cb0ef41Sopenharmony_ci  promise_test(t => {
4041cb0ef41Sopenharmony_ci
4051cb0ef41Sopenharmony_ci    const rs = recordingReadableStream({}, { highWaterMark: 0 });
4061cb0ef41Sopenharmony_ci    const theError = { name: 'boo!' };
4071cb0ef41Sopenharmony_ci
4081cb0ef41Sopenharmony_ci    const [reader1, reader2] = rs.tee().map(branch => branch.getReader());
4091cb0ef41Sopenharmony_ci
4101cb0ef41Sopenharmony_ci    return flushAsyncEvents().then(() => {
4111cb0ef41Sopenharmony_ci      assert_array_equals(rs.events, ['pull'], 'pull should be called once');
4121cb0ef41Sopenharmony_ci
4131cb0ef41Sopenharmony_ci      rs.controller.enqueue('a');
4141cb0ef41Sopenharmony_ci
4151cb0ef41Sopenharmony_ci      const reader = (branch === 1) ? reader1 : reader2;
4161cb0ef41Sopenharmony_ci      return reader.read();
4171cb0ef41Sopenharmony_ci    }).then(() => flushAsyncEvents()).then(() => {
4181cb0ef41Sopenharmony_ci      assert_array_equals(rs.events, ['pull', 'pull'], 'pull should be called twice');
4191cb0ef41Sopenharmony_ci
4201cb0ef41Sopenharmony_ci      rs.controller.error(theError);
4211cb0ef41Sopenharmony_ci
4221cb0ef41Sopenharmony_ci      return Promise.all([
4231cb0ef41Sopenharmony_ci        promise_rejects_exactly(t, theError, reader1.closed),
4241cb0ef41Sopenharmony_ci        promise_rejects_exactly(t, theError, reader2.closed)
4251cb0ef41Sopenharmony_ci      ]);
4261cb0ef41Sopenharmony_ci    }).then(() => flushAsyncEvents()).then(() => {
4271cb0ef41Sopenharmony_ci      assert_array_equals(rs.events, ['pull', 'pull'], 'pull should be called twice');
4281cb0ef41Sopenharmony_ci    });
4291cb0ef41Sopenharmony_ci
4301cb0ef41Sopenharmony_ci  }, `ReadableStreamTee stops pulling when original stream errors while branch ${branch} is reading`);
4311cb0ef41Sopenharmony_ci}
4321cb0ef41Sopenharmony_ci
4331cb0ef41Sopenharmony_cipromise_test(t => {
4341cb0ef41Sopenharmony_ci
4351cb0ef41Sopenharmony_ci  const rs = recordingReadableStream({}, { highWaterMark: 0 });
4361cb0ef41Sopenharmony_ci  const theError = { name: 'boo!' };
4371cb0ef41Sopenharmony_ci
4381cb0ef41Sopenharmony_ci  const [reader1, reader2] = rs.tee().map(branch => branch.getReader());
4391cb0ef41Sopenharmony_ci
4401cb0ef41Sopenharmony_ci  return flushAsyncEvents().then(() => {
4411cb0ef41Sopenharmony_ci    assert_array_equals(rs.events, ['pull'], 'pull should be called once');
4421cb0ef41Sopenharmony_ci
4431cb0ef41Sopenharmony_ci    rs.controller.enqueue('a');
4441cb0ef41Sopenharmony_ci
4451cb0ef41Sopenharmony_ci    return Promise.all([reader1.read(), reader2.read()]);
4461cb0ef41Sopenharmony_ci  }).then(() => flushAsyncEvents()).then(() => {
4471cb0ef41Sopenharmony_ci    assert_array_equals(rs.events, ['pull', 'pull'], 'pull should be called twice');
4481cb0ef41Sopenharmony_ci
4491cb0ef41Sopenharmony_ci    rs.controller.error(theError);
4501cb0ef41Sopenharmony_ci
4511cb0ef41Sopenharmony_ci    return Promise.all([
4521cb0ef41Sopenharmony_ci      promise_rejects_exactly(t, theError, reader1.closed),
4531cb0ef41Sopenharmony_ci      promise_rejects_exactly(t, theError, reader2.closed)
4541cb0ef41Sopenharmony_ci    ]);
4551cb0ef41Sopenharmony_ci  }).then(() => flushAsyncEvents()).then(() => {
4561cb0ef41Sopenharmony_ci    assert_array_equals(rs.events, ['pull', 'pull'], 'pull should be called twice');
4571cb0ef41Sopenharmony_ci  });
4581cb0ef41Sopenharmony_ci
4591cb0ef41Sopenharmony_ci}, 'ReadableStreamTee stops pulling when original stream errors while both branches are reading');
4601cb0ef41Sopenharmony_ci
4611cb0ef41Sopenharmony_cipromise_test(async () => {
4621cb0ef41Sopenharmony_ci
4631cb0ef41Sopenharmony_ci  const rs = recordingReadableStream();
4641cb0ef41Sopenharmony_ci
4651cb0ef41Sopenharmony_ci  const [reader1, reader2] = rs.tee().map(branch => branch.getReader());
4661cb0ef41Sopenharmony_ci  const branch1Reads = [reader1.read(), reader1.read()];
4671cb0ef41Sopenharmony_ci  const branch2Reads = [reader2.read(), reader2.read()];
4681cb0ef41Sopenharmony_ci
4691cb0ef41Sopenharmony_ci  await flushAsyncEvents();
4701cb0ef41Sopenharmony_ci  rs.controller.enqueue('a');
4711cb0ef41Sopenharmony_ci  rs.controller.close();
4721cb0ef41Sopenharmony_ci
4731cb0ef41Sopenharmony_ci  assert_object_equals(await branch1Reads[0], { value: 'a', done: false }, 'first chunk from branch1 should be correct');
4741cb0ef41Sopenharmony_ci  assert_object_equals(await branch2Reads[0], { value: 'a', done: false }, 'first chunk from branch2 should be correct');
4751cb0ef41Sopenharmony_ci
4761cb0ef41Sopenharmony_ci  assert_object_equals(await branch1Reads[1], { value: undefined, done: true }, 'second read() from branch1 should be done');
4771cb0ef41Sopenharmony_ci  assert_object_equals(await branch2Reads[1], { value: undefined, done: true }, 'second read() from branch2 should be done');
4781cb0ef41Sopenharmony_ci
4791cb0ef41Sopenharmony_ci}, 'ReadableStream teeing: enqueue() and close() while both branches are pulling');
480