Skip to content

Commit

Permalink
feat: 🎸 add lstat() and fstat() methods
Browse files Browse the repository at this point in the history
  • Loading branch information
streamich committed Jun 20, 2023
1 parent 505a1d9 commit ce5dd5e
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 19 deletions.
47 changes: 29 additions & 18 deletions src/fsa-to-node/FsaNodeFs.ts
Expand Up @@ -300,15 +300,13 @@ export class FsaNodeFs implements FsCallbackApi, FsCommonObjects {
throw new Error('Not implemented');
}

lstat(path: misc.PathLike, callback: misc.TCallback<misc.IStats>): void;
lstat(path: misc.PathLike, options: opts.IStatOptions, callback: misc.TCallback<misc.IStats>): void;
lstat(
public readonly lstat: FsCallbackApi['lstat'] = (
path: misc.PathLike,
a: misc.TCallback<misc.IStats> | opts.IStatOptions,
b?: misc.TCallback<misc.IStats>,
): void {
throw new Error('Not implemented');
}
): void => {
this.stat(path, <any>a, <any>b);
};

public readonly stat: FsCallbackApi['stat'] = (
path: misc.PathLike,
Expand All @@ -320,24 +318,37 @@ export class FsaNodeFs implements FsCallbackApi, FsCommonObjects {
const [folder, name] = pathToLocation(filename);
(async () => {
const handle = await this.getFileOrDir(folder, name, 'stat');
let size: number = 0;
if (handle.kind === 'file') {
const file = <fsa.IFileSystemFileHandle>handle;
const fileData = await file.getFile();
size = fileData.size;
}
const stats = new FsaNodeStats(bigint, bigint ? BigInt(size) : size, handle);
return stats;
return await this.getHandleStats(bigint, handle);
})().then(
stats => callback(null, stats),
error => callback(error),
);
};

fstat(fd: number, callback: misc.TCallback<misc.IStats>): void;
fstat(fd: number, options: opts.IFStatOptions, callback: misc.TCallback<misc.IStats>): void;
fstat(fd: number, a: misc.TCallback<misc.IStats> | opts.IFStatOptions, b?: misc.TCallback<misc.IStats>): void {
throw new Error('Not implemented');
public readonly fstat: FsCallbackApi['fstat'] = (
fd: number,
a: misc.TCallback<misc.IStats> | opts.IStatOptions,
b?: misc.TCallback<misc.IStats>,
): void => {
const [{ bigint = false, throwIfNoEntry = true }, callback] = getStatOptsAndCb(a, b);
(async () => {
const openFile = await this.getFileByFd(fd, 'fstat');
return await this.getHandleStats(bigint, openFile.file);
})().then(
stats => callback(null, stats),
error => callback(error),
);
};

private async getHandleStats(bigint: boolean, handle: fsa.IFileSystemHandle): Promise<misc.IStats> {
let size: number = 0;
if (handle.kind === 'file') {
const file = <fsa.IFileSystemFileHandle>handle;
const fileData = await file.getFile();
size = fileData.size;
}
const stats = new FsaNodeStats(bigint, bigint ? BigInt(size) : size, handle);
return stats;
}

public readonly rename: FsCallbackApi['rename'] = (
Expand Down
47 changes: 46 additions & 1 deletion src/fsa-to-node/__tests__/FsaNodeFs.test.ts
@@ -1,7 +1,7 @@
import { IFsWithVolume, NestedDirectoryJSON, memfs } from '../..';
import { AMODE } from '../../consts/AMODE';
import { nodeToFsa } from '../../node-to-fsa';
import { IDirent } from '../../node/types/misc';
import { IDirent, IStats } from '../../node/types/misc';
import { FsaNodeFs } from '../FsaNodeFs';

const setup = (json: NestedDirectoryJSON | null = null, mode: 'read' | 'readwrite' = 'readwrite') => {
Expand Down Expand Up @@ -494,3 +494,48 @@ describe('.stat()', () => {
}
});
});

describe('.lstat()', () => {
test('can stat a file', async () => {
const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' });
const stats = await fs.promises.lstat('/folder/file');
expect(stats.isFile()).toBe(true);
});

test('can retrieve file size', async () => {
const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' });
const stats = await fs.promises.lstat('/folder/file');
expect(stats.size).toBe(4);
});

test('can stat a folder', async () => {
const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' });
const stats = await fs.promises.lstat('/folder');
expect(stats.isFile()).toBe(false);
expect(stats.isDirectory()).toBe(true);
});

test('throws on non-existing path', async () => {
const { fs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' });
try {
await fs.promises.lstat('/folder/abc');
throw new Error('should not be here');
} catch (error) {
expect(error.code).toBe('ENOENT');
}
});
});

describe('.fstat()', () => {
test('can stat a file', async () => {
const { fs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' });
const handle = await fs.promises.open('/folder/file', 'r');
const stats = await new Promise<IStats>((resolve, reject) => {
fs.fstat(handle.fd, (error, stats) => {
if (error) reject(error);
else resolve(stats!);
});
});
expect(stats.isFile()).toBe(true);
});
});

0 comments on commit ce5dd5e

Please sign in to comment.