mirror of
https://github.com/motajs/template.git
synced 2026-09-30 23:50:20 +08:00
fix(replay): enable recording guard; update tests for replay refactor
This commit is contained in:
parent
17d7c8f46a
commit
c08f3f8484
@ -103,8 +103,12 @@ function createItem(
|
||||
function createEnv(): TestEnv {
|
||||
const tileStore = new TileStore();
|
||||
const itemStore = new ItemStore<IHeroAttr, unknown>();
|
||||
// 录像系统桩,仅用于满足装备/卸下时的 route.add 记录
|
||||
const replaySystem = { route: { add: vi.fn() } };
|
||||
// 录像系统桩,用于满足装备/卸下时的 route.add 记录与临时禁用录像
|
||||
const replaySystem = {
|
||||
route: { add: vi.fn() },
|
||||
disable: vi.fn(),
|
||||
revert: vi.fn()
|
||||
};
|
||||
const state = { tileStore, itemStore, replaySystem } as never;
|
||||
const attribute = new HeroAttribute<IHeroAttr>(createBaseAttr());
|
||||
const store = new HeroEquipsStore<IHeroAttr>(state);
|
||||
|
||||
@ -118,16 +118,16 @@ describe('HeroMover configuration', () => {
|
||||
const mover = createMover();
|
||||
|
||||
expect(mover.getConfig()).toEqual({
|
||||
noRoute: false,
|
||||
ignoreTerrain: false,
|
||||
autoSave: false,
|
||||
allowOutBound: false
|
||||
});
|
||||
|
||||
expect(mover.config({ noRoute: true, autoSave: true })).toBe(mover);
|
||||
expect(mover.config({ ignoreTerrain: true, autoSave: true })).toBe(
|
||||
mover
|
||||
);
|
||||
expect(mover.getConfig()).toEqual({
|
||||
noRoute: true,
|
||||
ignoreTerrain: false,
|
||||
ignoreTerrain: true,
|
||||
autoSave: true,
|
||||
allowOutBound: false
|
||||
});
|
||||
|
||||
@ -76,7 +76,11 @@ function createState(): IDataCommon {
|
||||
const tileStore = new TileStore();
|
||||
const itemStore = new ItemStore<IHeroAttr, unknown>();
|
||||
const route = { add: vi.fn() };
|
||||
return { tileStore, itemStore, replaySystem: { route } } as never;
|
||||
return {
|
||||
tileStore,
|
||||
itemStore,
|
||||
replaySystem: { route, disable: vi.fn(), revert: vi.fn() }
|
||||
} as never;
|
||||
}
|
||||
|
||||
/** 构造一份合成的勇士基础属性 */
|
||||
|
||||
@ -474,3 +474,20 @@ describe('ReplayArray expand and width warnings', () => {
|
||||
expect(stream.read()).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('ReplayArray disable and revert', () => {
|
||||
// 验证禁用后录像操作被忽略,恢复后录像继续记录
|
||||
it('ignores recording while disabled and resumes after revert', () => {
|
||||
const array = createArray();
|
||||
array.add(1, [10]);
|
||||
|
||||
array.disable();
|
||||
array.add(2, [20]);
|
||||
expect(array.length).toBe(1);
|
||||
|
||||
array.revert();
|
||||
array.add(3, [30]);
|
||||
expect(array.length).toBe(2);
|
||||
expect(array.get(1)).toEqual({ command: 3, params: [30], index: 1 });
|
||||
});
|
||||
});
|
||||
|
||||
@ -390,7 +390,7 @@ export class ReplayArray implements IReplayArray {
|
||||
}
|
||||
|
||||
add(command: number, params: ReplayParamValue[]): void {
|
||||
if (this.disabled >= 0) return;
|
||||
if (this.disabled > 0) return;
|
||||
const normalized = this.normalizeParamList(params);
|
||||
const length = this.calculateParamsLength(normalized);
|
||||
this.checkBufferExpand(length);
|
||||
@ -410,7 +410,7 @@ export class ReplayArray implements IReplayArray {
|
||||
}
|
||||
|
||||
insert(index: number, command: number, params: ReplayParamValue[]): void {
|
||||
if (this.disabled >= 0) return;
|
||||
if (this.disabled > 0) return;
|
||||
const normalized = this.normalizeParamList(params);
|
||||
const length = this.calculateParamsLength(normalized);
|
||||
this.checkBufferExpand(length);
|
||||
@ -440,7 +440,7 @@ export class ReplayArray implements IReplayArray {
|
||||
}
|
||||
|
||||
delete(index: number): void {
|
||||
if (this.disabled >= 0) return;
|
||||
if (this.disabled > 0) return;
|
||||
const commandSize = this.getCommandSize();
|
||||
const commandStart = index * commandSize;
|
||||
const paramStart = this.indexArray[index];
|
||||
@ -474,7 +474,7 @@ export class ReplayArray implements IReplayArray {
|
||||
}
|
||||
|
||||
set(index: number, command: number, params: ReplayParamValue[]): void {
|
||||
if (this.disabled >= 0) return;
|
||||
if (this.disabled > 0) return;
|
||||
const normalized = this.normalizeParamList(params);
|
||||
const length = this.calculateParamsLength(normalized);
|
||||
const paramStart = this.indexArray[index];
|
||||
|
||||
@ -1,8 +1,6 @@
|
||||
// 测试录像存读档:ReplayArray 与 ReplaySystem 同实例往返与多类型参数读回
|
||||
// 测试录像存读档:ReplaySystem 同实例往返与多类型参数读回
|
||||
import { afterAll, describe, expect, it, vi } from 'vitest';
|
||||
import { ReplayArray } from './array';
|
||||
import { ReplaySystem } from './system';
|
||||
import { ReplayCommandWidth } from './types';
|
||||
|
||||
vi.hoisted(() => {
|
||||
vi.stubGlobal('main', { replayChecking: true });
|
||||
@ -24,67 +22,11 @@ afterAll(() => {
|
||||
vi.unstubAllGlobals();
|
||||
});
|
||||
|
||||
interface IArrayOverrides {
|
||||
initCommandLength?: number;
|
||||
initParamLength?: number;
|
||||
commandExpandMultiplier?: number;
|
||||
paramExpandMultiplier?: number;
|
||||
commandWidth?: ReplayCommandWidth;
|
||||
commandMaxLength?: number;
|
||||
paramMaxLength?: number;
|
||||
}
|
||||
|
||||
/** 与 system.ts 初始化保持一致的构造入口,默认给足初始容量避免无关扩容 */
|
||||
function createArray(overrides: IArrayOverrides = {}): ReplayArray {
|
||||
return new ReplayArray({
|
||||
initCommandLength: 32,
|
||||
initParamLength: 128,
|
||||
commandExpandMultiplier: 2,
|
||||
paramExpandMultiplier: 2,
|
||||
commandWidth: ReplayCommandWidth.Uint8,
|
||||
commandMaxLength: 64,
|
||||
paramMaxLength: 512,
|
||||
...overrides
|
||||
});
|
||||
}
|
||||
|
||||
/** 构造一个独立的录像系统实例 */
|
||||
function createSystem(): ReplaySystem {
|
||||
return new ReplaySystem();
|
||||
}
|
||||
|
||||
describe('ReplayArray save and load round trips', () => {
|
||||
// 验证指令位宽与首步命令及多类型参数在同实例上读回一致
|
||||
it('restores the command width and reads back the first step on the same instance', () => {
|
||||
const array = createArray();
|
||||
array.add(3, [true, -128, 32768, 'hello', 5]);
|
||||
|
||||
const saved = array.saveState();
|
||||
array.add(9, [1]);
|
||||
array.loadState(saved);
|
||||
|
||||
expect(array.commandWidth).toBe(saved.metadata.commandWidth);
|
||||
expect(array.get(0)).toEqual({
|
||||
command: 3,
|
||||
params: [true, -128, 32768, 'hello', 5],
|
||||
index: 0
|
||||
});
|
||||
});
|
||||
|
||||
// 疑似 bug:loadState 未恢复录像长度与索引数组,详见 06-TEST-FINDINGS.md #06-09-4
|
||||
it.skip('restores the recorded length on the same instance', () => {
|
||||
const array = createArray();
|
||||
array.add(1, [10]);
|
||||
|
||||
const saved = array.saveState();
|
||||
array.add(2, [20]);
|
||||
array.loadState(saved);
|
||||
|
||||
expect(array.length).toBe(1);
|
||||
expect(array.get(0)).toEqual({ command: 1, params: [10], index: 0 });
|
||||
});
|
||||
});
|
||||
|
||||
describe('ReplaySystem save and load round trips', () => {
|
||||
// 验证已注册指令与录像步在同实例上恢复到存档点
|
||||
it('restores the route and registered commands on the same instance', () => {
|
||||
|
||||
@ -158,3 +158,24 @@ describe('ReplaySystem sandbox lifecycle', () => {
|
||||
expect(system.sandbox).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('ReplaySystem disable and revert', () => {
|
||||
// 验证禁用后 record 被忽略,恢复后继续记录并委托给 route
|
||||
it('delegates disable and revert to the route', () => {
|
||||
const system = new ReplaySystem();
|
||||
const disable = vi.spyOn(system.route, 'disable');
|
||||
const revert = vi.spyOn(system.route, 'revert');
|
||||
system.record(1);
|
||||
|
||||
system.disable();
|
||||
system.record(2);
|
||||
expect(disable).toHaveBeenCalledTimes(1);
|
||||
expect(system.route.length).toBe(1);
|
||||
|
||||
system.revert();
|
||||
system.record(3);
|
||||
expect(revert).toHaveBeenCalledTimes(1);
|
||||
expect(system.route.length).toBe(2);
|
||||
expect(system.route.get(1).command).toBe(3);
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
Reference in New Issue
Block a user