import { describe, it, expect, afterEach } from 'vitest'; import nodePath from 'node:path'; import os from 'node:os'; import { promises as fs } from 'node:fs'; import { writeFileAtomic, withFileLock } from '../../apps/desktop/src/main/safe/atomic-write'; const dir = nodePath.join(os.tmpdir(), 'dsh-atomic-test'); afterEach(async () => { await fs.rm(dir, { recursive: true, force: true }); }); describe('writeFileAtomic (FR-S5)', () => { it('写入内容并回读一致', async () => { const p = nodePath.join(dir, 'a.md'); await writeFileAtomic(p, '# 标题\n内容'); expect(await fs.readFile(p, 'utf8')).toBe('# 标题\n内容'); }); it('不残留临时文件', async () => { const p = nodePath.join(dir, 'b.md'); await writeFileAtomic(p, 'x'); const files = await fs.readdir(dir); expect(files).toEqual(['b.md']); }); it('覆盖已有文件', async () => { const p = nodePath.join(dir, 'c.md'); await writeFileAtomic(p, 'old'); await writeFileAtomic(p, 'new'); expect(await fs.readFile(p, 'utf8')).toBe('new'); }); }); describe('withFileLock 并发安全', () => { it('同文件请求串行执行', async () => { const p = nodePath.join(dir, 'lock.md'); const order: number[] = []; const t = (id: number, delay: number) => withFileLock(p, async () => { order.push(id); await new Promise(r => setTimeout(r, delay)); }); await Promise.all([t(1, 20), t(2, 1), t(3, 1)]); expect(order).toEqual([1, 2, 3]); }); });