51 lines
2.0 KiB
TypeScript
51 lines
2.0 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import nodePath from 'node:path';
|
|
import os from 'node:os';
|
|
import { promises as fs } from 'node:fs';
|
|
import { assertInsideVault, sanitizeName, dedupeName, IllegalPathError } from '../../apps/desktop/src/main/safe/safe-path';
|
|
|
|
describe('sanitizeName (FR-F13)', () => {
|
|
it('替换非法字符为下划线', () => {
|
|
expect(sanitizeName('a:b<c>d?')).toBe('a_b_c_d_');
|
|
});
|
|
it('空名回退为未命名', () => {
|
|
expect(sanitizeName(' ')).toBe('未命名');
|
|
expect(sanitizeName('')).toBe('未命名');
|
|
});
|
|
it('保留正常名', () => {
|
|
expect(sanitizeName('我的笔记')).toBe('我的笔记');
|
|
});
|
|
});
|
|
|
|
describe('assertInsideVault (FR-F15)', () => {
|
|
const root = nodePath.join(os.tmpdir(), 'dsh-vault-test');
|
|
it('接受库内相对路径', () => {
|
|
expect(assertInsideVault(root, 'a/b.md')).toBe(nodePath.resolve(root, 'a/b.md'));
|
|
});
|
|
it('拒绝绝对路径', () => {
|
|
expect(() => assertInsideVault(root, nodePath.resolve(root, 'x'))).toThrow(IllegalPathError);
|
|
});
|
|
it('拒绝盘符前缀', () => {
|
|
expect(() => assertInsideVault(root, 'C:/x')).toThrow(IllegalPathError);
|
|
});
|
|
it('拒绝 .. 穿越', () => {
|
|
expect(() => assertInsideVault(root, '../escape.md')).toThrow(IllegalPathError);
|
|
expect(() => assertInsideVault(root, 'a/../../escape.md')).toThrow(IllegalPathError);
|
|
});
|
|
});
|
|
|
|
describe('dedupeName (FR-F14)', () => {
|
|
const root = nodePath.join(os.tmpdir(), 'dsh-vault-dedupe');
|
|
it('重名追加序号', async () => {
|
|
await fs.rm(root, { recursive: true, force: true });
|
|
await fs.mkdir(nodePath.join(root, 'd'), { recursive: true });
|
|
await fs.writeFile(nodePath.join(root, 'd', 'n.md'), '');
|
|
expect(await dedupeName(root, 'd', 'n.md')).toBe('n-1.md');
|
|
await fs.writeFile(nodePath.join(root, 'd', 'n-1.md'), '');
|
|
expect(await dedupeName(root, 'd', 'n.md')).toBe('n-2.md');
|
|
});
|
|
it('不冲突时原样返回', async () => {
|
|
expect(await dedupeName(root, 'd', 'unique.md')).toBe('unique.md');
|
|
});
|
|
});
|