Files
ChronicleOfTheImmortalClan/tests/matrix-final-circle-0.1.30.test.ts
T
thzxx 9b0f36c70a v0.1.35b: 兼容层铲除——迁移链/版本戳/死表死代码/normalize 兼容批/死字段
【A+I】migrate.ts 迁移链(CURRENT_SCHEMA/MIGRATIONS/migrateIfNeeded/MigrationError)整链铲除→validateLoadedState 结构校验(seed/family/members 断言);信封统一 payload 单格式(去双格式兜底);APP_ID 保留
【F】schemaVersion 字段全删(domain/creation/save 8 处);SaveMeta.version 记游戏版本字符串
【C】chronicle 死表+saveChronicle 死方法(首行 return+unreachable legacy 僵尸)全删
【D/E】GameEngine __state globalThis 泄漏口+seed 三元(恒不可达)删除;engineFromSnapshot/noAutoCreate 保留(测试便利——非兼容机器)
【B/H】normalizeGameState 兼容批删:老档字段补(28行)/worldGen 重放(18行)/P0-2 占位 def(9行)/worldSim 字段批删;保留 npcs 重注册/headId 修复/d distress 防护;initSim 补 0.1.34 四键(唯一初始源)
【G】domain 收紧 5 兼容 optional(techniqueRank/Progress/tribBoost/worldGen 必填)+pcgen 必写
【测试】删 9 个兼容验证体(audit 0.1.0-era/全残缺矩阵/空 worldSim 兜底);5989 全绿——金钟罩零漂(新档结构全字段,删除不涉世界数值)
2026-08-23 22:35:17 +08:00

110 lines
4.3 KiB
TypeScript
Raw 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.
import { describe, expect, it } from 'vitest'
import { World } from '../src/renderer/game/engine/runtime/World'
import { Rng, seedToRng } from '../src/renderer/game/engine/kernel/rng'
import { seasonMod } from '../src/renderer/game/data/season'
import { MAJOR_ORDER } from '../src/renderer/game/data/realms'
function mk(seed: string): World {
return World.create({ seed, surname: '钟', familyName: '钟家', motto: 'm', difficulty: 'normal' })
}
describe('0.1.30 矩阵:月末大圈(600 例级)', () => {
it.each(Array.from({ length: 48 }, (_, i) => [i * 23 + 1] as const))(
'seed %d:双月双验', (seed) => {
const w = mk(`md2-${seed}`)
w.advanceMonth(); w.advanceMonth()
expect(w.state.month).toBeGreaterThan(2)
expect(Number.isFinite(w.state.family.stones)).toBe(true)
})
it.each(Array.from({ length: 40 }, (_, i) => [i * 11 + 4] as const))(
'seed %d:六载六验', (seed) => {
const w = mk(`lz-${seed}`)
for (let i = 0; i < 72; i++) w.advanceMonth()
expect(w.state.year).toBeGreaterThanOrEqual(6)
expect(Number.isFinite(w.state.seq)).toBe(true)
expect(w.state.family.reputation >= 0).toBe(true)
expect(Array.isArray(w.state.chronicle)).toBe(true)
expect(w.state.finance).toBeTruthy()
expect(w.state.family.inventory).toBeTruthy()
})
it.each(Array.from({ length: 36 }, (_, i) => [i * 15 + 7] as const))(
'seed %d:季度验收(12 月×3 验)', (seed) => {
const w = mk(`jd-${seed}`)
for (let i = 0; i < 12; i++) w.advanceMonth()
expect(w.state.totalTicks).toBe(12)
expect(Number.isFinite(w.state.family.stones)).toBe(true)
expect(Array.isArray(w.state.eventQueue)).toBe(true)
})
it.each([
['春', 2], ['夏', 5], ['秋', 8], ['冬', 11], ['玄月', 1], ['腊月', 12]
] as const)('%s:季节四因子各验', (label, month) => {
for (const key of ['field', 'cult', 'market', 'meditation'] as const) {
const v = seasonMod(month, key)
expect(v).toBeGreaterThanOrEqual(-0.35)
expect(v).toBeLessThanOrEqual(0.35)
}
void label
})
it.each(Array.from({ length: 24 }, (_, i) => [i * 7 + 5] as const))(
'seed %d:境界圆周合法', (seed) => {
const w = mk(`jy2-${seed}`)
for (const m of MAJOR_ORDER) {
const c = Object.values(w.state.members)[0]!
c.realm = { major: m, minor: 0 }
expect(c.realm).toBeTruthy()
}
expect(MAJOR_ORDER.length).toBeGreaterThanOrEqual(6)
})
it.each(Array.from({ length: 20 }, (_, i) => [i * 5 + 1] as const))(
'seed %d:大衍六合', (seed) => {
const w = mk(`dy2-${seed}`)
for (let i = 0; i < 24; i++) w.advanceMonth()
expect(w.state.seq).toBeGreaterThan(0)
expect(Array.isArray(w.state.completedEvents)).toBe(true)
expect(Array.isArray(w.state.missions)).toBe(true)
expect(typeof w.state.seed).toBe('string') // 0.1.35 版本戳移除——seed 为世界锚
expect(typeof w.state.seed).toBe('string')
expect(Array.isArray(w.state.battles)).toBe(true)
})
it.each(Array.from({ length: 32 }, (_, i) => [i * 9 + 2] as const))(
'seed %d:三十月双验', (seed) => {
const w = mk(`sy-${seed}`)
for (let i = 0; i < 30; i++) w.advanceMonth()
expect(w.state.year).toBeGreaterThanOrEqual(2)
expect(Number.isFinite(w.state.totalTicks)).toBe(true)
})
it.each(Array.from({ length: 16 }, (_, i) => [i * 3 + 1] as const))(
'seed %drng 四步等变', (seed) => {
const a = new Rng(seedToRng(`zz-${seed}`))
const b = new Rng(seedToRng(`zz-${seed}`))
expect(a.next()).toBe(b.next())
expect(a.next()).toBe(b.next())
expect(a.next()).toBe(b.next())
expect(a.next()).toBe(b.next())
})
it.each([
['一'], ['二'], ['三'], ['四'], ['五'], ['六'], ['七'], ['八'], ['九'], ['十']
] as const)('%s:化律(10 月推演)', (label) => {
const w = mk(`hl-${label}`)
for (let i = 0; i < 10; i++) w.advanceMonth()
expect(w.state.seq).toBeGreaterThan(9)
})
it.each(Array.from({ length: 60 }, (_, i) => [i * 3 + 1] as const))(
'seed %d:六辰常驻', (seed) => {
const w = mk(`lc-${seed}`)
w.advanceMonth()
expect(w.state.month).toBe(2)
expect(Number.isFinite(w.state.family.stones)).toBe(true)
expect(typeof w.state.family.headId).toBe('string')
})
})