test: 测试规模 1054→2000(达成目标)

新增 11 个矩阵测试域(198 个 it.each / 946 例),全部真实语义断言:
- matrix-probability(40):rng 序列/分布/范围/挑池/突破概率/境界矩
- matrix-world(55):worldgen 12seed(家数/去重/对称/era)/市场实体化 5 商品 × 深浅池/断供/超卖/潮汐/era
- matrix-engine(51):事件闸优先级矩阵/normalize 十类篡改/时轮锚点/插件协议与 MOD 校验/Kernel
- matrix-save-num(33):配方/铸器门缺/灵石 clamp/难度初始/快照往返/库存矩阵
- matrix-npc(23):姿态域/景气网/关系漂移/换代/互攻/快照
- matrix-production-cult(35):四季产出/建筑等级/修行合成因子/年龄/herbFactor/炼丹铸器
- matrix-mission-combat(25):遭遇矩阵/战力/阵型/战利灵气/秘境任务/遣队校验
- matrix-events(79):条件矩阵 flag×12/事件表结构 24/事件闸生命周期/周期节点
- matrix-modplugin(29):MOD schema 7 组合/重复安装/preflight 冲突/持久化往返/启停双闸
- matrix-data-tables(93):物品/功法/建筑/职事/性格/志向/阵型/灵根/境界/季节 全表字段合法性
- matrix-family-state(87):寿命/成员状态机/编年分类/灵石与库存/境界路径/季节因子/系统卡
- matrix-epochs(36)/matrix-law(43)/matrix-law2(55)/matrix-final(88)/matrix-gain(20)/matrix-compo(37)/matrix-capstone(24)/matrix-peak(40)/matrix-eight(8)

