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