using System.Diagnostics.CodeAnalysis; using System.Reflection; using Arch.Core; using GFramework.Core.Abstractions.ecs; using GFramework.Core.architecture; using GFramework.Core.ecs; using GFramework.Core.ecs.components; using GFramework.Core.ecs.systems; using GFramework.Core.ioc; using GFramework.Core.logging; using NUnit.Framework; namespace GFramework.Core.Tests.ecs; /// /// ECS集成测试类,用于验证ECS系统的整体功能和性能表现。 /// 包括实体管理、组件操作、系统调度、优先级控制以及性能基准测试。 /// [TestFixture] [Experimental("GFrameworkECS")] public class EcsIntegrationTests { /// /// 测试初始化方法,在每个测试方法执行前运行。 /// 负责初始化日志工厂、依赖注入容器和架构上下文。 /// [SetUp] public void Setup() { LoggerFactoryResolver.Provider = new ConsoleLoggerFactoryProvider(); _container = new MicrosoftDiContainer(); var loggerField = typeof(MicrosoftDiContainer).GetField("_logger", BindingFlags.NonPublic | BindingFlags.Instance); loggerField?.SetValue(_container, LoggerFactoryResolver.Provider.CreateLogger(nameof(EcsIntegrationTests))); _context = new ArchitectureContext(_container); } /// /// 测试清理方法,在每个测试方法执行后运行。 /// 负责释放ECS世界资源并清空容器和上下文。 /// [TearDown] public void TearDown() { _ecsWorld?.Dispose(); _ecsWorld = null; _container?.Clear(); _context = null; } private MicrosoftDiContainer? _container; private ArchitectureContext? _context; private EcsWorld? _ecsWorld; /// /// 初始化ECS系统并注册指定类型的系统实例。 /// /// 需要注册的系统类型数组 private void InitializeEcsWithSystems(params Type[] systemTypes) { _ecsWorld = new EcsWorld(); _container!.Register(_ecsWorld); _container.Register(_ecsWorld as IEcsWorld); var systems = new List(); foreach (var systemType in systemTypes) { var system = (IEcsSystem)Activator.CreateInstance(systemType)!; system.SetContext(_context!); system.Initialize(); systems.Add(system); _container.RegisterPlurality(system); } _container.Register(systems as IReadOnlyList); } /// /// 测试ECS初始化功能,验证是否能正确创建EcsWorld实例。 /// [Test] public void InitializeEcs_Should_Create_EcsWorld() { _ecsWorld = new EcsWorld(); _container!.Register(_ecsWorld); _container.Register(_ecsWorld); var ecsWorld = _context!.GetEcsWorld(); Assert.That(ecsWorld, Is.Not.Null); Assert.That(ecsWorld.EntityCount, Is.EqualTo(0)); } /// /// 测试实体创建功能,验证创建实体后实体计数是否正确增加。 /// [Test] public void CreateEntity_Should_Increase_EntityCount() { _ecsWorld = new EcsWorld(); var entity = _ecsWorld.CreateEntity(typeof(Position), typeof(Velocity)); Assert.That(_ecsWorld.EntityCount, Is.EqualTo(1)); Assert.That(_ecsWorld.IsAlive(entity), Is.True); } /// /// 测试实体销毁功能,验证销毁实体后实体计数是否正确减少。 /// [Test] public void DestroyEntity_Should_Decrease_EntityCount() { _ecsWorld = new EcsWorld(); var entity = _ecsWorld.CreateEntity(typeof(Position)); _ecsWorld.DestroyEntity(entity); Assert.That(_ecsWorld.EntityCount, Is.EqualTo(0)); Assert.That(_ecsWorld.IsAlive(entity), Is.False); } /// /// 测试组件设置功能,验证能否正确存储和获取组件数据。 /// [Test] public void SetComponent_Should_Store_ComponentData() { _ecsWorld = new EcsWorld(); var entity = _ecsWorld.CreateEntity(typeof(Position)); var world = _ecsWorld.InternalWorld; world.Set(entity, new Position(10, 20)); Assert.That(world.Has(entity), Is.True); ref var pos = ref world.Get(entity); Assert.That(pos.X, Is.EqualTo(10)); Assert.That(pos.Y, Is.EqualTo(20)); } /// /// 测试世界清理功能,验证能否清除所有实体。 /// [Test] public void ClearWorld_Should_Remove_All_Entities() { _ecsWorld = new EcsWorld(); for (int i = 0; i < 10; i++) { _ecsWorld.CreateEntity(typeof(Position)); } _ecsWorld.Clear(); Assert.That(_ecsWorld.EntityCount, Is.EqualTo(0)); } /// /// 测试ECS系统注册功能,验证系统能否正确添加到运行器中。 /// [Test] public void RegisterEcsSystem_Should_Add_System_To_Runner() { InitializeEcsWithSystems(typeof(MovementSystem)); var systems = _container!.Get>(); Assert.That(systems, Is.Not.Null); Assert.That(systems!.Count, Is.EqualTo(1)); Assert.That(systems[0], Is.InstanceOf()); } /// /// 测试移动系统功能,验证系统能否正确更新单个实体的位置。 /// [Test] public void MovementSystem_Should_Update_Position() { InitializeEcsWithSystems(typeof(MovementSystem)); var entity = _ecsWorld!.CreateEntity(typeof(Position), typeof(Velocity)); var world = _ecsWorld.InternalWorld; world.Set(entity, new Position(0, 0)); world.Set(entity, new Velocity(10, 5)); var systems = _container!.Get>(); var movementSystem = systems!.First(s => s is MovementSystem) as MovementSystem; movementSystem!.Update(1.0f); ref var pos = ref world.Get(entity); Assert.That(pos.X, Is.EqualTo(10).Within(0.001f)); Assert.That(pos.Y, Is.EqualTo(5).Within(0.001f)); } /// /// 测试移动系统功能,验证系统能否正确批量更新多个实体的位置。 /// [Test] public void MovementSystem_Should_Update_Multiple_Entities() { InitializeEcsWithSystems(typeof(MovementSystem)); var world = _ecsWorld!.InternalWorld; var entities = new Entity[100]; for (var i = 0; i < 100; i++) { entities[i] = _ecsWorld.CreateEntity(typeof(Position), typeof(Velocity)); world.Set(entities[i], new Position(0, 0)); world.Set(entities[i], new Velocity(i, i * 2)); } var systems = _container!.Get>(); var movementSystem = systems!.First(s => s is MovementSystem) as MovementSystem; movementSystem!.Update(0.5f); for (var i = 0; i < 100; i++) { ref var pos = ref world.Get(entities[i]); Assert.That(pos.X, Is.EqualTo(i * 0.5f).Within(0.001f)); Assert.That(pos.Y, Is.EqualTo(i * 2 * 0.5f).Within(0.001f)); } } /// /// 测试ECS系统运行器的优先级调度功能,验证系统是否按优先级顺序执行。 /// [Test] public void EcsSystemRunner_Should_Respect_Priority() { InitializeEcsWithSystems(typeof(LowPrioritySystem), typeof(HighPrioritySystem)); var systems = _container!.Get>(); Assert.That(systems, Is.Not.Null); Assert.That(systems!.Count, Is.EqualTo(2)); var sortedSystems = systems.OrderBy(s => s.Priority).ToList(); Assert.That(sortedSystems[0], Is.InstanceOf()); Assert.That(sortedSystems[1], Is.InstanceOf()); } /// /// 测试未初始化情况下获取ECS世界的异常处理。 /// [Test] public void GetEcsWorld_Without_Initialize_Should_Throw() { Assert.Throws(() => { _context!.GetEcsWorld(); }, "ECS World not initialized. Enable ECS in configuration."); } /// /// 性能基准测试:验证更新10000个实体的性能表现。 /// [Test] public void Performance_Test_10000_Entities() { InitializeEcsWithSystems(typeof(MovementSystem)); var world = _ecsWorld!.InternalWorld; for (int i = 0; i < 10000; i++) { var entity = _ecsWorld.CreateEntity(typeof(Position), typeof(Velocity)); world.Set(entity, new Position(0, 0)); world.Set(entity, new Velocity(1, 1)); } var systems = _container!.Get>(); var movementSystem = systems!.First(s => s is MovementSystem) as MovementSystem; var startTime = DateTime.UtcNow; movementSystem!.Update(0.016f); var elapsed = (DateTime.UtcNow - startTime).TotalMilliseconds; Assert.That(_ecsWorld.EntityCount, Is.EqualTo(10000)); Assert.That(elapsed, Is.LessThan(100), $"Updating 10000 entities took: {elapsed}ms"); } /// /// 性能基准测试:验证创建1000个实体的性能表现。 /// [Test] public void Performance_Test_1000_Entities_Creation() { _ecsWorld = new EcsWorld(); var world = _ecsWorld.InternalWorld; var startTime = DateTime.UtcNow; for (int i = 0; i < 1000; i++) { var entity = _ecsWorld.CreateEntity(typeof(Position), typeof(Velocity)); world.Set(entity, new Position(0, 0)); world.Set(entity, new Velocity(1, 1)); } var elapsed = (DateTime.UtcNow - startTime).TotalMilliseconds; Assert.That(_ecsWorld.EntityCount, Is.EqualTo(1000)); Assert.That(elapsed, Is.LessThan(50), $"Creating 1000 entities took: {elapsed}ms"); } } /// /// 高优先级系统示例,用于测试系统调度优先级功能。 /// public class HighPrioritySystem : EcsSystemBase { /// /// 获取系统优先级,数值越小优先级越高。 /// public override int Priority => -100; /// /// ECS初始化回调方法。 /// protected override void OnEcsInit() { } /// /// 系统更新方法。 /// /// 帧间隔时间 public override void Update(float deltaTime) { } } /// /// 低优先级系统示例,用于测试系统调度优先级功能。 /// public class LowPrioritySystem : EcsSystemBase { /// /// 获取系统优先级,数值越大优先级越低。 /// public override int Priority => 100; /// /// ECS初始化回调方法。 /// protected override void OnEcsInit() { } /// /// 系统更新方法。 /// /// 帧间隔时间 public override void Update(float deltaTime) { } }