Skip to content

Commit

Permalink
feat: support throwIfNoEntry: false in StatOptions
Browse files Browse the repository at this point in the history
This feature is available since node v14
  • Loading branch information
mausworks committed Nov 24, 2021
1 parent 7a4919d commit 23aa210
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 56 deletions.
34 changes: 34 additions & 0 deletions src/__tests__/promises.test.ts
Expand Up @@ -149,6 +149,40 @@ describe('Promises API', () => {
return expect(fileHandle.stat()).rejects.toBeInstanceOf(Error);
});
});
describe('.stat(path, options)', () => {
const { promises: vol } = new Volume();

it('Does not reject when entry does not exist if throwIfNoEntry is false', async () => {
const stat = await vol.stat('/no', { throwIfNoEntry: false });
expect(stat).toBeUndefined();
});
it('Rejects when entry does not exist if throwIfNoEntry is true', async () => {
await expect(vol.stat('/foo', { throwIfNoEntry: true })).rejects.toBeInstanceOf(Error);
});
it('Rejects when entry does not exist if throwIfNoEntry is not specified', async () => {
await expect(vol.stat('/foo')).rejects.toBeInstanceOf(Error);
});
it('Rejects when entry does not exist if throwIfNoEntry is explicitly undefined', async () => {
await expect(vol.stat('/foo', { throwIfNoEntry: undefined })).rejects.toBeInstanceOf(Error);
});
});
describe('.lstat(path, options)', () => {
const { promises: vol } = new Volume();

it('Does not throw when entry does not exist if throwIfNoEntry is false', async () => {
const stat = await vol.lstat('/foo', { throwIfNoEntry: false });
expect(stat).toBeUndefined();
});
it('Rejects when entry does not exist if throwIfNoEntry is true', async () => {
await expect(vol.lstat('/foo', { throwIfNoEntry: true })).rejects.toBeInstanceOf(Error);
});
it('Rejects when entry does not exist if throwIfNoEntry is not specified', async () => {
await expect(vol.lstat('/foo')).rejects.toBeInstanceOf(Error);
});
it('Rejects when entry does not exist if throwIfNoEntry is explicitly undefined', async () => {
await expect(vol.lstat('/foo', { throwIfNoEntry: undefined })).rejects.toBeInstanceOf(Error);
});
});
describe('truncate([len])', () => {
const vol = new Volume();
const { promises } = vol;
Expand Down
78 changes: 56 additions & 22 deletions src/__tests__/volume.test.ts
Expand Up @@ -385,7 +385,7 @@ describe('volume', () => {
describe('.open(path, flags[, mode], callback)', () => {
const vol = new Volume();
vol.mkdirSync('/test-dir');
it('Create new file at root (/test.txt)', done => {
it('Create new file at root (/test.txt)', (done) => {
vol.open('/test.txt', 'w', (err, fd) => {
expect(err).toBe(null);
expect(vol.root.getChild('test.txt')).toBeInstanceOf(Link);
Expand All @@ -394,13 +394,13 @@ describe('volume', () => {
done();
});
});
it('Error on file not found', done => {
it('Error on file not found', (done) => {
vol.open('/non-existing-file.txt', 'r', (err, fd) => {
expect(err).toHaveProperty('code', 'ENOENT');
done();
});
});
it('Invalid path correct error code thrown synchronously', done => {
it('Invalid path correct error code thrown synchronously', (done) => {
try {
(vol as any).open(123, 'r', (err, fd) => {
throw Error('This should not throw');
Expand All @@ -412,7 +412,7 @@ describe('volume', () => {
done();
}
});
it('Invalid flags correct error code thrown synchronously', done => {
it('Invalid flags correct error code thrown synchronously', (done) => {
try {
(vol as any).open('/non-existing-file.txt', undefined, () => {
throw Error('This should not throw');
Expand All @@ -423,7 +423,7 @@ describe('volume', () => {
done();
}
});
it('Invalid mode correct error code thrown synchronously', done => {
it('Invalid mode correct error code thrown synchronously', (done) => {
try {
(vol as any).openSync('/non-existing-file.txt', 'r', 'adfasdf', () => {
throw Error('This should not throw');
Expand All @@ -435,7 +435,7 @@ describe('volume', () => {
done();
}
});
it('Properly sets permissions from mode when creating a new file', done => {
it('Properly sets permissions from mode when creating a new file', (done) => {
vol.writeFileSync('/a.txt', 'foo');
const stats = vol.statSync('/a.txt');
// Write a new file, copying the mode from the old file
Expand All @@ -447,13 +447,13 @@ describe('volume', () => {
done();
});
});
it('Error on incorrect flags for directory', done => {
it('Error on incorrect flags for directory', (done) => {
vol.open('/test-dir', 'r+', (err, fd) => {
expect(err).toHaveProperty('code', 'EISDIR');
done();
});
});
it('Properly opens directory as read-only', done => {
it('Properly opens directory as read-only', (done) => {
vol.open('/test-dir', 'r', (err, fd) => {
expect(err).toBe(null);
expect(typeof fd).toBe('number');
Expand All @@ -463,10 +463,10 @@ describe('volume', () => {
});
describe('.close(fd, callback)', () => {
const vol = new Volume();
it('Closes file without errors', done => {
it('Closes file without errors', (done) => {
vol.open('/test.txt', 'w', (err, fd) => {
expect(err).toBe(null);
vol.close(fd || -1, err => {
vol.close(fd || -1, (err) => {
expect(err).toBe(null);
done();
});
Expand Down Expand Up @@ -535,7 +535,7 @@ describe('volume', () => {
const data = 'asdfasdf asdfasdf asdf';
const fileNode = (vol as any).createLink(vol.root, 'file.txt').getNode();
fileNode.setString(data);
it('Read file at root (/file.txt)', done => {
it('Read file at root (/file.txt)', (done) => {
vol.readFile('/file.txt', 'utf8', (err, str) => {
expect(err).toBe(null);
expect(str).toBe(data);
Expand Down Expand Up @@ -576,7 +576,7 @@ describe('volume', () => {
});
});
describe('.write(fd, buffer, offset, length, position, callback)', () => {
it('Simple write to a file descriptor', done => {
it('Simple write to a file descriptor', (done) => {
const vol = new Volume();
const fd = vol.openSync('/test.txt', 'w+');
const data = 'hello';
Expand All @@ -591,8 +591,8 @@ describe('volume', () => {
describe('.writeFile(path, data[, options], callback)', () => {
const vol = new Volume();
const data = 'asdfasidofjasdf';
it('Create a file at root (/writeFile.json)', done => {
vol.writeFile('/writeFile.json', data, err => {
it('Create a file at root (/writeFile.json)', (done) => {
vol.writeFile('/writeFile.json', data, (err) => {
expect(err).toBe(null);
const str = tryGetChildNode(vol.root, 'writeFile.json').getString();
expect(str).toBe(data);
Expand Down Expand Up @@ -683,7 +683,7 @@ describe('volume', () => {
const symlink = vol.root.createChild('mootools.link.js');
symlink.getNode().makeSymlink(['mootools.js']);

it('Basic one-jump symlink resolves', done => {
it('Basic one-jump symlink resolves', (done) => {
vol.realpath('/mootools.link.js', (err, path) => {
expect(path).toBe('/mootools.js');
done();
Expand All @@ -695,6 +695,40 @@ describe('volume', () => {
});
});
});
describe('.statSync(path, options)', () => {
const vol = new Volume();

it('Does not throw when entry does not exist if throwIfNoEntry is false', () => {
const stat = vol.statSync('/foo', { throwIfNoEntry: false });
expect(stat).toBeUndefined();
});
it('Throws when entry does not exist if throwIfNoEntry is true', () => {
expect(() => vol.statSync('/foo', { throwIfNoEntry: true })).toThrow();
});
it('Throws when entry does not exist if throwIfNoEntry is not specified', () => {
expect(() => vol.statSync('/foo')).toThrow();
});
it('Throws when entry does not exist if throwIfNoEntry is explicitly undefined', () => {
expect(() => vol.statSync('/foo', { throwIfNoEntry: undefined })).toThrow();
});
});
describe('.lstatSync(path, options)', () => {
const vol = new Volume();

it('Does not throw when entry does not exist if throwIfNoEntry is false', () => {
const stat = vol.lstatSync('/foo', { throwIfNoEntry: false });
expect(stat).toBeUndefined();
});
it('Throws when entry does not exist if throwIfNoEntry is true', () => {
expect(() => vol.lstatSync('/foo', { throwIfNoEntry: true })).toThrow();
});
it('Throws when entry does not exist if throwIfNoEntry is not specified', () => {
expect(() => vol.lstatSync('/foo')).toThrow();
});
it('Throws when entry does not exist if throwIfNoEntry is explicitly undefined', () => {
expect(() => vol.lstatSync('/foo', { throwIfNoEntry: undefined })).toThrow();
});
});
describe('.lstatSync(path)', () => {
const vol = new Volume();
const dojo = vol.root.createChild('dojo.js');
Expand Down Expand Up @@ -754,7 +788,7 @@ describe('volume', () => {
expect(stats.isFile()).toBe(true);
expect(stats.size).toBe(data.length);
});
it('Modification new write', done => {
it('Modification new write', (done) => {
vol.writeFileSync('/mtime.txt', '1');
const stats1 = vol.statSync('/mtime.txt');
setTimeout(() => {
Expand Down Expand Up @@ -852,10 +886,10 @@ describe('volume', () => {
});
});
describe('.readlink(path[, options], callback)', () => {
it('Simple symbolic link to one file', done => {
it('Simple symbolic link to one file', (done) => {
const vol = new Volume();
vol.writeFileSync('/1', '123');
vol.symlink('/1', '/2', err => {
vol.symlink('/1', '/2', (err) => {
vol.readlink('/2', (err, res) => {
expect(res).toBe('/1');
done();
Expand All @@ -873,7 +907,7 @@ describe('volume', () => {
describe('.fsync(fd, callback)', () => {
const vol = new Volume();
const fd = vol.openSync('/lol', 'w');
it('Executes without crashing', done => {
it('Executes without crashing', (done) => {
vol.fsync(fd, done);
});
});
Expand Down Expand Up @@ -1005,7 +1039,7 @@ describe('volume', () => {
});
describe('.rmdir(path, callback)', () => {
xit('Remove single dir', () => {});
it('Async remove dir /dir1/dir2/dir3 recursively', done => {
it('Async remove dir /dir1/dir2/dir3 recursively', (done) => {
const vol = new Volume();
vol.mkdirSync('/dir1/dir2/dir3', { recursive: true });
vol.rmdir('/dir1', { recursive: true }, () => {
Expand All @@ -1015,7 +1049,7 @@ describe('volume', () => {
});
});
describe('.watchFile(path[, options], listener)', () => {
it('Calls listener on .writeFile', done => {
it('Calls listener on .writeFile', (done) => {
const vol = new Volume();
vol.writeFileSync('/lol.txt', '1');
setTimeout(() => {
Expand All @@ -1031,7 +1065,7 @@ describe('volume', () => {
xit('Multiple listeners for one file', () => {});
});
describe('.unwatchFile(path[, listener])', () => {
it('Stops watching before .writeFile', done => {
it('Stops watching before .writeFile', (done) => {
const vol = new Volume();
vol.writeFileSync('/lol.txt', '1');
setTimeout(() => {
Expand Down
3 changes: 2 additions & 1 deletion src/promises.ts
Expand Up @@ -14,6 +14,7 @@ import {
IWriteFileOptions,
IStatOptions,
IRmOptions,
IFStatOptions,
} from './volume';
import Stats from './Stats';
import Dirent from './Dirent';
Expand Down Expand Up @@ -134,7 +135,7 @@ export class FileHandle implements IFileHandle {
return promisify(this.vol, 'readFile')(this.fd, options);
}

stat(options?: IStatOptions): Promise<Stats> {
stat(options?: IFStatOptions): Promise<Stats> {
return promisify(this.vol, 'fstat')(this.fd, options);
}

Expand Down

0 comments on commit 23aa210

Please sign in to comment.