1// Copyright Joyent, Inc. and other Node contributors. 2// 3// Permission is hereby granted, free of charge, to any person obtaining a 4// copy of this software and associated documentation files (the 5// "Software"), to deal in the Software without restriction, including 6// without limitation the rights to use, copy, modify, merge, publish, 7// distribute, sublicense, and/or sell copies of the Software, and to permit 8// persons to whom the Software is furnished to do so, subject to the 9// following conditions: 10// 11// The above copyright notice and this permission notice shall be included 12// in all copies or substantial portions of the Software. 13// 14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20// USE OR OTHER DEALINGS IN THE SOFTWARE. 21 22// Flags: --expose_externalize_string 23'use strict'; 24const common = require('../common'); 25const assert = require('assert'); 26const path = require('path'); 27const fs = require('fs'); 28const tmpdir = require('../common/tmpdir'); 29 30tmpdir.refresh(); 31 32const fn = path.join(tmpdir.path, 'write.txt'); 33const fn2 = path.join(tmpdir.path, 'write2.txt'); 34const fn3 = path.join(tmpdir.path, 'write3.txt'); 35const fn4 = path.join(tmpdir.path, 'write4.txt'); 36const fn5 = path.join(tmpdir.path, 'write5.txt'); 37const expected = 'ümlaut.'; 38const constants = fs.constants; 39 40const { externalizeString, isOneByteString } = global; 41 42// Account for extra globals exposed by --expose_externalize_string. 43common.allowGlobals(externalizeString, isOneByteString, global.x); 44 45{ 46 const expected = 'ümlaut sechzig'; // Must be a unique string. 47 externalizeString(expected); 48 assert.strictEqual(isOneByteString(expected), true); 49 const fd = fs.openSync(fn, 'w'); 50 fs.writeSync(fd, expected, 0, 'latin1'); 51 fs.closeSync(fd); 52 assert.strictEqual(fs.readFileSync(fn, 'latin1'), expected); 53} 54 55{ 56 const expected = 'ümlaut neunzig'; // Must be a unique string. 57 externalizeString(expected); 58 assert.strictEqual(isOneByteString(expected), true); 59 const fd = fs.openSync(fn, 'w'); 60 fs.writeSync(fd, expected, 0, 'utf8'); 61 fs.closeSync(fd); 62 assert.strictEqual(fs.readFileSync(fn, 'utf8'), expected); 63} 64 65{ 66 const expected = 'Zhōngwén 1'; // Must be a unique string. 67 externalizeString(expected); 68 assert.strictEqual(isOneByteString(expected), false); 69 const fd = fs.openSync(fn, 'w'); 70 fs.writeSync(fd, expected, 0, 'ucs2'); 71 fs.closeSync(fd); 72 assert.strictEqual(fs.readFileSync(fn, 'ucs2'), expected); 73} 74 75{ 76 const expected = 'Zhōngwén 2'; // Must be a unique string. 77 externalizeString(expected); 78 assert.strictEqual(isOneByteString(expected), false); 79 const fd = fs.openSync(fn, 'w'); 80 fs.writeSync(fd, expected, 0, 'utf8'); 81 fs.closeSync(fd); 82 assert.strictEqual(fs.readFileSync(fn, 'utf8'), expected); 83} 84 85fs.open(fn, 'w', 0o644, common.mustSucceed((fd) => { 86 const done = common.mustSucceed((written) => { 87 assert.strictEqual(written, Buffer.byteLength(expected)); 88 fs.closeSync(fd); 89 const found = fs.readFileSync(fn, 'utf8'); 90 fs.unlinkSync(fn); 91 assert.strictEqual(found, expected); 92 }); 93 94 const written = common.mustSucceed((written) => { 95 assert.strictEqual(written, 0); 96 fs.write(fd, expected, 0, 'utf8', done); 97 }); 98 99 fs.write(fd, '', 0, 'utf8', written); 100})); 101 102const args = constants.O_CREAT | constants.O_WRONLY | constants.O_TRUNC; 103fs.open(fn2, args, 0o644, common.mustSucceed((fd) => { 104 const done = common.mustSucceed((written) => { 105 assert.strictEqual(written, Buffer.byteLength(expected)); 106 fs.closeSync(fd); 107 const found = fs.readFileSync(fn2, 'utf8'); 108 fs.unlinkSync(fn2); 109 assert.strictEqual(found, expected); 110 }); 111 112 const written = common.mustSucceed((written) => { 113 assert.strictEqual(written, 0); 114 fs.write(fd, expected, 0, 'utf8', done); 115 }); 116 117 fs.write(fd, '', 0, 'utf8', written); 118})); 119 120fs.open(fn3, 'w', 0o644, common.mustSucceed((fd) => { 121 const done = common.mustSucceed((written) => { 122 assert.strictEqual(written, Buffer.byteLength(expected)); 123 fs.closeSync(fd); 124 }); 125 126 fs.write(fd, expected, done); 127})); 128 129 130// Test write with an object with an own toString function 131// Runtime deprecated by DEP0162 132common.expectWarning('DeprecationWarning', 133 'Implicit coercion of objects with own toString property is deprecated.', 134 'DEP0162'); 135fs.open(fn4, 'w', 0o644, common.mustSucceed((fd) => { 136 const done = common.mustSucceed((written) => { 137 assert.strictEqual(written, Buffer.byteLength(expected)); 138 fs.closeSync(fd); 139 }); 140 141 const data = { 142 toString() { return expected; } 143 }; 144 fs.write(fd, data, done); 145})); 146 147[false, 'test', {}, [], null, undefined].forEach((i) => { 148 assert.throws( 149 () => fs.write(i, common.mustNotCall()), 150 { 151 code: 'ERR_INVALID_ARG_TYPE', 152 name: 'TypeError' 153 } 154 ); 155 assert.throws( 156 () => fs.writeSync(i), 157 { 158 code: 'ERR_INVALID_ARG_TYPE', 159 name: 'TypeError' 160 } 161 ); 162}); 163 164[ 165 false, 5, {}, [], null, undefined, 166 new String('notPrimitive'), 167 { [Symbol.toPrimitive]: (hint) => 'amObject' }, 168].forEach((data) => { 169 assert.throws( 170 () => fs.write(1, data, common.mustNotCall()), 171 { 172 code: 'ERR_INVALID_ARG_TYPE', 173 message: /"buffer"/ 174 } 175 ); 176 assert.throws( 177 () => fs.writeSync(1, data), 178 { 179 code: 'ERR_INVALID_ARG_TYPE', 180 message: /"buffer"/ 181 } 182 ); 183}); 184 185{ 186 // Regression test for https://github.com/nodejs/node/issues/38168 187 const fd = fs.openSync(fn5, 'w'); 188 189 assert.throws( 190 () => fs.writeSync(fd, 'abc', 0, 'hex'), 191 { 192 code: 'ERR_INVALID_ARG_VALUE', 193 message: /'encoding' is invalid for data of length 3/ 194 } 195 ); 196 197 assert.throws( 198 () => fs.writeSync(fd, 'abc', 0, 'hex', common.mustNotCall()), 199 { 200 code: 'ERR_INVALID_ARG_VALUE', 201 message: /'encoding' is invalid for data of length 3/ 202 } 203 ); 204 205 assert.strictEqual(fs.writeSync(fd, 'abcd', 0, 'hex'), 2); 206 207 fs.write(fd, 'abcd', 0, 'hex', common.mustSucceed((written) => { 208 assert.strictEqual(written, 2); 209 fs.closeSync(fd); 210 })); 211} 212