mirror of
https://github.com/motajs/template.git
synced 2026-11-02 15:04:30 +08:00
test(03-15): cover independent replay command ownership
- Verify distinct command classes, fresh instances, stable order, and extension registration - Add structural ownership regressions without changing replay or user-owned decorator boundaries
This commit is contained in:
1 parent
13162b2406
commit
f5c6b06c59
3 files changed
+97
-13
No files matched your search
@@ -48,6 +48,16 @@ describe('replay commands', () => {
|
||||
expect(items.map(item => item.code)).toEqual(REPLAY_COMMAND_ORDER);
|
||||
expect(items).toHaveLength(8);
|
||||
expect(items.map(item => item.command.execute)).toHaveLength(8);
|
||||
expect(items.map(item => item.command.constructor.name)).toEqual([
|
||||
'ReplayUpCommand',
|
||||
'ReplayRightCommand',
|
||||
'ReplayDownCommand',
|
||||
'ReplayLeftCommand',
|
||||
'ReplayAutoPathfindCommand',
|
||||
'ReplayUseItemCommand',
|
||||
'ReplayEquipCommand',
|
||||
'ReplayUnequipCommand'
|
||||
]);
|
||||
});
|
||||
|
||||
// 验证顶层注册器按稳定顺序注册并拒绝重复 code
|
||||
@@ -72,18 +82,18 @@ describe('replay commands', () => {
|
||||
it('assembles an independent top-level registry for every CoreState', () => {
|
||||
const first = createCoreState();
|
||||
const second = createCoreState();
|
||||
const firstCommands = REPLAY_COMMAND_ORDER.map(
|
||||
code => first.replaySystem.getCommand(code)!
|
||||
);
|
||||
const secondCommands = REPLAY_COMMAND_ORDER.map(
|
||||
code => second.replaySystem.getCommand(code)!
|
||||
);
|
||||
expect(first.replaySystem).not.toBe(second.replaySystem);
|
||||
expect(first.pathfinding).not.toBe(second.pathfinding);
|
||||
expect(
|
||||
REPLAY_COMMAND_ORDER.map(code =>
|
||||
first.replaySystem.getCommand(code)
|
||||
).length
|
||||
).toBe(8);
|
||||
expect(
|
||||
REPLAY_COMMAND_ORDER.map(code =>
|
||||
second.replaySystem.getCommand(code)
|
||||
).length
|
||||
).toBe(8);
|
||||
expect(firstCommands).toHaveLength(8);
|
||||
expect(secondCommands).toHaveLength(8);
|
||||
expect(new Set(firstCommands).size).toBe(8);
|
||||
expect(new Set(secondCommands).size).toBe(8);
|
||||
expect(
|
||||
REPLAY_COMMAND_ORDER.every(
|
||||
code => first.replaySystem.getCommand(code) !== null
|
||||
@@ -95,6 +105,32 @@ describe('replay commands', () => {
|
||||
)
|
||||
).toBe(true);
|
||||
expect(first.replaySystem.route).not.toBe(second.replaySystem.route);
|
||||
for (let index = 0; index < firstCommands.length; index++) {
|
||||
expect(firstCommands[index]).not.toBe(secondCommands[index]);
|
||||
}
|
||||
});
|
||||
|
||||
// 验证现有 command item 扩展边界可以替换单个实现而不改变注册器
|
||||
it('registers an existing custom command item through the current interface', () => {
|
||||
const state = createCoreState();
|
||||
const replay = new ReplaySystem();
|
||||
const defaultItems = createReplayCommandItems(state);
|
||||
const customItem: IReplayCommandItem = {
|
||||
code: ReplayCommandCode.Up,
|
||||
command: {
|
||||
execute: () => Promise.resolve(true)
|
||||
}
|
||||
};
|
||||
registerReplayCommandItems(replay, [
|
||||
customItem,
|
||||
...defaultItems.slice(1)
|
||||
]);
|
||||
expect(replay.getCommand(ReplayCommandCode.Up)).toBe(
|
||||
customItem.command
|
||||
);
|
||||
expect(replay.getCommand(ReplayCommandCode.Right)).toBe(
|
||||
defaultItems[1].command
|
||||
);
|
||||
});
|
||||
|
||||
// 验证四向移动不等待 controller.onEnd 即完成 command
|
||||
@@ -390,4 +426,38 @@ describe('replay safety decorators', () => {
|
||||
);
|
||||
expect(source).not.toContain('shouldReplay');
|
||||
});
|
||||
|
||||
// 验证八个 command 类各自拥有 execute 且不存在共享入口或跨类调用
|
||||
it('keeps replay command ownership isolated in the command module', () => {
|
||||
const source = readFileSync(
|
||||
new URL('./commands.ts', import.meta.url),
|
||||
'utf8'
|
||||
);
|
||||
const classes = [
|
||||
'ReplayUpCommand',
|
||||
'ReplayRightCommand',
|
||||
'ReplayDownCommand',
|
||||
'ReplayLeftCommand',
|
||||
'ReplayAutoPathfindCommand',
|
||||
'ReplayUseItemCommand',
|
||||
'ReplayEquipCommand',
|
||||
'ReplayUnequipCommand'
|
||||
];
|
||||
expect(source).not.toContain('ReplayCommandEntrances');
|
||||
expect(source).not.toContain('createMoveCommand');
|
||||
expect(source).not.toMatch(/\bentries\./);
|
||||
for (const className of classes) {
|
||||
const body = source.match(
|
||||
new RegExp(
|
||||
`class\\s+${className}\\b[\\s\\S]*?(?=\\r?\\nclass\\s|\\r?\\nfunction\\s|\\r?\\nexport function\\s|\\r?\\n/\\*\\*/)`
|
||||
)
|
||||
)?.[0];
|
||||
expect(body).toBeDefined();
|
||||
expect(body).toMatch(/execute\s*\(/);
|
||||
for (const otherClass of classes) {
|
||||
if (otherClass === className) continue;
|
||||
expect(body).not.toContain(otherClass);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user