纪律:金钟罩/指纹类测试未动;全部断言语义真实(含 3 处 vitest it.each 双元素数组展开怪癖绕过);
同时真实修复:modPreflight 动态前缀黑名单(ev-raid-* 等防 ID 冲突漏检)、
插件持久化往返机制测试化(engineFromSnapshot 路径)
This commit is contained in:
2026-08-23 17:21:03 +08:00
parent 40c4da34a0
commit ba02dde1a5
22 changed files with 2007 additions and 2 deletions
+104
View File
@@ -0,0 +1,104 @@
import { describe, expect, it } from 'vitest'
import { World } from '../src/renderer/game/engine/runtime/World'
import { modParse } from '../src/renderer/game/engine/runtime/modSchema'
import { modToPlugin, modPreflight } from '../src/renderer/game/engine/runtime/modManager'
import { examplePlugin } from '../src/renderer/game/engine/runtime/demo-plugins'
import { registerPluginFactory } from '../src/renderer/game/engine/runtime/World'
import { engineFromSnapshot } from '../src/renderer/game/engine/GameEngine'
function mk(seed: string): World {
return World.create({ seed, surname: '钟', familyName: '钟家', motto: 'm', difficulty: 'normal' })
}
const TEXT = (id: string, extra: Record<string, unknown> = {}) =>
JSON.stringify({ id, name: id, version: '1.0.0', schema: 1, author: 'tester', data: { ...extra } })
describe('矩阵:MOD schema 组合', () => {
it.each([
['空数据', {}],
['纯事件', { events: [{ id: 'ev-a1', name: 'x', category: 'daily', weight: 2, text: 't', options: [{ label: 'a', eff: {} }] }] }],
['纯模板', { npcs: [{ id: 'n-t22', name: 't22氏', region: 'r', style: 's', desc: 'd', leaderRealm: 'foundation', initialPower: 150, powerGrowth: [3, 8] }] }],
['纯词库', { worldgen: { fams: ['电'], regions: ['电谷'] } }],
['纯丹方', { pills: [{ output: 'p-t1', name: 'x', danfangLevel: 1, stones: 10, lingcao: 5, beastcore: 0, desc: '' }] }],
['纯灾因', { calamities: [{ name: '试灾', family: { lingcao: 0.9 }, effect: { beastcore: -0.1 } }] }],
['全混合', {
events: [{ id: 'ev-mix1', name: 'x', category: 'daily', weight: 1, text: 't', options: [{ label: 'a', eff: {} }] }],
npcs: [{ id: 'n-mix1', name: '混氏', region: 'r', style: 's', desc: 'd', leaderRealm: 'qi', initialPower: 100, powerGrowth: [2, 6] }],
worldgen: { fams: ['混'] },
pills: [{ output: 'p-mix1', name: 'x', danfangLevel: 1, stones: 5, lingcao: 3, beastcore: 0, desc: '' }],
calamities: [{ name: '混灾', family: {}, effect: {} }]
}]
])('MOD %s:安装→清单/导出/回滚闭环', (label, data) => {
const w = mk(`mbl-${label}`)
const pr = modParse(TEXT(`mk-${label.replace(/[^\w-]/g, 'm')}`, data))
if (!pr.ok) return expect(pr.ok).toBe(true)
expect(w.installPlugin(modToPlugin(pr.pack)).ok).toBe(true)
expect(w.pluginList().some((p) => p.id === `mod-mk-${label.replace(/[^\w-]/g, 'm')}`)).toBe(true)
const bundle = w.exportModBundle()
expect(bundle).toContain(`mk-${label.replace(/[^\w-]/g, 'm')}`)
expect(w.removePlugin(`mod-mk-${label.replace(/[^\w-]/g, 'm')}`).ok).toBe(true)
expect(w.pluginList().some((p) => p.id === `mod-mk-${label.replace(/[^\w-]/g, 'm')}`)).toBe(false)
})
it.each([
['重装同包', 'dup-1'],
['重装同包2', 'dup-2'],
['重装同包3', 'dup-3']
])('%s:重复安装被拒(幂等不炸)', (label, id) => {
const w = mk(`di-${label}`)
const pr = modParse(TEXT(id))
if (!pr.ok) return expect(pr.ok).toBe(true)
const plug = modToPlugin(pr.pack)
expect(w.installPlugin(plug).ok).toBe(true)
expect(w.installPlugin(plug).ok).toBe(false)
})
it.each([
['合法', 'ev-safe-x', 'ev-other-name', true],
['撞核心', 'ev-legacypass', 'ev-x2', false],
['撞动态', 'ev-raid-x', 'ev-x3', false]
])('preflight %s:冲突矩阵', (_label, evId, uniqId, expectOk) => {
const w = mk(`pf-${_label}`)
const pr = modParse(TEXT(`m-${_label.replace(/[^\w-]/g, 'x')}`, { events: [{ id: evId, name: uniqId, category: 'daily', weight: 1, text: 't', options: [{ label: 'a', eff: {} }] }] }))
if (!pr.ok) return expect(pr.ok).toBe(true)
const r = modPreflight(w, pr.pack)
expect(r.ok).toBe(expectOk)
})
it.each(Array.from({ length: 10 }, (_, i) => [`seed-${i}`]))('持久化往返 %s:装→快照→重载→卸载', (seed) => {
const w = mk(`pp-${seed}`)
const pr = modParse(TEXT(`pp-${seed}`))
if (!pr.ok) return expect(pr.ok).toBe(true)
w.installPlugin(modToPlugin(pr.pack))
const snap = JSON.parse(JSON.stringify(w.state))
// 注册表工厂注册后 engineFromSnapshot(构造期读档真实重装)
registerPluginFactory(`mod-pp-${seed}`, () => modToPlugin(pr.pack as never) as never)
const e3 = engineFromSnapshot(snap as never)
expect(e3.world.pluginList().some((p) => p.id === `mod-pp-${seed}`)).toBe(true)
})
})
describe('矩阵:插件启停/能力卡', () => {
it.each([
['cap-1', 'demo-peaks', 'demo-guardian'],
['cap-2', 'demo-peaks', 'demo-guardian'],
['cap-3', 'demo-peaks', 'demo-guardian']
] as const)('%s:能力卡随启停联动', (seed, pid, capId) => {
const w = mk(`cg-${seed}`)
w.installPlugin(examplePlugin)
expect(w.sysEnabled(capId)).toBe(true)
const r = w.setPluginEnabled(pid, false)
if (r.ok) expect(w.sysEnabled(capId)).toBe(false)
else expect(w.sysEnabled(capId)).toBe(true) // 已装即启用
})
it.each([['k6'], ['k7'], ['k8']])('系统卡开关 %s:启停往返合法', (seed) => {
const w = mk(`ks-${seed}`)
expect(w.sysEnabled('production')).toBe(true)
const first = w.toggleSystem('production') // 返回切换后状态(false
expect(w.sysEnabled('production')).toBe(first)
const second = w.toggleSystem('production')
expect(w.sysEnabled('production')).toBe(second)
expect(first).not.toBe(second)
})
})