fix(03-08): guard registered event parameters

- Return safely before parsing nullish or non-object runtime parameters\n- Cover the real eventSetBlock registration with a null regression
This commit is contained in:
unanmed 2026-09-10 18:47:26 +08:00
parent 4dd28759d8
commit 95df6a0198
2 changed files with 33 additions and 0 deletions

View File

@ -27,6 +27,20 @@ interface EventFixture {
readonly env: IBlockEventEnv;
}
type RegisteredBuiltin = ReturnType<
typeof createEventBuiltinRegistrations
>[number];
function invokeBuiltin(
registration: RegisteredBuiltin,
param: null | undefined,
env: IBlockEventEnv
): Promise<void> {
return Promise.resolve(
Reflect.apply(registration.func, undefined, [param, env])
);
}
function createFixture(): EventFixture {
const state = new CoreState();
state.tileStore.addTile({
@ -207,6 +221,20 @@ describe('event built-ins', () => {
}
});
// 验证真实注册的 eventSetBlock 对 null 参数安全返回且不修改状态
it('safely resolves a null parameter through the eventSetBlock registration', async () => {
const fixture = createFixture();
const registration = createEventBuiltinRegistrations().find(
item => item.name === EventBuiltinName.SetBlock
);
expect(registration).toBeDefined();
if (!registration) throw new Error('eventSetBlock registration missing');
await expect(
invokeBuiltin(registration, null, fixture.env)
).resolves.toBeUndefined();
expect(fixture.layer.getBlock(0, 0)).toBe(1);
});
// 验证缺失地图、勇士和事件 id 时所有函数都安全返回
it('safely skips missing targets and event ids', async () => {
const fixture = createFixture();

View File

@ -117,8 +117,13 @@ type EventBuiltinHandler = (
env: IBlockEventEnv
) => void | Promise<void>;
function isBuiltinParameter(value: BuiltinParameter): value is BuiltinParameter {
return value !== null && typeof value === 'object';
}
function createBuiltin(handler: EventBuiltinHandler): BuiltInFunction['func'] {
return (param: BuiltinParameter, env: BuiltinEnvironment) => {
if (!isBuiltinParameter(param)) return;
if (!isBlockEventEnv(env)) return;
return handler(param, env);
};