blob: 7f0797ed66ffdd2127e345e3b24f234bf482c8b3 [file] [log] [blame]
<!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(label + ': 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(label + ': 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(label + ': 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(label + ': 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(label + ': 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(label + ': 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(label + ': 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(label + ': 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(label + ': 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(label + ': 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(label + ': 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(label + ': 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>