Files
new-markdown/tests/stage4.test.ts
Muse fb2315a2f3 audit(docs/29): 全项目审计——修分片载入卸载截断高危、Sidebar memo 击穿与 Rust 资源/搜索/恢复上限等 20 余处
三线并行审计(编辑器核心/Rust 后端/服务与组件)+ App 编排层自审。
高危:分片载入未收尾时窗格卸载回写部分序列化,干净标签会被静默
截断——cleanup 补 muted 守卫,create 完成回调补取消守卫。
性能:gitSync/outline/收起回调稳定化保住 Sidebar memo;光标行列
rAF 合并;图片显示解析加缓存;导出图片并发解析;chunkLoader
偏移前缀表;围栏切点只认顶格(列表内嵌围栏等价回归实测)。
Rust:资源命令 async 化 + 32MB 上限;搜索 junction 越界校验;
recovery/workspace 条数与单条上限;启动坏库改名重建 + WAL;
validate 补 ext:: 黑名单与 ref 形态;init 先种 .gitignore
(含 .*.tmp-* 防崩溃残留被提交);游离 HEAD 不再猜分支。
验证:vitest 122+2、tsc、构建通过;Rust 过 rustfmt 解析、
validate 纯函数抽出实跑断言、命令对账 28=28。
2026-11-14 18:00:31 +08:00

55 lines
2.6 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 阶段 4 验收:恢复记录纯逻辑(键/提供与清理划分)与标签 reducer 的重载/改路径动作。
import { describe, it, expect } from 'vitest'
import { recoveryKey, planRecovery } from '../src/utils/recovery'
import { tabsReducer, createTab, isDirty, type TabsState } from '../src/stores/tabs'
import type { RecoveryEntry } from '../src/services/platform'
describe('recoveryKey', () => {
it('文件文档按路径键,未命名按标签 id', () => {
// docs/29:路径先归一(斜杠统一 + Windows 大小写折叠),同文件不同写法同键
expect(recoveryKey({ id: 't1', path: 'D:\\a.md' })).toBe('path:d:/a.md')
expect(recoveryKey({ id: 't1', path: 'd:/A.md' })).toBe('path:d:/a.md')
expect(recoveryKey({ id: 't2', path: null })).toBe('untitled:t2')
})
})
describe('planRecovery', () => {
const fileRecord: RecoveryEntry = {
docKey: 'path:D:\\a.md', path: 'D:\\a.md', title: 'a', content: '新草稿', updatedAt: 2,
}
const savedRecord: RecoveryEntry = {
docKey: 'path:D:\\b.md', path: 'D:\\b.md', title: 'b', content: '已存内容', updatedAt: 1,
}
const untitledRecord: RecoveryEntry = {
docKey: 'untitled:t9', path: null, title: '未命名', content: '临时', updatedAt: 3,
}
it('与磁盘一致的记录清理、不一致与未命名的提供恢复、文件已删的也提供', () => {
const plan = planRecovery([fileRecord, savedRecord, untitledRecord], (path) =>
path === 'D:\\b.md' ? '已存内容' : '磁盘旧内容',
)
expect(plan.purgeKeys).toEqual(['path:D:\\b.md'])
expect(plan.offer.map((r) => r.docKey)).toEqual(['path:D:\\a.md', 'untitled:t9'])
const gonePlan = planRecovery([fileRecord], () => null)
expect(gonePlan.offer).toHaveLength(1)
expect(gonePlan.purgeKeys).toEqual([])
})
})
describe('tabs reducer 阶段 4 动作', () => {
it('loadContent 整表替换并变干净,setPath 改路径与标题', () => {
const tab = createTab({ path: 'D:\\a.md', title: 'a', content: '旧' })
let state: TabsState = { tabs: [tab], activeId: tab.id }
state = tabsReducer(state, { type: 'updateContent', id: tab.id, content: '我的修改' })
expect(isDirty(state.tabs[0])).toBe(true)
state = tabsReducer(state, { type: 'loadContent', id: tab.id, content: '磁盘新内容', encoding: 'GBK' })
expect(state.tabs[0].content).toBe('磁盘新内容')
expect(isDirty(state.tabs[0])).toBe(false)
expect(state.tabs[0].encoding).toBe('GBK')
state = tabsReducer(state, { type: 'setPath', id: tab.id, path: 'D:\\b.md', title: 'b' })
expect(state.tabs[0].path).toBe('D:\\b.md')
expect(state.tabs[0].title).toBe('b')
})
})