2025-07-28 17:38:18 +08:00
|
|
|
import { Component } from '../../src/ECS/Component';
|
|
|
|
|
import { Entity } from '../../src/ECS/Entity';
|
2025-10-10 16:31:43 +08:00
|
|
|
import { Scene } from '../../src/ECS/Scene';
|
2025-07-28 17:38:18 +08:00
|
|
|
|
|
|
|
|
// 测试组件
|
|
|
|
|
class TestComponent extends Component {
|
|
|
|
|
public value: number = 100;
|
|
|
|
|
public onAddedCalled = false;
|
|
|
|
|
public onRemovedCalled = false;
|
|
|
|
|
|
|
|
|
|
public override onAddedToEntity(): void {
|
|
|
|
|
this.onAddedCalled = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override onRemovedFromEntity(): void {
|
|
|
|
|
this.onRemovedCalled = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class AnotherTestComponent extends Component {
|
|
|
|
|
public name: string = 'test';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
describe('Component - 组件基类测试', () => {
|
|
|
|
|
let component: TestComponent;
|
|
|
|
|
let entity: Entity;
|
2025-10-10 16:31:43 +08:00
|
|
|
let scene: Scene;
|
2025-07-28 17:38:18 +08:00
|
|
|
|
|
|
|
|
beforeEach(() => {
|
|
|
|
|
Component._idGenerator = 0;
|
|
|
|
|
component = new TestComponent();
|
2025-10-10 16:31:43 +08:00
|
|
|
scene = new Scene();
|
|
|
|
|
entity = scene.createEntity('TestEntity');
|
2025-07-28 17:38:18 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
describe('基本功能', () => {
|
|
|
|
|
test('应该能够创建组件实例', () => {
|
|
|
|
|
expect(component).toBeInstanceOf(Component);
|
|
|
|
|
expect(component).toBeInstanceOf(TestComponent);
|
|
|
|
|
expect(component.id).toBeGreaterThanOrEqual(0);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('每个组件应该有唯一的ID', () => {
|
|
|
|
|
const component1 = new TestComponent();
|
|
|
|
|
const component2 = new TestComponent();
|
|
|
|
|
const component3 = new AnotherTestComponent();
|
|
|
|
|
|
|
|
|
|
expect(component1.id).not.toBe(component2.id);
|
|
|
|
|
expect(component2.id).not.toBe(component3.id);
|
|
|
|
|
expect(component1.id).not.toBe(component3.id);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('组件ID应该递增分配', () => {
|
|
|
|
|
const startId = Component._idGenerator;
|
|
|
|
|
const component1 = new TestComponent();
|
|
|
|
|
const component2 = new TestComponent();
|
|
|
|
|
|
|
|
|
|
expect(component2.id).toBe(component1.id + 1);
|
|
|
|
|
expect(component1.id).toBeGreaterThanOrEqual(startId);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
describe('生命周期回调', () => {
|
|
|
|
|
test('添加到实体时应该调用onAddedToEntity', () => {
|
|
|
|
|
expect(component.onAddedCalled).toBe(false);
|
2025-09-30 22:26:44 +08:00
|
|
|
|
2025-07-28 17:38:18 +08:00
|
|
|
entity.addComponent(component);
|
|
|
|
|
expect(component.onAddedCalled).toBe(true);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('从实体移除时应该调用onRemovedFromEntity', () => {
|
|
|
|
|
entity.addComponent(component);
|
|
|
|
|
expect(component.onRemovedCalled).toBe(false);
|
2025-09-30 22:26:44 +08:00
|
|
|
|
2025-07-28 17:38:18 +08:00
|
|
|
entity.removeComponent(component);
|
|
|
|
|
expect(component.onRemovedCalled).toBe(true);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('基类的默认生命周期方法应该安全调用', () => {
|
|
|
|
|
const baseComponent = new (class extends Component {})();
|
2025-09-30 22:26:44 +08:00
|
|
|
|
2025-07-28 17:38:18 +08:00
|
|
|
// 这些方法不应该抛出异常
|
|
|
|
|
expect(() => {
|
|
|
|
|
baseComponent.onAddedToEntity();
|
|
|
|
|
baseComponent.onRemovedFromEntity();
|
|
|
|
|
}).not.toThrow();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2025-09-30 22:26:44 +08:00
|
|
|
describe('实体-组件关系', () => {
|
|
|
|
|
test('组件可以被添加到实体', () => {
|
|
|
|
|
expect(() => {
|
|
|
|
|
entity.addComponent(component);
|
|
|
|
|
}).not.toThrow();
|
|
|
|
|
|
|
|
|
|
expect(entity.hasComponent(TestComponent)).toBe(true);
|
|
|
|
|
expect(entity.getComponent(TestComponent)).toBe(component);
|
2025-07-28 17:38:18 +08:00
|
|
|
});
|
|
|
|
|
|
2025-09-30 22:26:44 +08:00
|
|
|
test('组件可以从实体移除', () => {
|
2025-07-28 17:38:18 +08:00
|
|
|
entity.addComponent(component);
|
2025-09-30 22:26:44 +08:00
|
|
|
|
2025-07-28 17:38:18 +08:00
|
|
|
expect(() => {
|
2025-09-30 22:26:44 +08:00
|
|
|
entity.removeComponent(component);
|
2025-07-28 17:38:18 +08:00
|
|
|
}).not.toThrow();
|
2025-09-30 22:26:44 +08:00
|
|
|
|
|
|
|
|
expect(entity.hasComponent(TestComponent)).toBe(false);
|
2025-07-28 17:38:18 +08:00
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
describe('边界情况', () => {
|
|
|
|
|
test('大量组件创建应该有不同的ID', () => {
|
|
|
|
|
const components: Component[] = [];
|
|
|
|
|
const count = 1000;
|
2025-09-30 22:26:44 +08:00
|
|
|
|
2025-07-28 17:38:18 +08:00
|
|
|
for (let i = 0; i < count; i++) {
|
|
|
|
|
components.push(new TestComponent());
|
|
|
|
|
}
|
2025-09-30 22:26:44 +08:00
|
|
|
|
2025-07-28 17:38:18 +08:00
|
|
|
// 检查所有ID都不同
|
|
|
|
|
const ids = new Set(components.map(c => c.id));
|
|
|
|
|
expect(ids.size).toBe(count);
|
|
|
|
|
});
|
2025-09-30 22:26:44 +08:00
|
|
|
|
|
|
|
|
test('组件应该是纯数据容器', () => {
|
|
|
|
|
// 验证组件只有数据字段
|
|
|
|
|
const comp = new TestComponent();
|
|
|
|
|
expect(comp.value).toBe(100);
|
|
|
|
|
|
|
|
|
|
// 可以修改数据
|
|
|
|
|
comp.value = 200;
|
|
|
|
|
expect(comp.value).toBe(200);
|
|
|
|
|
});
|
2025-07-28 17:38:18 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
describe('继承和多态', () => {
|
|
|
|
|
test('不同类型的组件应该都继承自Component', () => {
|
|
|
|
|
const test1 = new TestComponent();
|
|
|
|
|
const test2 = new AnotherTestComponent();
|
2025-09-30 22:26:44 +08:00
|
|
|
|
2025-07-28 17:38:18 +08:00
|
|
|
expect(test1).toBeInstanceOf(Component);
|
|
|
|
|
expect(test2).toBeInstanceOf(Component);
|
|
|
|
|
expect(test1).toBeInstanceOf(TestComponent);
|
|
|
|
|
expect(test2).toBeInstanceOf(AnotherTestComponent);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('组件应该能够重写基类方法', () => {
|
|
|
|
|
const test = new TestComponent();
|
2025-09-30 22:26:44 +08:00
|
|
|
|
|
|
|
|
// 重写生命周期方法应该工作
|
|
|
|
|
entity.addComponent(test);
|
|
|
|
|
expect(test.onAddedCalled).toBe(true);
|
2025-07-28 17:38:18 +08:00
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|