-
Notifications
You must be signed in to change notification settings - Fork 28.2k
/
test-fs-write-optional-params.js
109 lines (94 loc) Β· 3.77 KB
/
test-fs-write-optional-params.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
'use strict';
const common = require('../common');
// This test ensures that fs.write 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 util = require('util');
tmpdir.refresh();
const destInvalid = path.resolve(tmpdir.path, 'rwopt_invalid');
const buffer = Buffer.from('zyx');
function testInvalidCb(fd, expectedCode, buffer, options, callback) {
assert.throws(
() => fs.write(fd, buffer, common.mustNotMutateObjectDeep(options), common.mustNotCall()),
{ code: expectedCode }
);
callback(0);
}
function testValidCb(buffer, options, index, callback) {
options = common.mustNotMutateObjectDeep(options);
const length = options?.length;
const offset = options?.offset;
const dest = path.resolve(tmpdir.path, `rwopt_valid_${index}`);
fs.open(dest, 'w+', common.mustSucceed((fd) => {
fs.write(fd, buffer, options, common.mustSucceed((bytesWritten, bufferWritten) => {
const writeBufCopy = Uint8Array.prototype.slice.call(bufferWritten);
fs.read(fd, buffer, options, common.mustSucceed((bytesRead, bufferRead) => {
const readBufCopy = Uint8Array.prototype.slice.call(bufferRead);
assert.ok(bytesWritten >= bytesRead);
if (length !== undefined && length !== null) {
assert.strictEqual(bytesWritten, length);
}
if (offset === undefined || offset === 0) {
assert.deepStrictEqual(writeBufCopy, readBufCopy);
}
assert.deepStrictEqual(bufferWritten, bufferRead);
fs.close(fd, common.mustSucceed(callback));
}));
}));
}));
}
// Promisify to reduce flakiness
const testInvalid = util.promisify(testInvalidCb);
const testValid = util.promisify(testValidCb);
async function runTests(fd) {
// Test if first argument is not wrongly interpreted as ArrayBufferView|string
for (const badBuffer of [
undefined, null, true, 42, 42n, Symbol('42'), NaN, [], () => {},
Promise.resolve(new Uint8Array(1)),
common.mustNotCall(),
common.mustNotMutateObjectDeep({}),
{},
{ buffer: 'amNotParam' },
{ string: 'amNotParam' },
{ buffer: new Uint8Array(1).buffer },
new Date(),
new String('notPrimitive'),
{ [Symbol.toPrimitive]: (hint) => 'amObject' },
{ toString() { return 'amObject'; } },
]) {
await testInvalid(fd, 'ERR_INVALID_ARG_TYPE', badBuffer, {});
}
// First argument (buffer or string) is mandatory
await testInvalid(fd, 'ERR_INVALID_ARG_TYPE', undefined, undefined);
// Various invalid options
await testInvalid(fd, 'ERR_OUT_OF_RANGE', buffer, { length: 5 });
await testInvalid(fd, 'ERR_OUT_OF_RANGE', buffer, { offset: 5 });
await testInvalid(fd, 'ERR_OUT_OF_RANGE', buffer, { length: 1, offset: 3 });
await testInvalid(fd, 'ERR_OUT_OF_RANGE', buffer, { length: -1 });
await testInvalid(fd, 'ERR_OUT_OF_RANGE', buffer, { offset: -1 });
await testInvalid(fd, 'ERR_INVALID_ARG_TYPE', buffer, { offset: false });
await testInvalid(fd, 'ERR_INVALID_ARG_TYPE', buffer, { offset: true });
await testInvalid(fd, 'ERR_INVALID_ARG_TYPE', buffer, true);
await testInvalid(fd, 'ERR_INVALID_ARG_TYPE', buffer, '42');
await testInvalid(fd, 'ERR_INVALID_ARG_TYPE', buffer, Symbol('42'));
// Test compatibility with fs.read counterpart
for (const [ index, options ] of [
null,
{},
{ length: 1 },
{ position: 5 },
{ length: 1, position: 5 },
{ length: 1, position: -1, offset: 2 },
{ length: null },
{ position: null },
{ offset: 1 },
].entries()) {
await testValid(buffer, options, index);
}
}
fs.open(destInvalid, 'w+', common.mustSucceed(async (fd) => {
runTests(fd).then(common.mustCall(() => fs.close(fd, common.mustSucceed())));
}));