Skip to content

Commit

Permalink
test: fs 模块补充单元测试
Browse files Browse the repository at this point in the history
  • Loading branch information
renxia committed Feb 27, 2025
1 parent d78fa28 commit 6ee3050
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 25 deletions.
20 changes: 12 additions & 8 deletions eslint.config.cjs → eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
const path = require('path');
const eslint = require('@eslint/js');
const tseslint = require('typescript-eslint');
// import path from 'path';
import eslint from '@eslint/js';
// import globals from 'globals';
import tseslint from 'typescript-eslint';
import eslintPluginUnicorn from 'eslint-plugin-unicorn';
import eslintPluginJest from 'eslint-plugin-jest';
import eslintPluginPrettier from 'eslint-plugin-prettier';

module.exports = [
export default [
...tseslint.config(
eslint.configs.recommended,
...tseslint.configs.recommendedTypeChecked,
{
languageOptions: {
parserOptions: {
tsconfigRootDir: path.resolve(__dirname),
// tsconfigRootDir: path.resolve(__dirname),
project: './tsconfig.eslint.json',
projectFolderIgnoreList: ['**/node_modules/**', '**/dist/**', '**/dist-admin/**'],
warnOnUnsupportedTypeScriptVersion: false,
Expand All @@ -24,9 +28,9 @@ module.exports = [
reportUnusedDisableDirectives: false,
},
plugins: {
prettier: require('eslint-plugin-prettier'),
unicorn: require('eslint-plugin-unicorn'),
jest: require('eslint-plugin-jest'),
prettier: eslintPluginPrettier,
unicorn: eslintPluginUnicorn,
jest: eslintPluginJest,
},
ignores: ['**/node_modules/**', 'dist/**', 'cjs/**', 'esm/**', 'docs/**', 'mock/**', '**/*.js', '**/*.d.ts'],
rules: {
Expand Down
22 changes: 11 additions & 11 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,36 +62,36 @@
"tslib": "^2.8.1"
},
"devDependencies": {
"@eslint/js": "^9.18.0",
"@eslint/js": "^9.21.0",
"@iarna/toml": "^2.2.5",
"@jest/core": "^29",
"@jest/types": "^29",
"@lzwme/fed-lint-helper": "^2.6.6",
"@types/eslint": "^9.6.1",
"@types/jest": "^29.5.14",
"@types/micromatch": "^4.0.9",
"@types/node": "^22.10.7",
"@typescript-eslint/eslint-plugin": "^8.21.0",
"@typescript-eslint/parser": "^8.21.0",
"@types/node": "^22.13.5",
"@typescript-eslint/eslint-plugin": "^8.25.0",
"@typescript-eslint/parser": "^8.25.0",
"compressing": "^1.10.1",
"eslint": "^9.18.0",
"eslint-config-prettier": "^10.0.1",
"eslint": "^9.21.0",
"eslint-config-prettier": "^10.0.2",
"eslint-plugin-jest": "^28.11.0",
"eslint-plugin-prettier": "^5.2.3",
"eslint-plugin-unicorn": "^56.0.1",
"eslint-plugin-unicorn": "^57.0.0",
"husky": "^9.1.7",
"jest": "^29.7.0",
"json5": "^2.2.3",
"micromatch": "^4.0.8",
"npm-run-all": "^4.1.5",
"prettier": "^3.4.2",
"prettier": "^3.5.2",
"standard-version": "^9.5.0",
"ts-jest": "^29.2.5",
"ts-jest": "^29.2.6",
"ts-jest-resolver": "^2.0.1",
"ts-node": "^10.9.2",
"typedoc": "^0.27.6",
"typedoc": "^0.27.9",
"typescript": "^5.7.3",
"typescript-eslint": "^8.21.0",
"typescript-eslint": "^8.25.0",
"windows-process-tree": "^0.4.0"
},
"peerDependencies": {
Expand Down
132 changes: 132 additions & 0 deletions src/node/fs.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import { resolve } from 'node:path';
import { fs } from './fs-system';
import { rmrf, mkdirp, outputFile, outputFileSync, readJsonFile, readJsonFileSync, copyDir, rmEmptyDir, findFiles } from './fs';

describe('fs utils', () => {
const testDir = resolve(__dirname, '.test-fs');
const testFile = resolve(testDir, 'test.txt');
const testJson = resolve(testDir, 'test.json');

beforeEach(() => {
rmrf(testDir);
mkdirp(testDir);
});

afterAll(() => {
rmrf(testDir);
});

describe('rmrf', () => {
it('should remove file', () => {
outputFileSync(testFile, 'test');
expect(fs.existsSync(testFile)).toBe(true);
rmrf(testFile);
expect(fs.existsSync(testFile)).toBe(false);
});

it('should remove directory recursively', () => {
const subDir = resolve(testDir, 'sub');
const subFile = resolve(subDir, 'test.txt');
mkdirp(subDir);
outputFileSync(subFile, 'test');
expect(fs.existsSync(subDir)).toBe(true);
rmrf(testDir);
expect(fs.existsSync(testDir)).toBe(false);
});
});

describe('mkdirp', () => {
it('should create directory recursively', () => {
const deepDir = resolve(testDir, 'a/b/c');
expect(fs.existsSync(deepDir)).toBe(false);
mkdirp(deepDir);
expect(fs.existsSync(deepDir)).toBe(true);
});

it('should return false if path exists as file', () => {
outputFileSync(testFile, 'test');
expect(mkdirp(testFile)).toBe(false);
});
});

describe('outputFile', () => {
it('should create file with directories', async () => {
const deepFile = resolve(testDir, 'a/b/c/test.txt');
await outputFile(deepFile, 'test');
expect(fs.existsSync(deepFile)).toBe(true);
expect(fs.readFileSync(deepFile, 'utf8')).toBe('test');
});
});

describe('readJsonFile', () => {
const testData = { test: 'data' };

beforeEach(() => {
outputFileSync(testJson, JSON.stringify(testData));
});

it('should read JSON file async', async () => {
const data = await readJsonFile(testJson);
expect(data).toEqual(testData);
});

it('should read JSON file sync', () => {
const data = readJsonFileSync(testJson);
expect(data).toEqual(testData);
});
});

describe('copyDir', () => {
const srcDir = resolve(testDir, 'src');
const destDir = resolve(testDir, 'dest');

beforeEach(() => {
mkdirp(srcDir);
outputFileSync(resolve(srcDir, 'test.txt'), 'test');
outputFileSync(resolve(srcDir, 'test.json'), '{"test":"data"}');
});

it('should copy directory with filter', () => {
copyDir(srcDir, destDir, (f, s) => s.isDirectory() || !f.endsWith('.json'));
expect(fs.existsSync(resolve(destDir, 'test.txt'))).toBe(true);
expect(fs.existsSync(resolve(destDir, 'test.json'))).toBe(false);
});
});

describe('findFiles', () => {
beforeEach(() => {
const deepDir = resolve(testDir, 'findFiles/b/c');
outputFileSync(resolve(testDir, 'test1.txt'), 'test1');
outputFileSync(resolve(deepDir, 'test2.txt'), 'test2');
});

it('should find files with validate function', () => {
const files = findFiles(resolve(testDir));
expect(files.length).toBe(2);
expect(files.every(f => f.endsWith('.txt'))).toBe(true);
});

it('should respect file limit', () => {
const files = findFiles(testDir, undefined, 1);
expect(files.length).toBe(1);
});
});

describe('rmEmptyDir', () => {
it('should remove empty directories', () => {
const deepDir = resolve(testDir, 'rmEmptyDir/b/c');
mkdirp(deepDir);
expect(fs.existsSync(testDir)).toBe(true); // root dir remains
rmEmptyDir(testDir);
expect(fs.existsSync(deepDir)).toBe(false);
});

it('should not remove non-empty directories', () => {
const deepDir = resolve(testDir, 'a/b/c');
mkdirp(deepDir);
outputFileSync(resolve(deepDir, 'test.txt'), 'test');
rmEmptyDir(testDir);
expect(fs.existsSync(deepDir)).toBe(true);
});
});
});
11 changes: 5 additions & 6 deletions src/node/fs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export async function rmrfAsync(filepath: string): Promise<void> {
* 创建一个深度的目录
*/
export function mkdirp(dirpath: string) {
if (fs.existsSync(dirpath)) return true;
if (fs.existsSync(dirpath)) return false;

try {
fs.mkdirSync(dirpath, { recursive: true });
Expand All @@ -45,11 +45,9 @@ export function mkdirp(dirpath: string) {
for (let i = 0; i < list.length; i++) {
const p = list.slice(0, i + 1).join(sep);
if (p === '') continue;
if (fs.existsSync(p)) {
if (!fs.statSync(p).isDirectory()) return false;
continue;
if (!fs.existsSync(p) || !fs.statSync(p).isDirectory()) {
fs.mkdirSync(p);
}
fs.mkdirSync(p);
}
}
return true;
Expand Down Expand Up @@ -95,7 +93,8 @@ export function copyDir(src: string, dest: string, filter: (filepath: string, st
}

try {
fs.promises.copyFile(filepath, outpath);
mkdirp(dest);
fs.copyFileSync(filepath, outpath);
} catch {
fs.createReadStream(filepath).pipe(fs.createWriteStream(outpath));
}
Expand Down

0 comments on commit 6ee3050

Please sign in to comment.