finalize-guard.test.js 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. import { test } from 'node:test'
  2. import assert from 'node:assert/strict'
  3. import path from 'node:path'
  4. import { promises as fs } from 'node:fs'
  5. import { run as finalizeCmd } from '../../src/commands/finalize.js'
  6. import { tempBookCtx } from './_helper.js'
  7. // R2:批次进行中的手动 finalize 必须被拒——放行会让 overlay 双计总章数,
  8. // 且 finalize-batch 再转正同章时撞「条目已存在」整批卡死。守卫在读 payload 之前,
  9. // 故测试无需构造定稿包。
  10. async function injectBatch(root, nums) {
  11. const rows = []
  12. for (const n of nums) {
  13. const dirName = `${String(n).padStart(4, '0')}-批内章`
  14. await fs.mkdir(path.join(root, '工作区', '待定稿', dirName), { recursive: true })
  15. rows.push({ 章号: n, 标题: '批内章', 状态: '待审收', 目录: dirName })
  16. }
  17. await fs.writeFile(
  18. path.join(root, '工作区', '待定稿', '批次.json'),
  19. JSON.stringify({ 章列表: rows }),
  20. 'utf8'
  21. )
  22. }
  23. test('R2:目标章在批内 → 手动 finalize 被拒,指向 finalize-batch', async () => {
  24. const { ctx, cleanup } = await tempBookCtx()
  25. try {
  26. await injectBatch(ctx.repoPath, [3, 4])
  27. const r = await finalizeCmd(['3'], {}, ctx)
  28. assert.equal(r.ok, false)
  29. assert.match(r.error, /已在待定稿批次/)
  30. assert.match(r.error, /finalize-batch/)
  31. } finally {
  32. await cleanup()
  33. }
  34. })
  35. test('R2:批次在场但目标章不在批内 → 同样被拒(防章号错位)', async () => {
  36. const { ctx, cleanup } = await tempBookCtx()
  37. try {
  38. await injectBatch(ctx.repoPath, [3, 4])
  39. const r = await finalizeCmd(['9'], {}, ctx)
  40. assert.equal(r.ok, false)
  41. assert.match(r.error, /待定稿批次/)
  42. assert.match(r.error, /batch-discard/)
  43. } finally {
  44. await cleanup()
  45. }
  46. })
  47. test('无批次时 finalize 不受守卫影响(走正常校验路径)', async () => {
  48. const { ctx, cleanup } = await tempBookCtx()
  49. try {
  50. const r = await finalizeCmd(['3'], {}, ctx)
  51. // 没给 payload:应报缺 payload 而不是批次守卫错
  52. assert.equal(r.ok, false)
  53. assert.doesNotMatch(r.error, /批次/)
  54. } finally {
  55. await cleanup()
  56. }
  57. })