chapter-key-validation.spec.ts 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243
  1. import { describe, expect, it } from 'vitest'
  2. import * as fs from 'node:fs'
  3. import * as os from 'node:os'
  4. import * as path from 'node:path'
  5. import { createNovelTools } from '../src/novel-tools'
  6. import { nativeWriteStub } from './fixtures/native-write-stub'
  7. /**
  8. * 真机缺陷回归(20章连写第2章,D-004):模型漏传必填的 卷 参数,Number(undefined)=NaN
  9. * 拼出「卷NaN-章名」路径,错误被报成「无待审稿」——工具不校验章键参数,真实原因被掩盖。
  10. * 修复:章键工具先校验 卷/章/章名,返回指明缺失参数的明确原因。
  11. */
  12. function makeBook(): { ws: string; bookRoot: string } {
  13. const ws = fs.mkdtempSync(path.join(os.tmpdir(), 'webnovel-keycheck-'))
  14. const bookRoot = path.join(ws, '探书')
  15. fs.mkdirSync(path.join(bookRoot, '作品契约'), { recursive: true })
  16. fs.writeFileSync(path.join(bookRoot, '作品契约', '契约.md'), '---\n书id: probe-key\n---\n正文\n', 'utf-8')
  17. return { ws, bookRoot }
  18. }
  19. describe('章键参数校验(D-004 回归)', () => {
  20. it('漏传 卷/章 或空章名时给出指明参数的明确原因,不报「无待审稿」', async () => {
  21. const { ws, bookRoot } = makeBook()
  22. const tools = createNovelTools({ nativeWrite: nativeWriteStub, workspaceRoot: () => ws, bookRootOfBookId: () => bookRoot })
  23. const call = (name: string, a: Record<string, unknown>) => tools.find((t) => t.name === name)!.execute(a)
  24. for (const name of ['novel_prepare_pack', 'novel_confirm_outline', 'novel_assemble_materials', 'novel_record_review_findings']) {
  25. const missing卷 = await call(name, { bookId: 'probe-key', 章: 1, 章名: '探章', 模块名: '章节结构审读', 发现项: [] }) as { ok: boolean; reason?: string }
  26. expect(missing卷.ok, name).toBe(false)
  27. expect(missing卷.reason, name).toContain('卷')
  28. expect(missing卷.reason, name).not.toContain('无待审稿')
  29. const missing章 = await call(name, { bookId: 'probe-key', 卷: 1, 章名: '探章', 模块名: '章节结构审读', 发现项: [] }) as { ok: boolean; reason?: string }
  30. expect(missing章.ok, name).toBe(false)
  31. expect(missing章.reason, name).toContain('章')
  32. const blank章名 = await call(name, { bookId: 'probe-key', 卷: 1, 章: 1, 章名: ' ', 模块名: '章节结构审读', 发现项: [] }) as { ok: boolean; reason?: string }
  33. expect(blank章名.ok, name).toBe(false)
  34. expect(blank章名.reason, name).toContain('章名')
  35. }
  36. const float = await call('novel_prepare_pack', { bookId: 'probe-key', 卷: 1.5, 章: 1, 章名: '探章' }) as { ok: boolean; reason?: string }
  37. expect(float.ok).toBe(false)
  38. expect(float.reason).toContain('正整数')
  39. fs.rmSync(ws, { recursive: true, force: true, maxRetries: 5 })
  40. })
  41. })