import { describe, it, expect, beforeEach, afterEach } from 'vitest'; import nodePath from 'node:path'; import os from 'node:os'; import { promises as fs } from 'node:fs'; import { FileService } from '../../apps/desktop/src/main/services/file-service'; import { SearchService } from '../../apps/desktop/src/main/services/search-service'; const tmp = nodePath.join(os.tmpdir(), 'dsh-search-test'); beforeEach(async () => { await fs.rm(tmp, { recursive: true, force: true }); await fs.mkdir(tmp, { recursive: true }); }); afterEach(async () => { await fs.rm(tmp, { recursive: true, force: true }); }); async function mk(root: string) { const fs2 = new FileService(root); const ss = new SearchService(root, fs2); return { fs2, ss }; } describe('M4 SearchService (FR-R)', () => { it('全文搜索命中标题与正文,返回摘要', async () => { const { fs2, ss } = await mk(tmp); await fs2.writeDoc({ path: 'a.md', meta: { title: 'Markdown 指南' }, body: '介绍 Markdown 的用法\n关键字段落' }); const hits = await ss.search('关键字'); expect(hits.length).toBe(1); expect(hits[0].title).toBe('Markdown 指南'); expect(hits[0].snippet).toContain('关键字'); }); it('大小写不敏感', async () => { const { fs2, ss } = await mk(tmp); await fs2.writeDoc({ path: 'b.md', meta: {}, body: 'Hello World' }); expect((await ss.search('hello')).length).toBe(1); expect((await ss.search('HELLO')).length).toBe(1); }); it('空查询返回空', async () => { const { fs2, ss } = await mk(tmp); await fs2.writeDoc({ path: 'c.md', meta: {}, body: 'x' }); expect(await ss.search('')).toEqual([]); expect(await ss.search(' ')).toEqual([]); }); it('标签汇总:按字母排序、计数', async () => { const { fs2, ss } = await mk(tmp); await fs2.writeDoc({ path: 'a.md', meta: { tags: ['z', 'a'] }, body: '1' }); await fs2.writeDoc({ path: 'b.md', meta: { tags: ['a'] }, body: '2' }); const stats = await ss.tagStats(); expect(stats.map(s => s.tag)).toEqual(['a', 'z']); expect(stats.find(s => s.tag === 'a')?.count).toBe(2); expect(stats.find(s => s.tag === 'z')?.count).toBe(1); }); it('搜索结果上限 100', async () => { const { fs2, ss } = await mk(tmp); for (let i = 0; i < 120; i++) await fs2.writeDoc({ path: `d${i}.md`, meta: {}, body: 'common' }); const hits = await ss.search('common'); expect(hits.length).toBeLessThanOrEqual(100); }); });