feat(performance): Add async utility functions and filesystem utilities
- Implemented async utilities including delay, retryWithBackoff, withTimeout, parallelLimit, debounceAsync, AsyncMutex, and CircuitBreaker. - Created tests for async utilities to ensure functionality and reliability. - Developed AsyncFileSystem class with methods for file and directory operations, including ensureDir, readFile, writeFile, remove, and more. - Added tests for filesystem utilities to validate file operations and error handling.
This commit is contained in:
185
test/core/utils/test.fs-utils.ts
Normal file
185
test/core/utils/test.fs-utils.ts
Normal file
@@ -0,0 +1,185 @@
|
||||
import { tap, expect } from '@git.zone/tstest/tapbundle';
|
||||
import * as path from 'path';
|
||||
import { AsyncFileSystem } from '../../../ts/core/utils/fs-utils.js';
|
||||
|
||||
// Use a temporary directory for tests
|
||||
const testDir = path.join(process.cwd(), '.nogit', 'test-fs-utils');
|
||||
const testFile = path.join(testDir, 'test.txt');
|
||||
const testJsonFile = path.join(testDir, 'test.json');
|
||||
|
||||
tap.test('should create and check directory existence', async () => {
|
||||
// Ensure directory
|
||||
await AsyncFileSystem.ensureDir(testDir);
|
||||
|
||||
// Check it exists
|
||||
const exists = await AsyncFileSystem.exists(testDir);
|
||||
expect(exists).toBeTrue();
|
||||
|
||||
// Check it's a directory
|
||||
const isDir = await AsyncFileSystem.isDirectory(testDir);
|
||||
expect(isDir).toBeTrue();
|
||||
});
|
||||
|
||||
tap.test('should write and read text files', async () => {
|
||||
const testContent = 'Hello, async filesystem!';
|
||||
|
||||
// Write file
|
||||
await AsyncFileSystem.writeFile(testFile, testContent);
|
||||
|
||||
// Check file exists
|
||||
const exists = await AsyncFileSystem.exists(testFile);
|
||||
expect(exists).toBeTrue();
|
||||
|
||||
// Read file
|
||||
const content = await AsyncFileSystem.readFile(testFile);
|
||||
expect(content).toEqual(testContent);
|
||||
|
||||
// Check it's a file
|
||||
const isFile = await AsyncFileSystem.isFile(testFile);
|
||||
expect(isFile).toBeTrue();
|
||||
});
|
||||
|
||||
tap.test('should write and read JSON files', async () => {
|
||||
const testData = {
|
||||
name: 'Test',
|
||||
value: 42,
|
||||
nested: {
|
||||
array: [1, 2, 3]
|
||||
}
|
||||
};
|
||||
|
||||
// Write JSON
|
||||
await AsyncFileSystem.writeJSON(testJsonFile, testData);
|
||||
|
||||
// Read JSON
|
||||
const readData = await AsyncFileSystem.readJSON(testJsonFile);
|
||||
expect(readData).toEqual(testData);
|
||||
});
|
||||
|
||||
tap.test('should copy files', async () => {
|
||||
const copyFile = path.join(testDir, 'copy.txt');
|
||||
|
||||
// Copy file
|
||||
await AsyncFileSystem.copyFile(testFile, copyFile);
|
||||
|
||||
// Check copy exists
|
||||
const exists = await AsyncFileSystem.exists(copyFile);
|
||||
expect(exists).toBeTrue();
|
||||
|
||||
// Check content matches
|
||||
const content = await AsyncFileSystem.readFile(copyFile);
|
||||
const originalContent = await AsyncFileSystem.readFile(testFile);
|
||||
expect(content).toEqual(originalContent);
|
||||
});
|
||||
|
||||
tap.test('should move files', async () => {
|
||||
const moveFile = path.join(testDir, 'moved.txt');
|
||||
const copyFile = path.join(testDir, 'copy.txt');
|
||||
|
||||
// Move file
|
||||
await AsyncFileSystem.moveFile(copyFile, moveFile);
|
||||
|
||||
// Check moved file exists
|
||||
const movedExists = await AsyncFileSystem.exists(moveFile);
|
||||
expect(movedExists).toBeTrue();
|
||||
|
||||
// Check original doesn't exist
|
||||
const originalExists = await AsyncFileSystem.exists(copyFile);
|
||||
expect(originalExists).toBeFalse();
|
||||
});
|
||||
|
||||
tap.test('should list files in directory', async () => {
|
||||
const files = await AsyncFileSystem.listFiles(testDir);
|
||||
|
||||
expect(files).toContain('test.txt');
|
||||
expect(files).toContain('test.json');
|
||||
expect(files).toContain('moved.txt');
|
||||
});
|
||||
|
||||
tap.test('should list files with full paths', async () => {
|
||||
const files = await AsyncFileSystem.listFilesFullPath(testDir);
|
||||
|
||||
const fileNames = files.map(f => path.basename(f));
|
||||
expect(fileNames).toContain('test.txt');
|
||||
expect(fileNames).toContain('test.json');
|
||||
|
||||
// All paths should be absolute
|
||||
files.forEach(file => {
|
||||
expect(path.isAbsolute(file)).toBeTrue();
|
||||
});
|
||||
});
|
||||
|
||||
tap.test('should get file stats', async () => {
|
||||
const stats = await AsyncFileSystem.getStats(testFile);
|
||||
|
||||
expect(stats).not.toBeNull();
|
||||
expect(stats?.isFile()).toBeTrue();
|
||||
expect(stats?.size).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
tap.test('should handle non-existent files gracefully', async () => {
|
||||
const nonExistent = path.join(testDir, 'does-not-exist.txt');
|
||||
|
||||
// Check existence
|
||||
const exists = await AsyncFileSystem.exists(nonExistent);
|
||||
expect(exists).toBeFalse();
|
||||
|
||||
// Get stats should return null
|
||||
const stats = await AsyncFileSystem.getStats(nonExistent);
|
||||
expect(stats).toBeNull();
|
||||
|
||||
// Remove should not throw
|
||||
await AsyncFileSystem.remove(nonExistent);
|
||||
});
|
||||
|
||||
tap.test('should remove files', async () => {
|
||||
// Remove a file
|
||||
await AsyncFileSystem.remove(testFile);
|
||||
|
||||
// Check it's gone
|
||||
const exists = await AsyncFileSystem.exists(testFile);
|
||||
expect(exists).toBeFalse();
|
||||
});
|
||||
|
||||
tap.test('should ensure file exists', async () => {
|
||||
const ensureFile = path.join(testDir, 'ensure.txt');
|
||||
|
||||
// Ensure file
|
||||
await AsyncFileSystem.ensureFile(ensureFile);
|
||||
|
||||
// Check it exists
|
||||
const exists = await AsyncFileSystem.exists(ensureFile);
|
||||
expect(exists).toBeTrue();
|
||||
|
||||
// Check it's empty
|
||||
const content = await AsyncFileSystem.readFile(ensureFile);
|
||||
expect(content).toEqual('');
|
||||
});
|
||||
|
||||
tap.test('should recursively list files', async () => {
|
||||
// Create subdirectory with file
|
||||
const subDir = path.join(testDir, 'subdir');
|
||||
const subFile = path.join(subDir, 'nested.txt');
|
||||
|
||||
await AsyncFileSystem.ensureDir(subDir);
|
||||
await AsyncFileSystem.writeFile(subFile, 'nested content');
|
||||
|
||||
// List recursively
|
||||
const files = await AsyncFileSystem.listFilesRecursive(testDir);
|
||||
|
||||
// Should include files from subdirectory
|
||||
const fileNames = files.map(f => path.relative(testDir, f));
|
||||
expect(fileNames).toContain('test.json');
|
||||
expect(fileNames).toContain(path.join('subdir', 'nested.txt'));
|
||||
});
|
||||
|
||||
tap.test('should clean up test directory', async () => {
|
||||
// Remove entire test directory
|
||||
await AsyncFileSystem.removeDir(testDir);
|
||||
|
||||
// Check it's gone
|
||||
const exists = await AsyncFileSystem.exists(testDir);
|
||||
expect(exists).toBeFalse();
|
||||
});
|
||||
|
||||
tap.start();
|
Reference in New Issue
Block a user