2022-12-17 21:08:20 +00:00
|
|
|
'use strict';
|
|
|
|
|
|
|
|
const common = require('../common');
|
2022-12-17 21:58:26 +00:00
|
|
|
const {
|
|
|
|
strictEqual,
|
|
|
|
rejects,
|
2023-04-15 18:21:16 +00:00
|
|
|
throws,
|
2022-12-17 21:58:26 +00:00
|
|
|
} = require('assert');
|
|
|
|
const { TextDecoder } = require('util');
|
|
|
|
const {
|
|
|
|
writeFileSync,
|
|
|
|
openAsBlob,
|
|
|
|
} = require('fs');
|
|
|
|
|
|
|
|
const {
|
|
|
|
unlink
|
|
|
|
} = require('fs/promises');
|
|
|
|
const { Blob } = require('buffer');
|
2022-12-17 21:08:20 +00:00
|
|
|
|
|
|
|
const tmpdir = require('../common/tmpdir');
|
2023-08-15 13:45:34 +00:00
|
|
|
const testfile = tmpdir.resolve('test-file-backed-blob.txt');
|
|
|
|
const testfile2 = tmpdir.resolve('test-file-backed-blob2.txt');
|
|
|
|
const testfile3 = tmpdir.resolve('test-file-backed-blob3.txt');
|
2024-07-20 13:16:23 +00:00
|
|
|
const testfile4 = tmpdir.resolve('test-file-backed-blob4.txt');
|
|
|
|
const testfile5 = tmpdir.resolve('test-file-backed-blob5.txt');
|
2022-12-17 21:08:20 +00:00
|
|
|
tmpdir.refresh();
|
|
|
|
|
|
|
|
const data = `${'a'.repeat(1000)}${'b'.repeat(2000)}`;
|
|
|
|
|
2022-12-17 21:58:26 +00:00
|
|
|
writeFileSync(testfile, data);
|
2024-07-20 13:16:23 +00:00
|
|
|
writeFileSync(testfile2, data);
|
|
|
|
writeFileSync(testfile3, data.repeat(100));
|
|
|
|
writeFileSync(testfile4, '');
|
|
|
|
writeFileSync(testfile5, '');
|
2022-12-17 21:08:20 +00:00
|
|
|
|
|
|
|
(async () => {
|
2022-12-17 21:58:26 +00:00
|
|
|
const blob = await openAsBlob(testfile);
|
2022-12-17 21:08:20 +00:00
|
|
|
|
|
|
|
const ab = await blob.arrayBuffer();
|
|
|
|
const dec = new TextDecoder();
|
|
|
|
|
|
|
|
strictEqual(dec.decode(new Uint8Array(ab)), data);
|
|
|
|
strictEqual(await blob.text(), data);
|
|
|
|
|
2022-12-17 21:58:26 +00:00
|
|
|
// Can be read multiple times
|
2022-12-17 21:08:20 +00:00
|
|
|
let stream = blob.stream();
|
|
|
|
let check = '';
|
|
|
|
for await (const chunk of stream)
|
|
|
|
check = dec.decode(chunk);
|
|
|
|
strictEqual(check, data);
|
|
|
|
|
2022-12-17 21:58:26 +00:00
|
|
|
// Can be combined with other Blob's and read
|
|
|
|
const combined = new Blob(['hello', blob, 'world']);
|
|
|
|
const ab2 = await combined.arrayBuffer();
|
|
|
|
strictEqual(dec.decode(ab2.slice(0, 5)), 'hello');
|
|
|
|
strictEqual(dec.decode(ab2.slice(5, -5)), data);
|
|
|
|
strictEqual(dec.decode(ab2.slice(-5)), 'world');
|
|
|
|
|
2022-12-17 21:08:20 +00:00
|
|
|
// If the file is modified tho, the stream errors.
|
2022-12-17 21:58:26 +00:00
|
|
|
writeFileSync(testfile, data + 'abc');
|
2022-12-17 21:08:20 +00:00
|
|
|
|
|
|
|
stream = blob.stream();
|
|
|
|
|
2022-12-17 21:58:26 +00:00
|
|
|
const read = async () => {
|
|
|
|
// eslint-disable-next-line no-unused-vars, no-empty
|
|
|
|
for await (const _ of stream) {}
|
|
|
|
};
|
|
|
|
|
|
|
|
await rejects(read(), { name: 'NotReadableError' });
|
|
|
|
|
|
|
|
await unlink(testfile);
|
|
|
|
})().then(common.mustCall());
|
|
|
|
|
2023-04-24 05:01:43 +00:00
|
|
|
(async () => {
|
|
|
|
// Refs: https://github.com/nodejs/node/issues/47683
|
2024-07-20 13:16:23 +00:00
|
|
|
const blob = await openAsBlob(testfile2);
|
2023-04-24 05:01:43 +00:00
|
|
|
const res = blob.slice(10, 20);
|
|
|
|
const ab = await res.arrayBuffer();
|
|
|
|
strictEqual(res.size, ab.byteLength);
|
|
|
|
|
|
|
|
let length = 0;
|
|
|
|
const stream = await res.stream();
|
|
|
|
for await (const chunk of stream)
|
|
|
|
length += chunk.length;
|
|
|
|
strictEqual(res.size, length);
|
|
|
|
|
|
|
|
const res1 = blob.slice(995, 1005);
|
|
|
|
strictEqual(await res1.text(), data.slice(995, 1005));
|
2024-07-22 18:25:30 +00:00
|
|
|
|
|
|
|
// Refs: https://github.com/nodejs/node/issues/53908
|
|
|
|
for (const res2 of [
|
|
|
|
blob.slice(995, 1005).slice(),
|
|
|
|
blob.slice(995).slice(0, 10),
|
|
|
|
blob.slice(0, 1005).slice(995),
|
|
|
|
]) {
|
|
|
|
strictEqual(await res2.text(), data.slice(995, 1005));
|
|
|
|
}
|
|
|
|
|
2024-07-20 13:16:23 +00:00
|
|
|
await unlink(testfile2);
|
2023-04-24 05:01:43 +00:00
|
|
|
})().then(common.mustCall());
|
|
|
|
|
2022-12-17 21:58:26 +00:00
|
|
|
(async () => {
|
2024-07-20 13:16:23 +00:00
|
|
|
const blob = await openAsBlob(testfile3);
|
2022-12-17 21:58:26 +00:00
|
|
|
const stream = blob.stream();
|
|
|
|
const read = async () => {
|
|
|
|
// eslint-disable-next-line no-unused-vars
|
|
|
|
for await (const _ of stream) {
|
2024-07-20 13:16:23 +00:00
|
|
|
writeFileSync(testfile3, data + 'abc');
|
2022-12-17 21:58:26 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
await rejects(read(), { name: 'NotReadableError' });
|
|
|
|
|
2024-07-20 13:16:23 +00:00
|
|
|
await unlink(testfile3);
|
2022-12-17 21:08:20 +00:00
|
|
|
})().then(common.mustCall());
|
2023-03-23 18:28:43 +00:00
|
|
|
|
|
|
|
(async () => {
|
2024-07-20 13:16:23 +00:00
|
|
|
const blob = await openAsBlob(testfile4);
|
2023-03-23 18:28:43 +00:00
|
|
|
strictEqual(blob.size, 0);
|
|
|
|
strictEqual(await blob.text(), '');
|
2024-07-20 13:16:23 +00:00
|
|
|
writeFileSync(testfile4, 'abc');
|
2023-03-23 18:28:43 +00:00
|
|
|
await rejects(blob.text(), { name: 'NotReadableError' });
|
2024-07-20 13:16:23 +00:00
|
|
|
await unlink(testfile4);
|
2023-03-23 18:28:43 +00:00
|
|
|
})().then(common.mustCall());
|
|
|
|
|
|
|
|
(async () => {
|
2024-07-20 13:16:23 +00:00
|
|
|
const blob = await openAsBlob(testfile5);
|
2023-03-23 18:28:43 +00:00
|
|
|
strictEqual(blob.size, 0);
|
2024-07-20 13:16:23 +00:00
|
|
|
writeFileSync(testfile5, 'abc');
|
2023-03-23 18:28:43 +00:00
|
|
|
const stream = blob.stream();
|
|
|
|
const reader = stream.getReader();
|
|
|
|
await rejects(() => reader.read(), { name: 'NotReadableError' });
|
2024-07-20 13:16:23 +00:00
|
|
|
await unlink(testfile5);
|
2023-03-23 18:28:43 +00:00
|
|
|
})().then(common.mustCall());
|
2023-04-15 18:21:16 +00:00
|
|
|
|
|
|
|
(async () => {
|
2024-09-28 13:58:55 +00:00
|
|
|
// We currently do not allow File-backed blobs to be cloned or transferred
|
2023-04-15 18:21:16 +00:00
|
|
|
// across worker threads. This is largely because the underlying FdEntry
|
|
|
|
// is bound to the Environment/Realm under which is was created.
|
|
|
|
const blob = await openAsBlob(__filename);
|
|
|
|
throws(() => structuredClone(blob), {
|
|
|
|
code: 'ERR_INVALID_STATE',
|
|
|
|
message: 'Invalid state: File-backed Blobs are not cloneable'
|
|
|
|
});
|
|
|
|
})().then(common.mustCall());
|