diff --git a/doc/api/fs.md b/doc/api/fs.md index 865813069e16b1..0ff32504570bc4 100644 --- a/doc/api/fs.md +++ b/doc/api/fs.md @@ -661,7 +661,7 @@ changes: buffers anymore. --> -* `buffer` {Buffer|TypedArray|DataView} +* `buffer` {Buffer|TypedArray|DataView|ArrayBuffer} * `offset` {integer} The start position from within `buffer` where the data to write begins. * `length` {integer} The number of bytes from `buffer` to write. **Default:** @@ -677,7 +677,7 @@ Write `buffer` to the file. The promise is resolved with an object containing two properties: * `bytesWritten` {integer} the number of bytes written -* `buffer` {Buffer|TypedArray|DataView} a reference to the +* `buffer` {Buffer|TypedArray|DataView|ArrayBuffer} a reference to the `buffer` written. It is unsafe to use `filehandle.write()` multiple times on the same file @@ -696,7 +696,7 @@ added: - v16.17.0 --> -* `buffer` {Buffer|TypedArray|DataView} +* `buffer` {Buffer|TypedArray|DataView|ArrayBuffer} * `options` {Object} * `offset` {integer} **Default:** `0` * `length` {integer} **Default:** `buffer.byteLength - offset` @@ -760,7 +760,8 @@ changes: strings anymore. --> -* `data` {string|Buffer|TypedArray|DataView|AsyncIterable|Iterable|Stream} +* `data` {string|Buffer|TypedArray|DataView|ArrayBuffer|AsyncIterable| + Iterable|Stream} * `options` {Object|string} * `encoding` {string|null} The expected character encoding when `data` is a string. **Default:** `'utf8'` @@ -788,19 +789,19 @@ beginning of the file. added: v12.9.0 --> -* `buffers` {Buffer\[]|TypedArray\[]|DataView\[]} +* `buffers` {Buffer\[]|TypedArray\[]|DataView\[]|ArrayBuffer\[]} * `position` {integer|null} The offset from the beginning of the file where the data from `buffers` should be written. If `position` is not a `number`, the data will be written at the current position. **Default:** `null` * Returns: {Promise} -Write an array of {ArrayBufferView}s to the file. +Write an array of {ArrayBufferView}s or {ArrayBuffer}s to the file. The promise is resolved with an object containing a two properties: * `bytesWritten` {integer} the number of bytes written -* `buffers` {Buffer\[]|TypedArray\[]|DataView\[]} a reference to the `buffers` - input. +* `buffers` {Buffer\[]|TypedArray\[]|DataView\[]|ArrayBuffer\[]} a reference + to the `buffers` input. It is unsafe to call `writev()` multiple times on the same file without waiting for the promise to be resolved (or rejected). @@ -856,7 +857,7 @@ added: v10.0.0 --> * `path` {string|Buffer|URL|FileHandle} filename or {FileHandle} -* `data` {string|Buffer} +* `data` {string|Buffer|ArrayBuffer} * `options` {Object|string} * `encoding` {string|null} **Default:** `'utf8'` * `mode` {integer} **Default:** `0o666` @@ -864,7 +865,7 @@ added: v10.0.0 * Returns: {Promise} Fulfills with `undefined` upon success. Asynchronously append data to a file, creating the file if it does not yet -exist. `data` can be a string or a {Buffer}. +exist. `data` can be a string, a {Buffer}, or an {ArrayBuffer}. If `options` is a string, then it specifies the `encoding`. @@ -1693,7 +1694,8 @@ changes: --> * `file` {string|Buffer|URL|FileHandle} filename or `FileHandle` -* `data` {string|Buffer|TypedArray|DataView|AsyncIterable|Iterable|Stream} +* `data` {string|Buffer|TypedArray|DataView|ArrayBuffer|AsyncIterable + |Iterable|Stream} * `options` {Object|string} * `encoding` {string|null} **Default:** `'utf8'` * `mode` {integer} **Default:** `0o666` @@ -1989,7 +1991,7 @@ changes: --> * `path` {string|Buffer|URL|number} filename or file descriptor -* `data` {string|Buffer} +* `data` {string|Buffer|ArrayBuffer} * `options` {Object|string} * `encoding` {string|null} **Default:** `'utf8'` * `mode` {integer} **Default:** `0o666` @@ -1998,7 +2000,7 @@ changes: * `err` {Error} Asynchronously append data to a file, creating the file if it does not yet -exist. `data` can be a string or a {Buffer}. +exist. `data` can be a string, a {Buffer}, or an {ArrayBuffer}. The `mode` option only affects the newly created file. See [`fs.open()`][] for more details. @@ -4594,7 +4596,7 @@ changes: --> * `fd` {integer} -* `buffer` {Buffer|TypedArray|DataView} +* `buffer` {Buffer|TypedArray|DataView|ArrayBuffer} * `offset` {integer} **Default:** `0` * `length` {integer} **Default:** `buffer.byteLength - offset` * `position` {integer|null} **Default:** `null` @@ -4780,7 +4782,7 @@ changes: --> * `file` {string|Buffer|URL|integer} filename or file descriptor -* `data` {string|Buffer|TypedArray|DataView} +* `data` {string|Buffer|TypedArray|DataView|ArrayBuffer} * `options` {Object|string} * `encoding` {string|null} **Default:** `'utf8'` * `mode` {integer} **Default:** `0o666` @@ -4891,15 +4893,15 @@ changes: --> * `fd` {integer} -* `buffers` {ArrayBufferView\[]} +* `buffers` {ArrayBufferView\[]|ArrayBuffer\[]} * `position` {integer|null} **Default:** `null` * `callback` {Function} * `err` {Error} * `bytesWritten` {integer} * `buffers` {ArrayBufferView\[]} -Write an array of `ArrayBufferView`s to the file specified by `fd` using -`writev()`. +Write an array of `ArrayBufferView`s or `ArrayBuffer`s to the file specified +by `fd` using `writev()`. `position` is the offset from the beginning of the file where this data should be written. If `typeof position !== 'number'`, the data will be written @@ -4973,14 +4975,14 @@ changes: --> * `path` {string|Buffer|URL|number} filename or file descriptor -* `data` {string|Buffer} +* `data` {string|Buffer|ArrayBuffer} * `options` {Object|string} * `encoding` {string|null} **Default:** `'utf8'` * `mode` {integer} **Default:** `0o666` * `flag` {string} See [support of file system `flags`][]. **Default:** `'a'`. Synchronously append data to a file, creating the file if it does not yet -exist. `data` can be a string or a {Buffer}. +exist. `data` can be a string, a {Buffer}, or an {ArrayBuffer}. The `mode` option only affects the newly created file. See [`fs.open()`][] for more details. @@ -6019,7 +6021,7 @@ changes: --> * `file` {string|Buffer|URL|integer} filename or file descriptor -* `data` {string|Buffer|TypedArray|DataView} +* `data` {string|Buffer|TypedArray|DataView|ArrayBuffer} * `options` {Object|string} * `encoding` {string|null} **Default:** `'utf8'` * `mode` {integer} **Default:** `0o666` @@ -6055,7 +6057,7 @@ changes: --> * `fd` {integer} -* `buffer` {Buffer|TypedArray|DataView} +* `buffer` {Buffer|TypedArray|DataView|ArrayBuffer} * `offset` {integer} **Default:** `0` * `length` {integer} **Default:** `buffer.byteLength - offset` * `position` {integer|null} **Default:** `null` @@ -6073,7 +6075,7 @@ added: --> * `fd` {integer} -* `buffer` {Buffer|TypedArray|DataView} +* `buffer` {Buffer|TypedArray|DataView|ArrayBuffer} * `options` {Object} * `offset` {integer} **Default:** `0` * `length` {integer} **Default:** `buffer.byteLength - offset` @@ -6113,7 +6115,7 @@ added: v12.9.0 --> * `fd` {integer} -* `buffers` {ArrayBufferView\[]} +* `buffers` {ArrayBufferView\[]|ArrayBuffer\[]} * `position` {integer|null} **Default:** `null` * Returns: {number} The number of bytes written. diff --git a/lib/fs.js b/lib/fs.js index 300abd73fada23..bcbb159e895840 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -38,6 +38,7 @@ const { StringPrototypeCharCodeAt, StringPrototypeIndexOf, StringPrototypeSlice, + Uint8Array, } = primordials; const { fs: constants } = internalBinding('constants'); @@ -56,7 +57,7 @@ const { } = constants; const pathModule = require('path'); -const { isArrayBufferView } = require('internal/util/types'); +const { isArrayBufferView, isArrayBuffer, isSharedArrayBuffer } = require('internal/util/types'); // We need to get the statValues from the binding at the callsite since // it's re-initialized after deserialization. @@ -108,6 +109,7 @@ const { stringToFlags, stringToSymlinkType, toUnixTimestamp, + validateAndNormalizeBufferArray, validateBufferArray, validateCpOptions, validateOffsetLengthRead, @@ -819,7 +821,8 @@ function write(fd, buffer, offsetOrOptions, length, position, callback) { fd = getValidatedFd(fd); let offset = offsetOrOptions; - if (isArrayBufferView(buffer)) { + const bufferToWrite = isArrayBuffer(buffer) || isSharedArrayBuffer(buffer) ? new Uint8Array(buffer) : buffer; + if (isArrayBufferView(bufferToWrite)) { callback = maybeCallback(callback || position || length || offset); if (typeof offset === 'object') { @@ -888,6 +891,9 @@ function writeSync(fd, buffer, offsetOrOptions, length, position) { let result; let offset = offsetOrOptions; + if (isArrayBuffer(buffer) || isSharedArrayBuffer(buffer)) { + buffer = new Uint8Array(buffer); + } if (isArrayBufferView(buffer)) { if (typeof offset === 'object') { ({ @@ -940,7 +946,7 @@ function writev(fd, buffers, position, callback) { } fd = getValidatedFd(fd); - validateBufferArray(buffers); + const buffersToWrite = validateAndNormalizeBufferArray(buffers); callback = maybeCallback(callback || position); if (buffers.length === 0) { @@ -954,7 +960,7 @@ function writev(fd, buffers, position, callback) { if (typeof position !== 'number') position = null; - return binding.writeBuffers(fd, buffers, position, req); + return binding.writeBuffers(fd, buffersToWrite, position, req); } ObjectDefineProperty(writev, kCustomPromisifyArgsSymbol, { @@ -973,7 +979,7 @@ ObjectDefineProperty(writev, kCustomPromisifyArgsSymbol, { */ function writevSync(fd, buffers, position) { fd = getValidatedFd(fd); - validateBufferArray(buffers); + buffers = validateAndNormalizeBufferArray(buffers); if (buffers.length === 0) { return 0; @@ -2163,7 +2169,7 @@ function writeAll(fd, isUserFd, buffer, offset, length, signal, callback) { /** * Asynchronously writes data to the file. * @param {string | Buffer | URL | number} path - * @param {string | Buffer | TypedArray | DataView} data + * @param {string | Buffer | TypedArray | DataView | ArrayBuffer} data * @param {{ * encoding?: string | null; * mode?: number; @@ -2178,6 +2184,10 @@ function writeFile(path, data, options, callback) { options = getOptions(options, { encoding: 'utf8', mode: 0o666, flag: 'w' }); const flag = options.flag || 'w'; + if (isArrayBuffer(data) || isSharedArrayBuffer(data)) { + data = new Uint8Array(data); + } + if (!isArrayBufferView(data)) { validateStringAfterArrayBufferView(data, 'data'); data = Buffer.from(data, options.encoding || 'utf8'); @@ -2207,7 +2217,7 @@ function writeFile(path, data, options, callback) { /** * Synchronously writes data to the file. * @param {string | Buffer | URL | number} path - * @param {string | Buffer | TypedArray | DataView} data + * @param {string | Buffer | TypedArray | DataView | ArrayBuffer} data * @param {{ * encoding?: string | null; * mode?: number; @@ -2218,6 +2228,10 @@ function writeFile(path, data, options, callback) { function writeFileSync(path, data, options) { options = getOptions(options, { encoding: 'utf8', mode: 0o666, flag: 'w' }); + if (isArrayBuffer(data) || isSharedArrayBuffer(data)) { + data = new Uint8Array(data); + } + if (!isArrayBufferView(data)) { validateStringAfterArrayBufferView(data, 'data'); data = Buffer.from(data, options.encoding || 'utf8'); @@ -2244,7 +2258,7 @@ function writeFileSync(path, data, options) { /** * Asynchronously appends data to a file. * @param {string | Buffer | URL | number} path - * @param {string | Buffer} data + * @param {string | Buffer | ArrayBuffer} data * @param {{ * encoding?: string | null; * mode?: number; @@ -2270,7 +2284,7 @@ function appendFile(path, data, options, callback) { /** * Synchronously appends data to a file. * @param {string | Buffer | URL | number} path - * @param {string | Buffer} data + * @param {string | Buffer | ArrayBuffer} data * @param {{ * encoding?: string | null; * mode?: number; diff --git a/lib/internal/fs/promises.js b/lib/internal/fs/promises.js index c61758d3bd3d5e..9d236d861acfe6 100644 --- a/lib/internal/fs/promises.js +++ b/lib/internal/fs/promises.js @@ -38,7 +38,7 @@ const { AbortError, aggregateTwoErrors, } = require('internal/errors'); -const { isArrayBufferView } = require('internal/util/types'); +const { isArrayBuffer, isArrayBufferView, isSharedArrayBuffer } = require('internal/util/types'); const { rimrafPromises } = require('internal/fs/rimraf'); const { constants: { @@ -61,6 +61,7 @@ const { stringToFlags, stringToSymlinkType, toUnixTimestamp, + validateAndNormalizeBufferArray, validateBufferArray, validateCpOptions, validateOffsetLengthRead, @@ -409,7 +410,11 @@ async function writeFileHandle(filehandle, data, signal, encoding) { } return; } - data = new Uint8Array(data.buffer, data.byteOffset, data.byteLength); + if (isArrayBuffer(data) || isSharedArrayBuffer(data)) { + data = new Uint8Array(data); + } else { + data = new Uint8Array(data.buffer, data.byteOffset, data.byteLength); + } let remaining = data.byteLength; if (remaining === 0) return; do { @@ -614,11 +619,12 @@ async function write(handle, buffer, offsetOrOptions, length, position) { return { __proto__: null, bytesWritten: 0, buffer }; let offset = offsetOrOptions; - if (isArrayBufferView(buffer)) { + const bufferView = isArrayBuffer(buffer) || isSharedArrayBuffer(buffer) ? new Uint8Array(buffer) : buffer; + if (isArrayBufferView(bufferView)) { if (typeof offset === 'object') { ({ offset = 0, - length = buffer.byteLength - offset, + length = bufferView.byteLength - offset, position = null, } = offsetOrOptions ?? kEmptyObject); } @@ -629,12 +635,12 @@ async function write(handle, buffer, offsetOrOptions, length, position) { validateInteger(offset, 'offset', 0); } if (typeof length !== 'number') - length = buffer.byteLength - offset; + length = bufferView.byteLength - offset; if (typeof position !== 'number') position = null; - validateOffsetLengthWrite(offset, length, buffer.byteLength); + validateOffsetLengthWrite(offset, length, bufferView.byteLength); const bytesWritten = - (await binding.writeBuffer(handle.fd, buffer, offset, + (await binding.writeBuffer(handle.fd, bufferView, offset, length, position, kUsePromises)) || 0; return { __proto__: null, bytesWritten, buffer }; } @@ -647,16 +653,16 @@ async function write(handle, buffer, offsetOrOptions, length, position) { } async function writev(handle, buffers, position) { - validateBufferArray(buffers); + const buffersToWrite = validateAndNormalizeBufferArray(buffers); - if (typeof position !== 'number') - position = null; - - if (buffers.length === 0) { + if (buffersToWrite.length === 0) { return { __proto__: null, bytesWritten: 0, buffers }; } - const bytesWritten = (await binding.writeBuffers(handle.fd, buffers, position, + if (typeof position !== 'number') + position = null; + + const bytesWritten = (await binding.writeBuffers(handle.fd, buffersToWrite, position, kUsePromises)) || 0; return { __proto__: null, bytesWritten, buffers }; } @@ -884,7 +890,7 @@ async function writeFile(path, data, options) { options = getOptions(options, { encoding: 'utf8', mode: 0o666, flag: 'w' }); const flag = options.flag || 'w'; - if (!isArrayBufferView(data) && !isCustomIterable(data)) { + if (!isArrayBufferView(data) && !isArrayBuffer(data) && !isSharedArrayBuffer(data) && !isCustomIterable(data)) { validateStringAfterArrayBufferView(data, 'data'); data = Buffer.from(data, options.encoding || 'utf8'); } diff --git a/lib/internal/fs/utils.js b/lib/internal/fs/utils.js index d06f963f6cde8a..a060cda2cb8513 100644 --- a/lib/internal/fs/utils.js +++ b/lib/internal/fs/utils.js @@ -2,6 +2,7 @@ const { ArrayIsArray, + ArrayPrototypePush, BigInt, Date, DateNow, @@ -21,6 +22,7 @@ const { StringPrototypeIncludes, Symbol, TypedArrayPrototypeIncludes, + Uint8Array, } = primordials; const { Buffer } = require('buffer'); @@ -37,9 +39,11 @@ const { uvException } = require('internal/errors'); const { + isArrayBuffer, isArrayBufferView, isBigInt64Array, isDate, + isSharedArrayBuffer, isUint8Array, } = require('internal/util/types'); const { @@ -727,6 +731,24 @@ const validateBufferArray = hideStackFrames((buffers, propName = 'buffers') => { return buffers; }); +const validateAndNormalizeBufferArray = hideStackFrames((buffers, propName = 'buffers') => { + if (!ArrayIsArray(buffers)) + throw new ERR_INVALID_ARG_TYPE(propName, ['ArrayBufferView[]', 'ArrayBuffer[]'], buffers); + + const output = []; + for (let i = 0; i < buffers.length; i++) { + const buffer = buffers[i]; + if (isArrayBufferView(buffers[i])) { + ArrayPrototypePush(output, buffer); + } else if (isArrayBuffer(buffer) || isSharedArrayBuffer(buffer)) { + ArrayPrototypePush(output, new Uint8Array(buffers[i])); + } else { + throw new ERR_INVALID_ARG_TYPE(propName, ['ArrayBufferView[]', 'ArrayBuffer[]'], buffers); + } + } + return output; +}); + let nonPortableTemplateWarn = true; function warnOnNonPortableTemplate(template) { @@ -887,7 +909,7 @@ const validateStringAfterArrayBufferView = hideStackFrames((buffer, name) => { if (typeof buffer !== 'string') { throw new ERR_INVALID_ARG_TYPE( name, - ['string', 'Buffer', 'TypedArray', 'DataView'], + ['string', 'Buffer', 'TypedArray', 'DataView', 'ArrayBuffer'], buffer, ); } @@ -936,6 +958,7 @@ module.exports = { stringToSymlinkType, Stats, toUnixTimestamp, + validateAndNormalizeBufferArray, validateBufferArray, validateCpOptions, validateOffsetLengthRead, diff --git a/test/parallel/test-fs-promises-file-handle-write.js b/test/parallel/test-fs-promises-file-handle-write.js index 7f3d12d4817042..e3d4b66b53870e 100644 --- a/test/parallel/test-fs-promises-file-handle-write.js +++ b/test/parallel/test-fs-promises-file-handle-write.js @@ -26,6 +26,18 @@ async function validateWrite() { await fileHandle.close(); } +async function validateArrayBufferWrite() { + const filePathForHandle = path.resolve(tmpDir, 'tmp-arraybuffer-write.txt'); + const fileHandle = await open(filePathForHandle, 'w+'); + const buffer = Buffer.from('Hello world'.repeat(100), 'utf8'); + + await fileHandle.write(buffer.buffer, buffer.byteOffset, buffer.length); + const readFileData = fs.readFileSync(filePathForHandle); + assert.deepStrictEqual(buffer, readFileData); + + await fileHandle.close(); +} + async function validateEmptyWrite() { const filePathForHandle = path.resolve(tmpDir, 'tmp-empty-write.txt'); const fileHandle = await open(filePathForHandle, 'w+'); @@ -71,6 +83,7 @@ async function validateNonStringValuesWrite() { Promise.all([ validateWrite(), + validateArrayBufferWrite(), validateEmptyWrite(), validateNonUint8ArrayWrite(), validateNonStringValuesWrite(), diff --git a/test/parallel/test-fs-writev-promises.js b/test/parallel/test-fs-writev-promises.js index 650f00dae74b69..f4a6f7aa92d819 100644 --- a/test/parallel/test-fs-writev-promises.js +++ b/test/parallel/test-fs-writev-promises.js @@ -5,6 +5,11 @@ const path = require('path'); const fs = require('fs').promises; const tmpdir = require('../common/tmpdir'); const expected = 'ümlaut. Лорем 運務ホソモ指及 आपको करने विकास 紙読決多密所 أضف'; +const arrayBufferExpected = new ArrayBuffer(expected.length * 2); +const bufferView = new Uint16Array(arrayBufferExpected); +for (let i = 0; i < expected.length; i++) { + bufferView[i] = expected.charCodeAt(i); +} let cnt = 0; function getFileName() { @@ -48,6 +53,23 @@ tmpdir.refresh(); handle.close(); } + // fs.promises.writev() with an array of ArrayBuffers without position. + { + const filename = getFileName(); + const handle = await fs.open(filename, 'w'); + const bufferArr = [arrayBufferExpected, arrayBufferExpected, arrayBufferExpected]; + const expectedLength = bufferArr.length * arrayBufferExpected.byteLength; + let { bytesWritten, buffers } = await handle.writev([Buffer.from('')]); + assert.strictEqual(bytesWritten, 0); + assert.deepStrictEqual(buffers, [Buffer.from('')]); + ({ bytesWritten, buffers } = await handle.writev(bufferArr)); + assert.deepStrictEqual(bytesWritten, expectedLength); + assert.deepStrictEqual(buffers, bufferArr); + const expectedResult = Buffer.concat(bufferArr.map((arrayBuffer) => new Uint8Array(arrayBuffer))); + assert(expectedResult.equals(await fs.readFile(filename))); + handle.close(); + } + { // Writev with empty array behavior const handle = await fs.open(getFileName(), 'w'); diff --git a/test/parallel/test-fs-writev-sync.js b/test/parallel/test-fs-writev-sync.js index 1db437972ed29d..fb7228c79c9e39 100644 --- a/test/parallel/test-fs-writev-sync.js +++ b/test/parallel/test-fs-writev-sync.js @@ -56,6 +56,27 @@ const getFileName = (i) => path.join(tmpdir.path, `writev_sync_${i}.txt`); assert(Buffer.concat(bufferArr).equals(fs.readFileSync(filename))); } +// fs.writevSync with array of ArrayBuffers without position +{ + const filename = getFileName(2); + const fd = fs.openSync(filename, 'w'); + + const buffer = Buffer.from(expected); + const arrayBuffer = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength); + const arrayBufferArr = [arrayBuffer, arrayBuffer, arrayBuffer]; + const expectedLength = arrayBufferArr.length * arrayBuffer.byteLength; + + let written = fs.writevSync(fd, [Buffer.from('')]); + assert.strictEqual(written, 0); + + written = fs.writevSync(fd, arrayBufferArr); + assert.strictEqual(written, expectedLength); + + fs.closeSync(fd); + const expectedResult = Buffer.concat(arrayBufferArr.map((buf) => new Uint8Array(buf))); + assert(expectedResult.equals(fs.readFileSync(filename))); +} + // fs.writevSync with empty array of buffers { const filename = getFileName(3); diff --git a/test/parallel/test-fs-writev.js b/test/parallel/test-fs-writev.js index 7ea52ef77ac4ee..8ad4974c0ab5d4 100644 --- a/test/parallel/test-fs-writev.js +++ b/test/parallel/test-fs-writev.js @@ -50,7 +50,6 @@ const getFileName = (i) => path.join(tmpdir.path, `writev_${i}.txt`); const expectedLength = bufferArr.length * buffer.byteLength; assert.deepStrictEqual(written, expectedLength); fs.closeSync(fd); - assert(Buffer.concat(bufferArr).equals(fs.readFileSync(filename))); }); @@ -76,6 +75,28 @@ const getFileName = (i) => path.join(tmpdir.path, `writev_${i}.txt`); afterSyncCall = true; } +// fs.writev with array of ArrayBuffers without position +{ + const filename = getFileName(5); + const fd = fs.openSync(filename, 'w'); + + const buffer = Buffer.from(expected); + const arrayBuffer = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength); + const arrayBufferArr = [arrayBuffer, arrayBuffer]; + + const done = common.mustSucceed((written, buffers) => { + assert.deepStrictEqual(arrayBufferArr, buffers); + + const expectedLength = arrayBufferArr.length * arrayBuffer.byteLength; + assert.deepStrictEqual(written, expectedLength); + fs.closeSync(fd); + const expectedResult = Buffer.concat(arrayBufferArr.map((buf) => new Uint8Array(buf))); + assert(expectedResult.equals(fs.readFileSync(filename))); + }); + + fs.writev(fd, arrayBufferArr, done); +} + /** * Testing with wrong input types */