Skip to content
File

Blob: src/workerd/api/tests/streams-byob-edge-cases-test.js

javascript275 lines
1// Copyright (c) 2026 Cloudflare, Inc.
2// Licensed under the Apache 2.0 license found in the LICENSE file or at:
3// https://opensource.org/licenses/Apache-2.0
4 
5// Tests for BYOB reader edge cases with various typed arrays.
6// These tests focus on different ArrayBufferView types beyond Uint8Array,
7// view offsets, and autoAllocateChunkSize variations.
8//
9// Test inspirations:
10// - Bun: test/js/node/test/parallel/test-whatwg-readablebytestreambyob.js (BYOB reader tests)
11// - Bun: test/js/node/test/parallel/test-whatwg-readablebytestream.js (ReadableByteStreamController)
12// - Deno: tests/unit_node/_fs/_fs_handle_test.ts (FileHandle BYOB reader)
13 
14import { strictEqual, ok } from 'node:assert';
15 
16// Helper to create a byte stream that responds with data
17function createByteStreamWithData(data) {
18 return new ReadableStream({
19 type: 'bytes',
20 pull(controller) {
21 if (controller.byobRequest) {
22 const view = controller.byobRequest.view;
23 const bytesToCopy = Math.min(view.byteLength, data.length);
24 new Uint8Array(view.buffer, view.byteOffset, bytesToCopy).set(
25 data.subarray(0, bytesToCopy)
26 );
27 data = data.subarray(bytesToCopy);
28 controller.byobRequest.respond(bytesToCopy);
29 if (data.length === 0) {
30 controller.close();
31 }
32 } else {
33 controller.enqueue(data);
34 controller.close();
35 }
36 },
37 });
38}
39 
40// Test BYOB read with Uint16Array view
41// Inspired by: Bun test/js/node/test/parallel/test-whatwg-readablebytestream.js
42export const byobUint16Array = {
43 async test() {
44 // Create data that's properly aligned for Uint16Array (even number of bytes)
45 const data = new Uint8Array([0x01, 0x02, 0x03, 0x04, 0x05, 0x06]);
46 const rs = createByteStreamWithData(data);
47 
48 const reader = rs.getReader({ mode: 'byob' });
49 
50 // Read with Uint16Array (3 elements = 6 bytes)
51 const view = new Uint16Array(3);
52 const { value, done } = await reader.read(view);
53 
54 ok(!done);
55 ok(value instanceof Uint16Array);
56 strictEqual(value.length, 3);
57 strictEqual(value.byteLength, 6);
58 
59 // Verify the data (endianness-dependent)
60 const asBytes = new Uint8Array(
61 value.buffer,
62 value.byteOffset,
63 value.byteLength
64 );
65 strictEqual(asBytes[0], 0x01);
66 strictEqual(asBytes[1], 0x02);
67 
68 reader.releaseLock();
69 },
70};
71 
72// Test BYOB read with Uint32Array view
73// Inspired by: Bun test/js/node/test/parallel/test-whatwg-readablebytestream.js
74export const byobUint32Array = {
75 async test() {
76 // Create data aligned for Uint32Array (multiple of 4 bytes)
77 const data = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]);
78 const rs = createByteStreamWithData(data);
79 
80 const reader = rs.getReader({ mode: 'byob' });
81 
82 const view = new Uint32Array(2);
83 const { value, done } = await reader.read(view);
84 
85 ok(!done);
86 ok(value instanceof Uint32Array);
87 strictEqual(value.length, 2);
88 strictEqual(value.byteLength, 8);
89 
90 reader.releaseLock();
91 },
92};
93 
94// Test BYOB read with Float32Array view
95// Inspired by: Bun test/js/node/test/parallel/test-whatwg-readablebytestream.js
96export const byobFloat32Array = {
97 async test() {
98 // Create 8 bytes of data (2 Float32 values)
99 const data = new Uint8Array(8);
100 const floatView = new Float32Array(data.buffer);
101 floatView[0] = 3.14;
102 floatView[1] = 2.71;
103 
104 const rs = createByteStreamWithData(data);
105 const reader = rs.getReader({ mode: 'byob' });
106 
107 const view = new Float32Array(2);
108 const { value, done } = await reader.read(view);
109 
110 ok(!done);
111 ok(value instanceof Float32Array);
112 strictEqual(value.length, 2);
113 ok(Math.abs(value[0] - 3.14) < 0.001);
114 ok(Math.abs(value[1] - 2.71) < 0.001);
115 
116 reader.releaseLock();
117 },
118};
119 
120// Test BYOB read with Float64Array view
121// Inspired by: Bun test/js/node/test/parallel/test-whatwg-readablebytestream.js
122export const byobFloat64Array = {
123 async test() {
124 // Create 16 bytes of data (2 Float64 values)
125 const data = new Uint8Array(16);
126 const floatView = new Float64Array(data.buffer);
127 floatView[0] = Math.PI;
128 floatView[1] = Math.E;
129 
130 const rs = createByteStreamWithData(data);
131 const reader = rs.getReader({ mode: 'byob' });
132 
133 const view = new Float64Array(2);
134 const { value, done } = await reader.read(view);
135 
136 ok(!done);
137 ok(value instanceof Float64Array);
138 strictEqual(value.length, 2);
139 ok(Math.abs(value[0] - Math.PI) < 0.0001);
140 ok(Math.abs(value[1] - Math.E) < 0.0001);
141 
142 reader.releaseLock();
143 },
144};
145 
146// Test BYOB read with DataView
147// Inspired by: Bun test/js/node/test/parallel/test-whatwg-readablebytestreambyob.js
148export const byobDataView = {
149 async test() {
150 const data = new Uint8Array([0xde, 0xad, 0xbe, 0xef]);
151 const rs = createByteStreamWithData(data);
152 
153 const reader = rs.getReader({ mode: 'byob' });
154 
155 const view = new DataView(new ArrayBuffer(4));
156 const { value, done } = await reader.read(view);
157 
158 ok(!done);
159 ok(value instanceof DataView);
160 strictEqual(value.byteLength, 4);
161 strictEqual(value.getUint8(0), 0xde);
162 strictEqual(value.getUint8(1), 0xad);
163 strictEqual(value.getUint8(2), 0xbe);
164 strictEqual(value.getUint8(3), 0xef);
165 
166 reader.releaseLock();
167 },
168};
169 
170// Test using different view types across consecutive reads
171// Inspired by: workerd streams-js-test.js readableStreamBytesMismatchedViewTypes
172export const byobMixedViewTypes = {
173 async test() {
174 let pullCount = 0;
175 const rs = new ReadableStream({
176 type: 'bytes',
177 pull(controller) {
178 pullCount++;
179 if (controller.byobRequest) {
180 const view = controller.byobRequest.view;
181 const u8 = new Uint8Array(
182 view.buffer,
183 view.byteOffset,
184 view.byteLength
185 );
186 for (let i = 0; i < u8.length; i++) {
187 u8[i] = pullCount * 10 + i;
188 }
189 controller.byobRequest.respond(view.byteLength);
190 }
191 },
192 });
193 
194 const reader = rs.getReader({ mode: 'byob' });
195 
196 const result1 = await reader.read(new Uint8Array(4));
197 ok(result1.value instanceof Uint8Array);
198 strictEqual(result1.value.byteLength, 4);
199 
200 const result2 = await reader.read(new Uint16Array(2));
201 ok(result2.value instanceof Uint16Array);
202 strictEqual(result2.value.byteLength, 4);
203 
204 const result3 = await reader.read(new Uint32Array(1));
205 ok(result3.value instanceof Uint32Array);
206 strictEqual(result3.value.byteLength, 4);
207 
208 strictEqual(pullCount, 3);
209 reader.releaseLock();
210 },
211};
212 
213// Test BYOB read with ArrayBufferView that has a non-zero byteOffset
214// Inspired by: Bun test/js/node/test/parallel/test-whatwg-readablebytestream.js
215export const byobViewOffset = {
216 async test() {
217 const data = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]);
218 const rs = createByteStreamWithData(data);
219 
220 const reader = rs.getReader({ mode: 'byob' });
221 
222 const buffer = new ArrayBuffer(16);
223 const view = new Uint8Array(buffer, 4, 8); // Start at offset 4, length 8
224 
225 strictEqual(view.byteOffset, 4);
226 strictEqual(view.byteLength, 8);
227 
228 const { value, done } = await reader.read(view);
229 
230 ok(!done);
231 ok(value instanceof Uint8Array);
232 strictEqual(value.byteLength, 8);
233 strictEqual(value.buffer.byteLength, 16);
234 
235 reader.releaseLock();
236 },
237};
238 
239// Test autoAllocateChunkSize with various values
240// Inspired by: Bun test/js/node/test/parallel/test-whatwg-readablebytestreambyob.js
241export const byobAutoAllocateSizes = {
242 async test() {
243 const testSizes = [1, 1024, 65536];
244 
245 for (const chunkSize of testSizes) {
246 let receivedSize = 0;
247 
248 const rs = new ReadableStream({
249 type: 'bytes',
250 autoAllocateChunkSize: chunkSize,
251 pull(controller) {
252 if (controller.byobRequest) {
253 receivedSize = controller.byobRequest.view.byteLength;
254 controller.byobRequest.view[0] = 42;
255 controller.byobRequest.respond(1);
256 controller.close();
257 }
258 },
259 });
260 
261 const reader = rs.getReader();
262 const { value } = await reader.read();
263 
264 strictEqual(
265 receivedSize,
266 chunkSize,
267 `autoAllocateChunkSize=${chunkSize}`
268 );
269 ok(value instanceof Uint8Array);
270 
271 reader.releaseLock();
272 }
273 },
274};