1'use strict'; 2 3const common = require('../common'); 4 5// This test ensures that fs.writeSync accepts "named parameters" object 6// and doesn't interpret objects as strings 7 8const assert = require('assert'); 9const fs = require('fs'); 10const path = require('path'); 11const tmpdir = require('../common/tmpdir'); 12 13tmpdir.refresh(); 14 15const dest = path.resolve(tmpdir.path, 'tmp.txt'); 16const buffer = Buffer.from('zyx'); 17 18function testInvalid(dest, expectedCode, ...bufferAndOptions) { 19 if (bufferAndOptions.length >= 2) { 20 bufferAndOptions[1] = common.mustNotMutateObjectDeep(bufferAndOptions[1]); 21 } 22 let fd; 23 try { 24 fd = fs.openSync(dest, 'w+'); 25 assert.throws( 26 () => fs.writeSync(fd, ...bufferAndOptions), 27 { code: expectedCode }); 28 } finally { 29 if (fd != null) fs.closeSync(fd); 30 } 31} 32 33function testValid(dest, buffer, options) { 34 const length = options?.length; 35 let fd, bytesWritten, bytesRead; 36 37 try { 38 fd = fs.openSync(dest, 'w'); 39 bytesWritten = fs.writeSync(fd, buffer, options); 40 } finally { 41 if (fd != null) fs.closeSync(fd); 42 } 43 44 try { 45 fd = fs.openSync(dest, 'r'); 46 bytesRead = fs.readSync(fd, buffer, options); 47 } finally { 48 if (fd != null) fs.closeSync(fd); 49 } 50 51 assert.ok(bytesWritten >= bytesRead); 52 if (length !== undefined && length !== null) { 53 assert.strictEqual(bytesWritten, length); 54 assert.strictEqual(bytesRead, length); 55 } 56} 57 58{ 59 // Test if second argument is not wrongly interpreted as string or options 60 for (const badBuffer of [ 61 undefined, null, true, 42, 42n, Symbol('42'), NaN, [], () => {}, 62 common.mustNotCall(), 63 common.mustNotMutateObjectDeep({}), 64 {}, 65 { buffer: 'amNotParam' }, 66 { string: 'amNotParam' }, 67 { buffer: new Uint8Array(1) }, 68 { buffer: new Uint8Array(1).buffer }, 69 Promise.resolve(new Uint8Array(1)), 70 new Date(), 71 new String('notPrimitive'), 72 { toString() { return 'amObject'; } }, 73 { [Symbol.toPrimitive]: (hint) => 'amObject' }, 74 ]) { 75 testInvalid(dest, 'ERR_INVALID_ARG_TYPE', common.mustNotMutateObjectDeep(badBuffer)); 76 } 77 78 // First argument (buffer or string) is mandatory 79 testInvalid(dest, 'ERR_INVALID_ARG_TYPE'); 80 81 // Various invalid options 82 testInvalid(dest, 'ERR_OUT_OF_RANGE', buffer, { length: 5 }); 83 testInvalid(dest, 'ERR_OUT_OF_RANGE', buffer, { offset: 5 }); 84 testInvalid(dest, 'ERR_OUT_OF_RANGE', buffer, { length: 1, offset: 3 }); 85 testInvalid(dest, 'ERR_OUT_OF_RANGE', buffer, { length: -1 }); 86 testInvalid(dest, 'ERR_OUT_OF_RANGE', buffer, { offset: -1 }); 87 testInvalid(dest, 'ERR_INVALID_ARG_TYPE', buffer, { offset: false }); 88 testInvalid(dest, 'ERR_INVALID_ARG_TYPE', buffer, { offset: true }); 89 90 // Test compatibility with fs.readSync counterpart with reused options 91 for (const options of [ 92 undefined, 93 null, 94 {}, 95 { length: 1 }, 96 { position: 5 }, 97 { length: 1, position: 5 }, 98 { length: 1, position: -1, offset: 2 }, 99 { length: null }, 100 { position: null }, 101 { offset: 1 }, 102 ]) { 103 testValid(dest, buffer, common.mustNotMutateObjectDeep(options)); 104 } 105} 106