三线并行审计(编辑器核心/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。
55 lines
2.6 KiB
TypeScript
55 lines
2.6 KiB
TypeScript
// 阶段 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')
|
||
})
|
||
})
|