2022-05-03 01:52:43 +08:00
|
|
|
import * as common from '../common/index.mjs';
|
|
|
|
import * as fixtures from '../common/fixtures.mjs';
|
|
|
|
import fs from 'fs';
|
|
|
|
import assert from 'assert';
|
|
|
|
|
|
|
|
// This test ensures that "position" argument is correctly validated
|
|
|
|
|
|
|
|
const filepath = fixtures.path('x.txt');
|
|
|
|
|
|
|
|
const buffer = Buffer.from('xyz\n');
|
|
|
|
const offset = 0;
|
|
|
|
const length = buffer.byteLength;
|
|
|
|
|
|
|
|
// allowedErrors is an array of acceptable internal errors
|
2022-06-22 19:23:01 +01:00
|
|
|
// For example, on some platforms read syscall might return -EFBIG or -EOVERFLOW
|
2022-05-03 01:52:43 +08:00
|
|
|
async function testValid(position, allowedErrors = []) {
|
2022-05-15 22:52:06 +08:00
|
|
|
return new Promise((resolve, reject) => {
|
2022-05-03 01:52:43 +08:00
|
|
|
fs.open(filepath, 'r', common.mustSucceed((fd) => {
|
2022-05-15 22:52:06 +08:00
|
|
|
let callCount = 3;
|
|
|
|
const handler = common.mustCall((err) => {
|
|
|
|
callCount--;
|
|
|
|
if (err && !allowedErrors.includes(err.code)) {
|
|
|
|
fs.close(fd, common.mustSucceed());
|
|
|
|
reject(err);
|
|
|
|
} else if (callCount === 0) {
|
|
|
|
fs.close(fd, common.mustSucceed(resolve));
|
|
|
|
}
|
|
|
|
}, callCount);
|
|
|
|
fs.read(fd, buffer, offset, length, position, handler);
|
|
|
|
fs.read(fd, { buffer, offset, length, position }, handler);
|
2022-07-24 22:29:06 +09:00
|
|
|
fs.read(fd, buffer, common.mustNotMutateObjectDeep({ offset, length, position }), handler);
|
2022-05-03 01:52:43 +08:00
|
|
|
}));
|
2022-05-15 22:52:06 +08:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
async function testInvalid(code, position) {
|
|
|
|
return new Promise((resolve, reject) => {
|
2022-05-03 01:52:43 +08:00
|
|
|
fs.open(filepath, 'r', common.mustSucceed((fd) => {
|
|
|
|
try {
|
|
|
|
assert.throws(
|
|
|
|
() => fs.read(fd, buffer, offset, length, position, common.mustNotCall()),
|
|
|
|
{ code }
|
|
|
|
);
|
|
|
|
assert.throws(
|
|
|
|
() => fs.read(fd, { buffer, offset, length, position }, common.mustNotCall()),
|
|
|
|
{ code }
|
|
|
|
);
|
2022-05-15 22:52:06 +08:00
|
|
|
assert.throws(
|
2022-07-24 22:29:06 +09:00
|
|
|
() => fs.read(fd, buffer, common.mustNotMutateObjectDeep({ offset, length, position }), common.mustNotCall()),
|
2022-05-15 22:52:06 +08:00
|
|
|
{ code }
|
|
|
|
);
|
|
|
|
resolve();
|
|
|
|
} catch (err) {
|
|
|
|
reject(err);
|
2022-05-03 01:52:43 +08:00
|
|
|
} finally {
|
|
|
|
fs.close(fd, common.mustSucceed());
|
|
|
|
}
|
|
|
|
}));
|
2022-05-15 22:52:06 +08:00
|
|
|
});
|
2022-05-03 01:52:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
await testValid(undefined);
|
|
|
|
await testValid(null);
|
|
|
|
await testValid(-1);
|
|
|
|
await testValid(-1n);
|
|
|
|
|
|
|
|
await testValid(0);
|
|
|
|
await testValid(0n);
|
|
|
|
await testValid(1);
|
|
|
|
await testValid(1n);
|
|
|
|
await testValid(9);
|
|
|
|
await testValid(9n);
|
2022-06-22 19:23:01 +01:00
|
|
|
await testValid(Number.MAX_SAFE_INTEGER, [ 'EFBIG', 'EOVERFLOW' ]);
|
2022-05-03 01:52:43 +08:00
|
|
|
|
2022-06-22 19:23:01 +01:00
|
|
|
await testValid(2n ** 63n - 1n - BigInt(length), [ 'EFBIG', 'EOVERFLOW' ]);
|
2022-05-03 01:52:43 +08:00
|
|
|
await testInvalid('ERR_OUT_OF_RANGE', 2n ** 63n);
|
2023-09-29 19:56:07 +09:00
|
|
|
await testInvalid('ERR_OUT_OF_RANGE', 2n ** 63n - BigInt(length));
|
2022-05-03 01:52:43 +08:00
|
|
|
|
|
|
|
await testInvalid('ERR_OUT_OF_RANGE', NaN);
|
|
|
|
await testInvalid('ERR_OUT_OF_RANGE', -Infinity);
|
|
|
|
await testInvalid('ERR_OUT_OF_RANGE', Infinity);
|
|
|
|
await testInvalid('ERR_OUT_OF_RANGE', -0.999);
|
|
|
|
await testInvalid('ERR_OUT_OF_RANGE', -(2n ** 64n));
|
|
|
|
await testInvalid('ERR_OUT_OF_RANGE', Number.MAX_SAFE_INTEGER + 1);
|
|
|
|
await testInvalid('ERR_OUT_OF_RANGE', Number.MAX_VALUE);
|
|
|
|
|
|
|
|
for (const badTypeValue of [
|
|
|
|
false, true, '1', Symbol(1), {}, [], () => {}, Promise.resolve(1),
|
|
|
|
]) {
|
|
|
|
await testInvalid('ERR_INVALID_ARG_TYPE', badTypeValue);
|
|
|
|
}
|
|
|
|
}
|