| 'use strict'; |
| const common = require('../common'); |
| |
| // This test ensures that fs.readFile correctly returns the |
| // contents of varying-sized files. |
| |
| const tmpdir = require('../../test/common/tmpdir'); |
| const assert = require('assert'); |
| const fs = require('fs'); |
| |
| const prefix = `.removeme-fs-readfile-${process.pid}`; |
| |
| tmpdir.refresh(); |
| |
| const fileInfo = [ |
| { name: tmpdir.resolve(`${prefix}-1K.txt`), |
| len: 1024 }, |
| { name: tmpdir.resolve(`${prefix}-64K.txt`), |
| len: 64 * 1024 }, |
| { name: tmpdir.resolve(`${prefix}-64KLessOne.txt`), |
| len: (64 * 1024) - 1 }, |
| { name: tmpdir.resolve(`${prefix}-1M.txt`), |
| len: 1 * 1024 * 1024 }, |
| { name: tmpdir.resolve(`${prefix}-1MPlusOne.txt`), |
| len: (1 * 1024 * 1024) + 1 }, |
| ]; |
| |
| // Populate each fileInfo (and file) with unique fill. |
| const sectorSize = 512; |
| for (const e of fileInfo) { |
| e.contents = Buffer.allocUnsafe(e.len); |
| |
| // This accounts for anything unusual in Node's implementation of readFile. |
| // Using e.g. 'aa...aa' would miss bugs like Node re-reading |
| // the same section twice instead of two separate sections. |
| for (let offset = 0; offset < e.len; offset += sectorSize) { |
| const fillByte = 256 * Math.random(); |
| const nBytesToFill = Math.min(sectorSize, e.len - offset); |
| e.contents.fill(fillByte, offset, offset + nBytesToFill); |
| } |
| |
| fs.writeFileSync(e.name, e.contents); |
| } |
| // All files are now populated. |
| |
| // Test readFile on each size. |
| for (const e of fileInfo) { |
| fs.readFile(e.name, common.mustCall((err, buf) => { |
| console.log(`Validating readFile on file ${e.name} of length ${e.len}`); |
| assert.ifError(err); |
| assert.deepStrictEqual(buf, e.contents); |
| })); |
| } |
| |
| // readFile() and readFileSync() should fail if the file is too big. |
| { |
| const kIoMaxLength = 2 ** 31 - 1; |
| |
| if (!tmpdir.hasEnoughSpace(kIoMaxLength)) { |
| // truncateSync() will fail with ENOSPC if there is not enough space. |
| common.printSkipMessage(`Not enough space in ${tmpdir.path}`); |
| } else { |
| const file = tmpdir.resolve(`${prefix}-too-large.txt`); |
| fs.writeFileSync(file, Buffer.from('0')); |
| fs.truncateSync(file, kIoMaxLength + 1); |
| |
| fs.readFile(file, common.expectsError({ |
| code: 'ERR_FS_FILE_TOO_LARGE', |
| name: 'RangeError', |
| })); |
| assert.throws(() => { |
| fs.readFileSync(file); |
| }, { code: 'ERR_FS_FILE_TOO_LARGE', name: 'RangeError' }); |
| } |
| } |
| |
| { |
| // Test cancellation, before |
| const signal = AbortSignal.abort(); |
| fs.readFile(fileInfo[0].name, { signal }, common.mustCall((err, buf) => { |
| assert.strictEqual(err.name, 'AbortError'); |
| })); |
| } |
| { |
| // Test cancellation, during read |
| const controller = new AbortController(); |
| const signal = controller.signal; |
| fs.readFile(fileInfo[0].name, { signal }, common.mustCall((err, buf) => { |
| assert.strictEqual(err.name, 'AbortError'); |
| })); |
| process.nextTick(() => controller.abort()); |
| } |
| { |
| // Verify that if something different than Abortcontroller.signal |
| // is passed, ERR_INVALID_ARG_TYPE is thrown |
| assert.throws(() => { |
| const callback = common.mustNotCall(); |
| fs.readFile(fileInfo[0].name, { signal: 'hello' }, callback); |
| }, { code: 'ERR_INVALID_ARG_TYPE', name: 'TypeError' }); |
| } |