diff --git a/test/parallel/test-fs-promises-write-optional-params.js b/test/parallel/test-fs-promises-write-optional-params.js index a76144b6bacae5..a432b13b63ad73 100644 --- a/test/parallel/test-fs-promises-write-optional-params.js +++ b/test/parallel/test-fs-promises-write-optional-params.js @@ -1,118 +1,41 @@ 'use strict'; const common = require('../common'); -const fs = require('fs'); -const fsPromises = fs.promises; + +// This test ensures that filehandle.write accepts "named parameters" object +// and doesn't interpret objects as strings + +const assert = require('assert'); +const fsPromises = require('fs').promises; const path = require('path'); const tmpdir = require('../common/tmpdir'); -const assert = require('assert'); tmpdir.refresh(); const dest = path.resolve(tmpdir.path, 'tmp.txt'); const buffer = Buffer.from('zyx'); -(async () => { - let fh = await fsPromises.open(dest, 'w+'); - - assert.rejects(async () => { - await fh.write( - {} - ); - }, { - code: 'ERR_INVALID_ARG_TYPE', - name: 'TypeError', - message: 'The "buffer" argument must be an instance of Buffer, ' + - 'TypedArray, or DataView. Received undefined' - }); - assert.rejects(async () => { - await fh.write( - { buffer: 'abc' } - ); - }, { - code: 'ERR_INVALID_ARG_TYPE', - name: 'TypeError', - message: 'The "buffer" argument must be an instance of Buffer, ' + - 'TypedArray, or DataView. Received type string (\'abc\')' - }); - assert.rejects(async () => { - await fh.write( - { buffer, length: 5 } - ); - }, { - code: 'ERR_OUT_OF_RANGE', - name: 'RangeError', - message: 'The value of "length" is out of range. ' + - 'It must be <= 3. Received 5' - }); - assert.rejects(async () => { - await fh.write( - { buffer, offset: 5 } - ); - }, { - code: 'ERR_OUT_OF_RANGE', - name: 'RangeError', - message: 'The value of "offset" is out of range. ' + - 'It must be <= 3. Received 5' - }); - assert.rejects(async () => { - await fh.write( - { buffer, offset: 1 } - ); - }, { - code: 'ERR_OUT_OF_RANGE', - name: 'RangeError', - message: 'The value of "length" is out of range. ' + - 'It must be <= 2. Received 3' - }); - assert.rejects(async () => { - await fh.write( - { buffer, length: 1, offset: 3 } - ); - }, { - code: 'ERR_OUT_OF_RANGE', - name: 'RangeError', - message: 'The value of "length" is out of range. ' + - 'It must be <= 0. Received 1' - }); - assert.rejects(async () => { - await fh.write( - { buffer, length: -1 } - ); - }, { - code: 'ERR_OUT_OF_RANGE', - name: 'RangeError', - message: 'The value of "length" is out of range. ' + - 'It must be >= 0. Received -1' - }); - assert.rejects(async () => { - await fh.write( - { buffer, offset: -1 } - ); - }, { - code: 'ERR_OUT_OF_RANGE', - name: 'RangeError', - message: 'The value of "offset" is out of range. ' + - 'It must be >= 0 && <= 9007199254740991. Received -1' - }); - - await fh.close(); +async function testInvalid(dest, expectedCode, params) { + let fh; + try { + fh = await fsPromises.open(dest, 'w+'); + await assert.rejects( + async () => fh.write(params), + { code: expectedCode }); + } finally { + await fh?.close(); + } +} - for (const params of [ - { buffer }, - { buffer, length: 1 }, - { buffer, position: 5 }, - { buffer, length: 1, position: 5 }, - { buffer, length: 1, position: -1, offset: 2 }, - { buffer, length: null }, - ]) { +async function testValid(dest, params) { + let fh; + try { fh = await fsPromises.open(dest, 'w+'); const writeResult = await fh.write(params); const writeBufCopy = Uint8Array.prototype.slice.call(writeResult.buffer); const readResult = await fh.read(params); const readBufCopy = Uint8Array.prototype.slice.call(readResult.buffer); - // Test compatibility with filehandle.read counterpart with reused params assert.ok(writeResult.bytesWritten >= readResult.bytesRead); if (params.length !== undefined && params.length !== null) { assert.strictEqual(writeResult.bytesWritten, params.length); @@ -121,6 +44,44 @@ const buffer = Buffer.from('zyx'); assert.deepStrictEqual(writeBufCopy, readBufCopy); } assert.deepStrictEqual(writeResult.buffer, readResult.buffer); - await fh.close(); + } finally { + await fh?.close(); + } +} + +(async () => { + // Test if first argument is not wrongly interpreted as ArrayBufferView|string + for (const badParams of [ + undefined, null, true, 42, 42n, Symbol('42'), NaN, [], + {}, + { buffer: 'amNotParam' }, + { string: 'amNotParam' }, + { buffer: new Uint8Array(1).buffer }, + new Date(), + new String('notPrimitive'), + { toString() { return 'amObject'; } }, + { [Symbol.toPrimitive]: (hint) => 'amObject' }, + ]) { + await testInvalid(dest, 'ERR_INVALID_ARG_TYPE', badParams); + } + + // Various invalid params + testInvalid(dest, 'ERR_OUT_OF_RANGE', { buffer, length: 5 }); + testInvalid(dest, 'ERR_OUT_OF_RANGE', { buffer, offset: 5 }); + testInvalid(dest, 'ERR_OUT_OF_RANGE', { buffer, offset: 1 }); + testInvalid(dest, 'ERR_OUT_OF_RANGE', { buffer, length: 1, offset: 3 }); + testInvalid(dest, 'ERR_OUT_OF_RANGE', { buffer, length: -1 }); + testInvalid(dest, 'ERR_OUT_OF_RANGE', { buffer, offset: -1 }); + + // Test compatibility with filehandle.read counterpart with reused params + for (const params of [ + { buffer }, + { buffer, length: 1 }, + { buffer, position: 5 }, + { buffer, length: 1, position: 5 }, + { buffer, length: 1, position: -1, offset: 2 }, + { buffer, length: null }, + ]) { + await testValid(dest, params); } })().then(common.mustCall()); diff --git a/test/parallel/test-fs-write-sync-optional-params.js b/test/parallel/test-fs-write-sync-optional-params.js index c8659610070819..fc5e46c53bd51a 100644 --- a/test/parallel/test-fs-write-sync-optional-params.js +++ b/test/parallel/test-fs-write-sync-optional-params.js @@ -1,95 +1,74 @@ 'use strict'; require('../common'); + +// This test ensures that fs.writeSync accepts "named parameters" object +// and doesn't interpret objects as strings + +const assert = require('assert'); const fs = require('fs'); const path = require('path'); const tmpdir = require('../common/tmpdir'); -const assert = require('assert'); tmpdir.refresh(); const dest = path.resolve(tmpdir.path, 'tmp.txt'); const buffer = Buffer.from('zyx'); -{ - let fd = fs.openSync(dest, 'w+'); +function testInvalid(dest, expectedCode, ...bufferAndParams) { + let fd; + try { + fd = fs.openSync(dest, 'w+'); + assert.throws( + () => fs.writeSync(fd, ...bufferAndParams), + { code: expectedCode }); + } finally { + if (fd != null) fs.closeSync(fd); + } +} - assert.throws(() => { - fs.writeSync(fd, {}); // Missing buffer, {} is second argument - }, { - code: 'ERR_INVALID_ARG_TYPE', - name: 'TypeError', - message: 'The "buffer" argument must be of type string or an instance ' + - 'of Buffer, TypedArray, or DataView. Received an instance of Object' - }); - assert.throws(() => { - fs.writeSync(fd, buffer, { length: 5 }); - }, { - code: 'ERR_OUT_OF_RANGE', - name: 'RangeError', - message: 'The value of "length" is out of range. ' + - 'It must be <= 3. Received 5' - }); - assert.throws(() => { - fs.writeSync(fd, buffer, { offset: 5 }); - }, { - code: 'ERR_OUT_OF_RANGE', - name: 'RangeError', - message: 'The value of "offset" is out of range. ' + - 'It must be <= 3. Received 5' - }); - assert.throws(() => { - fs.writeSync(fd, buffer, { offset: 1 }); - }, { - code: 'ERR_OUT_OF_RANGE', - name: 'RangeError', - message: 'The value of "length" is out of range. ' + - 'It must be <= 2. Received 3' - }); - assert.throws(() => { - fs.writeSync(fd, buffer, { length: 1, offset: 3 }); - }, { - code: 'ERR_OUT_OF_RANGE', - name: 'RangeError', - message: 'The value of "length" is out of range. ' + - 'It must be <= 0. Received 1' - }); - assert.throws(() => { - fs.writeSync(fd, buffer, { length: -1 }); - }, { - code: 'ERR_OUT_OF_RANGE', - name: 'RangeError', - message: 'The value of "length" is out of range. ' + - 'It must be >= 0. Received -1' - }); - assert.throws(() => { - fs.writeSync(fd, buffer, { offset: -1 }); - }, { - code: 'ERR_OUT_OF_RANGE', - name: 'RangeError', - message: 'The value of "offset" is out of range. ' + - 'It must be >= 0 && <= 9007199254740991. Received -1' - }); +function testValid(dest, buffer, params) { + let fd; + try { + fd = fs.openSync(dest, 'w+'); + const bytesWritten = fs.writeSync(fd, buffer, params); + const bytesRead = fs.readSync(fd, buffer, params); - // Test if object is not interpreted as string - for (const buffer of [ + assert.ok(bytesWritten >= bytesRead); + if (params.length !== undefined && params.length !== null) { + assert.strictEqual(bytesWritten, params.length); + } + } finally { + if (fd != null) fs.closeSync(fd); + } +} + +{ + // Test if second argument is not wrongly interpreted as string or params + for (const badBuffer of [ + undefined, null, true, 42, 42n, Symbol('42'), NaN, [], {}, + { buffer: 'amNotParam' }, + { string: 'amNotParam' }, + { buffer: new Uint8Array(1) }, + { buffer: new Uint8Array(1).buffer }, new Date(), new String('notPrimitive'), { toString() { return 'amObject'; } }, { [Symbol.toPrimitive]: (hint) => 'amObject' }, ]) { - assert.throws(() => { - fs.writeSync(fd, buffer); - }, { - code: 'ERR_INVALID_ARG_TYPE', - name: 'TypeError', - message: /^The "buffer" argument must be of type string or an instance of Buffer, TypedArray, or DataView/ - }); + testInvalid(dest, 'ERR_INVALID_ARG_TYPE', badBuffer); } - fs.closeSync(fd); + // Various invalid params + testInvalid(dest, 'ERR_OUT_OF_RANGE', buffer, { length: 5 }); + testInvalid(dest, 'ERR_OUT_OF_RANGE', buffer, { offset: 5 }); + testInvalid(dest, 'ERR_OUT_OF_RANGE', buffer, { offset: 1 }); + testInvalid(dest, 'ERR_OUT_OF_RANGE', buffer, { length: 1, offset: 3 }); + testInvalid(dest, 'ERR_OUT_OF_RANGE', buffer, { length: -1 }); + testInvalid(dest, 'ERR_OUT_OF_RANGE', buffer, { offset: -1 }); + // Test compatibility with fs.readSync counterpart with reused params for (const params of [ {}, { length: 1 }, @@ -98,15 +77,6 @@ const buffer = Buffer.from('zyx'); { length: 1, position: -1, offset: 2 }, { length: null }, ]) { - fd = fs.openSync(dest, 'w+'); - const bytesWritten = fs.writeSync(fd, buffer, params); - const bytesRead = fs.writeSync(fd, buffer, params); - - // Test compatibility with fs.readSync counterpart with reused params - assert.strictEqual(bytesWritten, bytesRead); - if (params.length !== undefined && params.length !== null) { - assert.strictEqual(bytesWritten, params.length); - } - fs.closeSync(fd); + testValid(dest, buffer, params); } }