| <!DOCTYPE html> |
| <script> |
| // Silence unhandled rejection messages. |
| window.addEventListener("unhandledrejection", function(event) { |
| event.stopImmediatePropagation(); |
| event.preventDefault(); |
| }); |
| </script> |
| <script src='../../resources/testharness.js'></script> |
| <script src='../../resources/testharnessreport.js'></script> |
| <script src='resources/streams-utils.js'></script> |
| <script> |
| // This is updated till https://github.com/whatwg/streams/commit/4ba861e6f60c248060811830e11271c84b439cc3 |
| |
| function templatedRSClosed(label, factory) { |
| test(function() { |
| }, 'Running templatedRSClosed with ' + label); |
| |
| var test1 = async_test('piping to a WritableStream in the writable state should close the writable stream'); |
| test1.step(function() { |
| var closeCalled = false; |
| |
| var rs = factory(); |
| |
| var startPromise = Promise.resolve(); |
| var ws = new WritableStream({ |
| start: function() { |
| return startPromise; |
| }, |
| write: function() { |
| assert_unreached('Unexpected write call'); |
| }, |
| close: function() { |
| closeCalled = true; |
| }, |
| abort: function() { |
| assert_unreached('Unexpected abort call'); |
| } |
| }); |
| |
| startPromise.then(test1.step_func(function() { |
| assert_equals(ws.state, 'writable', 'writable stream should start in writable state'); |
| |
| return rs.pipeTo(ws).then(test1.step_func(function() { |
| assert_true(closeCalled); |
| assert_equals(ws.state, 'closed', 'writable stream should become closed'); |
| test1.done('underlying source close should be called'); |
| })); |
| })).catch(test1.step_func(function(e) { assert_unreached(e); })); |
| }); |
| |
| var test2 = async_test('piping to a WritableStream in the writable state with { preventClose: true } should do nothing'); |
| test2.step(function() { |
| var rs = factory(); |
| |
| var startPromise = Promise.resolve(); |
| var ws = new WritableStream({ |
| start: function() { |
| return startPromise; |
| }, |
| write: function() { |
| assert_unreached('Unexpected write call'); |
| }, |
| close: function() { |
| assert_unreached('Unexpected close call'); |
| }, |
| abort: function() { |
| assert_unreached('Unexpected abort call'); |
| } |
| }); |
| |
| startPromise.then(test2.step_func(function() { |
| assert_equals(ws.state, 'writable', 'writable stream should start in writable state'); |
| |
| return rs.pipeTo(ws, { preventClose: true }).then(test2.step_func(function() { |
| assert_equals(ws.state, 'writable', 'writable stream should still be writable'); |
| test2.done('pipeTo promise should be fulfilled'); |
| })); |
| })).catch(test2.step_func(function(e) { assert_unreached(e); })); |
| }); |
| }; |
| |
| function templatedRSErrored(label, factory, error) { |
| test(function() { |
| }, 'Running templatedRSErrored with ' + label); |
| |
| var test1 = async_test('piping to a WritableStream in the writable state should abort the writable stream'); |
| test1.step(function() { |
| var rs = factory(); |
| |
| var startPromise = Promise.resolve(); |
| var ws = new WritableStream({ |
| start: function() { |
| return startPromise; |
| }, |
| write: function() { |
| assert_unreached('Unexpected write call'); |
| }, |
| close: function() { |
| assert_reached('Unexpected close call'); |
| }, |
| abort: function(reason) { |
| assert_equals(reason, error); |
| } |
| }); |
| |
| startPromise.then(test1.step_func(function() { |
| assert_equals(ws.state, 'writable'); |
| |
| rs.pipeTo(ws).then( |
| test1.step_func(function() { assert_unreached('pipeTo promise should not be fulfilled'); }), |
| test1.step_func(function(e) { |
| assert_equals(e, error, 'pipeTo promise should be rejected with the passed error'); |
| assert_equals(ws.state, 'errored', 'writable stream should become errored'); |
| test1.done(); |
| }) |
| ); |
| })); |
| }); |
| }; |
| |
| function templatedRSErroredAsyncOnly(label, factory, error) { |
| test(function() { |
| }, 'Running templatedRSErroredAsyncOnly with ' + label); |
| |
| var test1 = async_test('piping with no options'); |
| test1.step(function() { |
| var closeCalled = false; |
| |
| var rs = factory(); |
| |
| var ws = new WritableStream({ |
| abort: function(r) { |
| assert_equals(r, error, 'reason passed to abort should equal the source error'); |
| } |
| }); |
| |
| rs.pipeTo(ws).catch(test1.step_func(function(e) { |
| assert_equals(ws.state, 'errored', 'destination should be errored'); |
| assert_equals(e, error, 'rejection reason of pipeToPromise should be the source error'); |
| assert_true(closeCalled); |
| test1.done(); |
| })); |
| |
| ws.closed.catch(test1.step_func(function(e) { |
| assert_equals(e, error, 'rejection reason of dest closed should be the source error'); |
| closeCalled = true; |
| })) |
| }); |
| |
| var test2 = async_test('piping with { preventAbort: false }'); |
| test2.step(function() { |
| var abortCalled = false; |
| var closeRejected = false; |
| |
| var rs = factory(); |
| |
| var ws = new WritableStream({ |
| abort: function(r) { |
| assert_equals(r, error, 'reason passed to abort should equal the source error'); |
| abortCalled = true; |
| } |
| }); |
| |
| rs.pipeTo(ws, { preventAbort: false }).catch(test2.step_func(function(e) { |
| assert_equals(ws.state, 'errored', 'destination should be errored'); |
| assert_equals(e, error, 'rejection reason of pipeToPromise should be the source error'); |
| assert_true(abortCalled); |
| assert_true(closeRejected); |
| test2.done(); |
| })); |
| |
| ws.closed.catch(test2.step_func(function(e) { |
| assert_equals(e, error, 'rejection reason of dest closed should be the source error'); |
| closeRejected = true; |
| })); |
| }); |
| |
| var test3 = async_test('piping with { preventAbort: true }'); |
| test3.step(function() { |
| var rs = factory(); |
| |
| var ws = new WritableStream({ |
| abort: function() { |
| assert_unreached('underlying sink abort should not be called'); |
| } |
| }); |
| |
| rs.pipeTo(ws, { preventAbort: true }).catch(test3.step_func(function(e) { |
| assert_equals(ws.state, 'writable', 'destination should remain writable'); |
| assert_equals(e, error, 'rejection reason of pipeToPromise should be the source error'); |
| test3.done(); |
| })); |
| }); |
| }; |
| |
| function templatedRSTwoChunksClosed(label, factory, error) { |
| test(function() { |
| }, 'Running templatedRSTwoChunksClosed with ' + label); |
| |
| var test1 = async_test('piping with no options and no destination errors'); |
| test1.step(function() { |
| var rs = factory(); |
| |
| var chunksWritten = []; |
| var ws = new WritableStream({ |
| abort: function() { |
| assert_unreached('unexpected abort call'); |
| }, |
| write: function(chunk) { |
| chunksWritten.push(chunk); |
| } |
| }); |
| |
| rs.pipeTo(ws).then(test1.step_func(function() { |
| assert_equals(ws.state, 'closed', 'destination should be closed'); |
| assert_array_equals(chunksWritten, chunks); |
| test1.done(); |
| })); |
| }); |
| |
| var test2 = async_test('piping with { preventClose: false } and no destination errors'); |
| test2.step(function() { |
| var rs = factory(); |
| |
| var chunksWritten = []; |
| var ws = new WritableStream({ |
| abort: function() { |
| assert_unreached('unexpected abort call'); |
| }, |
| write: function(chunk) { |
| chunksWritten.push(chunk); |
| } |
| }); |
| |
| rs.pipeTo(ws).then(test2.step_func(function() { |
| assert_equals(ws.state, 'closed', 'destination should be closed'); |
| assert_array_equals(chunksWritten, chunks); |
| test2.done(); |
| })); |
| }); |
| |
| var test3 = async_test('piping with { preventClose: true } and no destination errors'); |
| test3.step(function() { |
| var rs = factory(); |
| |
| var chunksWritten = []; |
| var ws = new WritableStream({ |
| close: function() { |
| assert_unreached('unexpected close call'); |
| }, |
| abort: function() { |
| assert_unreached('unexpected abort call'); |
| }, |
| write: function(chunk) { |
| chunksWritten.push(chunk); |
| } |
| }); |
| |
| rs.pipeTo(ws, { preventClose: true }).then(test3.step_func(function() { |
| assert_equals(ws.state, 'writable', 'destination should be writable'); |
| assert_array_equals(chunksWritten, chunks); |
| test3.done(); |
| })); |
| }); |
| |
| var test4 = async_test('piping with { preventClose: false } and a destination with that errors synchronously'); |
| test4.step(function() { |
| var rs = factory(); |
| |
| var theError = new Error('!!!'); |
| var ws = new WritableStream({ |
| close: function() { |
| assert_unreached('unexpected close call'); |
| }, |
| abort: function() { |
| assert_unreached('unexpected abort call'); |
| }, |
| write: function() { |
| throw theError; |
| } |
| }); |
| |
| rs.pipeTo(ws, { preventClose: false }).then( |
| test4.step_func(function() { assert_unreached('pipeTo promise should not fulfill'); }), |
| test4.step_func(function(e) { |
| assert_equals(e, theError, 'pipeTo promise should reject with the write error'); |
| test4.done(); |
| }) |
| ); |
| }); |
| |
| var test5 = async_test('piping with { preventClose: true } and a destination with that errors synchronously'); |
| test5.step(function() { |
| var rs = factory(); |
| |
| var theError = new Error('!!!'); |
| var ws = new WritableStream({ |
| close: function() { |
| assert_unreached('unexpected close call'); |
| }, |
| abort: function() { |
| assert_unreached('unexpected abort call'); |
| }, |
| write: function() { |
| throw theError; |
| } |
| }); |
| |
| rs.pipeTo(ws, { preventClose: true }).then( |
| test5.step_func(function() { assert_unreached('pipeTo promise should not fulfill'); }), |
| test5.step_func(function(e) { |
| assert_equals(e, theError, 'pipeTo promise should reject with the write error'); |
| test5.done(); |
| }) |
| ); |
| }); |
| |
| var test6 = async_test('piping with { preventClose: true } and a destination that errors on the last chunk'); |
| test6.step(function() { |
| var rs = factory(); |
| |
| var theError = new Error('!!!'); |
| var chunkCounter = 0; |
| var ws = new WritableStream( |
| { |
| close: function() { |
| assert_unreached('unexpected close call'); |
| }, |
| abort: function() { |
| assert_unreached('unexpected abort call'); |
| }, |
| write: function() { |
| if (++chunkCounter === 2) { |
| return new Promise(test6.step_func(function(r, reject) { setTimeout(test6.step_func(function() { reject(theError); }), 200); })); |
| } |
| } |
| }, |
| { |
| highWaterMark: Infinity, |
| size: function() { return 1; } |
| } |
| ); |
| |
| rs.pipeTo(ws, { preventClose: true }).then( |
| test6.step_func(function() { assert_unreached('pipeTo promise should not fulfill'); }), |
| test6.step_func(function(e) { |
| assert_equals(e, theError, 'pipeTo promise should reject with the write error'); |
| test6.done(); |
| }) |
| ); |
| }); |
| }; |
| |
| templatedRSClosed('ReadableStream (closed via call in start)', function() { |
| return new ReadableStream({ |
| start: function(c) { |
| c.close(); |
| } |
| }); |
| }); |
| |
| templatedRSClosed('ReadableStream (closed via cancel)', function() { |
| var stream = new ReadableStream(); |
| stream.cancel(); |
| return stream; |
| }); |
| var theError = new Error('boo!'); |
| |
| templatedRSErrored('ReadableStream (errored via call in start)', function() { |
| return new ReadableStream({ |
| start: function(c) { |
| c.error(theError); |
| } |
| })}, |
| theError |
| ); |
| |
| templatedRSErrored('ReadableStream (errored via returning a rejected promise in start)', function() { |
| return new ReadableStream({ |
| start: function() { |
| return Promise.reject(theError); |
| } |
| })}, |
| theError |
| ); |
| |
| templatedRSErroredAsyncOnly('ReadableStream (errored via returning a rejected promise in start) reader', function() { |
| return new ReadableStream({ |
| start: function() { return Promise.reject(theError); } |
| })}, |
| theError |
| ); |
| |
| var chunks = ['a', 'b']; |
| |
| templatedRSTwoChunksClosed('ReadableStream (two chunks enqueued, then closed)', function() { |
| return new ReadableStream({ |
| start: function(c) { |
| c.enqueue(chunks[0]); |
| c.enqueue(chunks[1]); |
| c.close(); |
| } |
| })}, |
| chunks |
| ); |
| |
| templatedRSTwoChunksClosed('ReadableStream (two chunks enqueued async, then closed)', function() { |
| return new ReadableStream({ |
| _cancelled: false, |
| start: function(c) { |
| setTimeout(() => { |
| if (!this._cancelled) |
| c.enqueue(chunks[0]); |
| }, 100); |
| setTimeout(() => { |
| if (!this._cancelled) |
| c.enqueue(chunks[1]); |
| }, 200); |
| setTimeout(() => { |
| if (!this._cancelled) |
| c.close(); |
| }, 300); |
| }, |
| cancel: function(reason) { |
| this._cancelled = true; |
| } |
| })}, |
| chunks |
| ); |
| |
| templatedRSTwoChunksClosed('ReadableStream (two chunks enqueued via pull, then closed)', function() { |
| var pullCall = 0; |
| |
| return new ReadableStream({ |
| pull:function(c) { |
| if (pullCall >= chunks.length) { |
| c.close(); |
| } else { |
| c.enqueue(chunks[pullCall++]); |
| } |
| } |
| }); |
| }, |
| chunks |
| ); |
| </script> |