|
| 1 | +// Flags: --js-immutable-arraybuffer --experimental-stream-iter |
| 2 | +'use strict'; |
| 3 | + |
| 4 | +require('../common'); |
| 5 | +const assert = require('node:assert'); |
| 6 | +const { test } = require('node:test'); |
| 7 | +const { Readable } = require('node:stream'); |
| 8 | +const iter = require('node:stream/iter'); |
| 9 | +const { serialize, deserialize } = require('node:v8'); |
| 10 | + |
| 11 | +// V8 currently checks the source of TypedArray.prototype.set() for write |
| 12 | +// access. Copying immutable bytes into a mutable destination must be allowed. |
| 13 | +function immutable(bytes = [65, 66, 67, 68]) { |
| 14 | + return new Uint8Array(Uint8Array.from(bytes).buffer.transferToImmutable()); |
| 15 | +} |
| 16 | + |
| 17 | +for (const [name, copy] of [ |
| 18 | + ['Buffer.from', (view) => Buffer.from(view)], |
| 19 | + ['Buffer.copyBytesFrom', (view) => Buffer.copyBytesFrom(view)], |
| 20 | + ['Buffer.concat', (view) => Buffer.concat([view])], |
| 21 | + ['Buffer.concat with length', (view) => Buffer.concat([view], view.length)], |
| 22 | +]) { |
| 23 | + test(name, () => { |
| 24 | + const source = immutable(); |
| 25 | + assert.deepStrictEqual([...copy(source)], [...source]); |
| 26 | + }); |
| 27 | +} |
| 28 | + |
| 29 | +test('TextDecoder single-byte non-ASCII input', () => { |
| 30 | + assert.strictEqual(new TextDecoder('windows-1252').decode(immutable([0xe9])), '\u00e9'); |
| 31 | +}); |
| 32 | + |
| 33 | +test('TextDecoder split UTF-8 sequence', () => { |
| 34 | + const decoder = new TextDecoder(); |
| 35 | + assert.strictEqual(decoder.decode(immutable([0xc3]), { stream: true }), ''); |
| 36 | + assert.strictEqual(decoder.decode(immutable([0xa9])), '\u00e9'); |
| 37 | +}); |
| 38 | + |
| 39 | +test('TextDecoderStream split UTF-8 sequence', async () => { |
| 40 | + const source = new ReadableStream({ |
| 41 | + start(controller) { |
| 42 | + controller.enqueue(immutable([0xc3])); |
| 43 | + controller.enqueue(immutable([0xa9])); |
| 44 | + controller.close(); |
| 45 | + }, |
| 46 | + }); |
| 47 | + let result = ''; |
| 48 | + for await (const chunk of source.pipeThrough(new TextDecoderStream())) { |
| 49 | + result += chunk; |
| 50 | + } |
| 51 | + assert.strictEqual(result, '\u00e9'); |
| 52 | +}); |
| 53 | + |
| 54 | +test('Readable.read spanning chunks', (t) => { |
| 55 | + const stream = new Readable({ read() {} }); |
| 56 | + t.after(() => stream.destroy()); |
| 57 | + stream.push(Buffer.from(immutable().buffer)); |
| 58 | + stream.push(Buffer.from(immutable().buffer)); |
| 59 | + stream.push(null); |
| 60 | + assert.deepStrictEqual([...stream.read(6)], [65, 66, 67, 68, 65, 66]); |
| 61 | +}); |
| 62 | + |
| 63 | +for (const name of ['bytes', 'bytesSync', 'arrayBuffer', 'arrayBufferSync', 'text', 'textSync']) { |
| 64 | + test(`stream/iter.${name}`, async () => { |
| 65 | + // A partial view cannot use the full-buffer fast path. |
| 66 | + const result = await iter[name](immutable().subarray(1)); |
| 67 | + if (typeof result === 'string') { |
| 68 | + assert.strictEqual(result, 'BCD'); |
| 69 | + } else { |
| 70 | + assert.deepStrictEqual([...new Uint8Array(result)], [66, 67, 68]); |
| 71 | + } |
| 72 | + }); |
| 73 | +} |
| 74 | + |
| 75 | +for (const [name, consume] of [ |
| 76 | + ['Response', (view) => new Response(view).text()], |
| 77 | + ['Request', (view) => new Request('http://localhost/', { |
| 78 | + method: 'POST', body: view, |
| 79 | + }).text()], |
| 80 | +]) { |
| 81 | + test(`${name} body`, async () => { |
| 82 | + assert.strictEqual(await consume(immutable()), 'ABCD'); |
| 83 | + }); |
| 84 | +} |
| 85 | + |
| 86 | +test('Response consumes immutable stream chunks', async () => { |
| 87 | + const stream = new ReadableStream({ |
| 88 | + start(controller) { |
| 89 | + controller.enqueue(immutable()); |
| 90 | + controller.close(); |
| 91 | + }, |
| 92 | + }); |
| 93 | + assert.strictEqual(await new Response(stream).text(), 'ABCD'); |
| 94 | +}); |
| 95 | + |
| 96 | +test('v8.deserialize copies an unaligned payload from immutable storage', () => { |
| 97 | + const wire = serialize(new Uint32Array([1, 2])); |
| 98 | + const source = wire.buffer.sliceToImmutable(wire.byteOffset, wire.byteOffset + wire.length); |
| 99 | + assert.deepStrictEqual([...deserialize(new Uint8Array(source))], [1, 2]); |
| 100 | +}); |
0 commit comments