import { describe, it, expect, beforeEach, afterEach } from 'vitest' import { DatabaseSync } from 'node:sqlite' import { migrate } from '../../src/main/db/migrate' import { VolumeRepository } from '../../src/main/db/repositories/volume.repo' import { ChapterRepository } from '../../src/main/db/repositories/chapter.repo' import { ftsSync } from '../../src/main/services/fts-sync.service' import { searchService } from '../../src/main/services/search.service' import type { SqliteDb } from '../../src/main/db/types' describe('SearchService', () => { let db: SqliteDb beforeEach(() => { db = new DatabaseSync(':memory:') migrate(db) const vol = new VolumeRepository(db).create('卷一', 0) const ch = new ChapterRepository(db).create(vol.id, '第一章', 0, '林远走进青云山') ftsSync.upsert(db, 'chapter', ch.id, ch.title, ch.content) }) afterEach(() => { db.close() }) it('finds chapter by FTS query', () => { const results = searchService.query(db, { text: '青云山' }) expect(results.length).toBeGreaterThanOrEqual(1) expect(results[0].kind).toBe('chapter') expect(results[0].snippet).toContain('青云') }) it('returns dry-run replace preview', () => { const { count, previews } = searchService.replace(db, { text: '林远', replacement: '李明', dryRun: true }) expect(count).toBeGreaterThanOrEqual(1) expect(previews.length).toBeGreaterThanOrEqual(1) }) it('supports regex fallback search', () => { const results = searchService.query(db, { text: '林.+山', regex: true }) expect(results.length).toBeGreaterThanOrEqual(1) }) })