general.any.js (100296B)
1 // META: global=window,worker,shadowrealm 2 // META: script=../resources/rs-utils.js 3 // META: script=../resources/test-utils.js 4 'use strict'; 5 6 const error1 = new Error('error1'); 7 error1.name = 'error1'; 8 9 test(() => { 10 assert_throws_js(TypeError, () => new ReadableStream().getReader({ mode: 'byob' })); 11 }, 'getReader({mode: "byob"}) throws on non-bytes streams'); 12 13 14 test(() => { 15 // Constructing ReadableStream with an empty underlying byte source object as parameter shouldn't throw. 16 new ReadableStream({ type: 'bytes' }).getReader({ mode: 'byob' }); 17 // Constructor must perform ToString(type). 18 new ReadableStream({ type: { toString() {return 'bytes';} } }) 19 .getReader({ mode: 'byob' }); 20 new ReadableStream({ type: { toString: null, valueOf() {return 'bytes';} } }) 21 .getReader({ mode: 'byob' }); 22 }, 'ReadableStream with byte source can be constructed with no errors'); 23 24 test(() => { 25 const ReadableStreamBYOBReader = new ReadableStream({ type: 'bytes' }).getReader({ mode: 'byob' }).constructor; 26 const rs = new ReadableStream({ type: 'bytes' }); 27 28 let reader = rs.getReader({ mode: { toString() { return 'byob'; } } }); 29 assert_true(reader instanceof ReadableStreamBYOBReader, 'must give a BYOB reader'); 30 reader.releaseLock(); 31 32 reader = rs.getReader({ mode: { toString: null, valueOf() {return 'byob';} } }); 33 assert_true(reader instanceof ReadableStreamBYOBReader, 'must give a BYOB reader'); 34 reader.releaseLock(); 35 36 reader = rs.getReader({ mode: 'byob', notmode: 'ignored' }); 37 assert_true(reader instanceof ReadableStreamBYOBReader, 'must give a BYOB reader'); 38 }, 'getReader({mode}) must perform ToString()'); 39 40 promise_test(() => { 41 let startCalled = false; 42 let startCalledBeforePull = false; 43 let desiredSize; 44 let controller; 45 46 let resolveTestPromise; 47 const testPromise = new Promise(resolve => { 48 resolveTestPromise = resolve; 49 }); 50 51 new ReadableStream({ 52 start(c) { 53 controller = c; 54 startCalled = true; 55 }, 56 pull() { 57 startCalledBeforePull = startCalled; 58 desiredSize = controller.desiredSize; 59 resolveTestPromise(); 60 }, 61 type: 'bytes' 62 }, { 63 highWaterMark: 256 64 }); 65 66 return testPromise.then(() => { 67 assert_true(startCalledBeforePull, 'start should be called before pull'); 68 assert_equals(desiredSize, 256, 'desiredSize should equal highWaterMark'); 69 }); 70 71 }, 'ReadableStream with byte source: Construct and expect start and pull being called'); 72 73 promise_test(() => { 74 let pullCount = 0; 75 let checkedNoPull = false; 76 77 let resolveTestPromise; 78 const testPromise = new Promise(resolve => { 79 resolveTestPromise = resolve; 80 }); 81 let resolveStartPromise; 82 83 new ReadableStream({ 84 start() { 85 return new Promise(resolve => { 86 resolveStartPromise = resolve; 87 }); 88 }, 89 pull() { 90 if (checkedNoPull) { 91 resolveTestPromise(); 92 } 93 94 ++pullCount; 95 }, 96 type: 'bytes' 97 }, { 98 highWaterMark: 256 99 }); 100 101 Promise.resolve().then(() => { 102 assert_equals(pullCount, 0); 103 checkedNoPull = true; 104 resolveStartPromise(); 105 }); 106 107 return testPromise; 108 109 }, 'ReadableStream with byte source: No automatic pull call if start doesn\'t finish'); 110 111 test(() => { 112 assert_throws_js(Error, () => new ReadableStream({ start() { throw new Error(); }, type:'bytes' }), 113 'start() can throw an exception with type: bytes'); 114 }, 'ReadableStream with byte source: start() throws an exception'); 115 116 promise_test(t => { 117 new ReadableStream({ 118 pull: t.unreached_func('pull() should not be called'), 119 type: 'bytes' 120 }, { 121 highWaterMark: 0 122 }); 123 124 return Promise.resolve(); 125 }, 'ReadableStream with byte source: Construct with highWaterMark of 0'); 126 127 test(() => { 128 new ReadableStream({ 129 start(c) { 130 assert_equals(c.desiredSize, 10, 'desiredSize must start at the highWaterMark'); 131 c.close(); 132 assert_equals(c.desiredSize, 0, 'after closing, desiredSize must be 0'); 133 }, 134 type: 'bytes' 135 }, { 136 highWaterMark: 10 137 }); 138 }, 'ReadableStream with byte source: desiredSize when closed'); 139 140 test(() => { 141 new ReadableStream({ 142 start(c) { 143 assert_equals(c.desiredSize, 10, 'desiredSize must start at the highWaterMark'); 144 c.error(); 145 assert_equals(c.desiredSize, null, 'after erroring, desiredSize must be null'); 146 }, 147 type: 'bytes' 148 }, { 149 highWaterMark: 10 150 }); 151 }, 'ReadableStream with byte source: desiredSize when errored'); 152 153 promise_test(t => { 154 const stream = new ReadableStream({ 155 type: 'bytes' 156 }); 157 158 const reader = stream.getReader(); 159 reader.releaseLock(); 160 161 return promise_rejects_js(t, TypeError, reader.closed, 'closed must reject'); 162 }, 'ReadableStream with byte source: getReader(), then releaseLock()'); 163 164 promise_test(t => { 165 const stream = new ReadableStream({ 166 type: 'bytes' 167 }); 168 169 const reader = stream.getReader({ mode: 'byob' }); 170 reader.releaseLock(); 171 172 return promise_rejects_js(t, TypeError, reader.closed, 'closed must reject'); 173 }, 'ReadableStream with byte source: getReader() with mode set to byob, then releaseLock()'); 174 175 promise_test(t => { 176 const stream = new ReadableStream({ 177 start(c) { 178 c.close(); 179 }, 180 pull: t.unreached_func('pull() should not be called'), 181 type: 'bytes' 182 }); 183 184 const reader = stream.getReader(); 185 186 return reader.closed.then(() => { 187 assert_throws_js(TypeError, () => stream.getReader(), 'getReader() must throw'); 188 }); 189 }, 'ReadableStream with byte source: Test that closing a stream does not release a reader automatically'); 190 191 promise_test(t => { 192 const stream = new ReadableStream({ 193 start(c) { 194 c.close(); 195 }, 196 pull: t.unreached_func('pull() should not be called'), 197 type: 'bytes' 198 }); 199 200 const reader = stream.getReader({ mode: 'byob' }); 201 202 return reader.closed.then(() => { 203 assert_throws_js(TypeError, () => stream.getReader({ mode: 'byob' }), 'getReader() must throw'); 204 }); 205 }, 'ReadableStream with byte source: Test that closing a stream does not release a BYOB reader automatically'); 206 207 promise_test(t => { 208 const stream = new ReadableStream({ 209 start(c) { 210 c.error(error1); 211 }, 212 pull: t.unreached_func('pull() should not be called'), 213 type: 'bytes' 214 }); 215 216 const reader = stream.getReader(); 217 218 return promise_rejects_exactly(t, error1, reader.closed, 'closed must reject').then(() => { 219 assert_throws_js(TypeError, () => stream.getReader(), 'getReader() must throw'); 220 }); 221 }, 'ReadableStream with byte source: Test that erroring a stream does not release a reader automatically'); 222 223 promise_test(t => { 224 const stream = new ReadableStream({ 225 start(c) { 226 c.error(error1); 227 }, 228 pull: t.unreached_func('pull() should not be called'), 229 type: 'bytes' 230 }); 231 232 const reader = stream.getReader({ mode: 'byob' }); 233 234 return promise_rejects_exactly(t, error1, reader.closed, 'closed must reject').then(() => { 235 assert_throws_js(TypeError, () => stream.getReader({ mode: 'byob' }), 'getReader() must throw'); 236 }); 237 }, 'ReadableStream with byte source: Test that erroring a stream does not release a BYOB reader automatically'); 238 239 promise_test(async t => { 240 const rs = new ReadableStream({ 241 type: 'bytes', 242 start(c) { 243 c.enqueue(new Uint8Array([1, 2, 3])); 244 } 245 }); 246 247 const reader1 = rs.getReader({mode: 'byob'}); 248 reader1.releaseLock(); 249 250 const reader2 = rs.getReader({mode: 'byob'}); 251 252 // Should be a no-op 253 reader1.releaseLock(); 254 255 const result = await reader2.read(new Uint8Array([0, 0, 0])); 256 assert_typed_array_equals(result.value, new Uint8Array([1, 2, 3]), 257 'read() should still work on reader2 even after reader1 is released'); 258 assert_false(result.done, 'done'); 259 260 }, 'ReadableStream with byte source: cannot use an already-released BYOB reader to unlock a stream again'); 261 262 promise_test(async t => { 263 const stream = new ReadableStream({ 264 type: 'bytes' 265 }); 266 267 const reader = stream.getReader(); 268 const read = reader.read(); 269 reader.releaseLock(); 270 await promise_rejects_js(t, TypeError, read, 'pending read must reject'); 271 }, 'ReadableStream with byte source: releaseLock() on ReadableStreamDefaultReader must reject pending read()'); 272 273 promise_test(async t => { 274 const stream = new ReadableStream({ 275 type: 'bytes' 276 }); 277 278 const reader = stream.getReader({ mode: 'byob' }); 279 const read = reader.read(new Uint8Array(1)); 280 reader.releaseLock(); 281 await promise_rejects_js(t, TypeError, read, 'pending read must reject'); 282 }, 'ReadableStream with byte source: releaseLock() on ReadableStreamBYOBReader must reject pending read()'); 283 284 promise_test(() => { 285 let pullCount = 0; 286 287 const stream = new ReadableStream({ 288 pull() { 289 ++pullCount; 290 }, 291 type: 'bytes' 292 }, { 293 highWaterMark: 8 294 }); 295 296 stream.getReader(); 297 298 assert_equals(pullCount, 0, 'No pull as start() just finished and is not yet reflected to the state of the stream'); 299 300 return Promise.resolve().then(() => { 301 assert_equals(pullCount, 1, 'pull must be invoked'); 302 }); 303 }, 'ReadableStream with byte source: Automatic pull() after start()'); 304 305 promise_test(() => { 306 let pullCount = 0; 307 308 const stream = new ReadableStream({ 309 pull() { 310 ++pullCount; 311 }, 312 type: 'bytes' 313 }, { 314 highWaterMark: 0 315 }); 316 317 const reader = stream.getReader(); 318 reader.read(); 319 320 assert_equals(pullCount, 0, 'No pull as start() just finished and is not yet reflected to the state of the stream'); 321 322 return Promise.resolve().then(() => { 323 assert_equals(pullCount, 1, 'pull must be invoked'); 324 }); 325 }, 'ReadableStream with byte source: Automatic pull() after start() and read()'); 326 327 // View buffers are detached after pull() returns, so record the information at the time that pull() was called. 328 function extractViewInfo(view) { 329 return { 330 constructor: view.constructor, 331 bufferByteLength: view.buffer.byteLength, 332 byteOffset: view.byteOffset, 333 byteLength: view.byteLength 334 }; 335 } 336 337 promise_test(() => { 338 let pullCount = 0; 339 let controller; 340 const byobRequests = []; 341 342 const stream = new ReadableStream({ 343 start(c) { 344 controller = c; 345 }, 346 pull() { 347 const byobRequest = controller.byobRequest; 348 const view = byobRequest.view; 349 byobRequests[pullCount] = { 350 nonNull: byobRequest !== null, 351 viewNonNull: view !== null, 352 viewInfo: extractViewInfo(view) 353 }; 354 if (pullCount === 0) { 355 view[0] = 0x01; 356 byobRequest.respond(1); 357 } else if (pullCount === 1) { 358 view[0] = 0x02; 359 view[1] = 0x03; 360 byobRequest.respond(2); 361 } 362 363 ++pullCount; 364 }, 365 type: 'bytes', 366 autoAllocateChunkSize: 16 367 }, { 368 highWaterMark: 0 369 }); 370 371 const reader = stream.getReader(); 372 const p0 = reader.read(); 373 const p1 = reader.read(); 374 375 assert_equals(pullCount, 0, 'No pull() as start() just finished and is not yet reflected to the state of the stream'); 376 377 return Promise.resolve().then(() => { 378 assert_equals(pullCount, 1, 'pull() must have been invoked once'); 379 const byobRequest = byobRequests[0]; 380 assert_true(byobRequest.nonNull, 'first byobRequest must not be null'); 381 assert_true(byobRequest.viewNonNull, 'first byobRequest.view must not be null'); 382 const viewInfo = byobRequest.viewInfo; 383 assert_equals(viewInfo.constructor, Uint8Array, 'first view.constructor should be Uint8Array'); 384 assert_equals(viewInfo.bufferByteLength, 16, 'first view.buffer.byteLength should be 16'); 385 assert_equals(viewInfo.byteOffset, 0, 'first view.byteOffset should be 0'); 386 assert_equals(viewInfo.byteLength, 16, 'first view.byteLength should be 16'); 387 388 return p0; 389 }).then(result => { 390 assert_equals(pullCount, 2, 'pull() must have been invoked twice'); 391 const value = result.value; 392 assert_not_equals(value, undefined, 'first read should have a value'); 393 assert_equals(value.constructor, Uint8Array, 'first value should be a Uint8Array'); 394 assert_equals(value.buffer.byteLength, 16, 'first value.buffer.byteLength should be 16'); 395 assert_equals(value.byteOffset, 0, 'first value.byteOffset should be 0'); 396 assert_equals(value.byteLength, 1, 'first value.byteLength should be 1'); 397 assert_equals(value[0], 0x01, 'first value[0] should be 0x01'); 398 const byobRequest = byobRequests[1]; 399 assert_true(byobRequest.nonNull, 'second byobRequest must not be null'); 400 assert_true(byobRequest.viewNonNull, 'second byobRequest.view must not be null'); 401 const viewInfo = byobRequest.viewInfo; 402 assert_equals(viewInfo.constructor, Uint8Array, 'second view.constructor should be Uint8Array'); 403 assert_equals(viewInfo.bufferByteLength, 16, 'second view.buffer.byteLength should be 16'); 404 assert_equals(viewInfo.byteOffset, 0, 'second view.byteOffset should be 0'); 405 assert_equals(viewInfo.byteLength, 16, 'second view.byteLength should be 16'); 406 407 return p1; 408 }).then(result => { 409 assert_equals(pullCount, 2, 'pull() should only be invoked twice'); 410 const value = result.value; 411 assert_not_equals(value, undefined, 'second read should have a value'); 412 assert_equals(value.constructor, Uint8Array, 'second value should be a Uint8Array'); 413 assert_equals(value.buffer.byteLength, 16, 'second value.buffer.byteLength should be 16'); 414 assert_equals(value.byteOffset, 0, 'second value.byteOffset should be 0'); 415 assert_equals(value.byteLength, 2, 'second value.byteLength should be 2'); 416 assert_equals(value[0], 0x02, 'second value[0] should be 0x02'); 417 assert_equals(value[1], 0x03, 'second value[1] should be 0x03'); 418 }); 419 }, 'ReadableStream with byte source: autoAllocateChunkSize'); 420 421 promise_test(() => { 422 let pullCount = 0; 423 let controller; 424 const byobRequests = []; 425 426 const stream = new ReadableStream({ 427 start(c) { 428 controller = c; 429 }, 430 pull() { 431 const byobRequest = controller.byobRequest; 432 const view = byobRequest.view; 433 byobRequests[pullCount] = { 434 nonNull: byobRequest !== null, 435 viewNonNull: view !== null, 436 viewInfo: extractViewInfo(view) 437 }; 438 if (pullCount === 0) { 439 view[0] = 0x01; 440 byobRequest.respond(1); 441 } else if (pullCount === 1) { 442 view[0] = 0x02; 443 view[1] = 0x03; 444 byobRequest.respond(2); 445 } 446 447 ++pullCount; 448 }, 449 type: 'bytes', 450 autoAllocateChunkSize: 16 451 }, { 452 highWaterMark: 0 453 }); 454 455 const reader = stream.getReader(); 456 return reader.read().then(result => { 457 const value = result.value; 458 assert_not_equals(value, undefined, 'first read should have a value'); 459 assert_equals(value.constructor, Uint8Array, 'first value should be a Uint8Array'); 460 assert_equals(value.buffer.byteLength, 16, 'first value.buffer.byteLength should be 16'); 461 assert_equals(value.byteOffset, 0, 'first value.byteOffset should be 0'); 462 assert_equals(value.byteLength, 1, 'first value.byteLength should be 1'); 463 assert_equals(value[0], 0x01, 'first value[0] should be 0x01'); 464 const byobRequest = byobRequests[0]; 465 assert_true(byobRequest.nonNull, 'first byobRequest must not be null'); 466 assert_true(byobRequest.viewNonNull, 'first byobRequest.view must not be null'); 467 const viewInfo = byobRequest.viewInfo; 468 assert_equals(viewInfo.constructor, Uint8Array, 'first view.constructor should be Uint8Array'); 469 assert_equals(viewInfo.bufferByteLength, 16, 'first view.buffer.byteLength should be 16'); 470 assert_equals(viewInfo.byteOffset, 0, 'first view.byteOffset should be 0'); 471 assert_equals(viewInfo.byteLength, 16, 'first view.byteLength should be 16'); 472 473 reader.releaseLock(); 474 const byobReader = stream.getReader({ mode: 'byob' }); 475 return byobReader.read(new Uint8Array(32)); 476 }).then(result => { 477 const value = result.value; 478 assert_not_equals(value, undefined, 'second read should have a value'); 479 assert_equals(value.constructor, Uint8Array, 'second value should be a Uint8Array'); 480 assert_equals(value.buffer.byteLength, 32, 'second value.buffer.byteLength should be 32'); 481 assert_equals(value.byteOffset, 0, 'second value.byteOffset should be 0'); 482 assert_equals(value.byteLength, 2, 'second value.byteLength should be 2'); 483 assert_equals(value[0], 0x02, 'second value[0] should be 0x02'); 484 assert_equals(value[1], 0x03, 'second value[1] should be 0x03'); 485 const byobRequest = byobRequests[1]; 486 assert_true(byobRequest.nonNull, 'second byobRequest must not be null'); 487 assert_true(byobRequest.viewNonNull, 'second byobRequest.view must not be null'); 488 const viewInfo = byobRequest.viewInfo; 489 assert_equals(viewInfo.constructor, Uint8Array, 'second view.constructor should be Uint8Array'); 490 assert_equals(viewInfo.bufferByteLength, 32, 'second view.buffer.byteLength should be 32'); 491 assert_equals(viewInfo.byteOffset, 0, 'second view.byteOffset should be 0'); 492 assert_equals(viewInfo.byteLength, 32, 'second view.byteLength should be 32'); 493 assert_equals(pullCount, 2, 'pullCount should be 2'); 494 }); 495 }, 'ReadableStream with byte source: Mix of auto allocate and BYOB'); 496 497 promise_test(() => { 498 let pullCount = 0; 499 500 const stream = new ReadableStream({ 501 pull() { 502 ++pullCount; 503 }, 504 type: 'bytes' 505 }, { 506 highWaterMark: 0 507 }); 508 509 const reader = stream.getReader(); 510 reader.read(new Uint8Array(8)); 511 512 assert_equals(pullCount, 0, 'No pull as start() just finished and is not yet reflected to the state of the stream'); 513 514 return Promise.resolve().then(() => { 515 assert_equals(pullCount, 1, 'pull must be invoked'); 516 }); 517 }, 'ReadableStream with byte source: Automatic pull() after start() and read(view)'); 518 519 promise_test(() => { 520 let pullCount = 0; 521 522 let controller; 523 let desiredSizeInStart; 524 let desiredSizeInPull; 525 526 const stream = new ReadableStream({ 527 start(c) { 528 c.enqueue(new Uint8Array(16)); 529 desiredSizeInStart = c.desiredSize; 530 controller = c; 531 }, 532 pull() { 533 ++pullCount; 534 535 if (pullCount === 1) { 536 desiredSizeInPull = controller.desiredSize; 537 } 538 }, 539 type: 'bytes' 540 }, { 541 highWaterMark: 8 542 }); 543 544 return Promise.resolve().then(() => { 545 assert_equals(pullCount, 0, 'No pull as the queue was filled by start()'); 546 assert_equals(desiredSizeInStart, -8, 'desiredSize after enqueue() in start()'); 547 548 const reader = stream.getReader(); 549 550 const promise = reader.read(); 551 assert_equals(pullCount, 1, 'The first pull() should be made on read()'); 552 assert_equals(desiredSizeInPull, 8, 'desiredSize in pull()'); 553 554 return promise.then(result => { 555 assert_false(result.done, 'result.done'); 556 557 const view = result.value; 558 assert_equals(view.constructor, Uint8Array, 'view.constructor'); 559 assert_equals(view.buffer.byteLength, 16, 'view.buffer'); 560 assert_equals(view.byteOffset, 0, 'view.byteOffset'); 561 assert_equals(view.byteLength, 16, 'view.byteLength'); 562 }); 563 }); 564 }, 'ReadableStream with byte source: enqueue(), getReader(), then read()'); 565 566 promise_test(() => { 567 let controller; 568 569 const stream = new ReadableStream({ 570 start(c) { 571 controller = c; 572 }, 573 type: 'bytes' 574 }); 575 576 const reader = stream.getReader(); 577 578 const promise = reader.read().then(result => { 579 assert_false(result.done); 580 581 const view = result.value; 582 assert_equals(view.constructor, Uint8Array); 583 assert_equals(view.buffer.byteLength, 1); 584 assert_equals(view.byteOffset, 0); 585 assert_equals(view.byteLength, 1); 586 }); 587 588 controller.enqueue(new Uint8Array(1)); 589 590 return promise; 591 }, 'ReadableStream with byte source: Push source that doesn\'t understand pull signal'); 592 593 test(() => { 594 assert_throws_js(TypeError, () => new ReadableStream({ 595 pull: 'foo', 596 type: 'bytes' 597 }), 'constructor should throw'); 598 }, 'ReadableStream with byte source: pull() function is not callable'); 599 600 promise_test(() => { 601 const stream = new ReadableStream({ 602 start(c) { 603 c.enqueue(new Uint16Array(16)); 604 }, 605 type: 'bytes' 606 }); 607 608 const reader = stream.getReader(); 609 610 return reader.read().then(result => { 611 assert_false(result.done); 612 613 const view = result.value; 614 assert_equals(view.constructor, Uint8Array); 615 assert_equals(view.buffer.byteLength, 32); 616 assert_equals(view.byteOffset, 0); 617 assert_equals(view.byteLength, 32); 618 }); 619 }, 'ReadableStream with byte source: enqueue() with Uint16Array, getReader(), then read()'); 620 621 promise_test(t => { 622 const stream = new ReadableStream({ 623 start(c) { 624 const view = new Uint8Array(16); 625 view[0] = 0x01; 626 view[8] = 0x02; 627 c.enqueue(view); 628 }, 629 pull: t.unreached_func('pull() should not be called'), 630 type: 'bytes' 631 }); 632 633 const byobReader = stream.getReader({ mode: 'byob' }); 634 635 return byobReader.read(new Uint8Array(8)).then(result => { 636 assert_false(result.done, 'done'); 637 638 const view = result.value; 639 assert_equals(view.constructor, Uint8Array, 'value.constructor'); 640 assert_equals(view.buffer.byteLength, 8, 'value.buffer.byteLength'); 641 assert_equals(view.byteOffset, 0, 'value.byteOffset'); 642 assert_equals(view.byteLength, 8, 'value.byteLength'); 643 assert_equals(view[0], 0x01); 644 645 byobReader.releaseLock(); 646 647 const reader = stream.getReader(); 648 649 return reader.read(); 650 }).then(result => { 651 assert_false(result.done, 'done'); 652 653 const view = result.value; 654 assert_equals(view.constructor, Uint8Array, 'value.constructor'); 655 assert_equals(view.buffer.byteLength, 16, 'value.buffer.byteLength'); 656 assert_equals(view.byteOffset, 8, 'value.byteOffset'); 657 assert_equals(view.byteLength, 8, 'value.byteLength'); 658 assert_equals(view[0], 0x02); 659 }); 660 }, 'ReadableStream with byte source: enqueue(), read(view) partially, then read()'); 661 662 promise_test(t => { 663 let controller; 664 665 const stream = new ReadableStream({ 666 start(c) { 667 controller = c; 668 }, 669 pull: t.unreached_func('pull() should not be called'), 670 type: 'bytes' 671 }); 672 673 const reader = stream.getReader(); 674 675 controller.enqueue(new Uint8Array(16)); 676 controller.close(); 677 678 return reader.read().then(result => { 679 assert_false(result.done, 'done'); 680 681 const view = result.value; 682 assert_equals(view.byteOffset, 0, 'byteOffset'); 683 assert_equals(view.byteLength, 16, 'byteLength'); 684 685 return reader.read(); 686 }).then(result => { 687 assert_true(result.done, 'done'); 688 assert_equals(result.value, undefined, 'value'); 689 }); 690 }, 'ReadableStream with byte source: getReader(), enqueue(), close(), then read()'); 691 692 promise_test(t => { 693 const stream = new ReadableStream({ 694 start(c) { 695 c.enqueue(new Uint8Array(16)); 696 c.close(); 697 }, 698 pull: t.unreached_func('pull() should not be called'), 699 type: 'bytes' 700 }); 701 702 const reader = stream.getReader(); 703 704 return reader.read().then(result => { 705 assert_false(result.done, 'done'); 706 707 const view = result.value; 708 assert_equals(view.byteOffset, 0, 'byteOffset'); 709 assert_equals(view.byteLength, 16, 'byteLength'); 710 711 return reader.read(); 712 }).then(result => { 713 assert_true(result.done, 'done'); 714 assert_equals(result.value, undefined, 'value'); 715 }); 716 }, 'ReadableStream with byte source: enqueue(), close(), getReader(), then read()'); 717 718 promise_test(() => { 719 let controller; 720 let byobRequest; 721 722 const stream = new ReadableStream({ 723 start(c) { 724 controller = c; 725 }, 726 pull() { 727 controller.enqueue(new Uint8Array(16)); 728 byobRequest = controller.byobRequest; 729 }, 730 type: 'bytes' 731 }); 732 733 const reader = stream.getReader(); 734 735 return reader.read().then(result => { 736 assert_false(result.done, 'done'); 737 assert_equals(result.value.byteLength, 16, 'byteLength'); 738 assert_equals(byobRequest, null, 'byobRequest must be null'); 739 }); 740 }, 'ReadableStream with byte source: Respond to pull() by enqueue()'); 741 742 promise_test(() => { 743 let pullCount = 0; 744 745 let controller; 746 let byobRequest; 747 const desiredSizes = []; 748 749 const stream = new ReadableStream({ 750 start(c) { 751 controller = c; 752 }, 753 pull() { 754 byobRequest = controller.byobRequest; 755 desiredSizes.push(controller.desiredSize); 756 controller.enqueue(new Uint8Array(1)); 757 desiredSizes.push(controller.desiredSize); 758 controller.enqueue(new Uint8Array(1)); 759 desiredSizes.push(controller.desiredSize); 760 761 ++pullCount; 762 }, 763 type: 'bytes' 764 }, { 765 highWaterMark: 0 766 }); 767 768 const reader = stream.getReader(); 769 770 const p0 = reader.read(); 771 const p1 = reader.read(); 772 const p2 = reader.read(); 773 774 // Respond to the first pull call. 775 controller.enqueue(new Uint8Array(1)); 776 777 assert_equals(pullCount, 0, 'pullCount after the enqueue() outside pull'); 778 779 return Promise.all([p0, p1, p2]).then(result => { 780 assert_equals(pullCount, 1, 'pullCount after completion of all read()s'); 781 782 assert_equals(result[0].done, false, 'result[0].done'); 783 assert_equals(result[0].value.byteLength, 1, 'result[0].value.byteLength'); 784 assert_equals(result[1].done, false, 'result[1].done'); 785 assert_equals(result[1].value.byteLength, 1, 'result[1].value.byteLength'); 786 assert_equals(result[2].done, false, 'result[2].done'); 787 assert_equals(result[2].value.byteLength, 1, 'result[2].value.byteLength'); 788 assert_equals(byobRequest, null, 'byobRequest should be null'); 789 assert_equals(desiredSizes[0], 0, 'desiredSize on pull should be 0'); 790 assert_equals(desiredSizes[1], 0, 'desiredSize after 1st enqueue() should be 0'); 791 assert_equals(desiredSizes[2], 0, 'desiredSize after 2nd enqueue() should be 0'); 792 assert_equals(pullCount, 1, 'pull() should only be called once'); 793 }); 794 }, 'ReadableStream with byte source: Respond to pull() by enqueue() asynchronously'); 795 796 promise_test(() => { 797 let pullCount = 0; 798 799 let byobRequest; 800 const desiredSizes = []; 801 802 const stream = new ReadableStream({ 803 pull(c) { 804 byobRequest = c.byobRequest; 805 desiredSizes.push(c.desiredSize); 806 807 if (pullCount < 3) { 808 c.enqueue(new Uint8Array(1)); 809 } else { 810 c.close(); 811 } 812 813 ++pullCount; 814 }, 815 type: 'bytes' 816 }, { 817 highWaterMark: 256 818 }); 819 820 const reader = stream.getReader(); 821 822 const p0 = reader.read(); 823 const p1 = reader.read(); 824 const p2 = reader.read(); 825 826 assert_equals(pullCount, 0, 'No pull as start() just finished and is not yet reflected to the state of the stream'); 827 828 return Promise.all([p0, p1, p2]).then(result => { 829 assert_equals(pullCount, 4, 'pullCount after completion of all read()s'); 830 831 assert_equals(result[0].done, false, 'result[0].done'); 832 assert_equals(result[0].value.byteLength, 1, 'result[0].value.byteLength'); 833 assert_equals(result[1].done, false, 'result[1].done'); 834 assert_equals(result[1].value.byteLength, 1, 'result[1].value.byteLength'); 835 assert_equals(result[2].done, false, 'result[2].done'); 836 assert_equals(result[2].value.byteLength, 1, 'result[2].value.byteLength'); 837 assert_equals(byobRequest, null, 'byobRequest should be null'); 838 assert_equals(desiredSizes[0], 256, 'desiredSize on pull should be 256'); 839 assert_equals(desiredSizes[1], 256, 'desiredSize after 1st enqueue() should be 256'); 840 assert_equals(desiredSizes[2], 256, 'desiredSize after 2nd enqueue() should be 256'); 841 assert_equals(desiredSizes[3], 256, 'desiredSize after 3rd enqueue() should be 256'); 842 }); 843 }, 'ReadableStream with byte source: Respond to multiple pull() by separate enqueue()'); 844 845 promise_test(() => { 846 let controller; 847 848 let pullCount = 0; 849 const byobRequestDefined = []; 850 let byobRequestViewDefined; 851 852 const stream = new ReadableStream({ 853 start(c) { 854 controller = c; 855 }, 856 pull() { 857 byobRequestDefined.push(controller.byobRequest !== null); 858 const initialByobRequest = controller.byobRequest; 859 860 const view = controller.byobRequest.view; 861 view[0] = 0x01; 862 controller.byobRequest.respond(1); 863 864 byobRequestDefined.push(controller.byobRequest !== null); 865 byobRequestViewDefined = initialByobRequest.view !== null; 866 867 ++pullCount; 868 }, 869 type: 'bytes' 870 }); 871 872 const reader = stream.getReader({ mode: 'byob' }); 873 874 return reader.read(new Uint8Array(1)).then(result => { 875 assert_false(result.done, 'result.done'); 876 assert_equals(result.value.byteLength, 1, 'result.value.byteLength'); 877 assert_equals(result.value[0], 0x01, 'result.value[0]'); 878 assert_equals(pullCount, 1, 'pull() should be called only once'); 879 assert_true(byobRequestDefined[0], 'byobRequest must not be null before respond()'); 880 assert_false(byobRequestDefined[1], 'byobRequest must be null after respond()'); 881 assert_false(byobRequestViewDefined, 'view of initial byobRequest must be null after respond()'); 882 }); 883 }, 'ReadableStream with byte source: read(view), then respond()'); 884 885 promise_test(() => { 886 let controller; 887 888 let pullCount = 0; 889 const byobRequestDefined = []; 890 let byobRequestViewDefined; 891 892 const stream = new ReadableStream({ 893 start(c) { 894 controller = c; 895 }, 896 pull() { 897 byobRequestDefined.push(controller.byobRequest !== null); 898 const initialByobRequest = controller.byobRequest; 899 900 const transferredView = transferArrayBufferView(controller.byobRequest.view); 901 transferredView[0] = 0x01; 902 controller.byobRequest.respondWithNewView(transferredView); 903 904 byobRequestDefined.push(controller.byobRequest !== null); 905 byobRequestViewDefined = initialByobRequest.view !== null; 906 907 ++pullCount; 908 }, 909 type: 'bytes' 910 }); 911 912 const reader = stream.getReader({ mode: 'byob' }); 913 914 return reader.read(new Uint8Array(1)).then(result => { 915 assert_false(result.done, 'result.done'); 916 assert_equals(result.value.byteLength, 1, 'result.value.byteLength'); 917 assert_equals(result.value[0], 0x01, 'result.value[0]'); 918 assert_equals(pullCount, 1, 'pull() should be called only once'); 919 assert_true(byobRequestDefined[0], 'byobRequest must not be null before respondWithNewView()'); 920 assert_false(byobRequestDefined[1], 'byobRequest must be null after respondWithNewView()'); 921 assert_false(byobRequestViewDefined, 'view of initial byobRequest must be null after respondWithNewView()'); 922 }); 923 }, 'ReadableStream with byte source: read(view), then respondWithNewView() with a transferred ArrayBuffer'); 924 925 promise_test(() => { 926 let controller; 927 let byobRequestWasDefined; 928 let incorrectRespondException; 929 930 const stream = new ReadableStream({ 931 start(c) { 932 controller = c; 933 }, 934 pull() { 935 byobRequestWasDefined = controller.byobRequest !== null; 936 937 try { 938 controller.byobRequest.respond(2); 939 } catch (e) { 940 incorrectRespondException = e; 941 } 942 943 controller.byobRequest.respond(1); 944 }, 945 type: 'bytes' 946 }); 947 948 const reader = stream.getReader({ mode: 'byob' }); 949 950 return reader.read(new Uint8Array(1)).then(() => { 951 assert_true(byobRequestWasDefined, 'byobRequest should be non-null'); 952 assert_not_equals(incorrectRespondException, undefined, 'respond() must throw'); 953 assert_equals(incorrectRespondException.name, 'RangeError', 'respond() must throw a RangeError'); 954 }); 955 }, 'ReadableStream with byte source: read(view), then respond() with too big value'); 956 957 promise_test(() => { 958 let pullCount = 0; 959 960 let controller; 961 let byobRequest; 962 let viewInfo; 963 964 const stream = new ReadableStream({ 965 start(c) { 966 controller = c; 967 }, 968 pull() { 969 ++pullCount; 970 971 byobRequest = controller.byobRequest; 972 const view = byobRequest.view; 973 viewInfo = extractViewInfo(view); 974 975 view[0] = 0x01; 976 view[1] = 0x02; 977 view[2] = 0x03; 978 979 controller.byobRequest.respond(3); 980 }, 981 type: 'bytes' 982 }); 983 984 const reader = stream.getReader({ mode: 'byob' }); 985 986 return reader.read(new Uint16Array(2)).then(result => { 987 assert_equals(pullCount, 1); 988 989 assert_false(result.done, 'done'); 990 991 const view = result.value; 992 assert_equals(view.byteOffset, 0, 'byteOffset'); 993 assert_equals(view.byteLength, 2, 'byteLength'); 994 995 const dataView = new DataView(view.buffer, view.byteOffset, view.byteLength); 996 assert_equals(dataView.getUint16(0), 0x0102); 997 998 return reader.read(new Uint8Array(1)); 999 }).then(result => { 1000 assert_equals(pullCount, 1); 1001 assert_not_equals(byobRequest, null, 'byobRequest must not be null'); 1002 assert_equals(viewInfo.constructor, Uint8Array, 'view.constructor should be Uint8Array'); 1003 assert_equals(viewInfo.bufferByteLength, 4, 'view.buffer.byteLength should be 4'); 1004 assert_equals(viewInfo.byteOffset, 0, 'view.byteOffset should be 0'); 1005 assert_equals(viewInfo.byteLength, 4, 'view.byteLength should be 4'); 1006 1007 assert_false(result.done, 'done'); 1008 1009 const view = result.value; 1010 assert_equals(view.byteOffset, 0, 'byteOffset'); 1011 assert_equals(view.byteLength, 1, 'byteLength'); 1012 1013 assert_equals(view[0], 0x03); 1014 }); 1015 }, 'ReadableStream with byte source: respond(3) to read(view) with 2 element Uint16Array enqueues the 1 byte ' + 1016 'remainder'); 1017 1018 promise_test(() => { 1019 let pullCount = 0; 1020 1021 let controller; 1022 let byobRequest; 1023 let viewInfo; 1024 1025 const stream = new ReadableStream({ 1026 start(c) { 1027 controller = c; 1028 }, 1029 pull() { 1030 ++pullCount; 1031 1032 byobRequest = controller.byobRequest; 1033 const view = byobRequest.view; 1034 viewInfo = extractViewInfo(view); 1035 1036 view[0] = 0x01; 1037 view[1] = 0x02; 1038 view[2] = 0x03; 1039 1040 controller.byobRequest.respond(3); 1041 }, 1042 type: 'bytes' 1043 }); 1044 1045 const reader = stream.getReader({ mode: 'byob' }); 1046 const read1 = reader.read(new Uint16Array(2)); 1047 const read2 = reader.read(new Uint8Array(1)); 1048 1049 return read1.then(result => { 1050 assert_equals(pullCount, 1); 1051 1052 assert_false(result.done, 'done'); 1053 1054 const view = result.value; 1055 assert_equals(view.byteOffset, 0, 'byteOffset'); 1056 assert_equals(view.byteLength, 2, 'byteLength'); 1057 1058 const dataView = new DataView(view.buffer, view.byteOffset, view.byteLength); 1059 assert_equals(dataView.getUint16(0), 0x0102); 1060 1061 return read2; 1062 }).then(result => { 1063 assert_equals(pullCount, 1); 1064 assert_not_equals(byobRequest, null, 'byobRequest must not be null'); 1065 assert_equals(viewInfo.constructor, Uint8Array, 'view.constructor should be Uint8Array'); 1066 assert_equals(viewInfo.bufferByteLength, 4, 'view.buffer.byteLength should be 4'); 1067 assert_equals(viewInfo.byteOffset, 0, 'view.byteOffset should be 0'); 1068 assert_equals(viewInfo.byteLength, 4, 'view.byteLength should be 4'); 1069 1070 assert_false(result.done, 'done'); 1071 1072 const view = result.value; 1073 assert_equals(view.byteOffset, 0, 'byteOffset'); 1074 assert_equals(view.byteLength, 1, 'byteLength'); 1075 1076 assert_equals(view[0], 0x03); 1077 }); 1078 }, 'ReadableStream with byte source: respond(3) to read(view) with 2 element Uint16Array fulfills second read(view) ' + 1079 'with the 1 byte remainder'); 1080 1081 promise_test(t => { 1082 const stream = new ReadableStream({ 1083 start(controller) { 1084 const view = new Uint8Array(16); 1085 view[15] = 0x01; 1086 controller.enqueue(view); 1087 }, 1088 pull: t.unreached_func('pull() should not be called'), 1089 type: 'bytes' 1090 }); 1091 1092 const reader = stream.getReader({ mode: 'byob' }); 1093 1094 return reader.read(new Uint8Array(16)).then(result => { 1095 assert_false(result.done); 1096 1097 const view = result.value; 1098 assert_equals(view.byteOffset, 0); 1099 assert_equals(view.byteLength, 16); 1100 assert_equals(view[15], 0x01); 1101 }); 1102 }, 'ReadableStream with byte source: enqueue(), getReader(), then read(view)'); 1103 1104 promise_test(t => { 1105 let cancelCount = 0; 1106 let reason; 1107 1108 const passedReason = new TypeError('foo'); 1109 1110 const stream = new ReadableStream({ 1111 start(c) { 1112 c.enqueue(new Uint8Array(16)); 1113 }, 1114 pull: t.unreached_func('pull() should not be called'), 1115 cancel(r) { 1116 if (cancelCount === 0) { 1117 reason = r; 1118 } 1119 1120 ++cancelCount; 1121 }, 1122 type: 'bytes' 1123 }); 1124 1125 const reader = stream.getReader(); 1126 1127 return reader.cancel(passedReason).then(result => { 1128 assert_equals(result, undefined); 1129 assert_equals(cancelCount, 1); 1130 assert_equals(reason, passedReason, 'reason should equal the passed reason'); 1131 }); 1132 }, 'ReadableStream with byte source: enqueue(), getReader(), then cancel() (mode = not BYOB)'); 1133 1134 promise_test(t => { 1135 let cancelCount = 0; 1136 let reason; 1137 1138 const passedReason = new TypeError('foo'); 1139 1140 const stream = new ReadableStream({ 1141 start(c) { 1142 c.enqueue(new Uint8Array(16)); 1143 }, 1144 pull: t.unreached_func('pull() should not be called'), 1145 cancel(r) { 1146 if (cancelCount === 0) { 1147 reason = r; 1148 } 1149 1150 ++cancelCount; 1151 }, 1152 type: 'bytes' 1153 }); 1154 1155 const reader = stream.getReader({ mode: 'byob' }); 1156 1157 return reader.cancel(passedReason).then(result => { 1158 assert_equals(result, undefined); 1159 assert_equals(cancelCount, 1); 1160 assert_equals(reason, passedReason, 'reason should equal the passed reason'); 1161 }); 1162 }, 'ReadableStream with byte source: enqueue(), getReader(), then cancel() (mode = BYOB)'); 1163 1164 promise_test(t => { 1165 let cancelCount = 0; 1166 let reason; 1167 1168 const passedReason = new TypeError('foo'); 1169 1170 let controller; 1171 1172 const stream = new ReadableStream({ 1173 start(c) { 1174 controller = c; 1175 }, 1176 pull: t.unreached_func('pull() should not be called'), 1177 cancel(r) { 1178 if (cancelCount === 0) { 1179 reason = r; 1180 } 1181 1182 ++cancelCount; 1183 1184 return 'bar'; 1185 }, 1186 type: 'bytes' 1187 }); 1188 1189 const reader = stream.getReader({ mode: 'byob' }); 1190 1191 const readPromise = reader.read(new Uint8Array(1)).then(result => { 1192 assert_true(result.done, 'result.done'); 1193 assert_equals(result.value, undefined, 'result.value'); 1194 }); 1195 1196 const cancelPromise = reader.cancel(passedReason).then(result => { 1197 assert_equals(result, undefined, 'cancel() return value should be fulfilled with undefined'); 1198 assert_equals(cancelCount, 1, 'cancel() should be called only once'); 1199 assert_equals(reason, passedReason, 'reason should equal the passed reason'); 1200 }); 1201 1202 return Promise.all([readPromise, cancelPromise]); 1203 }, 'ReadableStream with byte source: getReader(), read(view), then cancel()'); 1204 1205 promise_test(() => { 1206 let pullCount = 0; 1207 1208 let controller; 1209 let byobRequest; 1210 const viewInfos = []; 1211 1212 const stream = new ReadableStream({ 1213 start(c) { 1214 controller = c; 1215 }, 1216 pull() { 1217 byobRequest = controller.byobRequest; 1218 1219 viewInfos.push(extractViewInfo(controller.byobRequest.view)); 1220 controller.enqueue(new Uint8Array(1)); 1221 viewInfos.push(extractViewInfo(controller.byobRequest.view)); 1222 1223 ++pullCount; 1224 }, 1225 type: 'bytes' 1226 }); 1227 1228 return Promise.resolve().then(() => { 1229 assert_equals(pullCount, 0, 'No pull() as no read(view) yet'); 1230 1231 const reader = stream.getReader({ mode: 'byob' }); 1232 1233 const promise = reader.read(new Uint16Array(1)).then(result => { 1234 assert_true(result.done, 'result.done'); 1235 assert_equals(result.value, undefined, 'result.value'); 1236 }); 1237 1238 assert_equals(pullCount, 1, '1 pull() should have been made in response to partial fill by enqueue()'); 1239 assert_not_equals(byobRequest, null, 'byobRequest should not be null'); 1240 assert_equals(viewInfos[0].byteLength, 2, 'byteLength before enqueue() should be 2'); 1241 assert_equals(viewInfos[1].byteLength, 1, 'byteLength after enqueue() should be 1'); 1242 1243 reader.cancel(); 1244 1245 assert_equals(pullCount, 1, 'pull() should only be called once'); 1246 return promise; 1247 }); 1248 }, 'ReadableStream with byte source: cancel() with partially filled pending pull() request'); 1249 1250 promise_test(() => { 1251 let controller; 1252 let pullCalled = false; 1253 1254 const stream = new ReadableStream({ 1255 start(c) { 1256 const view = new Uint8Array(8); 1257 view[7] = 0x01; 1258 c.enqueue(view); 1259 1260 controller = c; 1261 }, 1262 pull() { 1263 pullCalled = true; 1264 }, 1265 type: 'bytes' 1266 }); 1267 1268 const reader = stream.getReader({ mode: 'byob' }); 1269 1270 const buffer = new ArrayBuffer(16); 1271 1272 return reader.read(new Uint8Array(buffer, 8, 8)).then(result => { 1273 assert_false(result.done); 1274 1275 assert_false(pullCalled, 'pull() must not have been called'); 1276 1277 const view = result.value; 1278 assert_equals(view.constructor, Uint8Array); 1279 assert_equals(view.buffer.byteLength, 16); 1280 assert_equals(view.byteOffset, 8); 1281 assert_equals(view.byteLength, 8); 1282 assert_equals(view[7], 0x01); 1283 }); 1284 }, 'ReadableStream with byte source: enqueue(), getReader(), then read(view) where view.buffer is not fully ' + 1285 'covered by view'); 1286 1287 promise_test(() => { 1288 let controller; 1289 let pullCalled = false; 1290 1291 const stream = new ReadableStream({ 1292 start(c) { 1293 let view; 1294 1295 view = new Uint8Array(16); 1296 view[15] = 123; 1297 c.enqueue(view); 1298 1299 view = new Uint8Array(8); 1300 view[7] = 111; 1301 c.enqueue(view); 1302 1303 controller = c; 1304 }, 1305 pull() { 1306 pullCalled = true; 1307 }, 1308 type: 'bytes' 1309 }); 1310 1311 const reader = stream.getReader({ mode: 'byob' }); 1312 1313 return reader.read(new Uint8Array(24)).then(result => { 1314 assert_false(result.done, 'done'); 1315 1316 assert_false(pullCalled, 'pull() must not have been called'); 1317 1318 const view = result.value; 1319 assert_equals(view.byteOffset, 0, 'byteOffset'); 1320 assert_equals(view.byteLength, 24, 'byteLength'); 1321 assert_equals(view[15], 123, 'Contents are set from the first chunk'); 1322 assert_equals(view[23], 111, 'Contents are set from the second chunk'); 1323 }); 1324 }, 'ReadableStream with byte source: Multiple enqueue(), getReader(), then read(view)'); 1325 1326 promise_test(() => { 1327 let pullCalled = false; 1328 1329 const stream = new ReadableStream({ 1330 start(c) { 1331 const view = new Uint8Array(16); 1332 view[15] = 0x01; 1333 c.enqueue(view); 1334 }, 1335 pull() { 1336 pullCalled = true; 1337 }, 1338 type: 'bytes' 1339 }); 1340 1341 const reader = stream.getReader({ mode: 'byob' }); 1342 1343 return reader.read(new Uint8Array(24)).then(result => { 1344 assert_false(result.done); 1345 1346 assert_false(pullCalled, 'pull() must not have been called'); 1347 1348 const view = result.value; 1349 assert_equals(view.byteOffset, 0); 1350 assert_equals(view.byteLength, 16); 1351 assert_equals(view[15], 0x01); 1352 }); 1353 }, 'ReadableStream with byte source: enqueue(), getReader(), then read(view) with a bigger view'); 1354 1355 promise_test(() => { 1356 let pullCalled = false; 1357 1358 const stream = new ReadableStream({ 1359 start(c) { 1360 const view = new Uint8Array(16); 1361 view[7] = 0x01; 1362 view[15] = 0x02; 1363 c.enqueue(view); 1364 }, 1365 pull() { 1366 pullCalled = true; 1367 }, 1368 type: 'bytes' 1369 }); 1370 1371 const reader = stream.getReader({ mode: 'byob' }); 1372 1373 return reader.read(new Uint8Array(8)).then(result => { 1374 assert_false(result.done, 'done'); 1375 1376 const view = result.value; 1377 assert_equals(view.byteOffset, 0); 1378 assert_equals(view.byteLength, 8); 1379 assert_equals(view[7], 0x01); 1380 1381 return reader.read(new Uint8Array(8)); 1382 }).then(result => { 1383 assert_false(result.done, 'done'); 1384 1385 assert_false(pullCalled, 'pull() must not have been called'); 1386 1387 const view = result.value; 1388 assert_equals(view.byteOffset, 0); 1389 assert_equals(view.byteLength, 8); 1390 assert_equals(view[7], 0x02); 1391 }); 1392 }, 'ReadableStream with byte source: enqueue(), getReader(), then read(view) with smaller views'); 1393 1394 promise_test(() => { 1395 let controller; 1396 let viewInfo; 1397 1398 const stream = new ReadableStream({ 1399 start(c) { 1400 const view = new Uint8Array(1); 1401 view[0] = 0xff; 1402 c.enqueue(view); 1403 1404 controller = c; 1405 }, 1406 pull() { 1407 if (controller.byobRequest === null) { 1408 return; 1409 } 1410 1411 const view = controller.byobRequest.view; 1412 viewInfo = extractViewInfo(view); 1413 1414 view[0] = 0xaa; 1415 controller.byobRequest.respond(1); 1416 }, 1417 type: 'bytes' 1418 }); 1419 1420 const reader = stream.getReader({ mode: 'byob' }); 1421 1422 return reader.read(new Uint16Array(1)).then(result => { 1423 assert_false(result.done); 1424 1425 const view = result.value; 1426 assert_equals(view.byteOffset, 0); 1427 assert_equals(view.byteLength, 2); 1428 1429 const dataView = new DataView(view.buffer, view.byteOffset, view.byteLength); 1430 assert_equals(dataView.getUint16(0), 0xffaa); 1431 1432 assert_equals(viewInfo.constructor, Uint8Array, 'view.constructor should be Uint8Array'); 1433 assert_equals(viewInfo.bufferByteLength, 2, 'view.buffer.byteLength should be 2'); 1434 assert_equals(viewInfo.byteOffset, 1, 'view.byteOffset should be 1'); 1435 assert_equals(viewInfo.byteLength, 1, 'view.byteLength should be 1'); 1436 }); 1437 }, 'ReadableStream with byte source: enqueue() 1 byte, getReader(), then read(view) with Uint16Array'); 1438 1439 promise_test(() => { 1440 let pullCount = 0; 1441 1442 let controller; 1443 let byobRequest; 1444 let viewInfo; 1445 let desiredSize; 1446 1447 const stream = new ReadableStream({ 1448 start(c) { 1449 const view = new Uint8Array(3); 1450 view[0] = 0x01; 1451 view[2] = 0x02; 1452 c.enqueue(view); 1453 1454 controller = c; 1455 }, 1456 pull() { 1457 byobRequest = controller.byobRequest; 1458 1459 const view = controller.byobRequest.view; 1460 1461 viewInfo = extractViewInfo(view); 1462 1463 view[0] = 0x03; 1464 controller.byobRequest.respond(1); 1465 1466 desiredSize = controller.desiredSize; 1467 1468 ++pullCount; 1469 }, 1470 type: 'bytes' 1471 }); 1472 1473 // Wait for completion of the start method to be reflected. 1474 return Promise.resolve().then(() => { 1475 const reader = stream.getReader({ mode: 'byob' }); 1476 1477 const promise = reader.read(new Uint16Array(2)).then(result => { 1478 assert_false(result.done, 'done'); 1479 1480 const view = result.value; 1481 assert_equals(view.constructor, Uint16Array, 'constructor'); 1482 assert_equals(view.buffer.byteLength, 4, 'buffer.byteLength'); 1483 assert_equals(view.byteOffset, 0, 'byteOffset'); 1484 assert_equals(view.byteLength, 2, 'byteLength'); 1485 1486 const dataView = new DataView(view.buffer, view.byteOffset, view.byteLength); 1487 assert_equals(dataView.getUint16(0), 0x0100, 'contents are set'); 1488 1489 const p = reader.read(new Uint16Array(1)); 1490 1491 assert_equals(pullCount, 1); 1492 1493 return p; 1494 }).then(result => { 1495 assert_false(result.done, 'done'); 1496 1497 const view = result.value; 1498 assert_equals(view.buffer.byteLength, 2, 'buffer.byteLength'); 1499 assert_equals(view.byteOffset, 0, 'byteOffset'); 1500 assert_equals(view.byteLength, 2, 'byteLength'); 1501 1502 const dataView = new DataView(view.buffer, view.byteOffset, view.byteLength); 1503 assert_equals(dataView.getUint16(0), 0x0203, 'contents are set'); 1504 1505 assert_not_equals(byobRequest, null, 'byobRequest must not be null'); 1506 assert_equals(viewInfo.constructor, Uint8Array, 'view.constructor should be Uint8Array'); 1507 assert_equals(viewInfo.bufferByteLength, 2, 'view.buffer.byteLength should be 2'); 1508 assert_equals(viewInfo.byteOffset, 1, 'view.byteOffset should be 1'); 1509 assert_equals(viewInfo.byteLength, 1, 'view.byteLength should be 1'); 1510 assert_equals(desiredSize, 0, 'desiredSize should be zero'); 1511 }); 1512 1513 assert_equals(pullCount, 0); 1514 1515 return promise; 1516 }); 1517 }, 'ReadableStream with byte source: enqueue() 3 byte, getReader(), then read(view) with 2-element Uint16Array'); 1518 1519 promise_test(t => { 1520 const stream = new ReadableStream({ 1521 start(c) { 1522 const view = new Uint8Array(1); 1523 view[0] = 0xff; 1524 c.enqueue(view); 1525 c.close(); 1526 }, 1527 pull: t.unreached_func('pull() should not be called'), 1528 type: 'bytes' 1529 }); 1530 1531 const reader = stream.getReader({ mode: 'byob' }); 1532 1533 1534 return promise_rejects_js(t, TypeError, reader.read(new Uint16Array(1)), 'read(view) must fail') 1535 .then(() => promise_rejects_js(t, TypeError, reader.closed, 'reader.closed should reject')); 1536 }, 'ReadableStream with byte source: read(view) with Uint16Array on close()-d stream with 1 byte enqueue()-d must ' + 1537 'fail'); 1538 1539 promise_test(t => { 1540 let controller; 1541 1542 const stream = new ReadableStream({ 1543 start(c) { 1544 const view = new Uint8Array(1); 1545 view[0] = 0xff; 1546 c.enqueue(view); 1547 1548 controller = c; 1549 }, 1550 pull: t.unreached_func('pull() should not be called'), 1551 type: 'bytes' 1552 }); 1553 1554 const reader = stream.getReader({ mode: 'byob' }); 1555 1556 const readPromise = reader.read(new Uint16Array(1)); 1557 1558 assert_throws_js(TypeError, () => controller.close(), 'controller.close() must throw'); 1559 1560 return promise_rejects_js(t, TypeError, readPromise, 'read(view) must fail') 1561 .then(() => promise_rejects_js(t, TypeError, reader.closed, 'reader.closed must reject')); 1562 }, 'ReadableStream with byte source: A stream must be errored if close()-d before fulfilling read(view) with ' + 1563 'Uint16Array'); 1564 1565 test(() => { 1566 let controller; 1567 1568 new ReadableStream({ 1569 start(c) { 1570 controller = c; 1571 }, 1572 type: 'bytes' 1573 }); 1574 1575 // Enqueue a chunk so that the stream doesn't get closed. This is to check duplicate close() calls are rejected 1576 // even if the stream has not yet entered the closed state. 1577 const view = new Uint8Array(1); 1578 controller.enqueue(view); 1579 controller.close(); 1580 1581 assert_throws_js(TypeError, () => controller.close(), 'controller.close() must throw'); 1582 }, 'ReadableStream with byte source: Throw if close()-ed more than once'); 1583 1584 test(() => { 1585 let controller; 1586 1587 new ReadableStream({ 1588 start(c) { 1589 controller = c; 1590 }, 1591 type: 'bytes' 1592 }); 1593 1594 // Enqueue a chunk so that the stream doesn't get closed. This is to check enqueue() after close() is rejected 1595 // even if the stream has not yet entered the closed state. 1596 const view = new Uint8Array(1); 1597 controller.enqueue(view); 1598 controller.close(); 1599 1600 assert_throws_js(TypeError, () => controller.enqueue(view), 'controller.close() must throw'); 1601 }, 'ReadableStream with byte source: Throw on enqueue() after close()'); 1602 1603 promise_test(() => { 1604 let controller; 1605 let byobRequest; 1606 let viewInfo; 1607 1608 const stream = new ReadableStream({ 1609 start(c) { 1610 controller = c; 1611 }, 1612 pull() { 1613 byobRequest = controller.byobRequest; 1614 const view = controller.byobRequest.view; 1615 viewInfo = extractViewInfo(view); 1616 1617 view[15] = 0x01; 1618 controller.byobRequest.respond(16); 1619 controller.close(); 1620 }, 1621 type: 'bytes' 1622 }); 1623 1624 const reader = stream.getReader({ mode: 'byob' }); 1625 1626 return reader.read(new Uint8Array(16)).then(result => { 1627 assert_false(result.done); 1628 1629 const view = result.value; 1630 assert_equals(view.byteOffset, 0); 1631 assert_equals(view.byteLength, 16); 1632 assert_equals(view[15], 0x01); 1633 1634 return reader.read(new Uint8Array(16)); 1635 }).then(result => { 1636 assert_true(result.done); 1637 1638 const view = result.value; 1639 assert_equals(view.byteOffset, 0); 1640 assert_equals(view.byteLength, 0); 1641 1642 assert_not_equals(byobRequest, null, 'byobRequest must not be null'); 1643 assert_equals(viewInfo.constructor, Uint8Array, 'view.constructor should be Uint8Array'); 1644 assert_equals(viewInfo.bufferByteLength, 16, 'view.buffer.byteLength should be 16'); 1645 assert_equals(viewInfo.byteOffset, 0, 'view.byteOffset should be 0'); 1646 assert_equals(viewInfo.byteLength, 16, 'view.byteLength should be 16'); 1647 }); 1648 }, 'ReadableStream with byte source: read(view), then respond() and close() in pull()'); 1649 1650 promise_test(() => { 1651 let pullCount = 0; 1652 1653 let controller; 1654 const viewInfos = []; 1655 const viewInfosAfterRespond = []; 1656 1657 const stream = new ReadableStream({ 1658 start(c) { 1659 controller = c; 1660 }, 1661 pull() { 1662 if (controller.byobRequest === null) { 1663 return; 1664 } 1665 1666 for (let i = 0; i < 4; ++i) { 1667 const view = controller.byobRequest.view; 1668 viewInfos.push(extractViewInfo(view)); 1669 1670 view[0] = 0x01; 1671 controller.byobRequest.respond(1); 1672 viewInfosAfterRespond.push(extractViewInfo(view)); 1673 } 1674 1675 ++pullCount; 1676 }, 1677 type: 'bytes' 1678 }); 1679 1680 const reader = stream.getReader({ mode: 'byob' }); 1681 1682 return reader.read(new Uint32Array(1)).then(result => { 1683 assert_false(result.done, 'result.done'); 1684 1685 const view = result.value; 1686 assert_equals(view.byteOffset, 0, 'result.value.byteOffset'); 1687 assert_equals(view.byteLength, 4, 'result.value.byteLength'); 1688 assert_equals(view[0], 0x01010101, 'result.value[0]'); 1689 1690 assert_equals(pullCount, 1, 'pull() should only be called once'); 1691 1692 for (let i = 0; i < 4; ++i) { 1693 assert_equals(viewInfos[i].constructor, Uint8Array, 'view.constructor should be Uint8Array'); 1694 assert_equals(viewInfos[i].bufferByteLength, 4, 'view.buffer.byteLength should be 4'); 1695 1696 assert_equals(viewInfos[i].byteOffset, i, 'view.byteOffset should be i'); 1697 assert_equals(viewInfos[i].byteLength, 4 - i, 'view.byteLength should be 4 - i'); 1698 1699 assert_equals(viewInfosAfterRespond[i].bufferByteLength, 0, 'view.buffer should be transferred after respond()'); 1700 } 1701 }); 1702 }, 'ReadableStream with byte source: read(view) with Uint32Array, then fill it by multiple respond() calls'); 1703 1704 promise_test(() => { 1705 let pullCount = 0; 1706 1707 let controller; 1708 const viewInfos = []; 1709 const viewInfosAfterEnqueue = []; 1710 1711 const stream = new ReadableStream({ 1712 start(c) { 1713 controller = c; 1714 }, 1715 pull() { 1716 if (controller.byobRequest === null) { 1717 return; 1718 } 1719 1720 for (let i = 0; i < 4; ++i) { 1721 const view = controller.byobRequest.view; 1722 viewInfos.push(extractViewInfo(view)); 1723 1724 controller.enqueue(new Uint8Array([0x01])); 1725 viewInfosAfterEnqueue.push(extractViewInfo(view)); 1726 } 1727 1728 ++pullCount; 1729 }, 1730 type: 'bytes' 1731 }); 1732 1733 const reader = stream.getReader({ mode: 'byob' }); 1734 1735 return reader.read(new Uint32Array(1)).then(result => { 1736 assert_false(result.done, 'result.done'); 1737 1738 const view = result.value; 1739 assert_equals(view.byteOffset, 0, 'result.value.byteOffset'); 1740 assert_equals(view.byteLength, 4, 'result.value.byteLength'); 1741 assert_equals(view[0], 0x01010101, 'result.value[0]'); 1742 1743 assert_equals(pullCount, 1, 'pull() should only be called once'); 1744 1745 for (let i = 0; i < 4; ++i) { 1746 assert_equals(viewInfos[i].constructor, Uint8Array, 'view.constructor should be Uint8Array'); 1747 assert_equals(viewInfos[i].bufferByteLength, 4, 'view.buffer.byteLength should be 4'); 1748 1749 assert_equals(viewInfos[i].byteOffset, i, 'view.byteOffset should be i'); 1750 assert_equals(viewInfos[i].byteLength, 4 - i, 'view.byteLength should be 4 - i'); 1751 1752 assert_equals(viewInfosAfterEnqueue[i].bufferByteLength, 0, 'view.buffer should be transferred after enqueue()'); 1753 } 1754 }); 1755 }, 'ReadableStream with byte source: read(view) with Uint32Array, then fill it by multiple enqueue() calls'); 1756 1757 promise_test(() => { 1758 let pullCount = 0; 1759 1760 let controller; 1761 let byobRequest; 1762 1763 const stream = new ReadableStream({ 1764 start(c) { 1765 controller = c; 1766 }, 1767 pull() { 1768 byobRequest = controller.byobRequest; 1769 1770 ++pullCount; 1771 }, 1772 type: 'bytes' 1773 }); 1774 1775 const reader = stream.getReader(); 1776 1777 const p0 = reader.read().then(result => { 1778 assert_equals(pullCount, 1); 1779 1780 controller.enqueue(new Uint8Array(2)); 1781 1782 // Since the queue has data no less than HWM, no more pull. 1783 assert_equals(pullCount, 1); 1784 1785 assert_false(result.done); 1786 1787 const view = result.value; 1788 assert_equals(view.constructor, Uint8Array); 1789 assert_equals(view.buffer.byteLength, 1); 1790 assert_equals(view.byteOffset, 0); 1791 assert_equals(view.byteLength, 1); 1792 }); 1793 1794 assert_equals(pullCount, 0, 'No pull should have been made since the startPromise has not yet been handled'); 1795 1796 const p1 = reader.read().then(result => { 1797 assert_equals(pullCount, 1); 1798 1799 assert_false(result.done); 1800 1801 const view = result.value; 1802 assert_equals(view.constructor, Uint8Array); 1803 assert_equals(view.buffer.byteLength, 2); 1804 assert_equals(view.byteOffset, 0); 1805 assert_equals(view.byteLength, 2); 1806 1807 assert_equals(byobRequest, null, 'byobRequest must be null'); 1808 }); 1809 1810 assert_equals(pullCount, 0, 'No pull should have been made since the startPromise has not yet been handled'); 1811 1812 controller.enqueue(new Uint8Array(1)); 1813 1814 assert_equals(pullCount, 0, 'No pull should have been made since the startPromise has not yet been handled'); 1815 1816 return Promise.all([p0, p1]); 1817 }, 'ReadableStream with byte source: read() twice, then enqueue() twice'); 1818 1819 promise_test(t => { 1820 let controller; 1821 1822 const stream = new ReadableStream({ 1823 start(c) { 1824 controller = c; 1825 }, 1826 pull: t.unreached_func('pull() should not be called'), 1827 type: 'bytes' 1828 }); 1829 1830 const reader = stream.getReader({ mode: 'byob' }); 1831 1832 const p0 = reader.read(new Uint8Array(16)).then(result => { 1833 assert_true(result.done, '1st read: done'); 1834 1835 const view = result.value; 1836 assert_equals(view.buffer.byteLength, 16, '1st read: buffer.byteLength'); 1837 assert_equals(view.byteOffset, 0, '1st read: byteOffset'); 1838 assert_equals(view.byteLength, 0, '1st read: byteLength'); 1839 }); 1840 1841 const p1 = reader.read(new Uint8Array(32)).then(result => { 1842 assert_true(result.done, '2nd read: done'); 1843 1844 const view = result.value; 1845 assert_equals(view.buffer.byteLength, 32, '2nd read: buffer.byteLength'); 1846 assert_equals(view.byteOffset, 0, '2nd read: byteOffset'); 1847 assert_equals(view.byteLength, 0, '2nd read: byteLength'); 1848 }); 1849 1850 controller.close(); 1851 controller.byobRequest.respond(0); 1852 1853 return Promise.all([p0, p1]); 1854 }, 'ReadableStream with byte source: Multiple read(view), close() and respond()'); 1855 1856 promise_test(t => { 1857 let controller; 1858 1859 const stream = new ReadableStream({ 1860 start(c) { 1861 controller = c; 1862 }, 1863 pull: t.unreached_func('pull() should not be called'), 1864 type: 'bytes' 1865 }); 1866 1867 const reader = stream.getReader({ mode: 'byob' }); 1868 1869 const p0 = reader.read(new Uint8Array(16)).then(result => { 1870 assert_false(result.done, '1st read: done'); 1871 1872 const view = result.value; 1873 assert_equals(view.buffer.byteLength, 16, '1st read: buffer.byteLength'); 1874 assert_equals(view.byteOffset, 0, '1st read: byteOffset'); 1875 assert_equals(view.byteLength, 16, '1st read: byteLength'); 1876 }); 1877 1878 const p1 = reader.read(new Uint8Array(16)).then(result => { 1879 assert_false(result.done, '2nd read: done'); 1880 1881 const view = result.value; 1882 assert_equals(view.buffer.byteLength, 16, '2nd read: buffer.byteLength'); 1883 assert_equals(view.byteOffset, 0, '2nd read: byteOffset'); 1884 assert_equals(view.byteLength, 8, '2nd read: byteLength'); 1885 }); 1886 1887 controller.enqueue(new Uint8Array(24)); 1888 1889 return Promise.all([p0, p1]); 1890 }, 'ReadableStream with byte source: Multiple read(view), big enqueue()'); 1891 1892 promise_test(t => { 1893 let controller; 1894 1895 const stream = new ReadableStream({ 1896 start(c) { 1897 controller = c; 1898 }, 1899 pull: t.unreached_func('pull() should not be called'), 1900 type: 'bytes' 1901 }); 1902 1903 const reader = stream.getReader({ mode: 'byob' }); 1904 1905 let bytesRead = 0; 1906 1907 function pump() { 1908 return reader.read(new Uint8Array(7)).then(result => { 1909 if (result.done) { 1910 assert_equals(bytesRead, 1024); 1911 return undefined; 1912 } 1913 1914 bytesRead += result.value.byteLength; 1915 1916 return pump(); 1917 }); 1918 } 1919 const promise = pump(); 1920 1921 controller.enqueue(new Uint8Array(512)); 1922 controller.enqueue(new Uint8Array(512)); 1923 controller.close(); 1924 1925 return promise; 1926 }, 'ReadableStream with byte source: Multiple read(view) and multiple enqueue()'); 1927 1928 promise_test(t => { 1929 let pullCalled = false; 1930 const stream = new ReadableStream({ 1931 pull(controller) { 1932 pullCalled = true; 1933 }, 1934 type: 'bytes' 1935 }); 1936 1937 const reader = stream.getReader({ mode: 'byob' }); 1938 1939 return promise_rejects_js(t, TypeError, reader.read(), 'read() must fail') 1940 .then(() => assert_false(pullCalled, 'pull() must not have been called')); 1941 }, 'ReadableStream with byte source: read(view) with passing undefined as view must fail'); 1942 1943 promise_test(t => { 1944 const stream = new ReadableStream({ 1945 type: 'bytes' 1946 }); 1947 1948 const reader = stream.getReader({ mode: 'byob' }); 1949 1950 return promise_rejects_js(t, TypeError, reader.read({}), 'read(view) must fail'); 1951 }, 'ReadableStream with byte source: read(view) with passing an empty object as view must fail'); 1952 1953 promise_test(t => { 1954 const stream = new ReadableStream({ 1955 type: 'bytes' 1956 }); 1957 1958 const reader = stream.getReader({ mode: 'byob' }); 1959 1960 return promise_rejects_js(t, TypeError, 1961 reader.read({ buffer: new ArrayBuffer(10), byteOffset: 0, byteLength: 10 }), 1962 'read(view) must fail'); 1963 }, 'ReadableStream with byte source: Even read(view) with passing ArrayBufferView like object as view must fail'); 1964 1965 promise_test(t => { 1966 const stream = new ReadableStream({ 1967 start(c) { 1968 c.error(error1); 1969 }, 1970 pull: t.unreached_func('pull() should not be called'), 1971 type: 'bytes' 1972 }); 1973 1974 const reader = stream.getReader(); 1975 1976 return promise_rejects_exactly(t, error1, reader.read(), 'read() must fail'); 1977 }, 'ReadableStream with byte source: read() on an errored stream'); 1978 1979 promise_test(t => { 1980 let controller; 1981 1982 const stream = new ReadableStream({ 1983 start(c) { 1984 controller = c; 1985 }, 1986 type: 'bytes' 1987 }); 1988 1989 const reader = stream.getReader(); 1990 1991 const promise = promise_rejects_exactly(t, error1, reader.read(), 'read() must fail'); 1992 1993 controller.error(error1); 1994 1995 return promise; 1996 }, 'ReadableStream with byte source: read(), then error()'); 1997 1998 promise_test(t => { 1999 const stream = new ReadableStream({ 2000 start(c) { 2001 c.error(error1); 2002 }, 2003 pull: t.unreached_func('pull() should not be called'), 2004 type: 'bytes' 2005 }); 2006 2007 const reader = stream.getReader({ mode: 'byob' }); 2008 2009 return promise_rejects_exactly(t, error1, reader.read(new Uint8Array(1)), 'read() must fail'); 2010 }, 'ReadableStream with byte source: read(view) on an errored stream'); 2011 2012 promise_test(t => { 2013 let controller; 2014 2015 const stream = new ReadableStream({ 2016 start(c) { 2017 controller = c; 2018 }, 2019 type: 'bytes' 2020 }); 2021 2022 const reader = stream.getReader({ mode: 'byob' }); 2023 2024 const promise = promise_rejects_exactly(t, error1, reader.read(new Uint8Array(1)), 'read() must fail'); 2025 2026 controller.error(error1); 2027 2028 return promise; 2029 }, 'ReadableStream with byte source: read(view), then error()'); 2030 2031 promise_test(t => { 2032 let controller; 2033 let byobRequest; 2034 2035 const testError = new TypeError('foo'); 2036 2037 const stream = new ReadableStream({ 2038 start(c) { 2039 controller = c; 2040 }, 2041 pull() { 2042 byobRequest = controller.byobRequest; 2043 throw testError; 2044 }, 2045 type: 'bytes' 2046 }); 2047 2048 const reader = stream.getReader(); 2049 2050 const promise = promise_rejects_exactly(t, testError, reader.read(), 'read() must fail'); 2051 return promise_rejects_exactly(t, testError, promise.then(() => reader.closed)) 2052 .then(() => assert_equals(byobRequest, null, 'byobRequest must be null')); 2053 }, 'ReadableStream with byte source: Throwing in pull function must error the stream'); 2054 2055 promise_test(t => { 2056 let byobRequest; 2057 2058 const stream = new ReadableStream({ 2059 pull(controller) { 2060 byobRequest = controller.byobRequest; 2061 controller.error(error1); 2062 throw new TypeError('foo'); 2063 }, 2064 type: 'bytes' 2065 }); 2066 2067 const reader = stream.getReader(); 2068 2069 return promise_rejects_exactly(t, error1, reader.read(), 'read() must fail') 2070 .then(() => promise_rejects_exactly(t, error1, reader.closed, 'closed must fail')) 2071 .then(() => assert_equals(byobRequest, null, 'byobRequest must be null')); 2072 }, 'ReadableStream with byte source: Throwing in pull in response to read() must be ignored if the stream is ' + 2073 'errored in it'); 2074 2075 promise_test(t => { 2076 let byobRequest; 2077 2078 const testError = new TypeError('foo'); 2079 2080 const stream = new ReadableStream({ 2081 pull(controller) { 2082 byobRequest = controller.byobRequest; 2083 throw testError; 2084 }, 2085 type: 'bytes' 2086 }); 2087 2088 const reader = stream.getReader({ mode: 'byob' }); 2089 2090 return promise_rejects_exactly(t, testError, reader.read(new Uint8Array(1)), 'read(view) must fail') 2091 .then(() => promise_rejects_exactly(t, testError, reader.closed, 'reader.closed must reject')) 2092 .then(() => assert_not_equals(byobRequest, null, 'byobRequest must not be null')); 2093 }, 'ReadableStream with byte source: Throwing in pull in response to read(view) function must error the stream'); 2094 2095 promise_test(t => { 2096 let byobRequest; 2097 2098 const stream = new ReadableStream({ 2099 pull(controller) { 2100 byobRequest = controller.byobRequest; 2101 controller.error(error1); 2102 throw new TypeError('foo'); 2103 }, 2104 type: 'bytes' 2105 }); 2106 2107 const reader = stream.getReader({ mode: 'byob' }); 2108 2109 return promise_rejects_exactly(t, error1, reader.read(new Uint8Array(1)), 'read(view) must fail') 2110 .then(() => promise_rejects_exactly(t, error1, reader.closed, 'closed must fail')) 2111 .then(() => assert_not_equals(byobRequest, null, 'byobRequest must not be null')); 2112 }, 'ReadableStream with byte source: Throwing in pull in response to read(view) must be ignored if the stream is ' + 2113 'errored in it'); 2114 2115 promise_test(() => { 2116 let byobRequest; 2117 const rs = new ReadableStream({ 2118 pull(controller) { 2119 byobRequest = controller.byobRequest; 2120 byobRequest.respond(4); 2121 }, 2122 type: 'bytes' 2123 }); 2124 const reader = rs.getReader({ mode: 'byob' }); 2125 const view = new Uint8Array(16); 2126 return reader.read(view).then(() => { 2127 assert_throws_js(TypeError, () => byobRequest.respond(4), 'respond() should throw a TypeError'); 2128 }); 2129 }, 'calling respond() twice on the same byobRequest should throw'); 2130 2131 promise_test(() => { 2132 let byobRequest; 2133 const newView = () => new Uint8Array(16); 2134 const rs = new ReadableStream({ 2135 pull(controller) { 2136 byobRequest = controller.byobRequest; 2137 byobRequest.respondWithNewView(newView()); 2138 }, 2139 type: 'bytes' 2140 }); 2141 const reader = rs.getReader({ mode: 'byob' }); 2142 return reader.read(newView()).then(() => { 2143 assert_throws_js(TypeError, () => byobRequest.respondWithNewView(newView()), 2144 'respondWithNewView() should throw a TypeError'); 2145 }); 2146 }, 'calling respondWithNewView() twice on the same byobRequest should throw'); 2147 2148 promise_test(() => { 2149 let controller; 2150 let byobRequest; 2151 let resolvePullCalledPromise; 2152 const pullCalledPromise = new Promise(resolve => { 2153 resolvePullCalledPromise = resolve; 2154 }); 2155 let resolvePull; 2156 const rs = new ReadableStream({ 2157 start(c) { 2158 controller = c; 2159 }, 2160 pull(c) { 2161 byobRequest = c.byobRequest; 2162 resolvePullCalledPromise(); 2163 return new Promise(resolve => { 2164 resolvePull = resolve; 2165 }); 2166 }, 2167 type: 'bytes' 2168 }); 2169 const reader = rs.getReader({ mode: 'byob' }); 2170 const readPromise = reader.read(new Uint8Array(16)); 2171 return pullCalledPromise.then(() => { 2172 controller.close(); 2173 byobRequest.respond(0); 2174 resolvePull(); 2175 return readPromise.then(() => { 2176 assert_throws_js(TypeError, () => byobRequest.respond(0), 'respond() should throw'); 2177 }); 2178 }); 2179 }, 'calling respond(0) twice on the same byobRequest should throw even when closed'); 2180 2181 promise_test(() => { 2182 let controller; 2183 let byobRequest; 2184 let resolvePullCalledPromise; 2185 const pullCalledPromise = new Promise(resolve => { 2186 resolvePullCalledPromise = resolve; 2187 }); 2188 let resolvePull; 2189 const rs = new ReadableStream({ 2190 start(c) { 2191 controller = c; 2192 }, 2193 pull(c) { 2194 byobRequest = c.byobRequest; 2195 resolvePullCalledPromise(); 2196 return new Promise(resolve => { 2197 resolvePull = resolve; 2198 }); 2199 }, 2200 type: 'bytes' 2201 }); 2202 const reader = rs.getReader({ mode: 'byob' }); 2203 const readPromise = reader.read(new Uint8Array(16)); 2204 return pullCalledPromise.then(() => { 2205 const cancelPromise = reader.cancel('meh'); 2206 assert_throws_js(TypeError, () => byobRequest.respond(0), 'respond() should throw'); 2207 resolvePull(); 2208 return Promise.all([readPromise, cancelPromise]); 2209 }); 2210 }, 'calling respond() should throw when canceled'); 2211 2212 promise_test(async t => { 2213 let resolvePullCalledPromise; 2214 const pullCalledPromise = new Promise(resolve => { 2215 resolvePullCalledPromise = resolve; 2216 }); 2217 let resolvePull; 2218 const rs = new ReadableStream({ 2219 pull() { 2220 resolvePullCalledPromise(); 2221 return new Promise(resolve => { 2222 resolvePull = resolve; 2223 }); 2224 }, 2225 type: 'bytes' 2226 }); 2227 const reader = rs.getReader({ mode: 'byob' }); 2228 const read = reader.read(new Uint8Array(16)); 2229 await pullCalledPromise; 2230 resolvePull(); 2231 await delay(0); 2232 reader.releaseLock(); 2233 await promise_rejects_js(t, TypeError, read, 'pending read should reject'); 2234 }, 'pull() resolving should not resolve read()'); 2235 2236 promise_test(() => { 2237 // Tests https://github.com/whatwg/streams/issues/686 2238 2239 let controller; 2240 const rs = new ReadableStream({ 2241 autoAllocateChunkSize: 128, 2242 start(c) { 2243 controller = c; 2244 }, 2245 type: 'bytes' 2246 }); 2247 2248 const readPromise = rs.getReader().read(); 2249 2250 const br = controller.byobRequest; 2251 controller.close(); 2252 2253 br.respond(0); 2254 2255 return readPromise; 2256 }, 'ReadableStream with byte source: default reader + autoAllocateChunkSize + byobRequest interaction'); 2257 2258 test(() => { 2259 assert_throws_js(TypeError, () => new ReadableStream({ autoAllocateChunkSize: 0, type: 'bytes' }), 2260 'controller cannot be setup with autoAllocateChunkSize = 0'); 2261 }, 'ReadableStream with byte source: autoAllocateChunkSize cannot be 0'); 2262 2263 test(() => { 2264 const ReadableStreamBYOBReader = new ReadableStream({ type: 'bytes' }).getReader({ mode: 'byob' }).constructor; 2265 const stream = new ReadableStream({ type: 'bytes' }); 2266 new ReadableStreamBYOBReader(stream); 2267 }, 'ReadableStreamBYOBReader can be constructed directly'); 2268 2269 test(() => { 2270 const ReadableStreamBYOBReader = new ReadableStream({ type: 'bytes' }).getReader({ mode: 'byob' }).constructor; 2271 assert_throws_js(TypeError, () => new ReadableStreamBYOBReader({}), 'constructor must throw'); 2272 }, 'ReadableStreamBYOBReader constructor requires a ReadableStream argument'); 2273 2274 test(() => { 2275 const ReadableStreamBYOBReader = new ReadableStream({ type: 'bytes' }).getReader({ mode: 'byob' }).constructor; 2276 const stream = new ReadableStream({ type: 'bytes' }); 2277 stream.getReader(); 2278 assert_throws_js(TypeError, () => new ReadableStreamBYOBReader(stream), 'constructor must throw'); 2279 }, 'ReadableStreamBYOBReader constructor requires an unlocked ReadableStream'); 2280 2281 test(() => { 2282 const ReadableStreamBYOBReader = new ReadableStream({ type: 'bytes' }).getReader({ mode: 'byob' }).constructor; 2283 const stream = new ReadableStream(); 2284 assert_throws_js(TypeError, () => new ReadableStreamBYOBReader(stream), 'constructor must throw'); 2285 }, 'ReadableStreamBYOBReader constructor requires a ReadableStream with type "bytes"'); 2286 2287 test(() => { 2288 assert_throws_js(RangeError, () => new ReadableStream({ type: 'bytes' }, { 2289 size() { 2290 return 1; 2291 } 2292 }), 'constructor should throw for size function'); 2293 2294 assert_throws_js(RangeError, 2295 () => new ReadableStream({ type: 'bytes' }, new CountQueuingStrategy({ highWaterMark: 1 })), 2296 'constructor should throw when strategy is CountQueuingStrategy'); 2297 2298 assert_throws_js(RangeError, 2299 () => new ReadableStream({ type: 'bytes' }, new ByteLengthQueuingStrategy({ highWaterMark: 512 })), 2300 'constructor should throw when strategy is ByteLengthQueuingStrategy'); 2301 2302 class HasSizeMethod { 2303 size() {} 2304 } 2305 2306 assert_throws_js(RangeError, () => new ReadableStream({ type: 'bytes' }, new HasSizeMethod()), 2307 'constructor should throw when size on the prototype chain'); 2308 }, 'ReadableStream constructor should not accept a strategy with a size defined if type is "bytes"'); 2309 2310 promise_test(async t => { 2311 const stream = new ReadableStream({ 2312 pull: t.step_func(c => { 2313 const view = new Uint8Array(c.byobRequest.view.buffer, 0, 1); 2314 view[0] = 1; 2315 2316 c.byobRequest.respondWithNewView(view); 2317 }), 2318 type: 'bytes' 2319 }); 2320 const reader = stream.getReader({ mode: 'byob' }); 2321 2322 const result = await reader.read(new Uint8Array([4, 5, 6])); 2323 assert_false(result.done, 'result.done'); 2324 2325 const view = result.value; 2326 assert_equals(view.byteOffset, 0, 'result.value.byteOffset'); 2327 assert_equals(view.byteLength, 1, 'result.value.byteLength'); 2328 assert_equals(view[0], 1, 'result.value[0]'); 2329 assert_equals(view.buffer.byteLength, 3, 'result.value.buffer.byteLength'); 2330 assert_array_equals([...new Uint8Array(view.buffer)], [1, 5, 6], 'result.value.buffer'); 2331 }, 'ReadableStream with byte source: respondWithNewView() with a smaller view'); 2332 2333 promise_test(async t => { 2334 const stream = new ReadableStream({ 2335 pull: t.step_func(c => { 2336 const view = new Uint8Array(c.byobRequest.view.buffer, 0, 0); 2337 2338 c.close(); 2339 2340 c.byobRequest.respondWithNewView(view); 2341 }), 2342 type: 'bytes' 2343 }); 2344 const reader = stream.getReader({ mode: 'byob' }); 2345 2346 const result = await reader.read(new Uint8Array([4, 5, 6])); 2347 assert_true(result.done, 'result.done'); 2348 2349 const view = result.value; 2350 assert_equals(view.byteOffset, 0, 'result.value.byteOffset'); 2351 assert_equals(view.byteLength, 0, 'result.value.byteLength'); 2352 assert_equals(view.buffer.byteLength, 3, 'result.value.buffer.byteLength'); 2353 assert_array_equals([...new Uint8Array(view.buffer)], [4, 5, 6], 'result.value.buffer'); 2354 }, 'ReadableStream with byte source: respondWithNewView() with a zero-length view (in the closed state)'); 2355 2356 promise_test(async t => { 2357 let controller; 2358 let resolvePullCalledPromise; 2359 const pullCalledPromise = new Promise(resolve => { 2360 resolvePullCalledPromise = resolve; 2361 }); 2362 const stream = new ReadableStream({ 2363 start: t.step_func((c) => { 2364 controller = c; 2365 }), 2366 pull: t.step_func(() => { 2367 resolvePullCalledPromise(); 2368 }), 2369 type: 'bytes' 2370 }); 2371 2372 const reader = stream.getReader({ mode: 'byob' }); 2373 const readPromise = reader.read(new Uint8Array([4, 5, 6])); 2374 await pullCalledPromise; 2375 2376 // Transfer the original BYOB request's buffer, and respond with a new view on that buffer 2377 const transferredView = transferArrayBufferView(controller.byobRequest.view); 2378 const newView = transferredView.subarray(0, 1); 2379 newView[0] = 42; 2380 2381 controller.byobRequest.respondWithNewView(newView); 2382 2383 const result = await readPromise; 2384 assert_false(result.done, 'result.done'); 2385 2386 const view = result.value; 2387 assert_equals(view.byteOffset, 0, 'result.value.byteOffset'); 2388 assert_equals(view.byteLength, 1, 'result.value.byteLength'); 2389 assert_equals(view[0], 42, 'result.value[0]'); 2390 assert_equals(view.buffer.byteLength, 3, 'result.value.buffer.byteLength'); 2391 assert_array_equals([...new Uint8Array(view.buffer)], [42, 5, 6], 'result.value.buffer'); 2392 2393 }, 'ReadableStream with byte source: respondWithNewView() with a transferred non-zero-length view ' + 2394 '(in the readable state)'); 2395 2396 promise_test(async t => { 2397 let controller; 2398 let resolvePullCalledPromise; 2399 const pullCalledPromise = new Promise(resolve => { 2400 resolvePullCalledPromise = resolve; 2401 }); 2402 const stream = new ReadableStream({ 2403 start: t.step_func((c) => { 2404 controller = c; 2405 }), 2406 pull: t.step_func(() => { 2407 resolvePullCalledPromise(); 2408 }), 2409 type: 'bytes' 2410 }); 2411 2412 const reader = stream.getReader({ mode: 'byob' }); 2413 const readPromise = reader.read(new Uint8Array([4, 5, 6])); 2414 await pullCalledPromise; 2415 2416 // Transfer the original BYOB request's buffer, and respond with an empty view on that buffer 2417 const transferredView = transferArrayBufferView(controller.byobRequest.view); 2418 const newView = transferredView.subarray(0, 0); 2419 2420 controller.close(); 2421 controller.byobRequest.respondWithNewView(newView); 2422 2423 const result = await readPromise; 2424 assert_true(result.done, 'result.done'); 2425 2426 const view = result.value; 2427 assert_equals(view.byteOffset, 0, 'result.value.byteOffset'); 2428 assert_equals(view.byteLength, 0, 'result.value.byteLength'); 2429 assert_equals(view.buffer.byteLength, 3, 'result.value.buffer.byteLength'); 2430 assert_array_equals([...new Uint8Array(view.buffer)], [4, 5, 6], 'result.value.buffer'); 2431 2432 }, 'ReadableStream with byte source: respondWithNewView() with a transferred zero-length view ' + 2433 '(in the closed state)'); 2434 2435 promise_test(async t => { 2436 let controller; 2437 let pullCount = 0; 2438 const rs = new ReadableStream({ 2439 type: 'bytes', 2440 autoAllocateChunkSize: 10, 2441 start: t.step_func((c) => { 2442 controller = c; 2443 }), 2444 pull: t.step_func(() => { 2445 ++pullCount; 2446 }) 2447 }); 2448 2449 await flushAsyncEvents(); 2450 assert_equals(pullCount, 0, 'pull() must not have been invoked yet'); 2451 2452 const reader1 = rs.getReader(); 2453 const read1 = reader1.read(); 2454 assert_equals(pullCount, 1, 'pull() must have been invoked once'); 2455 const byobRequest1 = controller.byobRequest; 2456 assert_equals(byobRequest1.view.byteLength, 10, 'first byobRequest.view.byteLength'); 2457 2458 // enqueue() must discard the auto-allocated BYOB request 2459 controller.enqueue(new Uint8Array([1, 2, 3])); 2460 assert_equals(byobRequest1.view, null, 'first byobRequest must be invalidated after enqueue()'); 2461 2462 const result1 = await read1; 2463 assert_false(result1.done, 'first result.done'); 2464 const view1 = result1.value; 2465 assert_equals(view1.byteOffset, 0, 'first result.value.byteOffset'); 2466 assert_equals(view1.byteLength, 3, 'first result.value.byteLength'); 2467 assert_array_equals([...new Uint8Array(view1.buffer)], [1, 2, 3], 'first result.value.buffer'); 2468 2469 reader1.releaseLock(); 2470 2471 // read(view) should work after discarding the auto-allocated BYOB request 2472 const reader2 = rs.getReader({ mode: 'byob' }); 2473 const read2 = reader2.read(new Uint8Array([4, 5, 6])); 2474 assert_equals(pullCount, 2, 'pull() must have been invoked twice'); 2475 const byobRequest2 = controller.byobRequest; 2476 assert_equals(byobRequest2.view.byteOffset, 0, 'second byobRequest.view.byteOffset'); 2477 assert_equals(byobRequest2.view.byteLength, 3, 'second byobRequest.view.byteLength'); 2478 assert_array_equals([...new Uint8Array(byobRequest2.view.buffer)], [4, 5, 6], 'second byobRequest.view.buffer'); 2479 2480 byobRequest2.respond(3); 2481 assert_equals(byobRequest2.view, null, 'second byobRequest must be invalidated after respond()'); 2482 2483 const result2 = await read2; 2484 assert_false(result2.done, 'second result.done'); 2485 const view2 = result2.value; 2486 assert_equals(view2.byteOffset, 0, 'second result.value.byteOffset'); 2487 assert_equals(view2.byteLength, 3, 'second result.value.byteLength'); 2488 assert_array_equals([...new Uint8Array(view2.buffer)], [4, 5, 6], 'second result.value.buffer'); 2489 2490 reader2.releaseLock(); 2491 assert_equals(pullCount, 2, 'pull() must only have been invoked twice'); 2492 }, 'ReadableStream with byte source: enqueue() discards auto-allocated BYOB request'); 2493 2494 promise_test(async t => { 2495 let controller; 2496 const rs = new ReadableStream({ 2497 type: 'bytes', 2498 start: t.step_func((c) => { 2499 controller = c; 2500 }) 2501 }); 2502 await flushAsyncEvents(); 2503 2504 const reader1 = rs.getReader({ mode: 'byob' }); 2505 const read1 = reader1.read(new Uint8Array([1, 2, 3])); 2506 const byobRequest1 = controller.byobRequest; 2507 assert_not_equals(byobRequest1, null, 'first byobRequest should exist'); 2508 assert_typed_array_equals(byobRequest1.view, new Uint8Array([1, 2, 3]), 'first byobRequest.view'); 2509 2510 // releaseLock() should reject the pending read, but *not* invalidate the BYOB request 2511 reader1.releaseLock(); 2512 const reader2 = rs.getReader({ mode: 'byob' }); 2513 const read2 = reader2.read(new Uint8Array([4, 5, 6])); 2514 assert_not_equals(controller.byobRequest, null, 'byobRequest should not be invalidated after releaseLock()'); 2515 assert_equals(controller.byobRequest, byobRequest1, 'byobRequest should be unchanged'); 2516 assert_array_equals([...new Uint8Array(byobRequest1.view.buffer)], [1, 2, 3], 'byobRequest.view.buffer should be unchanged'); 2517 await promise_rejects_js(t, TypeError, read1, 'pending read must reject after releaseLock()'); 2518 2519 // respond() should fulfill the *second* read() request 2520 byobRequest1.view[0] = 11; 2521 byobRequest1.respond(1); 2522 const byobRequest2 = controller.byobRequest; 2523 assert_equals(byobRequest2, null, 'byobRequest should be null after respond()'); 2524 2525 const result2 = await read2; 2526 assert_false(result2.done, 'second result.done'); 2527 assert_typed_array_equals(result2.value, new Uint8Array([11, 5, 6]).subarray(0, 1), 'second result.value'); 2528 2529 }, 'ReadableStream with byte source: releaseLock() with pending read(view), read(view) on second reader, respond()'); 2530 2531 promise_test(async t => { 2532 let controller; 2533 const rs = new ReadableStream({ 2534 type: 'bytes', 2535 start: t.step_func((c) => { 2536 controller = c; 2537 }) 2538 }); 2539 await flushAsyncEvents(); 2540 2541 const reader1 = rs.getReader({ mode: 'byob' }); 2542 const read1 = reader1.read(new Uint8Array([1, 2, 3])); 2543 const byobRequest1 = controller.byobRequest; 2544 assert_not_equals(byobRequest1, null, 'first byobRequest should exist'); 2545 assert_typed_array_equals(byobRequest1.view, new Uint8Array([1, 2, 3]), 'first byobRequest.view'); 2546 2547 // releaseLock() should reject the pending read, but *not* invalidate the BYOB request 2548 reader1.releaseLock(); 2549 const reader2 = rs.getReader({ mode: 'byob' }); 2550 const read2 = reader2.read(new Uint16Array(1)); 2551 assert_not_equals(controller.byobRequest, null, 'byobRequest should not be invalidated after releaseLock()'); 2552 assert_equals(controller.byobRequest, byobRequest1, 'byobRequest should be unchanged'); 2553 assert_array_equals([...new Uint8Array(byobRequest1.view.buffer)], [1, 2, 3], 'byobRequest.view.buffer should be unchanged'); 2554 await promise_rejects_js(t, TypeError, read1, 'pending read must reject after releaseLock()'); 2555 2556 // respond(1) should partially fill the second read(), but not yet fulfill it 2557 byobRequest1.view[0] = 0x11; 2558 byobRequest1.respond(1); 2559 2560 // second BYOB request should use remaining buffer from the second read() 2561 const byobRequest2 = controller.byobRequest; 2562 assert_not_equals(byobRequest2, null, 'second byobRequest should exist'); 2563 assert_typed_array_equals(byobRequest2.view, new Uint8Array([0x11, 0]).subarray(1, 2), 'second byobRequest.view'); 2564 2565 // second respond(1) should fill the read request and fulfill it 2566 byobRequest2.view[0] = 0x22; 2567 byobRequest2.respond(1); 2568 const result2 = await read2; 2569 assert_false(result2.done, 'second result.done'); 2570 const view2 = result2.value; 2571 assert_equals(view2.byteOffset, 0, 'second result.value.byteOffset'); 2572 assert_equals(view2.byteLength, 2, 'second result.value.byteLength'); 2573 const dataView2 = new DataView(view2.buffer, view2.byteOffset, view2.byteLength); 2574 assert_equals(dataView2.getUint16(0), 0x1122, 'second result.value[0]'); 2575 2576 }, 'ReadableStream with byte source: releaseLock() with pending read(view), read(view) on second reader with ' + 2577 '1 element Uint16Array, respond(1)'); 2578 2579 promise_test(async t => { 2580 let controller; 2581 const rs = new ReadableStream({ 2582 type: 'bytes', 2583 start: t.step_func((c) => { 2584 controller = c; 2585 }) 2586 }); 2587 await flushAsyncEvents(); 2588 2589 const reader1 = rs.getReader({ mode: 'byob' }); 2590 const read1 = reader1.read(new Uint8Array([1, 2, 3])); 2591 const byobRequest1 = controller.byobRequest; 2592 assert_not_equals(byobRequest1, null, 'first byobRequest should exist'); 2593 assert_typed_array_equals(byobRequest1.view, new Uint8Array([1, 2, 3]), 'first byobRequest.view'); 2594 2595 // releaseLock() should reject the pending read, but *not* invalidate the BYOB request 2596 reader1.releaseLock(); 2597 const reader2 = rs.getReader({ mode: 'byob' }); 2598 const read2 = reader2.read(new Uint8Array([4, 5])); 2599 assert_not_equals(controller.byobRequest, null, 'byobRequest should not be invalidated after releaseLock()'); 2600 assert_equals(controller.byobRequest, byobRequest1, 'byobRequest should be unchanged'); 2601 assert_array_equals([...new Uint8Array(byobRequest1.view.buffer)], [1, 2, 3], 'byobRequest.view.buffer should be unchanged'); 2602 await promise_rejects_js(t, TypeError, read1, 'pending read must reject after releaseLock()'); 2603 2604 // respond(3) should fulfill the second read(), and put 1 remaining byte in the queue 2605 byobRequest1.view[0] = 6; 2606 byobRequest1.view[1] = 7; 2607 byobRequest1.view[2] = 8; 2608 byobRequest1.respond(3); 2609 const byobRequest2 = controller.byobRequest; 2610 assert_equals(byobRequest2, null, 'byobRequest should be null after respond()'); 2611 2612 const result2 = await read2; 2613 assert_false(result2.done, 'second result.done'); 2614 assert_typed_array_equals(result2.value, new Uint8Array([6, 7]), 'second result.value'); 2615 2616 // third read() should fulfill with the remaining byte 2617 const result3 = await reader2.read(new Uint8Array([0, 0, 0])); 2618 assert_false(result3.done, 'third result.done'); 2619 assert_typed_array_equals(result3.value, new Uint8Array([8, 0, 0]).subarray(0, 1), 'third result.value'); 2620 2621 }, 'ReadableStream with byte source: releaseLock() with pending read(view), read(view) on second reader with ' + 2622 '2 element Uint8Array, respond(3)'); 2623 2624 promise_test(async t => { 2625 let controller; 2626 const rs = new ReadableStream({ 2627 type: 'bytes', 2628 start: t.step_func((c) => { 2629 controller = c; 2630 }) 2631 }); 2632 await flushAsyncEvents(); 2633 2634 const reader1 = rs.getReader({ mode: 'byob' }); 2635 const read1 = reader1.read(new Uint8Array([1, 2, 3])); 2636 const byobRequest1 = controller.byobRequest; 2637 assert_not_equals(byobRequest1, null, 'first byobRequest should exist'); 2638 assert_typed_array_equals(byobRequest1.view, new Uint8Array([1, 2, 3]), 'first byobRequest.view'); 2639 2640 // releaseLock() should reject the pending read, but *not* invalidate the BYOB request 2641 reader1.releaseLock(); 2642 const reader2 = rs.getReader({ mode: 'byob' }); 2643 const read2 = reader2.read(new Uint8Array([4, 5, 6])); 2644 assert_not_equals(controller.byobRequest, null, 'byobRequest should not be invalidated after releaseLock()'); 2645 await promise_rejects_js(t, TypeError, read1, 'pending read must reject after releaseLock()'); 2646 2647 // respondWithNewView() should fulfill the *second* read() request 2648 byobRequest1.view[0] = 11; 2649 byobRequest1.view[1] = 12; 2650 byobRequest1.respondWithNewView(byobRequest1.view.subarray(0, 2)); 2651 const byobRequest2 = controller.byobRequest; 2652 assert_equals(byobRequest2, null, 'byobRequest should be null after respondWithNewView()'); 2653 2654 const result2 = await read2; 2655 assert_false(result2.done, 'second result.done'); 2656 assert_typed_array_equals(result2.value, new Uint8Array([11, 12, 6]).subarray(0, 2), 'second result.value'); 2657 2658 }, 'ReadableStream with byte source: releaseLock() with pending read(view), read(view) on second reader, respondWithNewView()'); 2659 2660 promise_test(async t => { 2661 let controller; 2662 const rs = new ReadableStream({ 2663 type: 'bytes', 2664 start: t.step_func((c) => { 2665 controller = c; 2666 }) 2667 }); 2668 await flushAsyncEvents(); 2669 2670 const reader1 = rs.getReader({ mode: 'byob' }); 2671 const read1 = reader1.read(new Uint8Array([1, 2, 3])); 2672 const byobRequest1 = controller.byobRequest; 2673 assert_not_equals(byobRequest1, null, 'first byobRequest should exist'); 2674 assert_typed_array_equals(byobRequest1.view, new Uint8Array([1, 2, 3]), 'first byobRequest.view'); 2675 2676 // releaseLock() should reject the pending read, but *not* invalidate the BYOB request 2677 reader1.releaseLock(); 2678 const reader2 = rs.getReader({ mode: 'byob' }); 2679 const read2 = reader2.read(new Uint8Array([4, 5, 6])); 2680 assert_not_equals(controller.byobRequest, null, 'byobRequest should not be invalidated after releaseLock()'); 2681 await promise_rejects_js(t, TypeError, read1, 'pending read must reject after releaseLock()'); 2682 2683 // enqueue() should fulfill the *second* read() request 2684 controller.enqueue(new Uint8Array([11, 12])); 2685 const byobRequest2 = controller.byobRequest; 2686 assert_equals(byobRequest2, null, 'byobRequest should be null after enqueue()'); 2687 2688 const result2 = await read2; 2689 assert_false(result2.done, 'second result.done'); 2690 assert_typed_array_equals(result2.value, new Uint8Array([11, 12, 6]).subarray(0, 2), 'second result.value'); 2691 2692 }, 'ReadableStream with byte source: releaseLock() with pending read(view), read(view) on second reader, enqueue()'); 2693 2694 promise_test(async t => { 2695 let controller; 2696 const rs = new ReadableStream({ 2697 type: 'bytes', 2698 start: t.step_func((c) => { 2699 controller = c; 2700 }) 2701 }); 2702 await flushAsyncEvents(); 2703 2704 const reader1 = rs.getReader({ mode: 'byob' }); 2705 const read1 = reader1.read(new Uint8Array([1, 2, 3])); 2706 const byobRequest1 = controller.byobRequest; 2707 assert_not_equals(byobRequest1, null, 'first byobRequest should exist'); 2708 assert_typed_array_equals(byobRequest1.view, new Uint8Array([1, 2, 3]), 'first byobRequest.view'); 2709 2710 // releaseLock() should reject the pending read, but *not* invalidate the BYOB request 2711 reader1.releaseLock(); 2712 const reader2 = rs.getReader({ mode: 'byob' }); 2713 const read2 = reader2.read(new Uint8Array([4, 5, 6])); 2714 assert_not_equals(controller.byobRequest, null, 'byobRequest should not be invalidated after releaseLock()'); 2715 await promise_rejects_js(t, TypeError, read1, 'pending read must reject after releaseLock()'); 2716 2717 // close() followed by respond(0) should fulfill the second read() 2718 controller.close(); 2719 byobRequest1.respond(0); 2720 const byobRequest2 = controller.byobRequest; 2721 assert_equals(byobRequest2, null, 'byobRequest should be null after respond()'); 2722 2723 const result2 = await read2; 2724 assert_true(result2.done, 'second result.done'); 2725 assert_typed_array_equals(result2.value, new Uint8Array([4, 5, 6]).subarray(0, 0), 'second result.value'); 2726 }, 'ReadableStream with byte source: releaseLock() with pending read(view), read(view) on second reader, ' + 2727 'close(), respond(0)'); 2728 2729 promise_test(async t => { 2730 let controller; 2731 const rs = new ReadableStream({ 2732 type: 'bytes', 2733 autoAllocateChunkSize: 4, 2734 start: t.step_func((c) => { 2735 controller = c; 2736 }) 2737 }); 2738 await flushAsyncEvents(); 2739 2740 const reader1 = rs.getReader(); 2741 const read1 = reader1.read(); 2742 const byobRequest1 = controller.byobRequest; 2743 assert_not_equals(byobRequest1, null, 'first byobRequest should exist'); 2744 assert_typed_array_equals(byobRequest1.view, new Uint8Array(4), 'first byobRequest.view'); 2745 2746 // releaseLock() should reject the pending read, but *not* invalidate the BYOB request 2747 reader1.releaseLock(); 2748 const reader2 = rs.getReader(); 2749 const read2 = reader2.read(); 2750 assert_not_equals(controller.byobRequest, null, 'byobRequest should not be invalidated after releaseLock()'); 2751 await promise_rejects_js(t, TypeError, read1, 'pending read must reject after releaseLock()'); 2752 2753 // respond() should fulfill the *second* read() request 2754 byobRequest1.view[0] = 11; 2755 byobRequest1.respond(1); 2756 const byobRequest2 = controller.byobRequest; 2757 assert_equals(byobRequest2, null, 'byobRequest should be null after respond()'); 2758 2759 const result2 = await read2; 2760 assert_false(result2.done, 'second result.done'); 2761 assert_typed_array_equals(result2.value, new Uint8Array([11, 0, 0, 0]).subarray(0, 1), 'second result.value'); 2762 2763 }, 'ReadableStream with byte source: autoAllocateChunkSize, releaseLock() with pending read(), read() on second reader, respond()'); 2764 2765 promise_test(async t => { 2766 let controller; 2767 const rs = new ReadableStream({ 2768 type: 'bytes', 2769 autoAllocateChunkSize: 4, 2770 start: t.step_func((c) => { 2771 controller = c; 2772 }) 2773 }); 2774 await flushAsyncEvents(); 2775 2776 const reader1 = rs.getReader(); 2777 const read1 = reader1.read(); 2778 const byobRequest1 = controller.byobRequest; 2779 assert_not_equals(byobRequest1, null, 'first byobRequest should exist'); 2780 assert_typed_array_equals(byobRequest1.view, new Uint8Array(4), 'first byobRequest.view'); 2781 2782 // releaseLock() should reject the pending read, but *not* invalidate the BYOB request 2783 reader1.releaseLock(); 2784 const reader2 = rs.getReader(); 2785 const read2 = reader2.read(); 2786 assert_not_equals(controller.byobRequest, null, 'byobRequest should not be invalidated after releaseLock()'); 2787 await promise_rejects_js(t, TypeError, read1, 'pending read must reject after releaseLock()'); 2788 2789 // enqueue() should fulfill the *second* read() request 2790 controller.enqueue(new Uint8Array([11])); 2791 const byobRequest2 = controller.byobRequest; 2792 assert_equals(byobRequest2, null, 'byobRequest should be null after enqueue()'); 2793 2794 const result2 = await read2; 2795 assert_false(result2.done, 'second result.done'); 2796 assert_typed_array_equals(result2.value, new Uint8Array([11]), 'second result.value'); 2797 2798 }, 'ReadableStream with byte source: autoAllocateChunkSize, releaseLock() with pending read(), read() on second reader, enqueue()'); 2799 2800 promise_test(async t => { 2801 let controller; 2802 const rs = new ReadableStream({ 2803 type: 'bytes', 2804 autoAllocateChunkSize: 4, 2805 start: t.step_func((c) => { 2806 controller = c; 2807 }) 2808 }); 2809 await flushAsyncEvents(); 2810 2811 const reader1 = rs.getReader(); 2812 const read1 = reader1.read(); 2813 const byobRequest1 = controller.byobRequest; 2814 assert_not_equals(byobRequest1, null, 'first byobRequest should exist'); 2815 assert_typed_array_equals(byobRequest1.view, new Uint8Array(4), 'first byobRequest.view'); 2816 2817 // releaseLock() should reject the pending read, but *not* invalidate the BYOB request 2818 reader1.releaseLock(); 2819 const reader2 = rs.getReader({ mode: 'byob' }); 2820 const read2 = reader2.read(new Uint8Array([4, 5, 6])); 2821 assert_not_equals(controller.byobRequest, null, 'byobRequest should not be invalidated after releaseLock()'); 2822 await promise_rejects_js(t, TypeError, read1, 'pending read must reject after releaseLock()'); 2823 2824 // respond() should fulfill the *second* read() request 2825 byobRequest1.view[0] = 11; 2826 byobRequest1.respond(1); 2827 const byobRequest2 = controller.byobRequest; 2828 assert_equals(byobRequest2, null, 'byobRequest should be null after respond()'); 2829 2830 const result2 = await read2; 2831 assert_false(result2.done, 'second result.done'); 2832 assert_typed_array_equals(result2.value, new Uint8Array([11, 5, 6]).subarray(0, 1), 'second result.value'); 2833 2834 }, 'ReadableStream with byte source: autoAllocateChunkSize, releaseLock() with pending read(), read(view) on second reader, respond()'); 2835 2836 promise_test(async t => { 2837 let controller; 2838 const rs = new ReadableStream({ 2839 type: 'bytes', 2840 autoAllocateChunkSize: 4, 2841 start: t.step_func((c) => { 2842 controller = c; 2843 }) 2844 }); 2845 await flushAsyncEvents(); 2846 2847 const reader1 = rs.getReader(); 2848 const read1 = reader1.read(); 2849 const byobRequest1 = controller.byobRequest; 2850 assert_not_equals(byobRequest1, null, 'first byobRequest should exist'); 2851 assert_typed_array_equals(byobRequest1.view, new Uint8Array(4), 'first byobRequest.view'); 2852 2853 // releaseLock() should reject the pending read, but *not* invalidate the BYOB request 2854 reader1.releaseLock(); 2855 const reader2 = rs.getReader({ mode: 'byob' }); 2856 const read2 = reader2.read(new Uint8Array([4, 5, 6])); 2857 assert_not_equals(controller.byobRequest, null, 'byobRequest should not be invalidated after releaseLock()'); 2858 await promise_rejects_js(t, TypeError, read1, 'pending read must reject after releaseLock()'); 2859 2860 // enqueue() should fulfill the *second* read() request 2861 controller.enqueue(new Uint8Array([11])); 2862 const byobRequest2 = controller.byobRequest; 2863 assert_equals(byobRequest2, null, 'byobRequest should be null after enqueue()'); 2864 2865 const result2 = await read2; 2866 assert_false(result2.done, 'second result.done'); 2867 assert_typed_array_equals(result2.value, new Uint8Array([11, 5, 6]).subarray(0, 1), 'second result.value'); 2868 2869 }, 'ReadableStream with byte source: autoAllocateChunkSize, releaseLock() with pending read(), read(view) on second reader, enqueue()'); 2870 2871 promise_test(async t => { 2872 let controller; 2873 const rs = new ReadableStream({ 2874 type: 'bytes', 2875 start: t.step_func((c) => { 2876 controller = c; 2877 }) 2878 }); 2879 await flushAsyncEvents(); 2880 2881 const reader1 = rs.getReader({ mode: 'byob' }); 2882 const read1 = reader1.read(new Uint16Array(1)); 2883 const byobRequest1 = controller.byobRequest; 2884 assert_not_equals(byobRequest1, null, 'first byobRequest should exist'); 2885 assert_typed_array_equals(byobRequest1.view, new Uint8Array([0, 0]), 'first byobRequest.view'); 2886 2887 // respond(1) should partially fill the first read(), but not yet fulfill it 2888 byobRequest1.view[0] = 0x11; 2889 byobRequest1.respond(1); 2890 const byobRequest2 = controller.byobRequest; 2891 assert_not_equals(byobRequest2, null, 'second byobRequest should exist'); 2892 assert_typed_array_equals(byobRequest2.view, new Uint8Array([0x11, 0]).subarray(1, 2), 'second byobRequest.view'); 2893 2894 // releaseLock() should reject the pending read, but *not* invalidate the BYOB request 2895 reader1.releaseLock(); 2896 const reader2 = rs.getReader({ mode: 'byob' }); 2897 const read2 = reader2.read(new Uint16Array(1)); 2898 assert_not_equals(controller.byobRequest, null, 'byobRequest should not be invalidated after releaseLock()'); 2899 assert_equals(controller.byobRequest, byobRequest2, 'byobRequest should be unchanged'); 2900 assert_typed_array_equals(byobRequest2.view, new Uint8Array([0x11, 0]).subarray(1, 2), 'byobRequest.view should be unchanged'); 2901 await promise_rejects_js(t, TypeError, read1, 'pending read must reject after releaseLock()'); 2902 2903 // second respond(1) should fill the read request and fulfill it 2904 byobRequest2.view[0] = 0x22; 2905 byobRequest2.respond(1); 2906 assert_equals(controller.byobRequest, null, 'byobRequest should be invalidated after second respond()'); 2907 2908 const result2 = await read2; 2909 assert_false(result2.done, 'second result.done'); 2910 const view2 = result2.value; 2911 assert_equals(view2.byteOffset, 0, 'second result.value.byteOffset'); 2912 assert_equals(view2.byteLength, 2, 'second result.value.byteLength'); 2913 const dataView2 = new DataView(view2.buffer, view2.byteOffset, view2.byteLength); 2914 assert_equals(dataView2.getUint16(0), 0x1122, 'second result.value[0]'); 2915 2916 }, 'ReadableStream with byte source: read(view) with 1 element Uint16Array, respond(1), releaseLock(), read(view) on ' + 2917 'second reader with 1 element Uint16Array, respond(1)'); 2918 2919 promise_test(async t => { 2920 let controller; 2921 const rs = new ReadableStream({ 2922 type: 'bytes', 2923 start: t.step_func((c) => { 2924 controller = c; 2925 }) 2926 }); 2927 await flushAsyncEvents(); 2928 2929 const reader1 = rs.getReader({ mode: 'byob' }); 2930 const read1 = reader1.read(new Uint16Array(1)); 2931 const byobRequest1 = controller.byobRequest; 2932 assert_not_equals(byobRequest1, null, 'first byobRequest should exist'); 2933 assert_typed_array_equals(byobRequest1.view, new Uint8Array([0, 0]), 'first byobRequest.view'); 2934 2935 // respond(1) should partially fill the first read(), but not yet fulfill it 2936 byobRequest1.view[0] = 0x11; 2937 byobRequest1.respond(1); 2938 const byobRequest2 = controller.byobRequest; 2939 assert_not_equals(byobRequest2, null, 'second byobRequest should exist'); 2940 assert_typed_array_equals(byobRequest2.view, new Uint8Array([0x11, 0]).subarray(1, 2), 'second byobRequest.view'); 2941 2942 // releaseLock() should reject the pending read, but *not* invalidate the BYOB request 2943 reader1.releaseLock(); 2944 const reader2 = rs.getReader(); 2945 const read2 = reader2.read(); 2946 assert_not_equals(controller.byobRequest, null, 'byobRequest should not be invalidated after releaseLock()'); 2947 assert_equals(controller.byobRequest, byobRequest2, 'byobRequest should be unchanged'); 2948 assert_typed_array_equals(byobRequest2.view, new Uint8Array([0x11, 0]).subarray(1, 2), 'byobRequest.view should be unchanged'); 2949 await promise_rejects_js(t, TypeError, read1, 'pending read must reject after releaseLock()'); 2950 2951 // enqueue() should fulfill the read request and put remaining byte in the queue 2952 controller.enqueue(new Uint8Array([0x22])); 2953 assert_equals(controller.byobRequest, null, 'byobRequest should be invalidated after second respond()'); 2954 2955 const result2 = await read2; 2956 assert_false(result2.done, 'second result.done'); 2957 assert_typed_array_equals(result2.value, new Uint8Array([0x11]), 'second result.value'); 2958 2959 const result3 = await reader2.read(); 2960 assert_false(result3.done, 'third result.done'); 2961 assert_typed_array_equals(result3.value, new Uint8Array([0x22]), 'third result.value'); 2962 2963 }, 'ReadableStream with byte source: read(view) with 1 element Uint16Array, respond(1), releaseLock(), read() on ' + 2964 'second reader, enqueue()'); 2965 2966 promise_test(async t => { 2967 // Tests https://github.com/nodejs/node/issues/41886 2968 const stream = new ReadableStream({ 2969 type: 'bytes', 2970 autoAllocateChunkSize: 10, 2971 pull: t.step_func((c) => { 2972 const newView = new Uint8Array(c.byobRequest.view.buffer, 0, 3); 2973 newView.set([20, 21, 22]); 2974 c.byobRequest.respondWithNewView(newView); 2975 }) 2976 }); 2977 2978 const reader = stream.getReader(); 2979 const result = await reader.read(); 2980 assert_false(result.done, 'result.done'); 2981 2982 const view = result.value; 2983 assert_equals(view.byteOffset, 0, 'result.value.byteOffset'); 2984 assert_equals(view.byteLength, 3, 'result.value.byteLength'); 2985 assert_equals(view.buffer.byteLength, 10, 'result.value.buffer.byteLength'); 2986 assert_array_equals([...new Uint8Array(view)], [20, 21, 22], 'result.value'); 2987 }, 'ReadableStream with byte source: autoAllocateChunkSize, read(), respondWithNewView()');