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