OLD | NEW |
(Empty) | |
| 1 'use strict'; |
| 2 |
| 3 if (self.importScripts) { |
| 4 self.importScripts('../resources/rs-utils.js'); |
| 5 self.importScripts('/resources/testharness.js'); |
| 6 } |
| 7 |
| 8 var ReadableStreamReader; |
| 9 |
| 10 test(function() { |
| 11 // It's not exposed globally, but we test a few of its properties here. |
| 12 ReadableStreamReader = (new ReadableStream()).getReader().constructor; |
| 13 }, 'Can get the ReadableStreamReader constructor indirectly'); |
| 14 |
| 15 test(function() { |
| 16 assert_throws(new TypeError(), function() { |
| 17 new ReadableStreamReader('potato'); |
| 18 }); |
| 19 assert_throws(new TypeError(), function() { |
| 20 new ReadableStreamReader({}); |
| 21 }); |
| 22 assert_throws(new TypeError(), function() { |
| 23 new ReadableStreamReader(); |
| 24 }); |
| 25 }, 'ReadableStreamReader constructor should get a ReadableStream object as argum
ent'); |
| 26 |
| 27 test(function() { |
| 28 var methods = ['cancel', 'constructor', 'read', 'releaseLock']; |
| 29 var properties = methods.concat(['closed']).sort(); |
| 30 |
| 31 var rsReader = new ReadableStreamReader(new ReadableStream()); |
| 32 var proto = Object.getPrototypeOf(rsReader); |
| 33 |
| 34 assert_array_equals(Object.getOwnPropertyNames(proto).sort(), properties); |
| 35 |
| 36 for (var m of methods) { |
| 37 var propDesc = Object.getOwnPropertyDescriptor(proto, m); |
| 38 assert_equals(propDesc.enumerable, false, 'method should be non-enumerab
le'); |
| 39 assert_equals(propDesc.configurable, true, 'method should be configurabl
e'); |
| 40 assert_equals(propDesc.writable, true, 'method should be writable'); |
| 41 assert_equals(typeof rsReader[m], 'function', 'should have be a method')
; |
| 42 } |
| 43 |
| 44 var closedPropDesc = Object.getOwnPropertyDescriptor(proto, 'closed'); |
| 45 assert_equals(closedPropDesc.enumerable, false, 'closed should be non-enumer
able'); |
| 46 assert_equals(closedPropDesc.configurable, true, 'closed should be configura
ble'); |
| 47 assert_not_equals(closedPropDesc.get, undefined, 'closed should have a gette
r'); |
| 48 assert_equals(closedPropDesc.set, undefined, 'closed should not have a sette
r'); |
| 49 |
| 50 assert_equals(rsReader.cancel.length, 1, 'cancel has 1 parameter'); |
| 51 assert_not_equals(rsReader.closed, undefined, 'has a non-undefined closed pr
operty'); |
| 52 assert_equals(typeof rsReader.closed.then, 'function', 'closed property is t
henable'); |
| 53 assert_equals(typeof rsReader.constructor, 'function', 'has a constructor me
thod'); |
| 54 assert_equals(rsReader.constructor.length, 1, 'constructor has 1 parameter')
; |
| 55 assert_equals(typeof rsReader.read, 'function', 'has a getReader method'); |
| 56 assert_equals(rsReader.read.length, 0, 'read has no parameters'); |
| 57 assert_equals(typeof rsReader.releaseLock, 'function', 'has a releaseLock me
thod'); |
| 58 assert_equals(rsReader.releaseLock.length, 0, 'releaseLock has no parameters
'); |
| 59 }, 'ReadableStreamReader instances should have the correct list of properties'); |
| 60 |
| 61 test(function() { |
| 62 var rsReader = new ReadableStreamReader(new ReadableStream()); |
| 63 |
| 64 assert_equals(rsReader.closed, rsReader.closed, 'closed should return the sa
me promise'); |
| 65 }, 'ReadableStreamReader closed should always return the same promise object'); |
| 66 |
| 67 test(function() { |
| 68 var rs = new ReadableStream(); |
| 69 new ReadableStreamReader(rs); // Constructing directly the first time should
be fine. |
| 70 assert_throws(new TypeError(), function() { new ReadableStreamReader(rs); },
'constructing directly the second time should fail'); |
| 71 }, 'Constructing a ReadableStreamReader directly should fail if the stream is al
ready locked (via direct construction)'); |
| 72 |
| 73 test(function() { |
| 74 var rs = new ReadableStream(); |
| 75 new ReadableStreamReader(rs); // Constructing directly should be fine. |
| 76 assert_throws(new TypeError(), function() { rs.getReader(); }, 'getReader()
should fail'); |
| 77 }, 'Getting a ReadableStreamReader via getReader should fail if the stream is al
ready locked (via direct construction)'); |
| 78 |
| 79 test(function() { |
| 80 var rs = new ReadableStream(); |
| 81 rs.getReader(); // getReader() should be fine. |
| 82 assert_throws(new TypeError(), function() { new ReadableStreamReader(rs); },
'constructing directly should fail'); |
| 83 }, 'Constructing a ReadableStreamReader directly should fail if the stream is al
ready locked (via getReader)'); |
| 84 |
| 85 test(function() { |
| 86 var rs = new ReadableStream(); |
| 87 rs.getReader(); // getReader() should be fine. |
| 88 assert_throws(new TypeError(), function() { rs.getReader(); }, 'getReader()
should fail'); |
| 89 }, 'Getting a ReadableStreamReader via getReader should fail if the stream is al
ready locked (via getReader)'); |
| 90 |
| 91 test(function() { |
| 92 var rs = new ReadableStream({ |
| 93 start: function(c) { |
| 94 c.close(); |
| 95 } |
| 96 }); |
| 97 |
| 98 new ReadableStreamReader(rs); // Constructing directly should not throw. |
| 99 }, 'Constructing a ReadableStreamReader directly should be OK if the stream is c
losed'); |
| 100 |
| 101 test(function() { |
| 102 var theError = new Error('don\'t say i didn\'t warn ya'); |
| 103 var rs = new ReadableStream({ |
| 104 start: function(c) { |
| 105 c.error(theError); |
| 106 } |
| 107 }); |
| 108 |
| 109 new ReadableStreamReader(rs); // Constructing directly should not throw. |
| 110 }, 'Constructing a ReadableStreamReader directly should be OK if the stream is e
rrored'); |
| 111 |
| 112 var test1 = async_test('Reading from a reader for an empty stream will wait unti
l a chunk is available'); |
| 113 test1.step(function() { |
| 114 var controller; |
| 115 var rs = new ReadableStream({ |
| 116 start: function(c) { |
| 117 controller = c; |
| 118 } |
| 119 }); |
| 120 var reader = rs.getReader(); |
| 121 |
| 122 reader.read().then(test1.step_func(function(result) { |
| 123 assert_object_equals(result, { value: 'a', done: false }, 'read() should
fulfill with the enqueued chunk'); |
| 124 test1.done(); |
| 125 })); |
| 126 |
| 127 controller.enqueue('a'); |
| 128 }); |
| 129 |
| 130 var test2 = async_test('cancel() on a reader does not release the reader'); |
| 131 test2.step(function() { |
| 132 var cancelCalled = false; |
| 133 var passedReason = new Error('it wasn\'t the right time, sorry'); |
| 134 var rs = new ReadableStream({ |
| 135 cancel: function(reason) { |
| 136 assert_true(rs.locked, 'the stream should still be locked'); |
| 137 assert_throws(new TypeError(), function() { rs.getReader(); }, 'shou
ld not be able to get another reader'); |
| 138 assert_equals(reason, passedReason, 'the cancellation reason is pass
ed through to the underlying source'); |
| 139 cancelCalled = true; |
| 140 } |
| 141 }); |
| 142 |
| 143 var reader = rs.getReader(); |
| 144 reader.cancel(passedReason).then( |
| 145 test2.step_func(function() { |
| 146 assert_true(cancelCalled); |
| 147 test2.done('reader.cancel() should fulfill'); |
| 148 }), |
| 149 test2.step_func(function(e) { assert_unreached('reader.cancel() should n
ot reject'); }) |
| 150 ); |
| 151 }); |
| 152 |
| 153 var test3 = async_test('closed should be fulfilled after stream is closed (.clos
ed access before acquiring)'); |
| 154 test3.step(function() { |
| 155 var controller; |
| 156 var rs = new ReadableStream({ |
| 157 start: function(c) { |
| 158 controller = c; |
| 159 } |
| 160 }); |
| 161 |
| 162 var reader = rs.getReader(); |
| 163 reader.closed.then(test3.step_func(function() { |
| 164 test3.done('reader closed should be fulfilled'); |
| 165 })); |
| 166 |
| 167 controller.close(); |
| 168 }); |
| 169 |
| 170 var test4 = async_test('closed should be rejected after reader releases its lock
(multiple stream locks)'); |
| 171 test4.step(function() { |
| 172 var promiseCalls = 0; |
| 173 var controller; |
| 174 var rs = new ReadableStream({ |
| 175 start: function(c) { |
| 176 controller = c; |
| 177 } |
| 178 }); |
| 179 |
| 180 var reader1 = rs.getReader(); |
| 181 |
| 182 reader1.releaseLock(); |
| 183 |
| 184 var reader2 = rs.getReader(); |
| 185 controller.close(); |
| 186 |
| 187 reader1.closed.catch(test4.step_func(function(e) { |
| 188 assert_throws(new TypeError(), function() { throw e; }, 'reader1 closed
should be rejected with a TypeError'); |
| 189 assert_equals(++promiseCalls, 1); |
| 190 })); |
| 191 |
| 192 reader2.closed.then(test4.step_func(function() { |
| 193 assert_equals(++promiseCalls, 2); |
| 194 test4.done('reader2 closed should be fulfilled'); |
| 195 })); |
| 196 }); |
| 197 |
| 198 var test5 = async_test('Multiple readers can access the stream in sequence'); |
| 199 test5.step(function() { |
| 200 var readCount = 0; |
| 201 var rs = new ReadableStream({ |
| 202 start: function(c) { |
| 203 c.enqueue('a'); |
| 204 c.enqueue('b'); |
| 205 c.close(); |
| 206 } |
| 207 }); |
| 208 |
| 209 var reader1 = rs.getReader(); |
| 210 reader1.read().then(test5.step_func(function(r) { |
| 211 assert_object_equals(r, { value: 'a', done: false }, 'reading the first
chunk from reader1 works'); |
| 212 ++readCount; |
| 213 })); |
| 214 reader1.releaseLock(); |
| 215 |
| 216 var reader2 = rs.getReader(); |
| 217 reader2.read().then(test5.step_func(function(r) { |
| 218 assert_object_equals(r, { value: 'b', done: false }, 'reading the second
chunk from reader2 works'); |
| 219 assert_equals(++readCount, 2); |
| 220 test5.done(); |
| 221 })); |
| 222 reader2.releaseLock(); |
| 223 }); |
| 224 |
| 225 var test6 = async_test('Cannot use an already-released reader to unlock a stream
again'); |
| 226 test6.step(function() { |
| 227 var rs = new ReadableStream({ |
| 228 start: function(c) { |
| 229 c.enqueue('a'); |
| 230 } |
| 231 }); |
| 232 |
| 233 var reader1 = rs.getReader(); |
| 234 reader1.releaseLock(); |
| 235 |
| 236 var reader2 = rs.getReader(); |
| 237 |
| 238 reader1.releaseLock(); |
| 239 reader2.read().then(test6.step_func(function(result) { |
| 240 assert_object_equals(result, { value: 'a', done: false }, 'read() should
still work on reader2 even after reader1 is released'); |
| 241 test6.done(); |
| 242 })); |
| 243 }); |
| 244 |
| 245 var test7 = async_test('cancel() on a released reader is a no-op and does not pa
ss through'); |
| 246 test7.step(function() { |
| 247 var promiseCalls = 0; |
| 248 var rs = new ReadableStream({ |
| 249 start: function(c) { |
| 250 c.enqueue('a'); |
| 251 }, |
| 252 cancel: function() { |
| 253 assert_unreached('underlying source cancel should not be called'); |
| 254 } |
| 255 }); |
| 256 |
| 257 var reader = rs.getReader(); |
| 258 reader.releaseLock(); |
| 259 reader.cancel().then(test7.step_func(function(v) { |
| 260 assert_unreached('cancel promise should not fulfill'); |
| 261 })).catch(test7.step_func(function(e) { |
| 262 assert_equals(++promiseCalls, 2); |
| 263 test7.done(); |
| 264 })); |
| 265 |
| 266 var reader2 = rs.getReader(); |
| 267 reader2.read().then(test7.step_func(function(r) { |
| 268 assert_object_equals(r, { value: 'a', done: false }, 'a new reader shoul
d be able to read a chunk'); |
| 269 assert_equals(++promiseCalls, 1); |
| 270 })); |
| 271 }); |
| 272 |
| 273 var test8 = async_test('Getting a second reader after erroring the stream should
succeed'); |
| 274 test8.step(function() { |
| 275 var controller; |
| 276 var receivedErrors = 0; |
| 277 var theError = new Error('bad'); |
| 278 var rs = new ReadableStream({ |
| 279 start: function(c) { |
| 280 controller = c; |
| 281 } |
| 282 }); |
| 283 |
| 284 var reader1 = rs.getReader(); |
| 285 |
| 286 reader1.closed.catch(test8.step_func(function(e) { |
| 287 assert_equals(e, theError, 'the first reader closed getter should be rej
ected with the error'); |
| 288 ++receivedErrors; |
| 289 })); |
| 290 |
| 291 reader1.read().catch(test8.step_func(function(e) { |
| 292 assert_equals(e, theError, 'the first reader read() should be rejected w
ith the error'); |
| 293 ++receivedErrors; |
| 294 })); |
| 295 |
| 296 assert_throws(new TypeError(), function() { rs.getReader(); }, 'trying to ge
t another reader before erroring should throw'); |
| 297 |
| 298 controller.error(theError); |
| 299 |
| 300 reader1.releaseLock(); |
| 301 |
| 302 var reader2 = rs.getReader(); |
| 303 |
| 304 reader2.closed.catch(test8.step_func(function(e) { |
| 305 assert_equals(e, theError, 'the second reader closed getter should be re
jected with the error'); |
| 306 ++receivedErrors; |
| 307 })); |
| 308 |
| 309 reader2.read().catch(test8.step_func(function(e) { |
| 310 assert_equals(e, theError, 'the third reader read() should be rejected w
ith the error'); |
| 311 assert_equals(++receivedErrors, 4); |
| 312 test8.done(); |
| 313 })); |
| 314 }); |
| 315 |
| 316 var test9 = async_test('ReadableStreamReader closed promise should be rejected w
ith undefined if that is the error'); |
| 317 test9.step(function() { |
| 318 var controller; |
| 319 var rs = new ReadableStream({ |
| 320 start: function(c) { |
| 321 controller = c; |
| 322 } |
| 323 }); |
| 324 |
| 325 rs.getReader().closed.then(test9.step_func(function() { |
| 326 assert_unreached("closed promise should not be resolved when stream is e
rrored"); |
| 327 }), test9.step_func(function(err) { |
| 328 assert_equals(err, undefined, 'passed error should be undefined as it wa
s'); |
| 329 test9.done(); |
| 330 })); |
| 331 |
| 332 controller.error(); |
| 333 }); |
| 334 |
| 335 done(); |
OLD | NEW |