| Index: third_party/WebKit/LayoutTests/http/tests/streams/readable-streams/readable-stream-reader.js
|
| diff --git a/third_party/WebKit/LayoutTests/http/tests/streams/readable-streams/readable-stream-reader.js b/third_party/WebKit/LayoutTests/http/tests/streams/readable-streams/readable-stream-reader.js
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..f82b1d67db2fdaa1365bbd7884c8407a29e92dd1
|
| --- /dev/null
|
| +++ b/third_party/WebKit/LayoutTests/http/tests/streams/readable-streams/readable-stream-reader.js
|
| @@ -0,0 +1,335 @@
|
| +'use strict';
|
| +
|
| +if (self.importScripts) {
|
| + self.importScripts('../resources/rs-utils.js');
|
| + self.importScripts('/resources/testharness.js');
|
| +}
|
| +
|
| +var ReadableStreamReader;
|
| +
|
| +test(function() {
|
| + // It's not exposed globally, but we test a few of its properties here.
|
| + ReadableStreamReader = (new ReadableStream()).getReader().constructor;
|
| +}, 'Can get the ReadableStreamReader constructor indirectly');
|
| +
|
| +test(function() {
|
| + assert_throws(new TypeError(), function() {
|
| + new ReadableStreamReader('potato');
|
| + });
|
| + assert_throws(new TypeError(), function() {
|
| + new ReadableStreamReader({});
|
| + });
|
| + assert_throws(new TypeError(), function() {
|
| + new ReadableStreamReader();
|
| + });
|
| +}, 'ReadableStreamReader constructor should get a ReadableStream object as argument');
|
| +
|
| +test(function() {
|
| + var methods = ['cancel', 'constructor', 'read', 'releaseLock'];
|
| + var properties = methods.concat(['closed']).sort();
|
| +
|
| + var rsReader = new ReadableStreamReader(new ReadableStream());
|
| + var proto = Object.getPrototypeOf(rsReader);
|
| +
|
| + assert_array_equals(Object.getOwnPropertyNames(proto).sort(), properties);
|
| +
|
| + for (var m of methods) {
|
| + var propDesc = Object.getOwnPropertyDescriptor(proto, m);
|
| + assert_equals(propDesc.enumerable, false, 'method should be non-enumerable');
|
| + assert_equals(propDesc.configurable, true, 'method should be configurable');
|
| + assert_equals(propDesc.writable, true, 'method should be writable');
|
| + assert_equals(typeof rsReader[m], 'function', 'should have be a method');
|
| + }
|
| +
|
| + var closedPropDesc = Object.getOwnPropertyDescriptor(proto, 'closed');
|
| + assert_equals(closedPropDesc.enumerable, false, 'closed should be non-enumerable');
|
| + assert_equals(closedPropDesc.configurable, true, 'closed should be configurable');
|
| + assert_not_equals(closedPropDesc.get, undefined, 'closed should have a getter');
|
| + assert_equals(closedPropDesc.set, undefined, 'closed should not have a setter');
|
| +
|
| + assert_equals(rsReader.cancel.length, 1, 'cancel has 1 parameter');
|
| + assert_not_equals(rsReader.closed, undefined, 'has a non-undefined closed property');
|
| + assert_equals(typeof rsReader.closed.then, 'function', 'closed property is thenable');
|
| + assert_equals(typeof rsReader.constructor, 'function', 'has a constructor method');
|
| + assert_equals(rsReader.constructor.length, 1, 'constructor has 1 parameter');
|
| + assert_equals(typeof rsReader.read, 'function', 'has a getReader method');
|
| + assert_equals(rsReader.read.length, 0, 'read has no parameters');
|
| + assert_equals(typeof rsReader.releaseLock, 'function', 'has a releaseLock method');
|
| + assert_equals(rsReader.releaseLock.length, 0, 'releaseLock has no parameters');
|
| +}, 'ReadableStreamReader instances should have the correct list of properties');
|
| +
|
| +test(function() {
|
| + var rsReader = new ReadableStreamReader(new ReadableStream());
|
| +
|
| + assert_equals(rsReader.closed, rsReader.closed, 'closed should return the same promise');
|
| +}, 'ReadableStreamReader closed should always return the same promise object');
|
| +
|
| +test(function() {
|
| + var rs = new ReadableStream();
|
| + new ReadableStreamReader(rs); // Constructing directly the first time should be fine.
|
| + assert_throws(new TypeError(), function() { new ReadableStreamReader(rs); }, 'constructing directly the second time should fail');
|
| +}, 'Constructing a ReadableStreamReader directly should fail if the stream is already locked (via direct construction)');
|
| +
|
| +test(function() {
|
| + var rs = new ReadableStream();
|
| + new ReadableStreamReader(rs); // Constructing directly should be fine.
|
| + assert_throws(new TypeError(), function() { rs.getReader(); }, 'getReader() should fail');
|
| +}, 'Getting a ReadableStreamReader via getReader should fail if the stream is already locked (via direct construction)');
|
| +
|
| +test(function() {
|
| + var rs = new ReadableStream();
|
| + rs.getReader(); // getReader() should be fine.
|
| + assert_throws(new TypeError(), function() { new ReadableStreamReader(rs); }, 'constructing directly should fail');
|
| +}, 'Constructing a ReadableStreamReader directly should fail if the stream is already locked (via getReader)');
|
| +
|
| +test(function() {
|
| + var rs = new ReadableStream();
|
| + rs.getReader(); // getReader() should be fine.
|
| + assert_throws(new TypeError(), function() { rs.getReader(); }, 'getReader() should fail');
|
| +}, 'Getting a ReadableStreamReader via getReader should fail if the stream is already locked (via getReader)');
|
| +
|
| +test(function() {
|
| + var rs = new ReadableStream({
|
| + start: function(c) {
|
| + c.close();
|
| + }
|
| + });
|
| +
|
| + new ReadableStreamReader(rs); // Constructing directly should not throw.
|
| +}, 'Constructing a ReadableStreamReader directly should be OK if the stream is closed');
|
| +
|
| +test(function() {
|
| + var theError = new Error('don\'t say i didn\'t warn ya');
|
| + var rs = new ReadableStream({
|
| + start: function(c) {
|
| + c.error(theError);
|
| + }
|
| + });
|
| +
|
| + new ReadableStreamReader(rs); // Constructing directly should not throw.
|
| +}, 'Constructing a ReadableStreamReader directly should be OK if the stream is errored');
|
| +
|
| +var test1 = async_test('Reading from a reader for an empty stream will wait until a chunk is available');
|
| +test1.step(function() {
|
| + var controller;
|
| + var rs = new ReadableStream({
|
| + start: function(c) {
|
| + controller = c;
|
| + }
|
| + });
|
| + var reader = rs.getReader();
|
| +
|
| + reader.read().then(test1.step_func(function(result) {
|
| + assert_object_equals(result, { value: 'a', done: false }, 'read() should fulfill with the enqueued chunk');
|
| + test1.done();
|
| + }));
|
| +
|
| + controller.enqueue('a');
|
| +});
|
| +
|
| +var test2 = async_test('cancel() on a reader does not release the reader');
|
| +test2.step(function() {
|
| + var cancelCalled = false;
|
| + var passedReason = new Error('it wasn\'t the right time, sorry');
|
| + var rs = new ReadableStream({
|
| + cancel: function(reason) {
|
| + assert_true(rs.locked, 'the stream should still be locked');
|
| + assert_throws(new TypeError(), function() { rs.getReader(); }, 'should not be able to get another reader');
|
| + assert_equals(reason, passedReason, 'the cancellation reason is passed through to the underlying source');
|
| + cancelCalled = true;
|
| + }
|
| + });
|
| +
|
| + var reader = rs.getReader();
|
| + reader.cancel(passedReason).then(
|
| + test2.step_func(function() {
|
| + assert_true(cancelCalled);
|
| + test2.done('reader.cancel() should fulfill');
|
| + }),
|
| + test2.step_func(function(e) { assert_unreached('reader.cancel() should not reject'); })
|
| + );
|
| +});
|
| +
|
| +var test3 = async_test('closed should be fulfilled after stream is closed (.closed access before acquiring)');
|
| +test3.step(function() {
|
| + var controller;
|
| + var rs = new ReadableStream({
|
| + start: function(c) {
|
| + controller = c;
|
| + }
|
| + });
|
| +
|
| + var reader = rs.getReader();
|
| + reader.closed.then(test3.step_func(function() {
|
| + test3.done('reader closed should be fulfilled');
|
| + }));
|
| +
|
| + controller.close();
|
| +});
|
| +
|
| +var test4 = async_test('closed should be rejected after reader releases its lock (multiple stream locks)');
|
| +test4.step(function() {
|
| + var promiseCalls = 0;
|
| + var controller;
|
| + var rs = new ReadableStream({
|
| + start: function(c) {
|
| + controller = c;
|
| + }
|
| + });
|
| +
|
| + var reader1 = rs.getReader();
|
| +
|
| + reader1.releaseLock();
|
| +
|
| + var reader2 = rs.getReader();
|
| + controller.close();
|
| +
|
| + reader1.closed.catch(test4.step_func(function(e) {
|
| + assert_throws(new TypeError(), function() { throw e; }, 'reader1 closed should be rejected with a TypeError');
|
| + assert_equals(++promiseCalls, 1);
|
| + }));
|
| +
|
| + reader2.closed.then(test4.step_func(function() {
|
| + assert_equals(++promiseCalls, 2);
|
| + test4.done('reader2 closed should be fulfilled');
|
| + }));
|
| +});
|
| +
|
| +var test5 = async_test('Multiple readers can access the stream in sequence');
|
| +test5.step(function() {
|
| + var readCount = 0;
|
| + var rs = new ReadableStream({
|
| + start: function(c) {
|
| + c.enqueue('a');
|
| + c.enqueue('b');
|
| + c.close();
|
| + }
|
| + });
|
| +
|
| + var reader1 = rs.getReader();
|
| + reader1.read().then(test5.step_func(function(r) {
|
| + assert_object_equals(r, { value: 'a', done: false }, 'reading the first chunk from reader1 works');
|
| + ++readCount;
|
| + }));
|
| + reader1.releaseLock();
|
| +
|
| + var reader2 = rs.getReader();
|
| + reader2.read().then(test5.step_func(function(r) {
|
| + assert_object_equals(r, { value: 'b', done: false }, 'reading the second chunk from reader2 works');
|
| + assert_equals(++readCount, 2);
|
| + test5.done();
|
| + }));
|
| + reader2.releaseLock();
|
| +});
|
| +
|
| +var test6 = async_test('Cannot use an already-released reader to unlock a stream again');
|
| +test6.step(function() {
|
| + var rs = new ReadableStream({
|
| + start: function(c) {
|
| + c.enqueue('a');
|
| + }
|
| + });
|
| +
|
| + var reader1 = rs.getReader();
|
| + reader1.releaseLock();
|
| +
|
| + var reader2 = rs.getReader();
|
| +
|
| + reader1.releaseLock();
|
| + reader2.read().then(test6.step_func(function(result) {
|
| + assert_object_equals(result, { value: 'a', done: false }, 'read() should still work on reader2 even after reader1 is released');
|
| + test6.done();
|
| + }));
|
| +});
|
| +
|
| +var test7 = async_test('cancel() on a released reader is a no-op and does not pass through');
|
| +test7.step(function() {
|
| + var promiseCalls = 0;
|
| + var rs = new ReadableStream({
|
| + start: function(c) {
|
| + c.enqueue('a');
|
| + },
|
| + cancel: function() {
|
| + assert_unreached('underlying source cancel should not be called');
|
| + }
|
| + });
|
| +
|
| + var reader = rs.getReader();
|
| + reader.releaseLock();
|
| + reader.cancel().then(test7.step_func(function(v) {
|
| + assert_unreached('cancel promise should not fulfill');
|
| + })).catch(test7.step_func(function(e) {
|
| + assert_equals(++promiseCalls, 2);
|
| + test7.done();
|
| + }));
|
| +
|
| + var reader2 = rs.getReader();
|
| + reader2.read().then(test7.step_func(function(r) {
|
| + assert_object_equals(r, { value: 'a', done: false }, 'a new reader should be able to read a chunk');
|
| + assert_equals(++promiseCalls, 1);
|
| + }));
|
| +});
|
| +
|
| +var test8 = async_test('Getting a second reader after erroring the stream should succeed');
|
| +test8.step(function() {
|
| + var controller;
|
| + var receivedErrors = 0;
|
| + var theError = new Error('bad');
|
| + var rs = new ReadableStream({
|
| + start: function(c) {
|
| + controller = c;
|
| + }
|
| + });
|
| +
|
| + var reader1 = rs.getReader();
|
| +
|
| + reader1.closed.catch(test8.step_func(function(e) {
|
| + assert_equals(e, theError, 'the first reader closed getter should be rejected with the error');
|
| + ++receivedErrors;
|
| + }));
|
| +
|
| + reader1.read().catch(test8.step_func(function(e) {
|
| + assert_equals(e, theError, 'the first reader read() should be rejected with the error');
|
| + ++receivedErrors;
|
| + }));
|
| +
|
| + assert_throws(new TypeError(), function() { rs.getReader(); }, 'trying to get another reader before erroring should throw');
|
| +
|
| + controller.error(theError);
|
| +
|
| + reader1.releaseLock();
|
| +
|
| + var reader2 = rs.getReader();
|
| +
|
| + reader2.closed.catch(test8.step_func(function(e) {
|
| + assert_equals(e, theError, 'the second reader closed getter should be rejected with the error');
|
| + ++receivedErrors;
|
| + }));
|
| +
|
| + reader2.read().catch(test8.step_func(function(e) {
|
| + assert_equals(e, theError, 'the third reader read() should be rejected with the error');
|
| + assert_equals(++receivedErrors, 4);
|
| + test8.done();
|
| + }));
|
| +});
|
| +
|
| +var test9 = async_test('ReadableStreamReader closed promise should be rejected with undefined if that is the error');
|
| +test9.step(function() {
|
| + var controller;
|
| + var rs = new ReadableStream({
|
| + start: function(c) {
|
| + controller = c;
|
| + }
|
| + });
|
| +
|
| + rs.getReader().closed.then(test9.step_func(function() {
|
| + assert_unreached("closed promise should not be resolved when stream is errored");
|
| + }), test9.step_func(function(err) {
|
| + assert_equals(err, undefined, 'passed error should be undefined as it was');
|
| + test9.done();
|
| + }));
|
| +
|
| + controller.error();
|
| +});
|
| +
|
| +done();
|
|
|