| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677 |
- import { test } from 'node:test'
- import assert from 'node:assert/strict'
- import path from 'node:path'
- import { fileURLToPath } from 'node:url'
- import { ChapterReader } from '../../../src/storage/adapters/ChapterReader.js'
- const __dirname = path.dirname(fileURLToPath(import.meta.url))
- const fixtureRoot = path.join(__dirname, '../../fixtures/sample-book')
- test('readFrontMatter:读取章节 front matter', async () => {
- const reader = new ChapterReader(fixtureRoot)
- const result = await reader.readFrontMatter(1)
- assert.equal(result.ok, true)
- assert.equal(result.data.章号, 1)
- assert.equal(result.data.标题, '开局')
- assert.equal(result.data.卷, 1)
- assert.equal(result.data.视角, '林晚')
- })
- test('readFrontMatter:不存在的章号', async () => {
- const reader = new ChapterReader(fixtureRoot)
- const result = await reader.readFrontMatter(999)
- assert.equal(result.ok, false)
- assert.ok(result.error.includes('不存在'))
- })
- test('readBody:读取章节正文', async () => {
- const reader = new ChapterReader(fixtureRoot)
- const result = await reader.readBody(1)
- assert.equal(result.ok, true)
- assert.ok(result.body.includes('林晚抬头望着宗门大殿'))
- assert.ok(result.body.includes('消失在夜色中'))
- assert.ok(!result.body.includes('---')) // 不含 front matter
- })
- test('readTail:读取章节末尾 N 字', async () => {
- const reader = new ChapterReader(fixtureRoot)
- const result = await reader.readTail(1, 50)
- assert.equal(result.ok, true)
- assert.ok(result.text.includes('消失在夜色中'))
- assert.ok(result.text.length <= 60) // 允许少量误差(字符 vs 字)
- })
- test('readHead:读取章节开头 N 字', async () => {
- const reader = new ChapterReader(fixtureRoot)
- const result = await reader.readHead(1, 20)
- assert.equal(result.ok, true)
- assert.ok(result.text.includes('林晚抬头'))
- })
- // A6:接口形状不随缓存冷热漂移——缓存命中与文件降级都输出中文键
- test('readFrontMatter:缓存命中与文件降级输出同一形状(中文键)', async () => {
- const fakeCache = {
- query: async () => [
- {
- chapter_num: 1, title: '开局', volume_num: 1, perspective: '林晚',
- story_time: null, word_count: 100, chapter_position: '开篇',
- hook_type: '悬念钩-强', mood_position: null, is_volume_end: 0,
- file_path: '/x/0001.md', is_key_chapter: 0,
- },
- ],
- }
- const warm = await new ChapterReader(fixtureRoot, fakeCache).readFrontMatter(1)
- const cold = await new ChapterReader(fixtureRoot).readFrontMatter(1)
- assert.equal(warm.ok, true)
- assert.equal(cold.ok, true)
- assert.equal(warm.data.章号, 1)
- assert.equal(warm.data.标题, '开局')
- assert.equal(warm.data.chapter_num, undefined, '缓存命中不得泄漏英文列名')
- assert.equal(warm.data.file_path, undefined, '不得泄漏文件路径')
- assert.equal(cold.data.标题, '开局')
- })
|