Index: third_party/WebKit/LayoutTests/http/tests/streams/readable-streams/general.js |
diff --git a/third_party/WebKit/LayoutTests/http/tests/streams/readable-streams/general.js b/third_party/WebKit/LayoutTests/http/tests/streams/readable-streams/general.js |
new file mode 100644 |
index 0000000000000000000000000000000000000000..56080e6c68d467707211b689991612cc1ef17e80 |
--- /dev/null |
+++ b/third_party/WebKit/LayoutTests/http/tests/streams/readable-streams/general.js |
@@ -0,0 +1,817 @@ |
+'use strict'; |
+ |
+if (self.importScripts) { |
+ self.importScripts('../resources/rs-utils.js'); |
+ self.importScripts('/resources/testharness.js'); |
+} |
+ |
+test(function() { |
+ new ReadableStream(); // ReadableStream constructed with no parameters. |
+ new ReadableStream({ }); // ReadableStream constructed with an empty object as parameter. |
+ new ReadableStream(undefined); // ReadableStream constructed with undefined as parameter. |
+ var x; |
+ new ReadableStream(x) // ReadableStream constructed with an undefined variable as parameter. |
+}, 'ReadableStream can be constructed with no errors'); |
+ |
+test(function() { |
+ assert_throws(new TypeError(), function() { new ReadableStream(null); }, 'constructor should throw when the source is null'); |
+}, 'ReadableStream can\'t be constructed with garbage'); |
+ |
+test(function() { |
+ var methods = ['cancel', 'constructor', 'getReader', 'tee']; |
+ var properties = methods.concat(['locked']).sort(); |
+ |
+ var rs = new ReadableStream(); |
+ var proto = Object.getPrototypeOf(rs); |
+ |
+ assert_array_equals(Object.getOwnPropertyNames(proto).sort(), properties, 'should have all the correct methods'); |
+ |
+ for (var m of methods) { |
+ var propDesc = Object.getOwnPropertyDescriptor(proto, m); |
+ assert_false(propDesc.enumerable, 'method should be non-enumerable'); |
+ assert_true(propDesc.configurable, 'method should be configurable'); |
+ assert_true(propDesc.writable, 'method should be writable'); |
+ assert_equals(typeof rs[m], 'function', 'should have be a method'); |
+ } |
+ |
+ var lockedPropDesc = Object.getOwnPropertyDescriptor(proto, 'locked'); |
+ assert_false(lockedPropDesc.enumerable, 'locked should be non-enumerable'); |
+ assert_equals(lockedPropDesc.writable, undefined, 'locked should not be a data property'); |
+ assert_equals(typeof lockedPropDesc.get, 'function', 'locked should have a getter'); |
+ assert_equals(lockedPropDesc.set, undefined, 'locked should not have a setter'); |
+ assert_true(lockedPropDesc.configurable, 'locked should be configurable'); |
+ |
+ assert_equals(rs.cancel.length, 1, 'cancel should have 1 parameter'); |
+ assert_equals(rs.constructor.length, 0, 'constructor should have no parameters'); |
+ assert_equals(rs.getReader.length, 0, 'getReader should have no parameters'); |
+ assert_equals(rs.tee.length, 0, 'tee should have no parameters'); |
+}, 'ReadableStream instances should have the correct list of properties'); |
+ |
+test(function() { |
+ assert_throws(new TypeError(), function() { |
+ new ReadableStream({ start: 'potato'}); |
+ }, 'constructor should throw when start is not a function'); |
+}, 'ReadableStream constructor should throw for non-function start arguments'); |
+ |
+test(function() { |
+ new ReadableStream({ cancel: '2'}); // Constructor should not throw when cancel is not a function. |
+}, 'ReadableStream constructor can get initial garbage as cancel argument'); |
+ |
+test(function() { |
+ new ReadableStream({ pull: { } }); // Constructor should not throw when pull is not a function. |
+}, 'ReadableStream constructor can get initial garbage as pull argument'); |
+ |
+test(function() { |
+ var startCalled = false; |
+ var source = { |
+ start: function(controller) { |
+ assert_equals(this, source, 'source is this during start'); |
+ |
+ var methods = ['close', 'enqueue', 'error', 'constructor']; |
+ var properties = ['desiredSize'].concat(methods).sort(); |
+ var proto = Object.getPrototypeOf(controller); |
+ |
+ assert_array_equals(Object.getOwnPropertyNames(proto).sort(), properties, |
+ 'the controller should have the right properties'); |
+ |
+ for (var m of methods) { |
+ var propDesc = Object.getOwnPropertyDescriptor(proto, m); |
+ assert_equals(typeof controller[m], 'function', `should have a ${m} method`); |
+ assert_false(propDesc.enumerable, m + " should be non-enumerable"); |
+ assert_true(propDesc.configurable, m + " should be configurable"); |
+ assert_true(propDesc.writable, m + " should be writable"); |
+ } |
+ |
+ var desiredSizePropDesc = Object.getOwnPropertyDescriptor(proto, 'desiredSize'); |
+ assert_false(desiredSizePropDesc.enumerable, 'desiredSize should be non-enumerable'); |
+ assert_equals(desiredSizePropDesc.writable, undefined, 'desiredSize should not be a data property'); |
+ assert_equals(typeof desiredSizePropDesc.get, 'function', 'desiredSize should have a getter'); |
+ assert_equals(desiredSizePropDesc.set, undefined, 'desiredSize should not have a setter'); |
+ assert_true(desiredSizePropDesc.configurable, 'desiredSize should be configurable'); |
+ |
+ assert_equals(controller.close.length, 0, 'close should have no parameters'); |
+ assert_equals(controller.constructor.length, 1, 'constructor should have 1 parameter'); |
+ assert_equals(controller.enqueue.length, 1, 'enqueue should have 1 parameter'); |
+ assert_equals(controller.error.length, 1, 'error should have 1 parameter'); |
+ |
+ startCalled = true; |
+ } |
+ }; |
+ |
+ new ReadableStream(source); |
+ assert_true(startCalled); |
+}, 'ReadableStream start should be called with the proper parameters'); |
+ |
+test(function() { |
+ var startCalled = false; |
+ var source = { |
+ start: function(controller) { |
+ var properties = ['close', 'constructor', 'desiredSize', 'enqueue', 'error']; |
+ assert_array_equals(Object.getOwnPropertyNames(Object.getPrototypeOf(controller)).sort(), properties, |
+ 'prototype should have the right properties'); |
+ controller.test = ''; |
+ assert_array_equals(Object.getOwnPropertyNames(Object.getPrototypeOf(controller)).sort(), properties, |
+ 'prototype should still have the right properties'); |
+ assert_not_equals(Object.getOwnPropertyNames(controller).indexOf('test'), -1, |
+ '"test" should be a property of the controller'); |
+ |
+ startCalled = true; |
+ } |
+ }; |
+ |
+ var rs = new ReadableStream(source); |
+ assert_true(startCalled); |
+}, 'ReadableStream start controller parameter should be extensible'); |
+ |
+var test1 = async_test('ReadableStream should be able to call start method within prototype chain of its source'); |
+test1.step(function() |
+{ |
+ function SimpleStreamSource() { |
+ }; |
+ SimpleStreamSource.prototype = { |
+ start: function() { |
+ test1.done('start should be called'); |
+ }, |
+ } |
+ |
+ new ReadableStream(new SimpleStreamSource()); |
+}); |
+ |
+var test2 = async_test('ReadableStream start should be able to return a promise'); |
+test2.step(function() |
+{ |
+ var readCalled = false; |
+ var rs = new ReadableStream({ |
+ start: function(c) { |
+ return new Promise(test2.step_func(function(resolve, reject) { |
+ setTimeout(test2.step_func(function() { |
+ c.enqueue('a'); |
+ c.close(); |
+ resolve(); |
+ }), 500); |
+ })); |
+ }, |
+ }); |
+ |
+ var reader = rs.getReader(); |
+ |
+ reader.read().then(test2.step_func(function(r) { |
+ readCalled = true; |
+ assert_object_equals(r, { value: 'a', done: false }, 'value read should be the one enqueued'); |
+ })); |
+ |
+ reader.closed.then(test2.step_func(function() { |
+ assert_true(readCalled); |
+ test2.done('stream should close successfully'); |
+ })); |
+}); |
+ |
+var test3 = async_test('ReadableStream start should be able to return a promise and reject it'); |
+test3.step(function() |
+{ |
+ var theError = new Error('rejected!'); |
+ var rs = new ReadableStream({ |
+ start: function() { |
+ return new Promise(test3.step_func(function(resolve, reject) { |
+ setTimeout(test3.step_func(function() { |
+ reject(theError); |
+ }), 500); |
+ })); |
+ }, |
+ }); |
+ |
+ rs.getReader().closed.catch(test3.step_func(function(e) { |
+ assert_equals(e, theError, 'promise should be rejected with the same error'); |
+ test3.done(); |
+ })); |
+}); |
+ |
+var test4 = async_test('ReadableStream should be able to enqueue different objects.'); |
+test4.step(function() { |
+ var readCalls = 0; |
+ var objects = [ |
+ { potato: 'Give me more!'}, |
+ 'test', |
+ 1 |
+ ]; |
+ |
+ var rs = new ReadableStream({ |
+ start: function(c) { |
+ for (var o of objects) { |
+ c.enqueue(o); |
+ } |
+ c.close(); |
+ } |
+ }); |
+ |
+ var reader = rs.getReader(); |
+ |
+ reader.read().then(test4.step_func(function(r) { |
+ assert_object_equals(r, { value: objects[readCalls++], done: false }, 'value read should be the one enqueued'); |
+ })); |
+ |
+ reader.read().then(test4.step_func(function(r) { |
+ assert_object_equals(r, { value: objects[readCalls++], done: false }, 'value read should be the one enqueued'); |
+ })); |
+ |
+ reader.read().then(test4.step_func(function(r) { |
+ assert_object_equals(r, { value: objects[readCalls++], done: false }, 'value read should be the one enqueued'); |
+ })); |
+ |
+ reader.closed.then(test4.step_func(function() { |
+ assert_equals(readCalls, 3); |
+ test4.done('stream should close correctly correctly'); |
+ })); |
+}); |
+ |
+var test5 = async_test('ReadableStream: if pull rejects, it should error the stream'); |
+test5.step(function() { |
+ var error = new Error('pull failure'); |
+ var rs = new ReadableStream({ |
+ pull: function() { |
+ return Promise.reject(error); |
+ } |
+ }); |
+ |
+ var reader = rs.getReader(); |
+ |
+ var closed = false; |
+ var read = false; |
+ |
+ reader.closed.catch(test5.step_func(function(e) { |
+ closed = true; |
+ assert_true(read); |
+ assert_equals(e, error, 'closed should reject with the thrown error'); |
+ test5.done(); |
+ })); |
+ |
+ reader.read().catch(test5.step_func(function(e) { |
+ read = true; |
+ assert_false(closed); |
+ assert_equals(e, error, 'read() should reject with the thrown error'); |
+ })); |
+}); |
+ |
+var test6 = async_test('ReadableStream: should only call pull once upon starting the stream'); |
+test6.step(function() { |
+ var pullCount = 0; |
+ var startPromise = Promise.resolve(); |
+ var rs = new ReadableStream({ |
+ start: function() { |
+ return startPromise; |
+ }, |
+ pull: function() { |
+ pullCount++; |
+ } |
+ }); |
+ |
+ startPromise.then(test6.step_func(function() { |
+ assert_equals(pullCount, 1, 'pull should be called once start finishes'); |
+ |
+ setTimeout(test6.step_func(function() { |
+ assert_equals(pullCount, 1, 'pull should be called exactly once'); |
+ test6.done(); |
+ }), 1000); |
+ })); |
+ |
+}); |
+ |
+var test7 = async_test('ReadableStream: should call pull when trying to read from a started, empty stream'); |
+test7.step(function() { |
+ var pullCount = 0; |
+ var startPromise = Promise.resolve(); |
+ var rs = new ReadableStream({ |
+ start: function() { |
+ return startPromise; |
+ }, |
+ pull: function(c) { |
+ // Don't enqueue immediately after start. We want the stream to be empty when we call .read() on it. |
+ if (pullCount > 0) { |
+ c.enqueue(pullCount); |
+ } |
+ |
+ ++pullCount; |
+ } |
+ }); |
+ |
+ startPromise.then(test7.step_func(function() { |
+ assert_equals(pullCount, 1, 'pull should be called once start finishes'); |
+ |
+ var reader = rs.getReader(); |
+ return reader.read().then(test7.step_func(function(result) { |
+ assert_equals(pullCount, 2, 'pull should be called again in reaction to calling read'); |
+ assert_object_equals(result, { value: 1, done: false }, 'the result read should be the one enqueued'); |
+ test7.done(); |
+ })); |
+ })).catch(test7.step_func(function(e) { assert_unreached(e); })); |
+}); |
+ |
+var test8 = async_test('ReadableStream: should only call pull once on a non-empty stream read from before start fulfills'); |
+test8.step(function() { |
+ var pullCount = 0; |
+ var startPromise = Promise.resolve(); |
+ var rs = new ReadableStream({ |
+ start: function(c) { |
+ c.enqueue('a'); |
+ return startPromise; |
+ }, |
+ pull: function() { |
+ pullCount++; |
+ } |
+ }); |
+ |
+ startPromise.then(test8.step_func(function() { |
+ assert_equals(pullCount, 1, 'pull should be called once start finishes'); |
+ })); |
+ |
+ rs.getReader().read().then(test8.step_func(function(r) { |
+ assert_object_equals(r, { value: 'a', done: false }, 'first read() should return first chunk'); |
+ assert_equals(pullCount, 1, 'pull should not have been called again'); |
+ |
+ setTimeout(test8.step_func(function() { |
+ assert_equals(pullCount, 1, 'pull should be called exactly once'); |
+ test8.done(); |
+ }), 1000); |
+ })); |
+ |
+ assert_equals(pullCount, 0, 'calling read() should not cause pull to be called yet'); |
+}); |
+ |
+var test9 = async_test('ReadableStream: should only call pull once on a non-empty stream read from after start fulfills'); |
+test9.step(function() { |
+ var pullCount = 0; |
+ var startPromise = Promise.resolve(); |
+ var rs = new ReadableStream({ |
+ start: function(c) { |
+ c.enqueue('a'); |
+ return startPromise; |
+ }, |
+ pull: function() { |
+ pullCount++; |
+ } |
+ }); |
+ |
+ startPromise.then(test9.step_func(function() { |
+ assert_equals(pullCount, 0, 'pull should not be called once start finishes, since the queue is full'); |
+ |
+ rs.getReader().read().then(test9.step_func(function(r) { |
+ assert_object_equals(r, { value: 'a', done: false }, 'first read() should return first chunk'); |
+ |
+ setTimeout(test9.step_func(function() { |
+ assert_equals(pullCount, 1, 'pull should be called exactly once'); |
+ test9.done(); |
+ }), 1000); |
+ |
+ })); |
+ |
+ assert_equals(pullCount, 1, 'calling read() should not cause pull to be called immediately'); |
+ })); |
+}); |
+ |
+var test10 = async_test('ReadableStream: should call pull in reaction to read()ing the last chunk, if not draining'); |
+test10.step(function() { |
+ var pullCount = 0; |
+ var controller; |
+ var startPromise = Promise.resolve(); |
+ var rs = new ReadableStream({ |
+ start: function(c) { |
+ controller = c; |
+ return startPromise; |
+ }, |
+ pull: function() { |
+ ++pullCount; |
+ } |
+ }); |
+ |
+ var reader = rs.getReader(); |
+ |
+ startPromise.then(test10.step_func(function() { |
+ assert_equals(pullCount, 1, 'pull should have been called once by the time the stream starts'); |
+ |
+ controller.enqueue('a'); |
+ assert_equals(pullCount, 1, 'pull should not have been called again after enqueue'); |
+ |
+ return reader.read().then(test10.step_func(function() { |
+ assert_equals(pullCount, 2, 'pull should have been called again after read'); |
+ |
+ setTimeout(test10.step_func(function() { |
+ assert_equals(pullCount, 2, 'pull should be called exactly twice'); |
+ test10.done(); |
+ }), 500); |
+ })); |
+ })).catch(test10.step_func(function(e) { assert_unreached(e); })); |
+}); |
+ |
+var test11 = async_test('ReadableStream: should not call pull() in reaction to read()ing the last chunk, if draining'); |
+test11.step(function() { |
+ var pullCount = 0; |
+ var controller; |
+ var startPromise = Promise.resolve(); |
+ var pullPromise = Promise.resolve(); |
+ var rs = new ReadableStream({ |
+ start: function(c) { |
+ controller = c; |
+ return startPromise; |
+ }, |
+ pull: function() { |
+ ++pullCount; |
+ return pullPromise; |
+ } |
+ }); |
+ |
+ var reader = rs.getReader(); |
+ |
+ startPromise.then(test11.step_func(function() { |
+ assert_equals(pullCount, 1, 'pull should have been called once by the time the stream starts'); |
+ |
+ controller.enqueue('a'); |
+ assert_equals(pullCount, 1, 'pull should not have been called again after enqueue'); |
+ |
+ controller.close(); |
+ |
+ return reader.read().then(test11.step_func(function() { |
+ assert_equals(pullCount, 1, 'pull should not have been called a second time after read'); |
+ |
+ setTimeout(test11.step_func(function() { |
+ assert_equals(pullCount, 1, 'pull should be called exactly once'); |
+ test11.done(); |
+ }), 1000); |
+ })); |
+ })).catch(test11.step_func(function(e) { assert_unreached(e); })); |
+}); |
+ |
+var test12 = async_test('ReadableStream: should not call pull until the previous pull call\'s promise fulfills'); |
+test12.step(function() { |
+ var resolve; |
+ var returnedPromise; |
+ var timesCalled = 0; |
+ var startPromise = Promise.resolve(); |
+ var rs = new ReadableStream({ |
+ start: function() { |
+ return startPromise; |
+ }, |
+ pull: function(c) { |
+ c.enqueue(++timesCalled); |
+ returnedPromise = new Promise(test12.step_func(function(r) { resolve = r; })); |
+ return returnedPromise; |
+ } |
+ }); |
+ var reader = rs.getReader(); |
+ |
+ startPromise.then(test12.step_func(function() { |
+ return reader.read().then(test12.step_func(function(result1) { |
+ assert_equals(timesCalled, 1, |
+ 'pull should have been called once after start, but not yet have been called a second time'); |
+ assert_object_equals(result1, { value: 1, done: false }, 'read() should fulfill with the enqueued value'); |
+ |
+ setTimeout(test12.step_func(function() { |
+ assert_equals(timesCalled, 1, 'after 30 ms, pull should still only have been called once'); |
+ |
+ resolve(); |
+ |
+ returnedPromise.then(test12.step_func(function() { |
+ assert_equals(timesCalled, 2, |
+ 'after the promise returned by pull is fulfilled, pull should be called a second time'); |
+ test12.done(); |
+ })); |
+ }), 500); |
+ })); |
+ })).catch(test12.step_func(function(e) { assert_unreached(e); })); |
+}); |
+ |
+var test13 = async_test('ReadableStream: should pull after start, and after every read'); |
+test13.step(function() { |
+ var timesCalled = 0; |
+ var startPromise = Promise.resolve(); |
+ var rs = new ReadableStream({ |
+ start: function(c) { |
+ c.enqueue('a'); |
+ c.enqueue('b'); |
+ c.enqueue('c'); |
+ return startPromise; |
+ }, |
+ pull() { |
+ ++timesCalled; |
+ } |
+ }, |
+ { |
+ size: function() { |
+ return 1; |
+ }, |
+ highWaterMark: Infinity |
+ }); |
+ var reader = rs.getReader(); |
+ |
+ startPromise.then(test13.step_func(function() { |
+ return reader.read().then(test13.step_func(function(result1) { |
+ assert_object_equals(result1, { value: 'a', done: false }, 'first chunk should be as expected'); |
+ |
+ return reader.read().then(test13.step_func(function(result2) { |
+ assert_object_equals(result2, { value: 'b', done: false }, 'second chunk should be as expected'); |
+ |
+ return reader.read().then(test13.step_func(function(result3) { |
+ assert_object_equals(result3, { value: 'c', done: false }, 'third chunk should be as expected'); |
+ |
+ setTimeout(test13.step_func(function() { |
+ // Once for after start, and once for every read. |
+ assert_equals(timesCalled, 4, 'pull() should be called exactly four times'); |
+ test13.done(); |
+ }), 1000); |
+ })); |
+ })); |
+ })); |
+ })).catch(test13.step_func(function(e) { assert_unreached(e); })); |
+}); |
+ |
+var test14 = async_test('ReadableStream: should not call pull after start if the stream is now closed'); |
+test14.step(function() { |
+ var timesCalled = 0; |
+ var startPromise = Promise.resolve(); |
+ var rs = new ReadableStream({ |
+ start: function(c) { |
+ c.enqueue('a'); |
+ c.close(); |
+ return startPromise; |
+ }, |
+ pull: function() { |
+ ++timesCalled; |
+ } |
+ }); |
+ |
+ startPromise.then(test14.step_func(function() { |
+ assert_equals(timesCalled, 0, 'after start finishes, pull should not have been called'); |
+ |
+ var reader = rs.getReader(); |
+ return reader.read().then(test14.step_func(function() { |
+ assert_equals(timesCalled, 0, 'reading should not have triggered a pull call'); |
+ |
+ return reader.closed.then(test14.step_func(function() { |
+ assert_equals(timesCalled, 0, 'stream should have closed with still no calls to pull'); |
+ test14.done(); |
+ })); |
+ })); |
+ })).catch(test14.step_func(function(e) { assert_unreached(e); })); |
+}); |
+ |
+var test15 = async_test('ReadableStream: should call pull after enqueueing from inside pull (with no read requests), if strategy allows'); |
+test15.step(function() { |
+ var timesCalled = 0; |
+ var startPromise = Promise.resolve(); |
+ var rs = new ReadableStream({ |
+ start: function() { |
+ return startPromise; |
+ }, |
+ pull: function(c) { |
+ c.enqueue(++timesCalled); |
+ |
+ if (timesCalled == 4) { |
+ setTimeout(test15.step_func(function() { |
+ // after start: size = 0, pull() |
+ // after enqueue(1): size = 1, pull() |
+ // after enqueue(2): size = 2, pull() |
+ // after enqueue(3): size = 3, pull() |
+ // after enqueue(4): size = 4, do not pull |
+ assert_equals(timesCalled, 4, 'pull() should have been called four times'); |
+ test15.done(); |
+ }), 1000); |
+ } |
+ } |
+ }, |
+ { |
+ size: function() { |
+ return 1; |
+ }, |
+ highWaterMark: 4 |
+ }); |
+}); |
+ |
+var test16 = async_test('ReadableStream pull should be able to close a stream.'); |
+test16.step(function() { |
+ var pullCalled = false; |
+ var rs = new ReadableStream({ |
+ pull: function(c) { |
+ pullCalled = true; |
+ c.close(); |
+ } |
+ }); |
+ |
+ var reader = rs.getReader(); |
+ reader.closed.then(test16.step_func(function() { |
+ assert_true(pullCalled); |
+ test16.done('stream was closed successfully'); |
+ })); |
+}); |
+ |
+test(function() { |
+ var startCalled = false; |
+ var rs = new ReadableStream({ |
+ start: function(c) { |
+ assert_equals(c.enqueue('a'), undefined, 'the first enqueue should return undefined'); |
+ c.close(); |
+ |
+ assert_throws(new TypeError(''), function() { c.enqueue('b'); }, 'enqueue after close should throw a TypeError'); |
+ startCalled = true; |
+ } |
+ }); |
+ assert_true(startCalled); |
+}, 'ReadableStream: enqueue should throw when the stream is readable but draining'); |
+ |
+test(function() { |
+ var startCalled = false; |
+ var rs = new ReadableStream({ |
+ start: function(c) { |
+ c.close(); |
+ |
+ assert_throws(new TypeError(), function() { c.enqueue('a'); }, 'enqueue after close should throw a TypeError'); |
+ startCalled = true; |
+ } |
+ }); |
+ assert_true(startCalled); |
+}, 'ReadableStream: enqueue should throw when the stream is closed'); |
+ |
+test(function() { |
+ var startCalled = false; |
+ var expectedError = new Error('i am sad'); |
+ var rs = new ReadableStream({ |
+ start: function(c) { |
+ c.error(expectedError); |
+ |
+ assert_throws(expectedError, function() { c.enqueue('a'); }, 'enqueue after error should throw that error'); |
+ startCalled = true; |
+ } |
+ }); |
+ assert_true(startCalled); |
+}, 'ReadableStream: enqueue should throw the stored error when the stream is errored'); |
+ |
+var test17 = async_test('ReadableStream: should call underlying source methods as methods'); |
+test17.step(function() { |
+ var startCalled = 0; |
+ var pullCalled = 0; |
+ var cancelCalled = 0; |
+ |
+ function Source() { |
+ } |
+ |
+ Source.prototype = { |
+ start: function(c) { |
+ startCalled++; |
+ assert_equals(this, theSource, 'start() should be called with the correct this'); |
+ c.enqueue('a'); |
+ }, |
+ |
+ pull: function() { |
+ pullCalled++; |
+ assert_equals(this, theSource, 'pull() should be called with the correct this'); |
+ }, |
+ |
+ cancel: function() { |
+ cancelCalled++; |
+ assert_equals(this, theSource, 'cancel() should be called with the correct this'); |
+ }, |
+ }; |
+ |
+ var theSource = new Source(); |
+ theSource.debugName = 'the source object passed to the constructor'; // makes test failures easier to diagnose |
+ var rs = new ReadableStream(theSource); |
+ |
+ var reader = rs.getReader(); |
+ reader.read().then(test17.step_func(function() { |
+ reader.releaseLock(); |
+ rs.cancel(); |
+ assert_equals(startCalled, 1); |
+ assert_equals(pullCalled, 1); |
+ assert_equals(cancelCalled, 1); |
+ test17.done(); |
+ })).catch(test17.step_func(function(e) { assert_unreached(e); } )); |
+}); |
+ |
+test(function() { |
+ var startCalled = false; |
+ new ReadableStream({ |
+ start: function(c) { |
+ assert_equals(c.desiredSize, 1); |
+ c.enqueue('a'); |
+ assert_equals(c.desiredSize, 0); |
+ c.enqueue('b'); |
+ assert_equals(c.desiredSize, -1); |
+ c.enqueue('c'); |
+ assert_equals(c.desiredSize, -2); |
+ c.enqueue('d'); |
+ assert_equals(c.desiredSize, -3); |
+ c.enqueue('e'); |
+ startCalled = true; |
+ } |
+ }); |
+ assert_true(startCalled); |
+}, 'ReadableStream strategies: the default strategy should give desiredSize of 1 to start, decreasing by 1 per enqueue'); |
+ |
+var test18 = async_test('ReadableStream strategies: the default strategy should continue giving desiredSize of 1 if the chunks are read immediately'); |
+test18.step(function() { |
+ var controller; |
+ var rs = new ReadableStream({ |
+ start: function(c) { |
+ controller = c; |
+ } |
+ }); |
+ var reader = rs.getReader(); |
+ |
+ assert_equals(controller.desiredSize, 1, 'desiredSize should start at 1'); |
+ controller.enqueue('a'); |
+ assert_equals(controller.desiredSize, 0, 'desiredSize should decrease to 0 after first enqueue'); |
+ |
+ reader.read().then(test18.step_func(function(result1) { |
+ assert_object_equals(result1, { value: 'a', done: false }, 'first chunk read should be correct'); |
+ |
+ assert_equals(controller.desiredSize, 1, 'desiredSize should go up to 1 after the first read'); |
+ controller.enqueue('b'); |
+ assert_equals(controller.desiredSize, 0, 'desiredSize should go down to 0 after the second enqueue'); |
+ |
+ return reader.read(); |
+ })).then(test18.step_func(function(result2) { |
+ assert_object_equals(result2, { value: 'b', done: false }, 'second chunk read should be correct'); |
+ |
+ assert_equals(controller.desiredSize, 1, 'desiredSize should go up to 1 after the second read'); |
+ controller.enqueue('c'); |
+ assert_equals(controller.desiredSize, 0, 'desiredSize should go down to 0 after the third enqueue'); |
+ |
+ return reader.read(); |
+ })).then(test18.step_func(function(result3) { |
+ assert_object_equals(result3, { value: 'c', done: false }, 'third chunk read should be correct'); |
+ |
+ assert_equals(controller.desiredSize, 1, 'desiredSize should go up to 1 after the third read'); |
+ controller.enqueue('d'); |
+ assert_equals(controller.desiredSize, 0, 'desiredSize should go down to 0 after the fourth enqueue'); |
+ |
+ test18.done(); |
+ })).catch(test18.step_func(function(e) { assert_unreached(e); })); |
+}); |
+ |
+var test19 = async_test('ReadableStream integration test: adapting a random push source'); |
+test19.step(function() { |
+ var pullChecked = false; |
+ var randomSource = new RandomPushSource(8); |
+ |
+ var rs = new ReadableStream({ |
+ start: function(c) { |
+ assert_equals(typeof c, 'object', 'c should be an object in start'); |
+ assert_equals(typeof c.enqueue, 'function', 'enqueue should be a function in start'); |
+ assert_equals(typeof c.close, 'function', 'close should be a function in start'); |
+ assert_equals(typeof c.error, 'function', 'error should be a function in start'); |
+ |
+ randomSource.ondata = test19.step_func(function(chunk) { |
+ if (!c.enqueue(chunk) <= 0) { |
+ randomSource.readStop(); |
+ } |
+ }); |
+ |
+ randomSource.onend = c.close.bind(c); |
+ randomSource.onerror = c.error.bind(c); |
+ }, |
+ |
+ pull: function(c) { |
+ if (!pullChecked) { |
+ pullChecked = true; |
+ assert_equals(typeof c, 'object', 'c should be an object in pull'); |
+ assert_equals(typeof c.enqueue, 'function', 'enqueue should be a function in pull'); |
+ assert_equals(typeof c.close, 'function', 'close should be a function in pull'); |
+ } |
+ |
+ randomSource.readStart(); |
+ } |
+ }); |
+ |
+ readableStreamToArray(rs).then(test19.step_func(function(chunks) { |
+ assert_equals(chunks.length, 8, '8 chunks should be read'); |
+ for (var i = 0; i < chunks.length; i++) { |
+ assert_equals(chunks[i].length, 128, 'chunk should have 128 bytes'); |
+ } |
+ |
+ test19.done(); |
+ }), test19.step_func(function(e) { assert_unreached(e); })); |
+}); |
+ |
+var test20 = async_test('ReadableStream integration test: adapting a sync pull source'); |
+test20.step(function() { |
+ var rs = sequentialReadableStream(10); |
+ |
+ readableStreamToArray(rs).then(test20.step_func(function(chunks) { |
+ assert_true(rs.source.closed, 'source should be closed after all chunks are read'); |
+ assert_array_equals(chunks, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 'the expected 10 chunks should be read'); |
+ |
+ test20.done(); |
+ })); |
+}); |
+ |
+var test21 = async_test('ReadableStream integration test: adapting an async pull source'); |
+test21.step(function() { |
+ var rs = sequentialReadableStream(10, { async: true }); |
+ |
+ readableStreamToArray(rs).then(test21.step_func(function(chunks) { |
+ assert_true(rs.source.closed, 'source should be closed after all chunks are read'); |
+ assert_array_equals(chunks, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 'the expected 10 chunks should be read'); |
+ |
+ test21.done(); |
+ })); |
+}); |
+ |
+done(); |