import { ComponentRegistry, ComponentStorage, ComponentStorageManager, ComponentType } from '../../../src/ECS/Core/ComponentStorage'; import { Component } from '../../../src/ECS/Component'; import { BigIntFactory } from '../../../src/ECS/Utils/BigIntCompatibility'; // 测试组件类(默认使用原始存储) class TestComponent extends Component { constructor(public value: number = 0) { super(); } } class PositionComponent extends Component { constructor(public x: number = 0, public y: number = 0) { super(); } } class VelocityComponent extends Component { constructor(public vx: number = 0, public vy: number = 0) { super(); } } class HealthComponent extends Component { constructor(public health: number = 100, public maxHealth: number = 100) { super(); } } describe('ComponentRegistry - 组件注册表测试', () => { beforeEach(() => { // 重置注册表状态 (ComponentRegistry as any).componentTypes = new Map(); (ComponentRegistry as any).nextBitIndex = 0; }); describe('组件注册功能', () => { test('应该能够注册组件类型', () => { const bitIndex = ComponentRegistry.register(TestComponent); expect(bitIndex).toBe(0); expect(ComponentRegistry.isRegistered(TestComponent)).toBe(true); }); test('重复注册相同组件应该返回相同的位索引', () => { const bitIndex1 = ComponentRegistry.register(TestComponent); const bitIndex2 = ComponentRegistry.register(TestComponent); expect(bitIndex1).toBe(bitIndex2); expect(bitIndex1).toBe(0); }); test('应该能够注册多个组件类型', () => { const bitIndex1 = ComponentRegistry.register(TestComponent); const bitIndex2 = ComponentRegistry.register(PositionComponent); const bitIndex3 = ComponentRegistry.register(VelocityComponent); expect(bitIndex1).toBe(0); expect(bitIndex2).toBe(1); expect(bitIndex3).toBe(2); }); test('应该能够检查组件是否已注册', () => { expect(ComponentRegistry.isRegistered(TestComponent)).toBe(false); ComponentRegistry.register(TestComponent); expect(ComponentRegistry.isRegistered(TestComponent)).toBe(true); }); test('超过最大组件数量应该抛出错误', () => { // 设置较小的最大组件数量用于测试 (ComponentRegistry as any).maxComponents = 3; ComponentRegistry.register(TestComponent); ComponentRegistry.register(PositionComponent); ComponentRegistry.register(VelocityComponent); expect(() => { ComponentRegistry.register(HealthComponent); }).toThrow('Maximum number of component types (3) exceeded'); }); }); describe('位掩码功能', () => { test('应该能够获取组件的位掩码', () => { ComponentRegistry.register(TestComponent); ComponentRegistry.register(PositionComponent); const mask1 = ComponentRegistry.getBitMask(TestComponent); const mask2 = ComponentRegistry.getBitMask(PositionComponent); expect(mask1.toString()).toBe('1'); // 2^0 expect(mask2.toString()).toBe('2'); // 2^1 }); test('应该能够获取组件的位索引', () => { ComponentRegistry.register(TestComponent); ComponentRegistry.register(PositionComponent); const index1 = ComponentRegistry.getBitIndex(TestComponent); const index2 = ComponentRegistry.getBitIndex(PositionComponent); expect(index1).toBe(0); expect(index2).toBe(1); }); test('获取未注册组件的位掩码应该抛出错误', () => { expect(() => { ComponentRegistry.getBitMask(TestComponent); }).toThrow('Component type TestComponent is not registered'); }); test('获取未注册组件的位索引应该抛出错误', () => { expect(() => { ComponentRegistry.getBitIndex(TestComponent); }).toThrow('Component type TestComponent is not registered'); }); }); describe('注册表管理', () => { test('应该能够获取所有已注册的组件类型', () => { ComponentRegistry.register(TestComponent); ComponentRegistry.register(PositionComponent); const allTypes = ComponentRegistry.getAllRegisteredTypes(); expect(allTypes.size).toBe(2); expect(allTypes.has(TestComponent)).toBe(true); expect(allTypes.has(PositionComponent)).toBe(true); expect(allTypes.get(TestComponent)).toBe(0); expect(allTypes.get(PositionComponent)).toBe(1); }); test('返回的注册表副本不应该影响原始数据', () => { ComponentRegistry.register(TestComponent); const allTypes = ComponentRegistry.getAllRegisteredTypes(); allTypes.set(PositionComponent, 999); expect(ComponentRegistry.isRegistered(PositionComponent)).toBe(false); }); }); }); describe('ComponentStorage - 组件存储器测试', () => { let storage: ComponentStorage; beforeEach(() => { // 重置注册表 (ComponentRegistry as any).componentTypes = new Map(); (ComponentRegistry as any).nextBitIndex = 0; storage = new ComponentStorage(TestComponent); }); describe('基本存储功能', () => { test('应该能够创建组件存储器', () => { expect(storage).toBeInstanceOf(ComponentStorage); expect(storage.size).toBe(0); expect(storage.type).toBe(TestComponent); }); test('应该能够添加组件', () => { const component = new TestComponent(100); storage.addComponent(1, component); expect(storage.size).toBe(1); expect(storage.hasComponent(1)).toBe(true); expect(storage.getComponent(1)).toBe(component); }); test('重复添加组件到同一实体应该抛出错误', () => { const component1 = new TestComponent(100); const component2 = new TestComponent(200); storage.addComponent(1, component1); expect(() => { storage.addComponent(1, component2); }).toThrow('Entity 1 already has component TestComponent'); }); test('应该能够获取组件', () => { const component = new TestComponent(100); storage.addComponent(1, component); const retrieved = storage.getComponent(1); expect(retrieved).toBe(component); expect(retrieved!.value).toBe(100); }); test('获取不存在的组件应该返回null', () => { const retrieved = storage.getComponent(999); expect(retrieved).toBeNull(); }); test('应该能够检查实体是否有组件', () => { expect(storage.hasComponent(1)).toBe(false); storage.addComponent(1, new TestComponent(100)); expect(storage.hasComponent(1)).toBe(true); }); test('应该能够移除组件', () => { const component = new TestComponent(100); storage.addComponent(1, component); const removed = storage.removeComponent(1); expect(removed).toBe(component); expect(storage.size).toBe(0); expect(storage.hasComponent(1)).toBe(false); expect(storage.getComponent(1)).toBeNull(); }); test('移除不存在的组件应该返回null', () => { const removed = storage.removeComponent(999); expect(removed).toBeNull(); }); }); describe('遍历和批量操作', () => { test('应该能够遍历所有组件', () => { const component1 = new TestComponent(100); const component2 = new TestComponent(200); const component3 = new TestComponent(300); storage.addComponent(1, component1); storage.addComponent(2, component2); storage.addComponent(3, component3); const results: Array<{component: TestComponent, entityId: number, index: number}> = []; storage.forEach((component, entityId, index) => { results.push({ component, entityId, index }); }); expect(results.length).toBe(3); expect(results.find(r => r.entityId === 1)?.component).toBe(component1); expect(results.find(r => r.entityId === 2)?.component).toBe(component2); expect(results.find(r => r.entityId === 3)?.component).toBe(component3); }); test('应该能够获取密集数组', () => { const component1 = new TestComponent(100); const component2 = new TestComponent(200); storage.addComponent(1, component1); storage.addComponent(2, component2); const { components, entityIds } = storage.getDenseArray(); expect(components.length).toBe(2); expect(entityIds.length).toBe(2); expect(components).toContain(component1); expect(components).toContain(component2); expect(entityIds).toContain(1); expect(entityIds).toContain(2); }); test('应该能够清空所有组件', () => { storage.addComponent(1, new TestComponent(100)); storage.addComponent(2, new TestComponent(200)); expect(storage.size).toBe(2); storage.clear(); expect(storage.size).toBe(0); expect(storage.hasComponent(1)).toBe(false); expect(storage.hasComponent(2)).toBe(false); }); }); describe('内存管理和优化', () => { test('应该能够重用空闲索引', () => { const component1 = new TestComponent(100); const component2 = new TestComponent(200); const component3 = new TestComponent(300); // 添加三个组件 storage.addComponent(1, component1); storage.addComponent(2, component2); storage.addComponent(3, component3); // 移除中间的组件 storage.removeComponent(2); // 添加新组件应该重用空闲索引 const component4 = new TestComponent(400); storage.addComponent(4, component4); expect(storage.size).toBe(3); expect(storage.getComponent(4)).toBe(component4); }); test('应该能够压缩存储', () => { // 添加多个组件 storage.addComponent(1, new TestComponent(100)); storage.addComponent(2, new TestComponent(200)); storage.addComponent(3, new TestComponent(300)); storage.addComponent(4, new TestComponent(400)); // 移除部分组件创建空洞 storage.removeComponent(2); storage.removeComponent(3); let stats = storage.getStats(); expect(stats.freeSlots).toBe(2); expect(stats.fragmentation).toBeGreaterThan(0); // 压缩存储 storage.compact(); stats = storage.getStats(); expect(stats.freeSlots).toBe(0); expect(stats.fragmentation).toBe(0); expect(storage.size).toBe(2); expect(storage.hasComponent(1)).toBe(true); expect(storage.hasComponent(4)).toBe(true); }); test('没有空洞时压缩应该不做任何操作', () => { storage.addComponent(1, new TestComponent(100)); storage.addComponent(2, new TestComponent(200)); const statsBefore = storage.getStats(); storage.compact(); const statsAfter = storage.getStats(); expect(statsBefore).toEqual(statsAfter); }); test('应该能够获取存储统计信息', () => { storage.addComponent(1, new TestComponent(100)); storage.addComponent(2, new TestComponent(200)); storage.addComponent(3, new TestComponent(300)); // 移除一个组件创建空洞 storage.removeComponent(2); const stats = storage.getStats(); expect(stats.totalSlots).toBe(3); expect(stats.usedSlots).toBe(2); expect(stats.freeSlots).toBe(1); expect(stats.fragmentation).toBeCloseTo(1/3); }); }); describe('边界情况', () => { test('空存储器的统计信息应该正确', () => { const stats = storage.getStats(); expect(stats.totalSlots).toBe(0); expect(stats.usedSlots).toBe(0); expect(stats.freeSlots).toBe(0); expect(stats.fragmentation).toBe(0); }); test('遍历空存储器应该安全', () => { let callCount = 0; storage.forEach(() => { callCount++; }); expect(callCount).toBe(0); }); test('获取空存储器的密集数组应该返回空数组', () => { const { components, entityIds } = storage.getDenseArray(); expect(components.length).toBe(0); expect(entityIds.length).toBe(0); }); }); }); describe('ComponentStorageManager - 组件存储管理器测试', () => { let manager: ComponentStorageManager; beforeEach(() => { // 重置注册表 (ComponentRegistry as any).componentTypes = new Map(); (ComponentRegistry as any).nextBitIndex = 0; manager = new ComponentStorageManager(); }); describe('存储器管理', () => { test('应该能够创建组件存储管理器', () => { expect(manager).toBeInstanceOf(ComponentStorageManager); }); test('应该能够获取或创建组件存储器', () => { const storage1 = manager.getStorage(TestComponent); const storage2 = manager.getStorage(TestComponent); expect(storage1).toBeInstanceOf(ComponentStorage); expect(storage1).toBe(storage2); // 应该是同一个实例 }); test('不同组件类型应该有不同的存储器', () => { const storage1 = manager.getStorage(TestComponent); const storage2 = manager.getStorage(PositionComponent); expect(storage1).not.toBe(storage2); expect(storage1.type).toBe(TestComponent); expect(storage2.type).toBe(PositionComponent); }); }); describe('组件操作', () => { test('应该能够添加组件', () => { const component = new TestComponent(100); manager.addComponent(1, component); expect(manager.hasComponent(1, TestComponent)).toBe(true); expect(manager.getComponent(1, TestComponent)).toBe(component); }); test('应该能够获取组件', () => { const testComponent = new TestComponent(100); const positionComponent = new PositionComponent(10, 20); manager.addComponent(1, testComponent); manager.addComponent(1, positionComponent); expect(manager.getComponent(1, TestComponent)).toBe(testComponent); expect(manager.getComponent(1, PositionComponent)).toBe(positionComponent); }); test('获取不存在的组件应该返回null', () => { const result = manager.getComponent(999, TestComponent); expect(result).toBeNull(); }); test('应该能够检查实体是否有组件', () => { expect(manager.hasComponent(1, TestComponent)).toBe(false); manager.addComponent(1, new TestComponent(100)); expect(manager.hasComponent(1, TestComponent)).toBe(true); }); test('应该能够移除组件', () => { const component = new TestComponent(100); manager.addComponent(1, component); const removed = manager.removeComponent(1, TestComponent); expect(removed).toBe(component); expect(manager.hasComponent(1, TestComponent)).toBe(false); }); test('移除不存在的组件应该返回null', () => { const removed = manager.removeComponent(999, TestComponent); expect(removed).toBeNull(); }); test('应该能够移除实体的所有组件', () => { manager.addComponent(1, new TestComponent(100)); manager.addComponent(1, new PositionComponent(10, 20)); manager.addComponent(1, new VelocityComponent(1, 2)); expect(manager.hasComponent(1, TestComponent)).toBe(true); expect(manager.hasComponent(1, PositionComponent)).toBe(true); expect(manager.hasComponent(1, VelocityComponent)).toBe(true); manager.removeAllComponents(1); expect(manager.hasComponent(1, TestComponent)).toBe(false); expect(manager.hasComponent(1, PositionComponent)).toBe(false); expect(manager.hasComponent(1, VelocityComponent)).toBe(false); }); }); describe('位掩码功能', () => { test('应该能够获取实体的组件位掩码', () => { // 确保组件已注册 ComponentRegistry.register(TestComponent); ComponentRegistry.register(PositionComponent); ComponentRegistry.register(VelocityComponent); manager.addComponent(1, new TestComponent(100)); manager.addComponent(1, new PositionComponent(10, 20)); const mask = manager.getComponentMask(1); // 应该包含TestComponent(位0)和PositionComponent(位1)的掩码 expect(mask.toString()).toBe('3'); // 1 | 2 = 3 }); test('没有组件的实体应该有零掩码', () => { const mask = manager.getComponentMask(999); expect(mask.isZero()).toBe(true); }); test('添加和移除组件应该更新掩码', () => { ComponentRegistry.register(TestComponent); ComponentRegistry.register(PositionComponent); manager.addComponent(1, new TestComponent(100)); let mask = manager.getComponentMask(1); expect(mask.toString()).toBe('1'); manager.addComponent(1, new PositionComponent(10, 20)); mask = manager.getComponentMask(1); expect(mask.toString()).toBe('3'); // 0b11 manager.removeComponent(1, TestComponent); mask = manager.getComponentMask(1); expect(mask.toString()).toBe('2'); // 0b10 }); }); describe('管理器级别操作', () => { test('应该能够压缩所有存储器', () => { manager.addComponent(1, new TestComponent(100)); manager.addComponent(2, new TestComponent(200)); manager.addComponent(3, new TestComponent(300)); manager.addComponent(1, new PositionComponent(10, 20)); manager.addComponent(2, new PositionComponent(30, 40)); // 移除部分组件创建空洞 manager.removeComponent(2, TestComponent); manager.removeComponent(1, PositionComponent); expect(() => { manager.compactAll(); }).not.toThrow(); }); test('应该能够获取所有存储器的统计信息', () => { manager.addComponent(1, new TestComponent(100)); manager.addComponent(2, new TestComponent(200)); manager.addComponent(1, new PositionComponent(10, 20)); const allStats = manager.getAllStats(); expect(allStats).toBeInstanceOf(Map); expect(allStats.size).toBe(2); expect(allStats.has('TestComponent')).toBe(true); expect(allStats.has('PositionComponent')).toBe(true); const testStats = allStats.get('TestComponent'); expect(testStats.usedSlots).toBe(2); const positionStats = allStats.get('PositionComponent'); expect(positionStats.usedSlots).toBe(1); }); test('应该能够清空所有存储器', () => { manager.addComponent(1, new TestComponent(100)); manager.addComponent(2, new PositionComponent(10, 20)); manager.addComponent(3, new VelocityComponent(1, 2)); expect(manager.hasComponent(1, TestComponent)).toBe(true); expect(manager.hasComponent(2, PositionComponent)).toBe(true); expect(manager.hasComponent(3, VelocityComponent)).toBe(true); manager.clear(); expect(manager.hasComponent(1, TestComponent)).toBe(false); expect(manager.hasComponent(2, PositionComponent)).toBe(false); expect(manager.hasComponent(3, VelocityComponent)).toBe(false); }); }); describe('边界情况和错误处理', () => { test('对不存在存储器的操作应该安全处理', () => { expect(manager.getComponent(1, TestComponent)).toBeNull(); expect(manager.hasComponent(1, TestComponent)).toBe(false); expect(manager.removeComponent(1, TestComponent)).toBeNull(); }); test('移除所有组件对空实体应该安全', () => { expect(() => { manager.removeAllComponents(999); }).not.toThrow(); }); test('统计信息应该处理未知组件类型', () => { // 创建一个匿名组件类来测试未知类型处理 const AnonymousComponent = class extends Component {}; manager.addComponent(1, new AnonymousComponent()); const stats = manager.getAllStats(); // 检查是否有任何统计条目(匿名类可能显示为空字符串或其他名称) expect(stats.size).toBeGreaterThan(0); }); test('多次清空应该安全', () => { manager.addComponent(1, new TestComponent(100)); manager.clear(); manager.clear(); // 第二次清空应该安全 expect(manager.hasComponent(1, TestComponent)).toBe(false); }); }); describe('性能和内存测试', () => { test('大量组件操作应该高效', () => { const entityCount = 1000; // 添加大量组件 for (let i = 1; i <= entityCount; i++) { manager.addComponent(i, new TestComponent(i)); if (i % 2 === 0) { manager.addComponent(i, new PositionComponent(i, i)); } } // 验证添加成功 expect(manager.hasComponent(1, TestComponent)).toBe(true); expect(manager.hasComponent(500, TestComponent)).toBe(true); expect(manager.hasComponent(2, PositionComponent)).toBe(true); expect(manager.hasComponent(1, PositionComponent)).toBe(false); // 移除部分组件 for (let i = 1; i <= entityCount; i += 3) { manager.removeComponent(i, TestComponent); } // 验证移除成功 expect(manager.hasComponent(1, TestComponent)).toBe(false); expect(manager.hasComponent(2, TestComponent)).toBe(true); const stats = manager.getAllStats(); expect(stats.get('TestComponent').usedSlots).toBeLessThan(entityCount); }); }); });