Files
esengine/tests/ECS/Core/BitMaskOptimizer.test.ts

333 lines
13 KiB
TypeScript
Raw Normal View History

2025-07-29 15:56:40 +08:00
import { BitMaskOptimizer } from '../../../src/ECS/Core/BitMaskOptimizer';
import { BigIntFactory } from '../../../src/ECS/Utils/BigIntCompatibility';
2025-07-29 15:56:40 +08:00
describe('BitMaskOptimizer - 位掩码优化器测试', () => {
let optimizer: BitMaskOptimizer;
beforeEach(() => {
optimizer = BitMaskOptimizer.getInstance();
optimizer.reset(); // 确保每个测试开始时都是干净的状态
});
describe('单例模式测试', () => {
it('应该返回同一个实例', () => {
const instance1 = BitMaskOptimizer.getInstance();
const instance2 = BitMaskOptimizer.getInstance();
expect(instance1).toBe(instance2);
});
});
describe('组件类型注册', () => {
it('应该能够注册组件类型', () => {
const id = optimizer.registerComponentType('Transform');
expect(id).toBe(0);
});
it('重复注册相同组件应该返回相同ID', () => {
const id1 = optimizer.registerComponentType('Transform');
const id2 = optimizer.registerComponentType('Transform');
expect(id1).toBe(id2);
});
it('应该能够注册多个不同组件类型', () => {
const id1 = optimizer.registerComponentType('Transform');
const id2 = optimizer.registerComponentType('Velocity');
const id3 = optimizer.registerComponentType('Health');
expect(id1).toBe(0);
expect(id2).toBe(1);
expect(id3).toBe(2);
});
it('应该能够获取已注册组件的类型ID', () => {
optimizer.registerComponentType('Transform');
const id = optimizer.getComponentTypeId('Transform');
expect(id).toBe(0);
});
it('获取未注册组件的类型ID应该返回undefined', () => {
const id = optimizer.getComponentTypeId('UnknownComponent');
expect(id).toBeUndefined();
});
});
describe('单组件掩码创建', () => {
beforeEach(() => {
optimizer.registerComponentType('Transform');
optimizer.registerComponentType('Velocity');
});
it('应该能够创建单个组件的掩码', () => {
const mask = optimizer.createSingleComponentMask('Transform');
expect(mask.toString()).toBe('1');
2025-07-29 15:56:40 +08:00
});
it('不同组件应该有不同的掩码', () => {
const transformMask = optimizer.createSingleComponentMask('Transform');
const velocityMask = optimizer.createSingleComponentMask('Velocity');
expect(transformMask.toString()).toBe('1');
expect(velocityMask.toString()).toBe('2');
2025-07-29 15:56:40 +08:00
});
it('创建未注册组件的掩码应该抛出错误', () => {
expect(() => {
optimizer.createSingleComponentMask('UnknownComponent');
}).toThrow('Component type not registered: UnknownComponent');
});
it('相同组件的掩码应该使用缓存', () => {
const mask1 = optimizer.createSingleComponentMask('Transform');
const mask2 = optimizer.createSingleComponentMask('Transform');
expect(mask1).toBe(mask2);
});
});
describe('组合掩码创建', () => {
beforeEach(() => {
optimizer.registerComponentType('Transform');
optimizer.registerComponentType('Velocity');
optimizer.registerComponentType('Health');
});
it('应该能够创建多个组件的组合掩码', () => {
const mask = optimizer.createCombinedMask(['Transform', 'Velocity']);
expect(mask.toString()).toBe('3'); // 1 | 2 = 3
2025-07-29 15:56:40 +08:00
});
it('组件顺序不应该影响掩码结果', () => {
const mask1 = optimizer.createCombinedMask(['Transform', 'Velocity']);
const mask2 = optimizer.createCombinedMask(['Velocity', 'Transform']);
expect(mask1).toBe(mask2);
});
it('三个组件的组合掩码应该正确', () => {
const mask = optimizer.createCombinedMask(['Transform', 'Velocity', 'Health']);
expect(mask.toString()).toBe('7'); // 1 | 2 | 4 = 7
2025-07-29 15:56:40 +08:00
});
it('空数组应该返回0掩码', () => {
const mask = optimizer.createCombinedMask([]);
expect(mask.isZero()).toBe(true);
2025-07-29 15:56:40 +08:00
});
it('包含未注册组件应该抛出错误', () => {
expect(() => {
optimizer.createCombinedMask(['Transform', 'UnknownComponent']);
}).toThrow('Component type not registered: UnknownComponent');
});
});
describe('掩码检查功能', () => {
beforeEach(() => {
optimizer.registerComponentType('Transform');
optimizer.registerComponentType('Velocity');
optimizer.registerComponentType('Health');
});
it('应该能够检查掩码是否包含指定组件', () => {
const mask = optimizer.createCombinedMask(['Transform', 'Velocity']);
expect(optimizer.maskContainsComponent(mask, 'Transform')).toBe(true);
expect(optimizer.maskContainsComponent(mask, 'Velocity')).toBe(true);
expect(optimizer.maskContainsComponent(mask, 'Health')).toBe(false);
});
it('应该能够检查掩码是否包含所有指定组件', () => {
const mask = optimizer.createCombinedMask(['Transform', 'Velocity', 'Health']);
expect(optimizer.maskContainsAllComponents(mask, ['Transform'])).toBe(true);
expect(optimizer.maskContainsAllComponents(mask, ['Transform', 'Velocity'])).toBe(true);
expect(optimizer.maskContainsAllComponents(mask, ['Transform', 'Velocity', 'Health'])).toBe(true);
});
it('不完全包含时maskContainsAllComponents应该返回false', () => {
const mask = optimizer.createCombinedMask(['Transform']);
expect(optimizer.maskContainsAllComponents(mask, ['Transform', 'Velocity'])).toBe(false);
});
it('应该能够检查掩码是否包含任一指定组件', () => {
const mask = optimizer.createCombinedMask(['Transform']);
expect(optimizer.maskContainsAnyComponent(mask, ['Transform', 'Velocity'])).toBe(true);
expect(optimizer.maskContainsAnyComponent(mask, ['Velocity', 'Health'])).toBe(false);
});
});
describe('掩码操作功能', () => {
beforeEach(() => {
optimizer.registerComponentType('Transform');
optimizer.registerComponentType('Velocity');
optimizer.registerComponentType('Health');
});
it('应该能够向掩码添加组件', () => {
let mask = optimizer.createSingleComponentMask('Transform');
mask = optimizer.addComponentToMask(mask, 'Velocity');
expect(optimizer.maskContainsComponent(mask, 'Transform')).toBe(true);
expect(optimizer.maskContainsComponent(mask, 'Velocity')).toBe(true);
});
it('应该能够从掩码移除组件', () => {
let mask = optimizer.createCombinedMask(['Transform', 'Velocity']);
mask = optimizer.removeComponentFromMask(mask, 'Velocity');
expect(optimizer.maskContainsComponent(mask, 'Transform')).toBe(true);
expect(optimizer.maskContainsComponent(mask, 'Velocity')).toBe(false);
});
it('移除不存在的组件不应该影响掩码', () => {
const originalMask = optimizer.createSingleComponentMask('Transform');
const newMask = optimizer.removeComponentFromMask(originalMask, 'Velocity');
expect(newMask.equals(originalMask)).toBe(true);
2025-07-29 15:56:40 +08:00
});
});
describe('工具功能', () => {
beforeEach(() => {
optimizer.registerComponentType('Transform');
optimizer.registerComponentType('Velocity');
optimizer.registerComponentType('Health');
});
it('应该能够将掩码转换为组件名称数组', () => {
const mask = optimizer.createCombinedMask(['Transform', 'Health']);
const componentNames = optimizer.maskToComponentNames(mask);
expect(componentNames).toContain('Transform');
expect(componentNames).toContain('Health');
expect(componentNames).not.toContain('Velocity');
expect(componentNames.length).toBe(2);
});
it('空掩码应该返回空数组', () => {
const componentNames = optimizer.maskToComponentNames(BigIntFactory.zero());
2025-07-29 15:56:40 +08:00
expect(componentNames).toEqual([]);
});
it('应该能够获取掩码中组件的数量', () => {
const mask1 = optimizer.createSingleComponentMask('Transform');
const mask2 = optimizer.createCombinedMask(['Transform', 'Velocity']);
const mask3 = optimizer.createCombinedMask(['Transform', 'Velocity', 'Health']);
expect(optimizer.getComponentCount(mask1)).toBe(1);
expect(optimizer.getComponentCount(mask2)).toBe(2);
expect(optimizer.getComponentCount(mask3)).toBe(3);
});
it('空掩码的组件数量应该为0', () => {
expect(optimizer.getComponentCount(BigIntFactory.zero())).toBe(0);
2025-07-29 15:56:40 +08:00
});
});
describe('缓存和性能优化', () => {
beforeEach(() => {
optimizer.registerComponentType('Transform');
optimizer.registerComponentType('Velocity');
optimizer.registerComponentType('Health');
});
it('应该能够预计算常用掩码组合', () => {
const commonCombinations = [
['Transform', 'Velocity'],
['Transform', 'Health'],
['Velocity', 'Health']
];
optimizer.precomputeCommonMasks(commonCombinations);
// 验证掩码已被缓存
const stats = optimizer.getCacheStats();
expect(stats.size).toBeGreaterThan(0);
});
it('应该能够获取缓存统计信息', () => {
optimizer.createSingleComponentMask('Transform');
optimizer.createCombinedMask(['Transform', 'Velocity']);
const stats = optimizer.getCacheStats();
expect(stats.size).toBeGreaterThan(0);
expect(stats.componentTypes).toBe(3);
});
it('应该能够清空缓存', () => {
optimizer.createSingleComponentMask('Transform');
optimizer.clearCache();
const stats = optimizer.getCacheStats();
expect(stats.size).toBe(0);
expect(stats.componentTypes).toBe(3); // 组件类型不会被清除
});
it('应该能够重置优化器', () => {
optimizer.registerComponentType('NewComponent');
optimizer.createSingleComponentMask('Transform');
optimizer.reset();
const stats = optimizer.getCacheStats();
expect(stats.size).toBe(0);
expect(stats.componentTypes).toBe(0);
});
});
describe('边界情况和错误处理', () => {
it('处理大量组件类型注册', () => {
for (let i = 0; i < 100; i++) {
const id = optimizer.registerComponentType(`Component${i}`);
expect(id).toBe(i);
}
});
it('处理大掩码值', () => {
// 注册64个组件类型
for (let i = 0; i < 64; i++) {
optimizer.registerComponentType(`Component${i}`);
}
const mask = optimizer.createSingleComponentMask('Component63');
expect(mask.toString()).toBe(BigIntFactory.one().shiftLeft(63).toString());
2025-07-29 15:56:40 +08:00
});
it('空组件名称数组的组合掩码', () => {
const mask = optimizer.createCombinedMask([]);
expect(mask.isZero()).toBe(true);
2025-07-29 15:56:40 +08:00
expect(optimizer.getComponentCount(mask)).toBe(0);
});
});
describe('性能测试', () => {
beforeEach(() => {
// 注册一些组件类型
for (let i = 0; i < 10; i++) {
optimizer.registerComponentType(`Component${i}`);
}
});
it('大量掩码创建应该高效', () => {
const startTime = performance.now();
for (let i = 0; i < 1000; i++) {
optimizer.createSingleComponentMask('Component0');
}
const endTime = performance.now();
expect(endTime - startTime).toBeLessThan(100); // 应该在100ms内完成
});
it('大量掩码检查应该高效', () => {
const mask = optimizer.createCombinedMask(['Component0', 'Component1', 'Component2']);
const startTime = performance.now();
for (let i = 0; i < 10000; i++) {
optimizer.maskContainsComponent(mask, 'Component1');
}
const endTime = performance.now();
expect(endTime - startTime).toBeLessThan(100); // 应该在100ms内完成
});
});
});