Skip to content

Commit ccf704b

Browse files
committed
feat(dirinfo): added DirInfo class for managing files in memory
Also added the following: - Unit tests for DirInfo. - Optimized the implementation of FileInfo and add Unit test.
1 parent c158cab commit ccf704b

File tree

11 files changed

+446
-36
lines changed

11 files changed

+446
-36
lines changed

__tests__/config.spec.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
import { describe, it, expect } from 'vitest';
22
import { Config, defaultRepo } from '@/Config';
3-
import { useEnvVar } from '@/utils';
4-
import { getPathnameMapByNameAndExtList } from './helper';
3+
import {
4+
getPathnameMapByNameAndExtList,
5+
getTempCacheDirFn,
6+
autoClearCacheDir,
7+
} from './helper';
58
import { nanoid } from 'nanoid';
69

710
import type { Repository } from '@/Source';
811

9-
const { __dir_cache_test } = useEnvVar();
12+
const getTempCacheDir = getTempCacheDirFn('config');
1013

1114
describe('Source', () => {
15+
autoClearCacheDir('config');
1216
let pathnameMap = {
1317
emptyYml: '',
1418
hasNotSourceYml: '',
@@ -102,9 +106,9 @@ describe('Source', () => {
102106
});
103107

104108
it('should generate file after save() called', () => {
105-
const configPathname = path.resolve(
106-
__dir_cache_test,
107-
`./config/${nanoid()}Config.yml`,
109+
const configPathname = path.join(
110+
getTempCacheDir(),
111+
`/${nanoid()}Config.yml`,
108112
);
109113

110114
expect(fs.existsSync(configPathname)).not.toBeTruthy();

__tests__/dir.spec.ts

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
import { DirInfo } from '@/Dir';
2+
import { describe, expect, it } from 'vitest';
3+
import { autoClearCacheDir, getTempCacheDirFn } from './helper';
4+
import fs from 'fs-extra';
5+
import { FileInfo } from '@/File';
6+
7+
const getTempCacheDir = getTempCacheDirFn('dir');
8+
9+
describe('Build DirInfo', () => {
10+
autoClearCacheDir('dir');
11+
12+
it('Should work correctly when using unexist paths', () => {
13+
const pathname = getTempCacheDir();
14+
expect(() => DirInfo.build({ pathname })).not.toThrowError();
15+
});
16+
17+
it('Should work correctly when using exist paths', () => {
18+
const pathname = getTempCacheDir(true);
19+
fs.ensureDirSync(path.join(pathname, '/subDir'));
20+
fs.ensureFileSync(path.join(pathname, '/subDir/content.txt'));
21+
expect(() => DirInfo.build({ pathname })).not.toThrowError();
22+
});
23+
24+
it('Should work correctly with cache', () => {
25+
const pathname = getTempCacheDir();
26+
const infoA = DirInfo.build({ pathname });
27+
const infoB = DirInfo.build({ pathname });
28+
expect(infoA === infoB).toBeTruthy();
29+
});
30+
});
31+
32+
describe('Get or check item in DirInfo', () => {
33+
autoClearCacheDir('dir');
34+
35+
it('Should has not un-ensure file or dir', () => {
36+
const pathname = getTempCacheDir();
37+
const dir = DirInfo.build({ pathname });
38+
39+
expect(dir.exist).not.toBeTruthy();
40+
expect(dir.has('/path/no/exist')).not.toBeTruthy();
41+
expect(dir.get('/path/no/exist')).not.toBeTruthy();
42+
});
43+
44+
it('Should has exist file or dir', () => {
45+
const pathname = getTempCacheDir(true);
46+
fs.ensureDirSync(path.join(pathname, '/path/exist'));
47+
const dir = DirInfo.build({ pathname });
48+
49+
expect(dir.exist).toBeTruthy();
50+
expect(dir.has('/path/exist')).toBeTruthy();
51+
expect(dir.get('/path/exist')).toBeTruthy();
52+
});
53+
54+
it('Should get item with correct type', () => {
55+
const pathname = getTempCacheDir();
56+
const dir = DirInfo.build({ pathname });
57+
58+
dir.ensure('/dir', { type: 'dir' });
59+
expect(dir.get('/dir') instanceof DirInfo).toBeTruthy();
60+
61+
dir.ensure('/file', { type: 'file' });
62+
expect(dir.get('/file') instanceof FileInfo).toBeTruthy();
63+
});
64+
});
65+
66+
describe('Ensure item in DirInfo', () => {
67+
autoClearCacheDir('dir');
68+
69+
it('Should ensure virtual file or dir', () => {
70+
const pathname = getTempCacheDir();
71+
const dir = DirInfo.build({ pathname });
72+
const subPathname = '/path/no/exist';
73+
74+
dir.ensure(subPathname, { type: 'dir' });
75+
76+
expect(dir.has(subPathname)).toBeTruthy();
77+
expect(dir.get(subPathname)?.exist).not.toBeTruthy();
78+
});
79+
80+
it('Should get error when ensure duplicate name at the end', () => {
81+
const pathname = getTempCacheDir();
82+
const dir = DirInfo.build({ pathname });
83+
84+
dir.ensure('/dir', { type: 'dir' });
85+
expect(() => dir.ensure('/dir', { type: 'file' })).toThrowError();
86+
});
87+
88+
it('Should work correctly when ensure same item at the end', () => {
89+
const pathname = getTempCacheDir();
90+
const dir = DirInfo.build({ pathname });
91+
92+
dir.ensure('/dir', { type: 'dir' });
93+
expect(() => dir.ensure('/dir', { type: 'dir' })).not.toThrowError();
94+
});
95+
96+
it('Should get error when there is an existing file before the end', () => {
97+
const pathname = getTempCacheDir();
98+
const dir = DirInfo.build({ pathname });
99+
100+
dir.ensure('/file', { type: 'file' });
101+
expect(() => dir.ensure('/file/file', { type: 'file' })).toThrowError();
102+
});
103+
104+
it('Should work correctly when there is an existing folder before the end', () => {
105+
const pathname = getTempCacheDir();
106+
const dir = DirInfo.build({ pathname });
107+
108+
dir.ensure('/dir', { type: 'dir' });
109+
expect(() => dir.ensure('/dir/file', { type: 'file' })).not.toThrowError();
110+
});
111+
});

__tests__/file.spec.ts

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,63 +12,73 @@ let pathnameMap = {
1212
somethingFile: '',
1313
} as const;
1414

15-
pathnameMap = getPathnameMapByNameAndExtList(['empty', 'something'], ['json', 'yml', 'file'], 'file') as typeof pathnameMap;
15+
pathnameMap = getPathnameMapByNameAndExtList(
16+
['empty', 'something'],
17+
['json', 'yml', 'file'],
18+
'file',
19+
) as typeof pathnameMap;
1620

1721
describe('FileInfo', () => {
1822
it('should throw error when pathname is illegal', () => {
19-
expect(() => new FileInfo('./illegal.file')).toThrowError();
23+
expect(() => FileInfo.build({ pathname: './illegal.file' })).toThrowError();
2024
});
2125

2226
it('should has empty content and jsonObj when file is empty', () => {
23-
let file = new FileInfo(pathnameMap.emptyJson);
27+
let file = FileInfo.build({ pathname: pathnameMap.emptyJson });
2428
expect(file.getContent()).not.toBeTruthy();
2529
expect(file.getJson()).not.toBeTruthy();
2630

27-
file = new FileInfo(pathnameMap.emptyYml);
31+
file = FileInfo.build({ pathname: pathnameMap.emptyYml });
2832
expect(file.getContent()).not.toBeTruthy();
2933
expect(file.getJson()).not.toBeTruthy();
3034

31-
file = new FileInfo(pathnameMap.emptyFile);
35+
file = FileInfo.build({ pathname: pathnameMap.emptyFile });
3236
expect(file.getContent()).not.toBeTruthy();
3337
expect(file.getJson()).not.toBeTruthy();
3438
});
3539

3640
it('should has content when file has content', () => {
37-
let file = new FileInfo(pathnameMap.somethingJson);
41+
let file = FileInfo.build({ pathname: pathnameMap.somethingJson });
3842
expect(file.getContent()).toBe('{ "something": "something" }\n');
3943

40-
file = new FileInfo(pathnameMap.somethingYml);
44+
file = FileInfo.build({ pathname: pathnameMap.somethingYml });
4145
expect(file.getContent()).toBe("something: 'something'\n");
4246

43-
file = new FileInfo(pathnameMap.somethingFile);
47+
file = FileInfo.build({ pathname: pathnameMap.somethingFile });
4448
expect(file.getContent()).toBe('something\n');
4549
});
4650

4751
it('should has jsonObj when .yml and .json are not empty', () => {
48-
let file = new FileInfo(pathnameMap.somethingJson);
52+
let file = FileInfo.build({ pathname: pathnameMap.somethingJson });
4953
expect(file.getJson()).toEqual({ something: 'something' });
5054

51-
file = new FileInfo(pathnameMap.somethingYml);
55+
file = FileInfo.build({ pathname: pathnameMap.somethingYml });
5256
expect(file.getJson()).toEqual({ something: 'something' });
5357
});
5458

5559
it('should has not jsonObj when not .yml and .json', () => {
56-
const file = new FileInfo(pathnameMap.somethingFile);
60+
const file = FileInfo.build({ pathname: pathnameMap.somethingFile });
5761
expect(file.getJson()).toBe(undefined);
5862
});
5963

6064
it('should update jsonObj when content update', () => {
61-
let file = new FileInfo(pathnameMap.somethingJson);
65+
let file = FileInfo.build({ pathname: pathnameMap.somethingJson });
6266
file.setContent('{ "something": "newSomething" }');
6367
expect(file.getJson()).toEqual({ something: 'newSomething' });
6468

65-
file = new FileInfo(pathnameMap.somethingYml);
69+
file = FileInfo.build({ pathname: pathnameMap.somethingYml });
6670
file.setContent("something: 'newSomething'");
6771
expect(file.getJson()).toEqual({ something: 'newSomething' });
6872
});
6973

7074
it('should has not content when file not exist', () => {
71-
const file = new FileInfo(path.resolve('unexist.file'));
75+
const file = FileInfo.build({ pathname: path.resolve('unexist.file') });
7276
expect(file.getContent()).toBeUndefined();
7377
});
78+
79+
it('should build with cache', () => {
80+
const fileA = FileInfo.build({ pathname: path.resolve('file') });
81+
const fileB = FileInfo.build({ pathname: path.resolve('file') });
82+
expect(fileA === fileB).toBeTruthy();
83+
});
7484
});

__tests__/helper.ts

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
import { TemplateSource } from '@/Source';
22
import path from 'path';
33
import { fileURLToPath } from 'url';
4+
import { useEnvVar } from '@/utils';
5+
import { nanoid } from 'nanoid';
6+
import { beforeAll, afterAll } from 'vitest';
7+
8+
const { __dir_cache_test } = useEnvVar();
49

510
export const getPathnameMapByNameAndExtList = (
611
nameList: string[],
@@ -32,11 +37,6 @@ export const getTestTemplateSource = async (name = 'default') =>
3237
repository: path.resolve(__dirname, './assets/source'),
3338
type: 'local',
3439
},
35-
{
36-
name: `${name}-remote`,
37-
repository: 'https://github.com/NoraH1to/setup-template-test.git',
38-
type: 'git',
39-
},
4040
],
4141
});
4242

@@ -50,3 +50,25 @@ export const templateSourcePathnameMap = getPathnameMapByNameAndExtList(
5050
[''],
5151
'source',
5252
);
53+
54+
export const getTempCacheDirFn = (pathname: string) => (ensure?: boolean) => {
55+
const target = path.join(__dir_cache_test, pathname, nanoid());
56+
ensure && fs.ensureDirSync(target);
57+
return target;
58+
};
59+
60+
export const clearCacheDir = (pathname?: string) => {
61+
pathname = path.join(__dir_cache_test, pathname);
62+
try {
63+
fs.readdirSync(pathname).forEach((name) =>
64+
fs.rmSync(path.join(pathname, name), { recursive: true }),
65+
);
66+
} catch {
67+
/* empty */
68+
}
69+
};
70+
71+
export const autoClearCacheDir = (pathname?: string) => {
72+
beforeAll(() => clearCacheDir(pathname));
73+
afterAll(() => clearCacheDir(pathname));
74+
};

__tests__/source.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@ describe('Template source', () => {
6666
it('should load correct template', async () => {
6767
const source = await getTestTemplateSource('default');
6868

69-
expect(source.baseSourceList.length).toBe(3);
70-
expect(source.injectSourceList.length).toBe(3);
69+
expect(source.baseSourceList.length).toBe(2);
70+
expect(source.injectSourceList.length).toBe(2);
7171

7272
expect(source.baseSourceMap['default/has-meta']).toBeTruthy();
7373
expect(source.baseSourceMap['default/has-not-meta']).toBeTruthy();

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
"tslib": "^2.4.1",
5757
"typescript": "^4.9.4",
5858
"typescript-transform-paths": "^3.4.6",
59+
"utility-types": "^3.10.0",
5960
"vitest": "^0.28.4"
6061
},
6162
"dependencies": {

pnpm-lock.yaml

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Config.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ export const defaultRepo = {
2121
export class Config extends FileInfo<{
2222
repository: { [key: string]: Repository };
2323
}> {
24-
constructor(pathname) {
25-
super(pathname);
24+
constructor(pathname: string) {
25+
super({ pathname });
2626
if (!this.jsonObj) this.jsonObj = { repository: defaultRepo };
2727
if (!this.jsonObj.repository) this.jsonObj.repository = defaultRepo;
2828
}

0 commit comments

Comments
 (0)