1import * as common from '../common/index.mjs'; 2import * as fixtures from '../common/fixtures.mjs'; 3import fs from 'fs'; 4import assert from 'assert'; 5 6// This test ensures that "position" argument is correctly validated 7 8const filepath = fixtures.path('x.txt'); 9 10const buffer = Buffer.from('xyz\n'); 11const offset = 0; 12const length = buffer.byteLength; 13 14// allowedErrors is an array of acceptable internal errors 15// For example, on some platforms read syscall might return -EFBIG or -EOVERFLOW 16async function testValid(position, allowedErrors = []) { 17 return new Promise((resolve, reject) => { 18 fs.open(filepath, 'r', common.mustSucceed((fd) => { 19 let callCount = 3; 20 const handler = common.mustCall((err) => { 21 callCount--; 22 if (err && !allowedErrors.includes(err.code)) { 23 fs.close(fd, common.mustSucceed()); 24 reject(err); 25 } else if (callCount === 0) { 26 fs.close(fd, common.mustSucceed(resolve)); 27 } 28 }, callCount); 29 fs.read(fd, buffer, offset, length, position, handler); 30 fs.read(fd, { buffer, offset, length, position }, handler); 31 fs.read(fd, buffer, common.mustNotMutateObjectDeep({ offset, length, position }), handler); 32 })); 33 }); 34} 35 36async function testInvalid(code, position) { 37 return new Promise((resolve, reject) => { 38 fs.open(filepath, 'r', common.mustSucceed((fd) => { 39 try { 40 assert.throws( 41 () => fs.read(fd, buffer, offset, length, position, common.mustNotCall()), 42 { code } 43 ); 44 assert.throws( 45 () => fs.read(fd, { buffer, offset, length, position }, common.mustNotCall()), 46 { code } 47 ); 48 assert.throws( 49 () => fs.read(fd, buffer, common.mustNotMutateObjectDeep({ offset, length, position }), common.mustNotCall()), 50 { code } 51 ); 52 resolve(); 53 } catch (err) { 54 reject(err); 55 } finally { 56 fs.close(fd, common.mustSucceed()); 57 } 58 })); 59 }); 60} 61 62{ 63 await testValid(undefined); 64 await testValid(null); 65 await testValid(-1); 66 await testValid(-1n); 67 68 await testValid(0); 69 await testValid(0n); 70 await testValid(1); 71 await testValid(1n); 72 await testValid(9); 73 await testValid(9n); 74 await testValid(Number.MAX_SAFE_INTEGER, [ 'EFBIG', 'EOVERFLOW' ]); 75 76 await testValid(2n ** 63n - 1n - BigInt(length), [ 'EFBIG', 'EOVERFLOW' ]); 77 await testInvalid('ERR_OUT_OF_RANGE', 2n ** 63n); 78 79 // TODO(LiviaMedeiros): test `2n ** 63n - BigInt(length)` 80 81 await testInvalid('ERR_OUT_OF_RANGE', NaN); 82 await testInvalid('ERR_OUT_OF_RANGE', -Infinity); 83 await testInvalid('ERR_OUT_OF_RANGE', Infinity); 84 await testInvalid('ERR_OUT_OF_RANGE', -0.999); 85 await testInvalid('ERR_OUT_OF_RANGE', -(2n ** 64n)); 86 await testInvalid('ERR_OUT_OF_RANGE', Number.MAX_SAFE_INTEGER + 1); 87 await testInvalid('ERR_OUT_OF_RANGE', Number.MAX_VALUE); 88 89 for (const badTypeValue of [ 90 false, true, '1', Symbol(1), {}, [], () => {}, Promise.resolve(1), 91 ]) { 92 await testInvalid('ERR_INVALID_ARG_TYPE', badTypeValue); 93 } 94} 95