read-min.any.js (29919B)
1 // META: global=window,worker,shadowrealm 2 // META: script=../resources/rs-utils.js 3 // META: script=../resources/test-utils.js 4 'use strict'; 5 6 // View buffers are detached after pull() returns, so record the information at the time that pull() was called. 7 function extractViewInfo(view) { 8 return { 9 constructor: view.constructor, 10 bufferByteLength: view.buffer.byteLength, 11 byteOffset: view.byteOffset, 12 byteLength: view.byteLength 13 }; 14 } 15 16 promise_test(async t => { 17 const rs = new ReadableStream({ 18 type: 'bytes', 19 pull: t.unreached_func('pull() should not be called'), 20 }); 21 const reader = rs.getReader({ mode: 'byob' }); 22 await promise_rejects_js(t, TypeError, reader.read(new Uint8Array(1), { min: 0 })); 23 }, 'ReadableStream with byte source: read({ min }) rejects if min is 0'); 24 25 promise_test(async t => { 26 const rs = new ReadableStream({ 27 type: 'bytes', 28 pull: t.unreached_func('pull() should not be called'), 29 }); 30 const reader = rs.getReader({ mode: 'byob' }); 31 await promise_rejects_js(t, TypeError, reader.read(new Uint8Array(1), { min: -1 })); 32 }, 'ReadableStream with byte source: read({ min }) rejects if min is negative'); 33 34 promise_test(async t => { 35 const rs = new ReadableStream({ 36 type: 'bytes', 37 pull: t.unreached_func('pull() should not be called'), 38 }); 39 const reader = rs.getReader({ mode: 'byob' }); 40 await promise_rejects_js(t, RangeError, reader.read(new Uint8Array(1), { min: 2 })); 41 }, 'ReadableStream with byte source: read({ min }) rejects if min is larger than view\'s length (Uint8Array)'); 42 43 promise_test(async t => { 44 const rs = new ReadableStream({ 45 type: 'bytes', 46 pull: t.unreached_func('pull() should not be called'), 47 }); 48 const reader = rs.getReader({ mode: 'byob' }); 49 await promise_rejects_js(t, RangeError, reader.read(new Uint16Array(1), { min: 2 })); 50 }, 'ReadableStream with byte source: read({ min }) rejects if min is larger than view\'s length (Uint16Array)'); 51 52 promise_test(async t => { 53 const rs = new ReadableStream({ 54 type: 'bytes', 55 pull: t.unreached_func('pull() should not be called'), 56 }); 57 const reader = rs.getReader({ mode: 'byob' }); 58 await promise_rejects_js(t, RangeError, reader.read(new DataView(new ArrayBuffer(1)), { min: 2 })); 59 }, 'ReadableStream with byte source: read({ min }) rejects if min is larger than view\'s length (DataView)'); 60 61 promise_test(async t => { 62 let pullCount = 0; 63 const byobRequests = []; 64 const rs = new ReadableStream({ 65 type: 'bytes', 66 pull: t.step_func((c) => { 67 const byobRequest = c.byobRequest; 68 const view = byobRequest.view; 69 byobRequests[pullCount] = { 70 nonNull: byobRequest !== null, 71 viewNonNull: view !== null, 72 viewInfo: extractViewInfo(view) 73 }; 74 if (pullCount === 0) { 75 view[0] = 0x01; 76 view[1] = 0x02; 77 byobRequest.respond(2); 78 } else if (pullCount === 1) { 79 view[0] = 0x03; 80 byobRequest.respond(1); 81 } else if (pullCount === 2) { 82 view[0] = 0x04; 83 byobRequest.respond(1); 84 } 85 ++pullCount; 86 }) 87 }); 88 const reader = rs.getReader({ mode: 'byob' }); 89 const read1 = reader.read(new Uint8Array(3), { min: 3 }); 90 const read2 = reader.read(new Uint8Array(1)); 91 92 const result1 = await read1; 93 assert_false(result1.done, 'first result should not be done'); 94 assert_typed_array_equals(result1.value, new Uint8Array([0x01, 0x02, 0x03]), 'first result value'); 95 96 const result2 = await read2; 97 assert_false(result2.done, 'second result should not be done'); 98 assert_typed_array_equals(result2.value, new Uint8Array([0x04]), 'second result value'); 99 100 assert_equals(pullCount, 3, 'pull() must have been called 3 times'); 101 102 { 103 const byobRequest = byobRequests[0]; 104 assert_true(byobRequest.nonNull, 'first byobRequest must not be null'); 105 assert_true(byobRequest.viewNonNull, 'first byobRequest.view must not be null'); 106 const viewInfo = byobRequest.viewInfo; 107 assert_equals(viewInfo.constructor, Uint8Array, 'first view.constructor should be Uint8Array'); 108 assert_equals(viewInfo.bufferByteLength, 3, 'first view.buffer.byteLength should be 3'); 109 assert_equals(viewInfo.byteOffset, 0, 'first view.byteOffset should be 0'); 110 assert_equals(viewInfo.byteLength, 3, 'first view.byteLength should be 3'); 111 } 112 113 { 114 const byobRequest = byobRequests[1]; 115 assert_true(byobRequest.nonNull, 'second byobRequest must not be null'); 116 assert_true(byobRequest.viewNonNull, 'second byobRequest.view must not be null'); 117 const viewInfo = byobRequest.viewInfo; 118 assert_equals(viewInfo.constructor, Uint8Array, 'second view.constructor should be Uint8Array'); 119 assert_equals(viewInfo.bufferByteLength, 3, 'second view.buffer.byteLength should be 3'); 120 assert_equals(viewInfo.byteOffset, 2, 'second view.byteOffset should be 2'); 121 assert_equals(viewInfo.byteLength, 1, 'second view.byteLength should be 1'); 122 } 123 124 { 125 const byobRequest = byobRequests[2]; 126 assert_true(byobRequest.nonNull, 'third byobRequest must not be null'); 127 assert_true(byobRequest.viewNonNull, 'third byobRequest.view must not be null'); 128 const viewInfo = byobRequest.viewInfo; 129 assert_equals(viewInfo.constructor, Uint8Array, 'third view.constructor should be Uint8Array'); 130 assert_equals(viewInfo.bufferByteLength, 1, 'third view.buffer.byteLength should be 1'); 131 assert_equals(viewInfo.byteOffset, 0, 'third view.byteOffset should be 0'); 132 assert_equals(viewInfo.byteLength, 1, 'third view.byteLength should be 1'); 133 } 134 135 }, 'ReadableStream with byte source: read({ min }), then read()'); 136 137 promise_test(async t => { 138 let pullCount = 0; 139 const byobRequests = []; 140 const rs = new ReadableStream({ 141 type: 'bytes', 142 pull: t.step_func((c) => { 143 const byobRequest = c.byobRequest; 144 const view = byobRequest.view; 145 byobRequests[pullCount] = { 146 nonNull: byobRequest !== null, 147 viewNonNull: view !== null, 148 viewInfo: extractViewInfo(view) 149 }; 150 if (pullCount === 0) { 151 view[0] = 0x01; 152 view[1] = 0x02; 153 byobRequest.respond(2); 154 } else if (pullCount === 1) { 155 view[0] = 0x03; 156 byobRequest.respond(1); 157 } 158 ++pullCount; 159 }) 160 }); 161 const reader = rs.getReader({ mode: 'byob' }); 162 163 const result = await reader.read(new DataView(new ArrayBuffer(3)), { min: 3 }); 164 assert_false(result.done, 'result should not be done'); 165 assert_equals(result.value.constructor, DataView, 'result.value must be a DataView'); 166 assert_equals(result.value.byteOffset, 0, 'result.value.byteOffset'); 167 assert_equals(result.value.byteLength, 3, 'result.value.byteLength'); 168 assert_equals(result.value.buffer.byteLength, 3, 'result.value.buffer.byteLength'); 169 assert_array_equals([...new Uint8Array(result.value.buffer)], [0x01, 0x02, 0x03], `result.value.buffer contents`); 170 171 assert_equals(pullCount, 2, 'pull() must have been called 2 times'); 172 173 { 174 const byobRequest = byobRequests[0]; 175 assert_true(byobRequest.nonNull, 'first byobRequest must not be null'); 176 assert_true(byobRequest.viewNonNull, 'first byobRequest.view must not be null'); 177 const viewInfo = byobRequest.viewInfo; 178 assert_equals(viewInfo.constructor, Uint8Array, 'first view.constructor should be Uint8Array'); 179 assert_equals(viewInfo.bufferByteLength, 3, 'first view.buffer.byteLength should be 3'); 180 assert_equals(viewInfo.byteOffset, 0, 'first view.byteOffset should be 0'); 181 assert_equals(viewInfo.byteLength, 3, 'first view.byteLength should be 3'); 182 } 183 184 { 185 const byobRequest = byobRequests[1]; 186 assert_true(byobRequest.nonNull, 'second byobRequest must not be null'); 187 assert_true(byobRequest.viewNonNull, 'second byobRequest.view must not be null'); 188 const viewInfo = byobRequest.viewInfo; 189 assert_equals(viewInfo.constructor, Uint8Array, 'second view.constructor should be Uint8Array'); 190 assert_equals(viewInfo.bufferByteLength, 3, 'second view.buffer.byteLength should be 3'); 191 assert_equals(viewInfo.byteOffset, 2, 'second view.byteOffset should be 2'); 192 assert_equals(viewInfo.byteLength, 1, 'second view.byteLength should be 1'); 193 } 194 195 }, 'ReadableStream with byte source: read({ min }) with a DataView'); 196 197 promise_test(async t => { 198 let pullCount = 0; 199 const byobRequests = []; 200 const rs = new ReadableStream({ 201 type: 'bytes', 202 start: t.step_func((c) => { 203 c.enqueue(new Uint8Array([0x01])); 204 }), 205 pull: t.step_func((c) => { 206 const byobRequest = c.byobRequest; 207 const view = byobRequest.view; 208 byobRequests[pullCount] = { 209 nonNull: byobRequest !== null, 210 viewNonNull: view !== null, 211 viewInfo: extractViewInfo(view) 212 }; 213 if (pullCount === 0) { 214 view[0] = 0x02; 215 view[1] = 0x03; 216 byobRequest.respond(2); 217 } 218 ++pullCount; 219 }) 220 }); 221 const reader = rs.getReader({ mode: 'byob' }); 222 223 const result = await reader.read(new Uint8Array(3), { min: 3 }); 224 assert_false(result.done, 'first result should not be done'); 225 assert_typed_array_equals(result.value, new Uint8Array([0x01, 0x02, 0x03]), 'first result value'); 226 227 assert_equals(pullCount, 1, 'pull() must have only been called once'); 228 229 const byobRequest = byobRequests[0]; 230 assert_true(byobRequest.nonNull, 'first byobRequest must not be null'); 231 assert_true(byobRequest.viewNonNull, 'first byobRequest.view must not be null'); 232 const viewInfo = byobRequest.viewInfo; 233 assert_equals(viewInfo.constructor, Uint8Array, 'first view.constructor should be Uint8Array'); 234 assert_equals(viewInfo.bufferByteLength, 3, 'first view.buffer.byteLength should be 3'); 235 assert_equals(viewInfo.byteOffset, 1, 'first view.byteOffset should be 1'); 236 assert_equals(viewInfo.byteLength, 2, 'first view.byteLength should be 2'); 237 238 }, 'ReadableStream with byte source: enqueue(), then read({ min })'); 239 240 promise_test(async t => { 241 let pullCount = 0; 242 const byobRequests = []; 243 const rs = new ReadableStream({ 244 type: 'bytes', 245 pull: t.step_func((c) => { 246 const byobRequest = c.byobRequest; 247 const view = byobRequest.view; 248 byobRequests[pullCount] = { 249 nonNull: byobRequest !== null, 250 viewNonNull: view !== null, 251 viewInfo: extractViewInfo(view) 252 }; 253 if (pullCount === 0) { 254 c.enqueue(new Uint8Array([0x01, 0x02])); 255 } else if (pullCount === 1) { 256 c.enqueue(new Uint8Array([0x03])); 257 } 258 ++pullCount; 259 }) 260 }); 261 const reader = rs.getReader({ mode: 'byob' }); 262 263 const result = await reader.read(new Uint8Array(3), { min: 3 }); 264 assert_false(result.done, 'first result should not be done'); 265 assert_typed_array_equals(result.value, new Uint8Array([0x01, 0x02, 0x03]), 'first result value'); 266 267 assert_equals(pullCount, 2, 'pull() must have been called 2 times'); 268 269 { 270 const byobRequest = byobRequests[0]; 271 assert_true(byobRequest.nonNull, 'first byobRequest must not be null'); 272 assert_true(byobRequest.viewNonNull, 'first byobRequest.view must not be null'); 273 const viewInfo = byobRequest.viewInfo; 274 assert_equals(viewInfo.constructor, Uint8Array, 'first view.constructor should be Uint8Array'); 275 assert_equals(viewInfo.bufferByteLength, 3, 'first view.buffer.byteLength should be 3'); 276 assert_equals(viewInfo.byteOffset, 0, 'first view.byteOffset should be 0'); 277 assert_equals(viewInfo.byteLength, 3, 'first view.byteLength should be 3'); 278 } 279 280 { 281 const byobRequest = byobRequests[1]; 282 assert_true(byobRequest.nonNull, 'second byobRequest must not be null'); 283 assert_true(byobRequest.viewNonNull, 'second byobRequest.view must not be null'); 284 const viewInfo = byobRequest.viewInfo; 285 assert_equals(viewInfo.constructor, Uint8Array, 'second view.constructor should be Uint8Array'); 286 assert_equals(viewInfo.bufferByteLength, 3, 'second view.buffer.byteLength should be 3'); 287 assert_equals(viewInfo.byteOffset, 2, 'second view.byteOffset should be 2'); 288 assert_equals(viewInfo.byteLength, 1, 'second view.byteLength should be 1'); 289 } 290 291 }, 'ReadableStream with byte source: read({ min: 3 }) on a 3-byte Uint8Array, then multiple enqueue() up to 3 bytes'); 292 293 promise_test(async t => { 294 let pullCount = 0; 295 const byobRequests = []; 296 const rs = new ReadableStream({ 297 type: 'bytes', 298 pull: t.step_func((c) => { 299 const byobRequest = c.byobRequest; 300 const view = byobRequest.view; 301 byobRequests[pullCount] = { 302 nonNull: byobRequest !== null, 303 viewNonNull: view !== null, 304 viewInfo: extractViewInfo(view) 305 }; 306 if (pullCount === 0) { 307 c.enqueue(new Uint8Array([0x01, 0x02])); 308 } else if (pullCount === 1) { 309 c.enqueue(new Uint8Array([0x03])); 310 } 311 ++pullCount; 312 }) 313 }); 314 const reader = rs.getReader({ mode: 'byob' }); 315 316 const result = await reader.read(new Uint8Array(5), { min: 3 }); 317 assert_false(result.done, 'first result should not be done'); 318 assert_typed_array_equals(result.value, new Uint8Array([0x01, 0x02, 0x03, 0, 0]).subarray(0, 3), 'first result value'); 319 320 assert_equals(pullCount, 2, 'pull() must have been called 2 times'); 321 322 { 323 const byobRequest = byobRequests[0]; 324 assert_true(byobRequest.nonNull, 'first byobRequest must not be null'); 325 assert_true(byobRequest.viewNonNull, 'first byobRequest.view must not be null'); 326 const viewInfo = byobRequest.viewInfo; 327 assert_equals(viewInfo.constructor, Uint8Array, 'first view.constructor should be Uint8Array'); 328 assert_equals(viewInfo.bufferByteLength, 5, 'first view.buffer.byteLength should be 5'); 329 assert_equals(viewInfo.byteOffset, 0, 'first view.byteOffset should be 0'); 330 assert_equals(viewInfo.byteLength, 5, 'first view.byteLength should be 5'); 331 } 332 333 { 334 const byobRequest = byobRequests[1]; 335 assert_true(byobRequest.nonNull, 'second byobRequest must not be null'); 336 assert_true(byobRequest.viewNonNull, 'second byobRequest.view must not be null'); 337 const viewInfo = byobRequest.viewInfo; 338 assert_equals(viewInfo.constructor, Uint8Array, 'second view.constructor should be Uint8Array'); 339 assert_equals(viewInfo.bufferByteLength, 5, 'second view.buffer.byteLength should be 5'); 340 assert_equals(viewInfo.byteOffset, 2, 'second view.byteOffset should be 2'); 341 assert_equals(viewInfo.byteLength, 3, 'second view.byteLength should be 3'); 342 } 343 344 }, 'ReadableStream with byte source: read({ min: 3 }) on a 5-byte Uint8Array, then multiple enqueue() up to 3 bytes'); 345 346 promise_test(async t => { 347 let pullCount = 0; 348 const byobRequests = []; 349 const rs = new ReadableStream({ 350 type: 'bytes', 351 pull: t.step_func((c) => { 352 const byobRequest = c.byobRequest; 353 const view = byobRequest.view; 354 byobRequests[pullCount] = { 355 nonNull: byobRequest !== null, 356 viewNonNull: view !== null, 357 viewInfo: extractViewInfo(view) 358 }; 359 if (pullCount === 0) { 360 c.enqueue(new Uint8Array([0x01, 0x02])); 361 } else if (pullCount === 1) { 362 c.enqueue(new Uint8Array([0x03, 0x04])); 363 } 364 ++pullCount; 365 }) 366 }); 367 const reader = rs.getReader({ mode: 'byob' }); 368 369 const result = await reader.read(new Uint8Array(5), { min: 3 }); 370 assert_false(result.done, 'first result should not be done'); 371 assert_typed_array_equals(result.value, new Uint8Array([0x01, 0x02, 0x03, 0x04, 0]).subarray(0, 4), 'first result value'); 372 373 assert_equals(pullCount, 2, 'pull() must have been called 2 times'); 374 375 { 376 const byobRequest = byobRequests[0]; 377 assert_true(byobRequest.nonNull, 'first byobRequest must not be null'); 378 assert_true(byobRequest.viewNonNull, 'first byobRequest.view must not be null'); 379 const viewInfo = byobRequest.viewInfo; 380 assert_equals(viewInfo.constructor, Uint8Array, 'first view.constructor should be Uint8Array'); 381 assert_equals(viewInfo.bufferByteLength, 5, 'first view.buffer.byteLength should be 5'); 382 assert_equals(viewInfo.byteOffset, 0, 'first view.byteOffset should be 0'); 383 assert_equals(viewInfo.byteLength, 5, 'first view.byteLength should be 5'); 384 } 385 386 { 387 const byobRequest = byobRequests[1]; 388 assert_true(byobRequest.nonNull, 'second byobRequest must not be null'); 389 assert_true(byobRequest.viewNonNull, 'second byobRequest.view must not be null'); 390 const viewInfo = byobRequest.viewInfo; 391 assert_equals(viewInfo.constructor, Uint8Array, 'second view.constructor should be Uint8Array'); 392 assert_equals(viewInfo.bufferByteLength, 5, 'second view.buffer.byteLength should be 5'); 393 assert_equals(viewInfo.byteOffset, 2, 'second view.byteOffset should be 2'); 394 assert_equals(viewInfo.byteLength, 3, 'second view.byteLength should be 3'); 395 } 396 397 }, 'ReadableStream with byte source: read({ min: 3 }) on a 5-byte Uint8Array, then multiple enqueue() up to 4 bytes'); 398 399 promise_test(async t => { 400 const stream = new ReadableStream({ 401 start(c) { 402 const view = new Uint8Array(16); 403 view[0] = 0x01; 404 view[8] = 0x02; 405 c.enqueue(view); 406 }, 407 pull: t.unreached_func('pull() should not be called'), 408 type: 'bytes' 409 }); 410 411 const byobReader = stream.getReader({ mode: 'byob' }); 412 const result1 = await byobReader.read(new Uint8Array(8), { min: 8 }); 413 assert_false(result1.done, 'result1.done'); 414 415 const view1 = result1.value; 416 assert_equals(view1.constructor, Uint8Array, 'result1.value.constructor'); 417 assert_equals(view1.buffer.byteLength, 8, 'result1.value.buffer.byteLength'); 418 assert_equals(view1.byteOffset, 0, 'result1.value.byteOffset'); 419 assert_equals(view1.byteLength, 8, 'result1.value.byteLength'); 420 assert_equals(view1[0], 0x01, 'result1.value[0]'); 421 422 byobReader.releaseLock(); 423 424 const reader = stream.getReader(); 425 const result2 = await reader.read(); 426 assert_false(result2.done, 'result2.done'); 427 428 const view2 = result2.value; 429 assert_equals(view2.constructor, Uint8Array, 'result2.value.constructor'); 430 assert_equals(view2.buffer.byteLength, 16, 'result2.value.buffer.byteLength'); 431 assert_equals(view2.byteOffset, 8, 'result2.value.byteOffset'); 432 assert_equals(view2.byteLength, 8, 'result2.value.byteLength'); 433 assert_equals(view2[0], 0x02, 'result2.value[0]'); 434 }, 'ReadableStream with byte source: enqueue(), read({ min }) partially, then read()'); 435 436 promise_test(async () => { 437 let pullCount = 0; 438 const byobRequestDefined = []; 439 let byobRequestViewDefined; 440 441 const stream = new ReadableStream({ 442 async pull(c) { 443 byobRequestDefined.push(c.byobRequest !== null); 444 const initialByobRequest = c.byobRequest; 445 446 const transferredView = await transferArrayBufferView(c.byobRequest.view); 447 transferredView[0] = 0x01; 448 c.byobRequest.respondWithNewView(transferredView); 449 450 byobRequestDefined.push(c.byobRequest !== null); 451 byobRequestViewDefined = initialByobRequest.view !== null; 452 453 ++pullCount; 454 }, 455 type: 'bytes' 456 }); 457 458 const reader = stream.getReader({ mode: 'byob' }); 459 const result = await reader.read(new Uint8Array(1), { min: 1 }); 460 assert_false(result.done, 'result.done'); 461 assert_equals(result.value.byteLength, 1, 'result.value.byteLength'); 462 assert_equals(result.value[0], 0x01, 'result.value[0]'); 463 assert_equals(pullCount, 1, 'pull() should be called only once'); 464 assert_true(byobRequestDefined[0], 'byobRequest must not be null before respondWithNewView()'); 465 assert_false(byobRequestDefined[1], 'byobRequest must be null after respondWithNewView()'); 466 assert_false(byobRequestViewDefined, 'view of initial byobRequest must be null after respondWithNewView()'); 467 }, 'ReadableStream with byte source: read({ min }), then respondWithNewView() with a transferred ArrayBuffer'); 468 469 promise_test(async t => { 470 const stream = new ReadableStream({ 471 start(c) { 472 c.close(); 473 }, 474 pull: t.unreached_func('pull() should not be called'), 475 type: 'bytes' 476 }); 477 478 const reader = stream.getReader({ mode: 'byob' }); 479 480 const result = await reader.read(new Uint8Array([0x01]), { min: 1 }); 481 assert_true(result.done, 'result.done'); 482 assert_typed_array_equals(result.value, new Uint8Array([0x01]).subarray(0, 0), 'result.value'); 483 484 await reader.closed; 485 }, 'ReadableStream with byte source: read({ min }) on a closed stream'); 486 487 promise_test(async t => { 488 let pullCount = 0; 489 const rs = new ReadableStream({ 490 type: 'bytes', 491 pull: t.step_func((c) => { 492 if (pullCount === 0) { 493 c.byobRequest.view[0] = 0x01; 494 c.byobRequest.respond(1); 495 } else if (pullCount === 1) { 496 c.close(); 497 c.byobRequest.respond(0); 498 } 499 ++pullCount; 500 }) 501 }); 502 const reader = rs.getReader({ mode: 'byob' }); 503 504 const result = await reader.read(new Uint8Array(3), { min: 3 }); 505 assert_true(result.done, 'result.done'); 506 assert_typed_array_equals(result.value, new Uint8Array([0x01, 0, 0]).subarray(0, 1), 'result.value'); 507 508 assert_equals(pullCount, 2, 'pull() must have been called 2 times'); 509 510 await reader.closed; 511 }, 'ReadableStream with byte source: read({ min }) when closed before view is filled'); 512 513 promise_test(async t => { 514 let pullCount = 0; 515 const rs = new ReadableStream({ 516 type: 'bytes', 517 pull: t.step_func((c) => { 518 if (pullCount === 0) { 519 c.byobRequest.view[0] = 0x01; 520 c.byobRequest.view[1] = 0x02; 521 c.byobRequest.respond(2); 522 } else if (pullCount === 1) { 523 c.byobRequest.view[0] = 0x03; 524 c.byobRequest.respond(1); 525 c.close(); 526 } 527 ++pullCount; 528 }) 529 }); 530 const reader = rs.getReader({ mode: 'byob' }); 531 532 const result = await reader.read(new Uint8Array(3), { min: 3 }); 533 assert_false(result.done, 'result.done'); 534 assert_typed_array_equals(result.value, new Uint8Array([0x01, 0x02, 0x03]), 'result.value'); 535 536 assert_equals(pullCount, 2, 'pull() must have been called 2 times'); 537 538 await reader.closed; 539 }, 'ReadableStream with byte source: read({ min }) when closed immediately after view is filled'); 540 541 promise_test(async t => { 542 const error1 = new Error('error1'); 543 const stream = new ReadableStream({ 544 start(c) { 545 c.error(error1); 546 }, 547 pull: t.unreached_func('pull() should not be called'), 548 type: 'bytes' 549 }); 550 551 const reader = stream.getReader({ mode: 'byob' }); 552 const read = reader.read(new Uint8Array(1), { min: 1 }); 553 554 await Promise.all([ 555 promise_rejects_exactly(t, error1, read, 'read() must fail'), 556 promise_rejects_exactly(t, error1, reader.closed, 'closed must fail') 557 ]); 558 }, 'ReadableStream with byte source: read({ min }) on an errored stream'); 559 560 promise_test(async t => { 561 const error1 = new Error('error1'); 562 let controller; 563 const stream = new ReadableStream({ 564 start(c) { 565 controller = c; 566 }, 567 type: 'bytes' 568 }); 569 570 const reader = stream.getReader({ mode: 'byob' }); 571 const read = reader.read(new Uint8Array(1), { min: 1 }); 572 573 controller.error(error1); 574 575 await Promise.all([ 576 promise_rejects_exactly(t, error1, read, 'read() must fail'), 577 promise_rejects_exactly(t, error1, reader.closed, 'closed must fail') 578 ]); 579 }, 'ReadableStream with byte source: read({ min }), then error()'); 580 581 promise_test(t => { 582 let cancelCount = 0; 583 let reason; 584 585 const passedReason = new TypeError('foo'); 586 587 const stream = new ReadableStream({ 588 pull: t.unreached_func('pull() should not be called'), 589 cancel(r) { 590 if (cancelCount === 0) { 591 reason = r; 592 } 593 594 ++cancelCount; 595 596 return 'bar'; 597 }, 598 type: 'bytes' 599 }); 600 601 const reader = stream.getReader({ mode: 'byob' }); 602 603 const readPromise = reader.read(new Uint8Array(1), { min: 1 }).then(result => { 604 assert_true(result.done, 'result.done'); 605 assert_equals(result.value, undefined, 'result.value'); 606 }); 607 608 const cancelPromise = reader.cancel(passedReason).then(result => { 609 assert_equals(result, undefined, 'cancel() return value should be fulfilled with undefined'); 610 assert_equals(cancelCount, 1, 'cancel() should be called only once'); 611 assert_equals(reason, passedReason, 'reason should equal the passed reason'); 612 }); 613 614 return Promise.all([readPromise, cancelPromise]); 615 }, 'ReadableStream with byte source: getReader(), read({ min }), then cancel()'); 616 617 promise_test(async t => { 618 let pullCount = 0; 619 let byobRequest; 620 const viewInfos = []; 621 const rs = new ReadableStream({ 622 type: 'bytes', 623 pull: t.step_func((c) => { 624 byobRequest = c.byobRequest; 625 626 viewInfos.push(extractViewInfo(c.byobRequest.view)); 627 c.byobRequest.view[0] = 0x01; 628 c.byobRequest.respond(1); 629 viewInfos.push(extractViewInfo(c.byobRequest.view)); 630 631 ++pullCount; 632 }) 633 }); 634 635 await Promise.resolve(); 636 assert_equals(pullCount, 0, 'pull() must not have been called yet'); 637 638 const reader = rs.getReader({ mode: 'byob' }); 639 const read = reader.read(new Uint8Array(3), { min: 3 }); 640 assert_equals(pullCount, 1, 'pull() must have been called once'); 641 assert_not_equals(byobRequest, null, 'byobRequest should not be null'); 642 assert_equals(viewInfos[0].byteLength, 3, 'byteLength before respond() should be 3'); 643 assert_equals(viewInfos[1].byteLength, 2, 'byteLength after respond() should be 2'); 644 645 reader.cancel().catch(t.unreached_func('cancel() should not reject')); 646 647 const result = await read; 648 assert_true(result.done, 'result.done'); 649 assert_equals(result.value, undefined, 'result.value'); 650 651 assert_equals(pullCount, 1, 'pull() must only be called once'); 652 653 await reader.closed; 654 }, 'ReadableStream with byte source: cancel() with partially filled pending read({ min }) request'); 655 656 promise_test(async () => { 657 let pullCalled = false; 658 659 const stream = new ReadableStream({ 660 start(c) { 661 const view = new Uint8Array(16); 662 view[7] = 0x01; 663 view[15] = 0x02; 664 c.enqueue(view); 665 }, 666 pull() { 667 pullCalled = true; 668 }, 669 type: 'bytes' 670 }); 671 672 const reader = stream.getReader({ mode: 'byob' }); 673 674 const result1 = await reader.read(new Uint8Array(8), { min: 8 }); 675 assert_false(result1.done, 'result1.done'); 676 677 const view1 = result1.value; 678 assert_equals(view1.byteOffset, 0, 'result1.value.byteOffset'); 679 assert_equals(view1.byteLength, 8, 'result1.value.byteLength'); 680 assert_equals(view1[7], 0x01, 'result1.value[7]'); 681 682 const result2 = await reader.read(new Uint8Array(8), { min: 8 }); 683 assert_false(pullCalled, 'pull() must not have been called'); 684 assert_false(result2.done, 'result2.done'); 685 686 const view2 = result2.value; 687 assert_equals(view2.byteOffset, 0, 'result2.value.byteOffset'); 688 assert_equals(view2.byteLength, 8, 'result2.value.byteLength'); 689 assert_equals(view2[7], 0x02, 'result2.value[7]'); 690 }, 'ReadableStream with byte source: enqueue(), then read({ min }) with smaller views'); 691 692 promise_test(async t => { 693 const stream = new ReadableStream({ 694 start(c) { 695 c.enqueue(new Uint8Array([0xaa, 0xbb, 0xcc])); 696 c.close(); 697 }, 698 pull: t.unreached_func('pull() should not be called'), 699 type: 'bytes' 700 }); 701 702 const reader = stream.getReader({ mode: 'byob' }); 703 704 await promise_rejects_js(t, TypeError, reader.read(new Uint16Array(2), { min: 2 }), 'read() must fail'); 705 await promise_rejects_js(t, TypeError, reader.closed, 'reader.closed should reject'); 706 }, 'ReadableStream with byte source: 3 byte enqueue(), then close(), then read({ min }) with 2-element Uint16Array must fail'); 707 708 promise_test(async t => { 709 let controller; 710 const stream = new ReadableStream({ 711 start(c) { 712 controller = c; 713 }, 714 pull: t.unreached_func('pull() should not be called'), 715 type: 'bytes' 716 }); 717 718 const reader = stream.getReader({ mode: 'byob' }); 719 const readPromise = reader.read(new Uint16Array(2), { min: 2 }); 720 721 controller.enqueue(new Uint8Array([0xaa, 0xbb, 0xcc])); 722 assert_throws_js(TypeError, () => controller.close(), 'controller.close() must throw'); 723 724 await promise_rejects_js(t, TypeError, readPromise, 'read() must fail'); 725 await promise_rejects_js(t, TypeError, reader.closed, 'reader.closed must reject'); 726 }, 'ReadableStream with byte source: read({ min }) with 2-element Uint16Array, then 3 byte enqueue(), then close() must fail'); 727 728 promise_test(async t => { 729 let pullCount = 0; 730 let controller; 731 const rs = new ReadableStream({ 732 type: 'bytes', 733 start: t.step_func((c) => { 734 controller = c; 735 }), 736 pull: t.step_func((c) => { 737 ++pullCount; 738 }) 739 }); 740 741 const [reader1, reader2] = rs.tee().map(branch => branch.getReader({ mode: 'byob' })); 742 743 await Promise.resolve(); 744 assert_equals(pullCount, 0, 'pull() must not have been called yet'); 745 746 const read1 = reader1.read(new Uint8Array(3), { min: 3 }); 747 const read2 = reader2.read(new Uint8Array(1)); 748 749 assert_equals(pullCount, 1, 'pull() must have been called once'); 750 const byobRequest1 = controller.byobRequest; 751 assert_equals(byobRequest1.view.byteLength, 3, 'first byobRequest.view.byteLength should be 3'); 752 byobRequest1.view[0] = 0x01; 753 byobRequest1.respond(1); 754 755 const result2 = await read2; 756 assert_false(result2.done, 'branch2 first read() should not be done'); 757 assert_typed_array_equals(result2.value, new Uint8Array([0x01]), 'branch2 first read() value'); 758 759 assert_equals(pullCount, 2, 'pull() must have been called 2 times'); 760 const byobRequest2 = controller.byobRequest; 761 assert_equals(byobRequest2.view.byteLength, 2, 'second byobRequest.view.byteLength should be 2'); 762 byobRequest2.view[0] = 0x02; 763 byobRequest2.view[1] = 0x03; 764 byobRequest2.respond(2); 765 766 const result1 = await read1; 767 assert_false(result1.done, 'branch1 read() should not be done'); 768 assert_typed_array_equals(result1.value, new Uint8Array([0x01, 0x02, 0x03]), 'branch1 read() value'); 769 770 const result3 = await reader2.read(new Uint8Array(2)); 771 assert_equals(pullCount, 2, 'pull() must only be called 2 times'); 772 assert_false(result3.done, 'branch2 second read() should not be done'); 773 assert_typed_array_equals(result3.value, new Uint8Array([0x02, 0x03]), 'branch2 second read() value'); 774 }, 'ReadableStream with byte source: tee() with read({ min }) from branch1 and read() from branch2');