diff --git a/GFramework.Core.Tests/GFramework.Core.Tests.csproj b/GFramework.Core.Tests/GFramework.Core.Tests.csproj
index 672904d..2392396 100644
--- a/GFramework.Core.Tests/GFramework.Core.Tests.csproj
+++ b/GFramework.Core.Tests/GFramework.Core.Tests.csproj
@@ -3,7 +3,7 @@
enable
enable
- net8.0;net9.0;net10.0
+ net10.0;net8.0
diff --git a/GFramework.Core.Tests/command/CommandBusTests.cs b/GFramework.Core.Tests/command/CommandBusTests.cs
new file mode 100644
index 0000000..5b1be15
--- /dev/null
+++ b/GFramework.Core.Tests/command/CommandBusTests.cs
@@ -0,0 +1,88 @@
+using GFramework.Core.Abstractions.command;
+using GFramework.Core.command;
+using NUnit.Framework;
+
+namespace GFramework.Core.Tests.command;
+
+[TestFixture]
+public class CommandBusTests
+{
+ [SetUp]
+ public void SetUp()
+ {
+ _commandBus = new CommandBus();
+ }
+
+ private CommandBus _commandBus = null!;
+
+ [Test]
+ public void Send_Should_Execute_Command()
+ {
+ var input = new TestCommandInput { Value = 42 };
+ var command = new TestCommand(input);
+
+ Assert.DoesNotThrow(() => _commandBus.Send(command));
+ Assert.That(command.Executed, Is.True);
+ Assert.That(command.ExecutedValue, Is.EqualTo(42));
+ }
+
+ [Test]
+ public void Send_WithNullCommand_Should_ThrowArgumentNullException()
+ {
+ Assert.Throws(() => _commandBus.Send(null!));
+ }
+
+ [Test]
+ public void Send_WithResult_Should_Return_Value()
+ {
+ var input = new TestCommandInput { Value = 100 };
+ var command = new TestCommandWithResult(input);
+
+ var result = _commandBus.Send(command);
+
+ Assert.That(command.Executed, Is.True);
+ Assert.That(result, Is.EqualTo(200));
+ }
+
+ [Test]
+ public void Send_WithResult_AndNullCommand_Should_ThrowArgumentNullException()
+ {
+ Assert.Throws(() => _commandBus.Send(null!));
+ }
+}
+
+public sealed class TestCommandInput : ICommandInput
+{
+ public int Value { get; init; }
+}
+
+public sealed class TestCommand : AbstractCommand
+{
+ public TestCommand(TestCommandInput input) : base(input)
+ {
+ }
+
+ public bool Executed { get; private set; }
+ public int ExecutedValue { get; private set; }
+
+ protected override void OnExecute(TestCommandInput input)
+ {
+ Executed = true;
+ ExecutedValue = 42;
+ }
+}
+
+public sealed class TestCommandWithResult : AbstractCommand
+{
+ public TestCommandWithResult(TestCommandInput input) : base(input)
+ {
+ }
+
+ public bool Executed { get; private set; }
+
+ protected override int OnExecute(TestCommandInput input)
+ {
+ Executed = true;
+ return input.Value * 2;
+ }
+}
\ No newline at end of file
diff --git a/GFramework.Core.Tests/events/EasyEventsTests.cs b/GFramework.Core.Tests/events/EasyEventsTests.cs
new file mode 100644
index 0000000..4364c98
--- /dev/null
+++ b/GFramework.Core.Tests/events/EasyEventsTests.cs
@@ -0,0 +1,50 @@
+using GFramework.Core.events;
+using NUnit.Framework;
+
+namespace GFramework.Core.Tests.events;
+
+[TestFixture]
+public class EasyEventsTests
+{
+ [SetUp]
+ public void SetUp()
+ {
+ _easyEvents = new EasyEvents();
+ }
+
+ private EasyEvents _easyEvents = null!;
+
+ [Test]
+ public void Get_EventT_Should_Trigger_With_Parameter()
+ {
+ _easyEvents.GetOrAddEvent>();
+
+ var receivedValue = 0;
+ var @event = EasyEvents.Get>();
+
+ @event.Register(value => { receivedValue = value; });
+ @event.Trigger(42);
+
+ Assert.That(receivedValue, Is.EqualTo(42));
+ }
+
+ [Test]
+ public void Get_EventTTK_Should_Trigger_With_Two_Parameters()
+ {
+ _easyEvents.GetOrAddEvent>();
+
+ var receivedInt = 0;
+ var receivedString = string.Empty;
+ var @event = EasyEvents.Get>();
+
+ @event.Register((i, s) =>
+ {
+ receivedInt = i;
+ receivedString = s;
+ });
+ @event.Trigger(100, "hello");
+
+ Assert.That(receivedInt, Is.EqualTo(100));
+ Assert.That(receivedString, Is.EqualTo("hello"));
+ }
+}
\ No newline at end of file
diff --git a/GFramework.Core.Tests/events/EventTests.cs b/GFramework.Core.Tests/events/EventTests.cs
new file mode 100644
index 0000000..8a5bd6b
--- /dev/null
+++ b/GFramework.Core.Tests/events/EventTests.cs
@@ -0,0 +1,134 @@
+using GFramework.Core.events;
+using NUnit.Framework;
+
+namespace GFramework.Core.Tests.events;
+
+[TestFixture]
+public class EventTests
+{
+ [SetUp]
+ public void SetUp()
+ {
+ _easyEvent = new EasyEvent();
+ _eventInt = new Event();
+ _eventIntString = new Event();
+ }
+
+ private EasyEvent _easyEvent = null!;
+ private Event _eventInt = null!;
+ private Event _eventIntString = null!;
+
+ [Test]
+ public void EasyEvent_Register_Should_Add_Handler()
+ {
+ var called = false;
+ _easyEvent.Register(() => { called = true; });
+
+ _easyEvent.Trigger();
+
+ Assert.That(called, Is.True);
+ }
+
+ [Test]
+ public void EasyEvent_UnRegister_Should_Remove_Handler()
+ {
+ var count = 0;
+ var handler = () => { count++; };
+
+ _easyEvent.Register(handler);
+ _easyEvent.Trigger();
+ Assert.That(count, Is.EqualTo(1));
+
+ _easyEvent.UnRegister(handler);
+ _easyEvent.Trigger();
+ Assert.That(count, Is.EqualTo(1));
+ }
+
+ [Test]
+ public void EasyEvent_Multiple_Handlers_Should_All_Be_Called()
+ {
+ var count1 = 0;
+ var count2 = 0;
+
+ _easyEvent.Register(() => { count1++; });
+ _easyEvent.Register(() => { count2++; });
+
+ _easyEvent.Trigger();
+
+ Assert.That(count1, Is.EqualTo(1));
+ Assert.That(count2, Is.EqualTo(1));
+ }
+
+ [Test]
+ public void EventT_Register_Should_Add_Handler()
+ {
+ var receivedValue = 0;
+ _eventInt.Register(value => { receivedValue = value; });
+
+ _eventInt.Trigger(42);
+
+ Assert.That(receivedValue, Is.EqualTo(42));
+ }
+
+ [Test]
+ public void EventT_UnRegister_Should_Remove_Handler()
+ {
+ var count = 0;
+ Action handler = value => { count++; };
+
+ _eventInt.Register(handler);
+ _eventInt.Trigger(1);
+ Assert.That(count, Is.EqualTo(1));
+
+ _eventInt.UnRegister(handler);
+ _eventInt.Trigger(2);
+ Assert.That(count, Is.EqualTo(1));
+ }
+
+ [Test]
+ public void EventT_Multiple_Handlers_Should_All_Be_Called()
+ {
+ var values = new List();
+
+ _eventInt.Register(value => { values.Add(value); });
+ _eventInt.Register(value => { values.Add(value * 2); });
+
+ _eventInt.Trigger(5);
+
+ Assert.That(values.Count, Is.EqualTo(2));
+ Assert.That(values, Does.Contain(5));
+ Assert.That(values, Does.Contain(10));
+ }
+
+ [Test]
+ public void EventTTK_Register_Should_Add_Handler()
+ {
+ var receivedInt = 0;
+ var receivedString = string.Empty;
+ _eventIntString.Register((i, s) =>
+ {
+ receivedInt = i;
+ receivedString = s;
+ });
+
+ _eventIntString.Trigger(42, "test");
+
+ Assert.That(receivedInt, Is.EqualTo(42));
+ Assert.That(receivedString, Is.EqualTo("test"));
+ }
+
+ [Test]
+ public void EventTTK_UnRegister_Should_Remove_Handler()
+ {
+ var count = 0;
+ Action handler = (i, s) => { count++; };
+
+ _eventIntString.Register(handler);
+ _eventIntString.Trigger(1, "a");
+ Assert.That(count, Is.EqualTo(1));
+
+ _eventIntString.UnRegister(handler);
+ _eventIntString.Trigger(2, "b");
+ Assert.That(count, Is.EqualTo(1));
+ }
+}
\ No newline at end of file
diff --git a/GFramework.Core.Tests/events/OrEventTests.cs b/GFramework.Core.Tests/events/OrEventTests.cs
new file mode 100644
index 0000000..51fa4ab
--- /dev/null
+++ b/GFramework.Core.Tests/events/OrEventTests.cs
@@ -0,0 +1,81 @@
+using GFramework.Core.events;
+using NUnit.Framework;
+
+namespace GFramework.Core.Tests.events;
+
+[TestFixture]
+public class OrEventTests
+{
+ [Test]
+ public void OrEvent_Should_Trigger_When_Any_Event_Fires()
+ {
+ var event1 = new Event();
+ var event2 = new Event();
+ var orEvent = new OrEvent();
+
+ var triggered = false;
+ orEvent.Register(() => { triggered = true; });
+
+ orEvent.Or(event1).Or(event2);
+
+ event1.Trigger(0);
+
+ Assert.That(triggered, Is.True);
+ }
+
+ [Test]
+ public void OrEvent_Should_Trigger_When_Second_Event_Fires()
+ {
+ var event1 = new Event();
+ var event2 = new Event();
+ var orEvent = new OrEvent();
+
+ var triggered = false;
+ orEvent.Register(() => { triggered = true; });
+
+ orEvent.Or(event1).Or(event2);
+
+ event2.Trigger(0);
+
+ Assert.That(triggered, Is.True);
+ }
+
+ [Test]
+ public void OrEvent_Should_Support_Multiple_Handlers()
+ {
+ var @event = new Event();
+ var orEvent = new OrEvent();
+
+ var count1 = 0;
+ var count2 = 0;
+
+ orEvent.Register(() => { count1++; });
+ orEvent.Register(() => { count2++; });
+
+ orEvent.Or(@event);
+ @event.Trigger(0);
+
+ Assert.That(count1, Is.EqualTo(1));
+ Assert.That(count2, Is.EqualTo(1));
+ }
+
+ [Test]
+ public void OrEvent_UnRegister_Should_Remove_Handler()
+ {
+ var @event = new Event();
+ var orEvent = new OrEvent();
+
+ var count = 0;
+ var handler = () => { count++; };
+
+ orEvent.Register(handler);
+ orEvent.Or(@event);
+
+ @event.Trigger(0);
+ Assert.That(count, Is.EqualTo(1));
+
+ orEvent.UnRegister(handler);
+ @event.Trigger(0);
+ Assert.That(count, Is.EqualTo(1));
+ }
+}
\ No newline at end of file
diff --git a/GFramework.Core.Tests/extensions/ObjectExtensionsTests.cs b/GFramework.Core.Tests/extensions/ObjectExtensionsTests.cs
new file mode 100644
index 0000000..b2d5433
--- /dev/null
+++ b/GFramework.Core.Tests/extensions/ObjectExtensionsTests.cs
@@ -0,0 +1,180 @@
+using GFramework.Core.extensions;
+using NUnit.Framework;
+
+namespace GFramework.Core.Tests.extensions;
+
+[TestFixture]
+public class ObjectExtensionsTests
+{
+ [Test]
+ public void IfType_Should_Execute_Action_When_Type_Matches()
+ {
+ var obj = new TestClass();
+ var executed = false;
+
+ obj.IfType(_ => { executed = true; });
+
+ Assert.That(executed, Is.True);
+ }
+
+ [Test]
+ public void IfType_Should_Not_Execute_Action_When_Type_Does_Not_Match()
+ {
+ var obj = new TestClass();
+ var executed = false;
+
+ obj.IfType(_ => { executed = true; });
+
+ Assert.That(executed, Is.False);
+ }
+
+ [Test]
+ public void IfType_WithPredicate_Should_Execute_When_Type_Matches_And_Predicate_True()
+ {
+ var obj = new TestClass { Value = 10 };
+ var executed = false;
+
+ obj.IfType(x => x.Value > 5, _ => { executed = true; });
+
+ Assert.That(executed, Is.True);
+ }
+
+ [Test]
+ public void IfType_WithPredicate_Should_Not_Execute_When_Predicate_False()
+ {
+ var obj = new TestClass { Value = 3 };
+ var executed = false;
+
+ obj.IfType(x => x.Value > 5, _ => { executed = true; });
+
+ Assert.That(executed, Is.False);
+ }
+
+ [Test]
+ public void IfType_WithBoth_Actions_Should_Execute_Correct_Action()
+ {
+ var matchCount = 0;
+ var noMatchCount = 0;
+
+ var obj = new TestClass();
+ obj.IfType(
+ _ => { matchCount++; },
+ _ => { noMatchCount++; }
+ );
+
+ Assert.That(matchCount, Is.EqualTo(1));
+ Assert.That(noMatchCount, Is.EqualTo(0));
+ }
+
+ [Test]
+ public void IfType_WithResult_Should_Return_Value_When_Type_Matches()
+ {
+ var obj = new TestClass { Name = "Test" };
+
+ var result = obj.IfType(x => x.Name);
+
+ Assert.That(result, Is.EqualTo("Test"));
+ }
+
+ [Test]
+ public void IfType_WithResult_Should_Return_Default_When_Type_Does_Not_Match()
+ {
+ var obj = new TestClass();
+
+ var result = obj.IfType(x => x);
+
+ Assert.That(result, Is.Null);
+ }
+
+ [Test]
+ public void As_Should_Return_Instance_When_Type_Matches()
+ {
+ var obj = new TestClass();
+
+ var result = obj.As();
+
+ Assert.That(result, Is.Not.Null);
+ Assert.That(result, Is.SameAs(obj));
+ }
+
+ [Test]
+ public void As_Should_Return_Null_When_Type_Does_Not_Match()
+ {
+ var obj = new TestClass();
+
+ var result = obj.As();
+
+ Assert.That(result, Is.Null);
+ }
+
+ [Test]
+ public void Do_Should_Execute_Action_And_Return_Object()
+ {
+ var obj = new TestClass { Value = 5 };
+
+ var result = obj.Do(x => x.Value = 10);
+
+ Assert.That(result, Is.SameAs(obj));
+ Assert.That(obj.Value, Is.EqualTo(10));
+ }
+
+ [Test]
+ public void Do_Should_Support_Chaining()
+ {
+ var obj = new TestClass { Value = 1, Name = "A" };
+
+ obj.Do(x => x.Value = 2)
+ .Do(x => x.Name = "B");
+
+ Assert.That(obj.Value, Is.EqualTo(2));
+ Assert.That(obj.Name, Is.EqualTo("B"));
+ }
+
+ [Test]
+ public void SwitchType_Should_Execute_Matching_Handler()
+ {
+ var obj = new TestClass();
+ var executed = false;
+
+ obj.SwitchType(
+ (typeof(TestClass), _ => { executed = true; }),
+ (typeof(string), _ => { Assert.Fail("Should not execute"); })
+ );
+
+ Assert.That(executed, Is.True);
+ }
+
+ [Test]
+ public void SwitchType_Should_Execute_First_Matching_Handler()
+ {
+ var obj = new TestClass();
+ var count = 0;
+
+ obj.SwitchType(
+ (typeof(TestClass), _ => { count++; }),
+ (typeof(TestClass), _ => { count++; })
+ );
+
+ Assert.That(count, Is.EqualTo(1));
+ }
+
+ [Test]
+ public void SwitchType_Should_Not_Execute_When_No_Match()
+ {
+ var obj = new TestClass();
+ var executed = false;
+
+ obj.SwitchType(
+ (typeof(string), _ => { executed = true; }),
+ (typeof(int), _ => { executed = true; })
+ );
+
+ Assert.That(executed, Is.False);
+ }
+}
+
+public class TestClass
+{
+ public int Value { get; set; }
+ public string Name { get; set; } = string.Empty;
+}
\ No newline at end of file
diff --git a/GFramework.Core.Tests/ioc/IocContainerTests.cs b/GFramework.Core.Tests/ioc/IocContainerTests.cs
new file mode 100644
index 0000000..207a456
--- /dev/null
+++ b/GFramework.Core.Tests/ioc/IocContainerTests.cs
@@ -0,0 +1,262 @@
+using System.Reflection;
+using GFramework.Core.ioc;
+using GFramework.Core.logging;
+using GFramework.Core.Tests.system;
+using NUnit.Framework;
+
+namespace GFramework.Core.Tests.ioc;
+
+[TestFixture]
+public class IocContainerTests
+{
+ [SetUp]
+ public void SetUp()
+ {
+ // 初始化 LoggerFactoryResolver 以支持 IocContainer
+ LoggerFactoryResolver.Provider = new ConsoleLoggerFactoryProvider();
+ _container = new IocContainer();
+
+ // 直接初始化 logger 字段
+ var loggerField = typeof(IocContainer).GetField("_logger",
+ BindingFlags.NonPublic | BindingFlags.Instance);
+ loggerField?.SetValue(_container,
+ LoggerFactoryResolver.Provider.CreateLogger(nameof(IocContainer)));
+ }
+
+ private IocContainer _container = null!;
+ private readonly Dictionary _mockContextServices = new();
+
+ [Test]
+ public void RegisterSingleton_Should_Register_Instance()
+ {
+ var instance = new TestService();
+
+ Assert.DoesNotThrow(() => _container.RegisterSingleton(instance));
+ }
+
+ [Test]
+ public void RegisterSingleton_WithDuplicate_Should_ThrowInvalidOperationException()
+ {
+ var instance1 = new TestService();
+ var instance2 = new TestService();
+
+ _container.RegisterSingleton(instance1);
+
+ Assert.Throws(() => _container.RegisterSingleton(instance2));
+ }
+
+ [Test]
+ public void RegisterSingleton_AfterFreeze_Should_ThrowInvalidOperationException()
+ {
+ var instance = new TestService();
+ _container.Freeze();
+
+ Assert.Throws(() => _container.RegisterSingleton(instance));
+ }
+
+ [Test]
+ public void RegisterPlurality_Should_Register_Instance_To_All_Types()
+ {
+ var instance = new TestService();
+
+ _container.RegisterPlurality(instance);
+
+ Assert.That(_container.Contains(), Is.True);
+ Assert.That(_container.Contains(), Is.True);
+ }
+
+ [Test]
+ public void RegisterPlurality_AfterFreeze_Should_ThrowInvalidOperationException()
+ {
+ var instance = new TestService();
+ _container.Freeze();
+
+ Assert.Throws(() => _container.RegisterPlurality(instance));
+ }
+
+ [Test]
+ public void Register_Generic_Should_Register_Instance()
+ {
+ var instance = new TestService();
+
+ _container.Register(instance);
+
+ Assert.That(_container.Contains(), Is.True);
+ }
+
+ [Test]
+ public void Register_Generic_AfterFreeze_Should_ThrowInvalidOperationException()
+ {
+ var instance = new TestService();
+ _container.Freeze();
+
+ Assert.Throws(() => _container.Register(instance));
+ }
+
+ [Test]
+ public void Register_Type_Should_Register_Instance()
+ {
+ var instance = new TestService();
+
+ _container.Register(typeof(TestService), instance);
+
+ Assert.That(_container.Contains(), Is.True);
+ }
+
+ [Test]
+ public void Get_Should_Return_First_Instance()
+ {
+ var instance = new TestService();
+ _container.Register(instance);
+
+ var result = _container.Get();
+
+ Assert.That(result, Is.Not.Null);
+ Assert.That(result, Is.SameAs(instance));
+ }
+
+ [Test]
+ public void Get_WithNoInstances_Should_ReturnNull()
+ {
+ var result = _container.Get();
+
+ Assert.That(result, Is.Null);
+ }
+
+ [Test]
+ public void GetRequired_Should_Return_Single_Instance()
+ {
+ var instance = new TestService();
+ _container.Register(instance);
+
+ var result = _container.GetRequired();
+
+ Assert.That(result, Is.Not.Null);
+ Assert.That(result, Is.SameAs(instance));
+ }
+
+ [Test]
+ public void GetRequired_WithNoInstances_Should_ThrowInvalidOperationException()
+ {
+ Assert.Throws(() => _container.GetRequired());
+ }
+
+ [Test]
+ public void GetRequired_WithMultipleInstances_Should_ThrowInvalidOperationException()
+ {
+ _container.Register(new TestService());
+ _container.Register(new TestService());
+
+ Assert.Throws(() => _container.GetRequired());
+ }
+
+ [Test]
+ public void GetAll_Should_Return_All_Instances()
+ {
+ var instance1 = new TestService();
+ var instance2 = new TestService();
+
+ _container.Register(instance1);
+ _container.Register(instance2);
+
+ var results = _container.GetAll();
+
+ Assert.That(results.Count, Is.EqualTo(2));
+ Assert.That(results, Does.Contain(instance1));
+ Assert.That(results, Does.Contain(instance2));
+ }
+
+ [Test]
+ public void GetAll_WithNoInstances_Should_Return_Empty_Array()
+ {
+ var results = _container.GetAll();
+
+ Assert.That(results.Count, Is.EqualTo(0));
+ }
+
+ [Test]
+ public void GetAllSorted_Should_Return_Sorted_Instances()
+ {
+ _container.Register(new TestService { Priority = 3 });
+ _container.Register(new TestService { Priority = 1 });
+ _container.Register(new TestService { Priority = 2 });
+
+ var results = _container.GetAllSorted((a, b) => a.Priority.CompareTo(b.Priority));
+
+ Assert.That(results.Count, Is.EqualTo(3));
+ Assert.That(results[0].Priority, Is.EqualTo(1));
+ Assert.That(results[1].Priority, Is.EqualTo(2));
+ Assert.That(results[2].Priority, Is.EqualTo(3));
+ }
+
+ [Test]
+ public void Contains_WithExistingInstance_Should_ReturnTrue()
+ {
+ var instance = new TestService();
+ _container.Register(instance);
+
+ Assert.That(_container.Contains(), Is.True);
+ }
+
+ [Test]
+ public void Contains_WithNoInstances_Should_ReturnFalse()
+ {
+ Assert.That(_container.Contains(), Is.False);
+ }
+
+ [Test]
+ public void ContainsInstance_WithExistingInstance_Should_ReturnTrue()
+ {
+ var instance = new TestService();
+ _container.Register(instance);
+
+ Assert.That(_container.ContainsInstance(instance), Is.True);
+ }
+
+ [Test]
+ public void ContainsInstance_WithNonExistingInstance_Should_ReturnFalse()
+ {
+ var instance = new TestService();
+
+ Assert.That(_container.ContainsInstance(instance), Is.False);
+ }
+
+ [Test]
+ public void Clear_Should_Remove_All_Instances()
+ {
+ var instance = new TestService();
+ _container.Register(instance);
+
+ _container.Clear();
+
+ Assert.That(_container.Contains(), Is.False);
+ }
+
+ [Test]
+ public void Freeze_Should_Prevent_Further_Registrations()
+ {
+ var instance1 = new TestService();
+ _container.Register(instance1);
+ _container.Freeze();
+
+ var instance2 = new TestService();
+ Assert.Throws(() => _container.Register(instance2));
+ }
+
+ [Test]
+ public void RegisterSystem_Should_Register_Instance()
+ {
+ var system = new TestSystem();
+
+ _container.RegisterSystem(system);
+
+ Assert.That(_container.Contains(), Is.True);
+ }
+}
+
+public interface IService;
+
+public sealed class TestService : IService
+{
+ public int Priority { get; set; }
+}
\ No newline at end of file
diff --git a/GFramework.Core.Tests/model/AsyncTestModel.cs b/GFramework.Core.Tests/model/AsyncTestModel.cs
index 2d0e80d..700229f 100644
--- a/GFramework.Core.Tests/model/AsyncTestModel.cs
+++ b/GFramework.Core.Tests/model/AsyncTestModel.cs
@@ -1,4 +1,4 @@
-using GFramework.Core.Abstractions.architecture;
+using GFramework.Core.Abstractions.architecture;
using GFramework.Core.Abstractions.enums;
using GFramework.Core.model;
@@ -38,7 +38,7 @@ public sealed class AsyncTestModel : AbstractModel, IAsyncInitializable
/// 处理架构阶段事件
///
/// 架构阶段枚举值
- public void OnArchitecturePhase(ArchitecturePhase phase)
+ public override void OnArchitecturePhase(ArchitecturePhase phase)
{
}
diff --git a/GFramework.Core.Tests/model/TestModel.cs b/GFramework.Core.Tests/model/TestModel.cs
index 26da6fa..59fc9ad 100644
--- a/GFramework.Core.Tests/model/TestModel.cs
+++ b/GFramework.Core.Tests/model/TestModel.cs
@@ -1,4 +1,4 @@
-using GFramework.Core.Abstractions.enums;
+using GFramework.Core.Abstractions.enums;
using GFramework.Core.model;
namespace GFramework.Core.Tests.model;
@@ -24,7 +24,7 @@ public sealed class TestModel : AbstractModel, ITestModel
}
- public void OnArchitecturePhase(ArchitecturePhase phase)
+ public override void OnArchitecturePhase(ArchitecturePhase phase)
{
}
diff --git a/GFramework.Core.Tests/pool/ObjectPoolTests.cs b/GFramework.Core.Tests/pool/ObjectPoolTests.cs
new file mode 100644
index 0000000..27c9449
--- /dev/null
+++ b/GFramework.Core.Tests/pool/ObjectPoolTests.cs
@@ -0,0 +1,131 @@
+using GFramework.Core.Abstractions.pool;
+using GFramework.Core.pool;
+using NUnit.Framework;
+
+namespace GFramework.Core.Tests.pool;
+
+[TestFixture]
+public class ObjectPoolTests
+{
+ [SetUp]
+ public void SetUp()
+ {
+ _pool = new TestObjectPool();
+ }
+
+ private TestObjectPool _pool = null!;
+
+ [Test]
+ public void Acquire_Should_Create_New_Object_When_Pool_Empty()
+ {
+ var obj = _pool.Acquire("test");
+
+ Assert.That(obj, Is.Not.Null);
+ Assert.That(obj.PoolKey, Is.EqualTo("test"));
+ Assert.That(obj.OnAcquireCalled, Is.True);
+ }
+
+ [Test]
+ public void Acquire_Should_Return_Pooled_Object()
+ {
+ var obj1 = _pool.Acquire("test");
+ obj1.TestValue = 100;
+
+ _pool.Release("test", obj1);
+
+ var obj2 = _pool.Acquire("test");
+
+ Assert.That(obj2, Is.SameAs(obj1));
+ Assert.That(obj2.TestValue, Is.EqualTo(100));
+ Assert.That(obj2.OnAcquireCalled, Is.True);
+ }
+
+ [Test]
+ public void Release_Should_Call_OnRelease()
+ {
+ var obj = _pool.Acquire("test");
+
+ _pool.Release("test", obj);
+
+ Assert.That(obj.OnReleaseCalled, Is.True);
+ }
+
+ [Test]
+ public void Clear_Should_Destroy_All_Objects()
+ {
+ var obj1 = _pool.Acquire("key1");
+ var obj2 = _pool.Acquire("key2");
+
+ _pool.Release("key1", obj1);
+ _pool.Release("key2", obj2);
+
+ _pool.Clear();
+
+ Assert.That(obj1.OnPoolDestroyCalled, Is.True);
+ Assert.That(obj2.OnPoolDestroyCalled, Is.True);
+ }
+
+ [Test]
+ public void Multiple_Pools_Should_Be_Independent()
+ {
+ var obj1 = _pool.Acquire("key1");
+ var obj2 = _pool.Acquire("key2");
+
+ _pool.Release("key1", obj1);
+
+ var obj3 = _pool.Acquire("key1");
+ var obj4 = _pool.Acquire("key2");
+
+ Assert.That(obj3, Is.SameAs(obj1));
+ Assert.That(obj4, Is.Not.SameAs(obj2));
+ }
+
+ [Test]
+ public void OnAcquire_Should_Be_Called_On_New_And_Pooled_Objects()
+ {
+ var obj1 = _pool.Acquire("test");
+ Assert.That(obj1.OnAcquireCalled, Is.True);
+
+ _pool.Release("test", obj1);
+ obj1.OnAcquireCalled = false;
+
+ var obj2 = _pool.Acquire("test");
+ Assert.That(obj2.OnAcquireCalled, Is.True);
+ }
+}
+
+public class TestObjectPool : AbstractObjectPoolSystem
+{
+ protected override TestPoolableObject Create(string key)
+ {
+ return new TestPoolableObject { PoolKey = key };
+ }
+
+ protected override void OnInit()
+ {
+ }
+}
+
+public class TestPoolableObject : IPoolableObject
+{
+ public string PoolKey { get; set; } = string.Empty;
+ public int TestValue { get; set; }
+ public bool OnAcquireCalled { get; set; }
+ public bool OnReleaseCalled { get; set; }
+ public bool OnPoolDestroyCalled { get; set; }
+
+ public void OnAcquire()
+ {
+ OnAcquireCalled = true;
+ }
+
+ public void OnRelease()
+ {
+ OnReleaseCalled = true;
+ }
+
+ public void OnPoolDestroy()
+ {
+ OnPoolDestroyCalled = true;
+ }
+}
\ No newline at end of file
diff --git a/GFramework.Core.Tests/property/BindablePropertyTests.cs b/GFramework.Core.Tests/property/BindablePropertyTests.cs
new file mode 100644
index 0000000..c87b277
--- /dev/null
+++ b/GFramework.Core.Tests/property/BindablePropertyTests.cs
@@ -0,0 +1,133 @@
+using GFramework.Core.property;
+using NUnit.Framework;
+
+namespace GFramework.Core.Tests.property;
+
+[TestFixture]
+public class BindablePropertyTests
+{
+ [Test]
+ public void Value_Get_Should_Return_Default_Value()
+ {
+ var property = new BindableProperty(5);
+
+ Assert.That(property.Value, Is.EqualTo(5));
+ }
+
+ [Test]
+ public void Value_Set_Should_Trigger_Event()
+ {
+ var property = new BindableProperty();
+ var receivedValue = 0;
+
+ property.Register(value => { receivedValue = value; });
+
+ property.Value = 42;
+
+ Assert.That(receivedValue, Is.EqualTo(42));
+ }
+
+ [Test]
+ public void Value_Set_To_Same_Value_Should_Not_Trigger_Event()
+ {
+ var property = new BindableProperty(5);
+ var count = 0;
+
+ property.Register(_ => { count++; });
+
+ property.Value = 5;
+
+ Assert.That(count, Is.EqualTo(0));
+ }
+
+ [Test]
+ public void UnRegister_Should_Remove_Handler()
+ {
+ var property = new BindableProperty();
+ var count = 0;
+
+ Action handler = _ => { count++; };
+ property.Register(handler);
+
+ property.Value = 1;
+ Assert.That(count, Is.EqualTo(1));
+
+ property.UnRegister(handler);
+ property.Value = 2;
+ Assert.That(count, Is.EqualTo(1));
+ }
+
+ [Test]
+ public void RegisterWithInitValue_Should_Call_Handler_Immediately()
+ {
+ var property = new BindableProperty(5);
+ var receivedValue = 0;
+
+ property.RegisterWithInitValue(value => { receivedValue = value; });
+
+ Assert.That(receivedValue, Is.EqualTo(5));
+ }
+
+ [Test]
+ public void SetValueWithoutEvent_Should_Not_Trigger_Event()
+ {
+ var property = new BindableProperty();
+ var count = 0;
+
+ property.Register(_ => { count++; });
+
+ property.SetValueWithoutEvent(42);
+
+ Assert.That(count, Is.EqualTo(0));
+ Assert.That(property.Value, Is.EqualTo(42));
+ }
+
+ [Test]
+ public void WithComparer_Should_Use_Custom_Comparer()
+ {
+ var property = new BindableProperty("test").WithComparer((a, b) => a.Length == b.Length);
+ var count = 0;
+
+ property.Register(_ => { count++; });
+
+ property.Value = "hello";
+
+ // "test" 和 "hello" 长度都是 4,所以不应该触发事件
+ Assert.That(count, Is.EqualTo(0));
+ }
+
+ [Test]
+ public void Multiple_Handlers_Should_All_Be_Called()
+ {
+ var property = new BindableProperty();
+ var count1 = 0;
+ var count2 = 0;
+
+ property.Register(_ => { count1++; });
+ property.Register(_ => { count2++; });
+
+ property.Value = 42;
+
+ Assert.That(count1, Is.EqualTo(1));
+ Assert.That(count2, Is.EqualTo(1));
+ }
+
+ [Test]
+ public void Register_Should_Return_IUnRegister()
+ {
+ var property = new BindableProperty();
+ var unRegister = property.Register(_ => { });
+
+ Assert.That(unRegister, Is.Not.Null);
+ }
+
+ [Test]
+ public void ToString_Should_Return_Value_As_String()
+ {
+ var property = new BindableProperty(42);
+
+ var result = property.ToString();
+
+ Assert.That(result, Is.EqualTo("42"));
+ }
+}
\ No newline at end of file
diff --git a/GFramework.Core.Tests/query/QueryBusTests.cs b/GFramework.Core.Tests/query/QueryBusTests.cs
new file mode 100644
index 0000000..2efa95a
--- /dev/null
+++ b/GFramework.Core.Tests/query/QueryBusTests.cs
@@ -0,0 +1,74 @@
+using GFramework.Core.Abstractions.query;
+using GFramework.Core.query;
+using NUnit.Framework;
+
+namespace GFramework.Core.Tests.query;
+
+[TestFixture]
+public class QueryBusTests
+{
+ [SetUp]
+ public void SetUp()
+ {
+ _queryBus = new QueryBus();
+ }
+
+ private QueryBus _queryBus = null!;
+
+ [Test]
+ public void Send_Should_Return_Query_Result()
+ {
+ var input = new TestQueryInput { Value = 10 };
+ var query = new TestQuery(input);
+
+ var result = _queryBus.Send(query);
+
+ Assert.That(result, Is.EqualTo(20));
+ }
+
+ [Test]
+ public void Send_WithNullQuery_Should_ThrowArgumentNullException()
+ {
+ Assert.Throws(() => _queryBus.Send(null!));
+ }
+
+ [Test]
+ public void Send_WithStringResult_Should_Return_String()
+ {
+ var input = new TestQueryInput { Value = 5 };
+ var query = new TestStringQuery(input);
+
+ var result = _queryBus.Send(query);
+
+ Assert.That(result, Is.EqualTo("Result: 10"));
+ }
+}
+
+public sealed class TestQueryInput : IQueryInput
+{
+ public int Value { get; init; }
+}
+
+public sealed class TestQuery : AbstractQuery
+{
+ public TestQuery(TestQueryInput input) : base(input)
+ {
+ }
+
+ protected override int OnDo(TestQueryInput input)
+ {
+ return input.Value * 2;
+ }
+}
+
+public sealed class TestStringQuery : AbstractQuery
+{
+ public TestStringQuery(TestQueryInput input) : base(input)
+ {
+ }
+
+ protected override string OnDo(TestQueryInput input)
+ {
+ return $"Result: {input.Value * 2}";
+ }
+}
\ No newline at end of file
diff --git a/GFramework.Core.Tests/query/TestQuery.cs b/GFramework.Core.Tests/query/TestQuery.cs
deleted file mode 100644
index 9dd62fc..0000000
--- a/GFramework.Core.Tests/query/TestQuery.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-using GFramework.Core.Abstractions.query;
-using GFramework.Core.extensions;
-using GFramework.Core.query;
-using GFramework.Core.Tests.model;
-
-namespace GFramework.Core.Tests.query;
-
-///
-/// 测试查询类,用于执行测试查询操作
-///
-/// 测试查询输入参数
-public class TestQuery(TestQueryInput input) : AbstractQuery(input)
-{
- ///
- /// 执行查询操作的重写方法
- ///
- /// 测试查询输入参数
- /// 返回固定的整数值42
- protected override int OnDo(TestQueryInput input)
- {
- return this.GetModel()!.GetCurrentXp;
- }
-}
-
-///
-/// 测试查询输入类,实现查询输入接口
-///
-public sealed class TestQueryInput : IQueryInput;
\ No newline at end of file
diff --git a/GFramework.Core.Tests/tests/SyncArchitectureTests.cs b/GFramework.Core.Tests/tests/SyncArchitectureTests.cs
index 0695be3..5fe0ed1 100644
--- a/GFramework.Core.Tests/tests/SyncArchitectureTests.cs
+++ b/GFramework.Core.Tests/tests/SyncArchitectureTests.cs
@@ -142,10 +142,10 @@ public class SyncArchitectureTests : ArchitectureTestsBase
}
///
- /// 测试事件是否能够被正确接收和处理
+ /// 测试事件是否能够被正确接收和处理
///
///
- /// 该测试验证了事件系统的注册和发送功能,确保事件能够被正确传递给注册的处理器
+ /// 该测试验证了事件系统的注册和发送功能,确保事件能够被正确传递给注册的处理器
///
[Test]
public void Event_Should_Be_Received()
@@ -168,10 +168,10 @@ public class SyncArchitectureTests : ArchitectureTestsBase
}
///
- /// 测试事件取消注册功能是否正常工作
+ /// 测试事件取消注册功能是否正常工作
///
///
- /// 该测试验证了事件处理器的取消注册功能,确保取消注册后事件处理器不再被调用
+ /// 该测试验证了事件处理器的取消注册功能,确保取消注册后事件处理器不再被调用
///
[Test]
public void Event_UnRegister_Should_Work()
diff --git a/GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj b/GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj
index 073a052..3679072 100644
--- a/GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj
+++ b/GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj
@@ -3,7 +3,7 @@
enable
enable
- net8.0;net9.0;net10.0
+ net10.0;net8.0