• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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