diff --git a/GFramework.Core.Tests/architecture/ContextProviderTests.cs b/GFramework.Core.Tests/architecture/ContextProviderTests.cs
new file mode 100644
index 0000000..d1358a7
--- /dev/null
+++ b/GFramework.Core.Tests/architecture/ContextProviderTests.cs
@@ -0,0 +1,157 @@
+using GFramework.Core.Abstractions.architecture;
+using GFramework.Core.architecture;
+using NUnit.Framework;
+
+namespace GFramework.Core.Tests.architecture;
+
+///
+/// ContextProvider 相关类的单元测试
+/// 测试内容包括:
+/// - GameContextProvider 获取第一个架构上下文
+/// - GameContextProvider 尝试获取指定类型的上下文
+/// - ScopedContextProvider 获取绑定的上下文
+/// - ScopedContextProvider 尝试获取指定类型的上下文
+/// - ScopedContextProvider 类型不匹配时返回 false
+///
+[TestFixture]
+public class ContextProviderTests
+{
+ ///
+ /// 测试初始化方法,在每个测试方法执行前清空 GameContext
+ ///
+ [SetUp]
+ public void SetUp()
+ {
+ GameContext.Clear();
+ }
+
+ ///
+ /// 测试清理方法,在每个测试方法执行后清空 GameContext
+ ///
+ [TearDown]
+ public void TearDown()
+ {
+ GameContext.Clear();
+ }
+
+ ///
+ /// 测试 GameContextProvider 是否能正确获取第一个架构上下文
+ ///
+ [Test]
+ public void GameContextProvider_GetContext_Should_Return_First_Context()
+ {
+ var context = new TestArchitectureContext();
+ GameContext.Bind(typeof(TestArchitecture), context);
+
+ var provider = new GameContextProvider();
+ var result = provider.GetContext();
+
+ Assert.That(result, Is.SameAs(context));
+ }
+
+ ///
+ /// 测试 GameContextProvider 在没有上下文时是否抛出异常
+ ///
+ [Test]
+ public void GameContextProvider_GetContext_Should_Throw_When_Empty()
+ {
+ var provider = new GameContextProvider();
+
+ Assert.Throws(() => provider.GetContext());
+ }
+
+ ///
+ /// 测试 GameContextProvider 的 TryGetContext 方法在找到上下文时返回 true
+ ///
+ [Test]
+ public void GameContextProvider_TryGetContext_Should_Return_True_When_Found()
+ {
+ var context = new TestArchitectureContext();
+ GameContext.Bind(typeof(TestArchitectureContext), context);
+
+ var provider = new GameContextProvider();
+ var result = provider.TryGetContext(out var foundContext);
+
+ Assert.That(result, Is.True);
+ Assert.That(foundContext, Is.SameAs(context));
+ }
+
+ ///
+ /// 测试 GameContextProvider 的 TryGetContext 方法在未找到上下文时返回 false
+ ///
+ [Test]
+ public void GameContextProvider_TryGetContext_Should_Return_False_When_Not_Found()
+ {
+ var provider = new GameContextProvider();
+ var result = provider.TryGetContext(out var foundContext);
+
+ Assert.That(result, Is.False);
+ Assert.That(foundContext, Is.Null);
+ }
+
+ ///
+ /// 测试 ScopedContextProvider 是否能正确返回绑定的上下文
+ ///
+ [Test]
+ public void ScopedContextProvider_GetContext_Should_Return_Bound_Context()
+ {
+ var context = new TestArchitectureContext();
+ var provider = new ScopedContextProvider(context);
+
+ var result = provider.GetContext();
+
+ Assert.That(result, Is.SameAs(context));
+ }
+
+ ///
+ /// 测试 ScopedContextProvider 的 TryGetContext 方法在类型匹配时返回 true
+ ///
+ [Test]
+ public void ScopedContextProvider_TryGetContext_Should_Return_True_When_Type_Matches()
+ {
+ var context = new TestArchitectureContext();
+ var provider = new ScopedContextProvider(context);
+
+ var result = provider.TryGetContext(out var foundContext);
+
+ Assert.That(result, Is.True);
+ Assert.That(foundContext, Is.SameAs(context));
+ }
+
+ ///
+ /// 测试 ScopedContextProvider 的 TryGetContext 方法在类型不匹配时返回 false
+ ///
+ [Test]
+ public void ScopedContextProvider_TryGetContext_Should_Return_False_When_Type_Does_Not_Match()
+ {
+ var context = new TestArchitectureContext();
+ var provider = new ScopedContextProvider(context);
+
+ var result = provider.TryGetContext(out var foundContext);
+
+ Assert.That(result, Is.False);
+ Assert.That(foundContext, Is.Null);
+ }
+
+ ///
+ /// 测试 ScopedContextProvider 的 TryGetContext 方法支持接口类型查询
+ ///
+ [Test]
+ public void ScopedContextProvider_TryGetContext_Should_Support_Interface_Type()
+ {
+ var context = new TestArchitectureContext();
+ var provider = new ScopedContextProvider(context);
+
+ var result = provider.TryGetContext(out var foundContext);
+
+ Assert.That(result, Is.True);
+ Assert.That(foundContext, Is.SameAs(context));
+ }
+}
+
+///
+/// 另一个测试用的架构上下文类,用于测试类型不匹配的情况
+///
+public class AnotherTestArchitectureContext : TestArchitectureContext
+{
+}
\ No newline at end of file
diff --git a/GFramework.Core.Tests/architecture/GameContextTests.cs b/GFramework.Core.Tests/architecture/GameContextTests.cs
index 88b3dc7..9db9d72 100644
--- a/GFramework.Core.Tests/architecture/GameContextTests.cs
+++ b/GFramework.Core.Tests/architecture/GameContextTests.cs
@@ -294,7 +294,7 @@ public class TestArchitectureContext : IArchitectureContext
///
/// 工具类型
/// 工具实例或null
- public TUtility? GetUtility() where TUtility : class, IUtility
+ public virtual TUtility? GetUtility() where TUtility : class, IUtility
{
return _container.Get();
}
diff --git a/GFramework.Core.Tests/architecture/RegistryInitializationHookBaseTests.cs b/GFramework.Core.Tests/architecture/RegistryInitializationHookBaseTests.cs
new file mode 100644
index 0000000..54515d2
--- /dev/null
+++ b/GFramework.Core.Tests/architecture/RegistryInitializationHookBaseTests.cs
@@ -0,0 +1,367 @@
+using GFramework.Core.Abstractions.architecture;
+using GFramework.Core.Abstractions.enums;
+using GFramework.Core.Abstractions.lifecycle;
+using GFramework.Core.Abstractions.model;
+using GFramework.Core.Abstractions.system;
+using GFramework.Core.Abstractions.utility;
+using GFramework.Core.architecture;
+using Microsoft.Extensions.DependencyInjection;
+using NUnit.Framework;
+
+namespace GFramework.Core.Tests.architecture;
+
+///
+/// RegistryInitializationHookBase 抽象基类的单元测试
+/// 测试内容包括:
+/// - 在目标阶段正确触发配置注册
+/// - 在非目标阶段不触发配置注册
+/// - 正确遍历所有配置项
+/// - 注册表不存在时不抛出异常
+/// - 支持自定义目标阶段
+///
+[TestFixture]
+public class RegistryInitializationHookBaseTests
+{
+ ///
+ /// 测试在目标阶段时是否正确触发配置注册
+ ///
+ [Test]
+ public void OnPhase_Should_Register_Configs_At_Target_Phase()
+ {
+ var registry = new TestRegistry();
+ var configs = new[] { "config1", "config2", "config3" };
+ var hook = new TestRegistryInitializationHook(configs);
+ var architecture = new TestArchitectureWithRegistry(registry);
+
+ hook.OnPhase(ArchitecturePhase.AfterSystemInit, architecture);
+
+ Assert.That(registry.RegisteredConfigs.Count, Is.EqualTo(3));
+ Assert.That(registry.RegisteredConfigs, Is.EquivalentTo(configs));
+ }
+
+ ///
+ /// 测试在非目标阶段时不触发配置注册
+ ///
+ [Test]
+ public void OnPhase_Should_Not_Register_Configs_At_Wrong_Phase()
+ {
+ var registry = new TestRegistry();
+ var configs = new[] { "config1", "config2" };
+ var hook = new TestRegistryInitializationHook(configs);
+ var architecture = new TestArchitectureWithRegistry(registry);
+
+ hook.OnPhase(ArchitecturePhase.BeforeSystemInit, architecture);
+
+ Assert.That(registry.RegisteredConfigs.Count, Is.EqualTo(0));
+ }
+
+ ///
+ /// 测试支持自定义目标阶段
+ ///
+ [Test]
+ public void OnPhase_Should_Support_Custom_Target_Phase()
+ {
+ var registry = new TestRegistry();
+ var configs = new[] { "config1" };
+ var hook = new TestRegistryInitializationHook(configs, ArchitecturePhase.AfterModelInit);
+ var architecture = new TestArchitectureWithRegistry(registry);
+
+ hook.OnPhase(ArchitecturePhase.AfterModelInit, architecture);
+
+ Assert.That(registry.RegisteredConfigs.Count, Is.EqualTo(1));
+ }
+
+ ///
+ /// 测试当注册表不存在时不抛出异常
+ ///
+ [Test]
+ public void OnPhase_Should_Not_Throw_When_Registry_Not_Found()
+ {
+ var configs = new[] { "config1" };
+ var hook = new TestRegistryInitializationHook(configs);
+ var architecture = new TestArchitectureWithoutRegistry();
+
+ Assert.DoesNotThrow(() => hook.OnPhase(ArchitecturePhase.AfterSystemInit, architecture));
+ }
+
+ ///
+ /// 测试空配置集合不会导致错误
+ ///
+ [Test]
+ public void OnPhase_Should_Handle_Empty_Configs()
+ {
+ var registry = new TestRegistry();
+ var configs = Array.Empty();
+ var hook = new TestRegistryInitializationHook(configs);
+ var architecture = new TestArchitectureWithRegistry(registry);
+
+ hook.OnPhase(ArchitecturePhase.AfterSystemInit, architecture);
+
+ Assert.That(registry.RegisteredConfigs.Count, Is.EqualTo(0));
+ }
+
+ ///
+ /// 测试多次调用同一阶段会重复注册
+ ///
+ [Test]
+ public void OnPhase_Should_Register_Multiple_Times_If_Called_Multiple_Times()
+ {
+ var registry = new TestRegistry();
+ var configs = new[] { "config1" };
+ var hook = new TestRegistryInitializationHook(configs);
+ var architecture = new TestArchitectureWithRegistry(registry);
+
+ hook.OnPhase(ArchitecturePhase.AfterSystemInit, architecture);
+ hook.OnPhase(ArchitecturePhase.AfterSystemInit, architecture);
+
+ Assert.That(registry.RegisteredConfigs.Count, Is.EqualTo(2));
+ }
+}
+
+///
+/// 测试用的注册表初始化钩子实现
+///
+public class TestRegistryInitializationHook : RegistryInitializationHookBase
+{
+ public TestRegistryInitializationHook(
+ IEnumerable configs,
+ ArchitecturePhase targetPhase = ArchitecturePhase.AfterSystemInit)
+ : base(configs, targetPhase)
+ {
+ }
+
+ protected override void RegisterConfig(TestRegistry registry, string config)
+ {
+ registry.Register(config);
+ }
+}
+
+///
+/// 测试用的注册表类
+///
+public class TestRegistry : IUtility
+{
+ public List RegisteredConfigs { get; } = new();
+
+ public void Register(string config)
+ {
+ RegisteredConfigs.Add(config);
+ }
+}
+
+///
+/// 测试用的架构类(包含注册表)
+///
+public class TestArchitectureWithRegistry : IArchitecture
+{
+ private readonly TestRegistry _registry;
+
+ public TestArchitectureWithRegistry(TestRegistry registry)
+ {
+ _registry = registry;
+ Context = new TestArchitectureContextWithRegistry(registry);
+ }
+
+ public Action? Configurator { get; }
+
+ public IArchitectureContext Context { get; }
+ Action? IArchitecture.Configurator => Configurator;
+
+ T IArchitecture.RegisterSystem(T system)
+ {
+ throw new NotImplementedException();
+ }
+
+ T IArchitecture.RegisterModel(T model)
+ {
+ throw new NotImplementedException();
+ }
+
+ T IArchitecture.RegisterUtility(T utility)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void RegisterMediatorBehavior() where TBehavior : class
+ {
+ throw new NotImplementedException();
+ }
+
+ public IArchitectureModule InstallModule(IArchitectureModule module)
+ {
+ throw new NotImplementedException();
+ }
+
+ IArchitectureLifecycleHook IArchitecture.RegisterLifecycleHook(IArchitectureLifecycleHook hook)
+ {
+ throw new NotImplementedException();
+ }
+
+ Task IArchitecture.WaitUntilReadyAsync()
+ {
+ return WaitUntilReadyAsync();
+ }
+
+ public void RegisterUtility(Action? onCreated = default(Action?)) where T : class, IUtility
+ {
+ throw new NotImplementedException();
+ }
+
+ public void RegisterModel(Action? onCreated = default(Action?)) where T : class, IModel
+ {
+ throw new NotImplementedException();
+ }
+
+ public void RegisterSystem(Action? onCreated = default(Action?)) where T : class, ISystem
+ {
+ throw new NotImplementedException();
+ }
+
+ public void Initialize()
+ {
+ }
+
+ public void Destroy()
+ {
+ throw new NotImplementedException();
+ }
+
+ Task IAsyncInitializable.InitializeAsync()
+ {
+ return InitializeAsync();
+ }
+
+ ValueTask IAsyncDestroyable.DestroyAsync()
+ {
+ return DestroyAsync();
+ }
+
+ public Task WaitUntilReadyAsync()
+ {
+ throw new NotImplementedException();
+ }
+
+ public void RegisterLifecycleHook(IArchitectureLifecycleHook hook)
+ {
+ }
+
+ public Task InitializeAsync()
+ {
+ throw new NotImplementedException();
+ }
+
+ public ValueTask DestroyAsync()
+ {
+ throw new NotImplementedException();
+ }
+}
+
+///
+/// 测试用的架构上下文类(包含注册表)
+///
+public class TestArchitectureContextWithRegistry : TestArchitectureContext
+{
+ private readonly TestRegistry _registry;
+
+ public TestArchitectureContextWithRegistry(TestRegistry registry)
+ {
+ _registry = registry;
+ }
+
+ public override TUtility GetUtility()
+ {
+ if (typeof(TUtility) == typeof(TestRegistry))
+ {
+ return _registry as TUtility;
+ }
+
+ return base.GetUtility();
+ }
+}
+
+///
+/// 测试用的架构类(不包含注册表)
+///
+public class TestArchitectureWithoutRegistry : IArchitecture
+{
+ public TestArchitectureWithoutRegistry()
+ {
+ Context = new TestArchitectureContext();
+ }
+
+ public IArchitectureContext Context { get; }
+ public Action? Configurator { get; }
+
+ T IArchitecture.RegisterSystem(T system)
+ {
+ throw new NotImplementedException();
+ }
+
+ T IArchitecture.RegisterModel(T model)
+ {
+ throw new NotImplementedException();
+ }
+
+ T IArchitecture.RegisterUtility(T utility)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void RegisterMediatorBehavior() where TBehavior : class
+ {
+ throw new NotImplementedException();
+ }
+
+ public IArchitectureModule InstallModule(IArchitectureModule module)
+ {
+ throw new NotImplementedException();
+ }
+
+ IArchitectureLifecycleHook IArchitecture.RegisterLifecycleHook(IArchitectureLifecycleHook hook)
+ {
+ throw new NotImplementedException();
+ }
+
+ public Task WaitUntilReadyAsync()
+ {
+ throw new NotImplementedException();
+ }
+
+ public void RegisterUtility(Action? onCreated = default(Action?)) where T : class, IUtility
+ {
+ throw new NotImplementedException();
+ }
+
+ public void RegisterModel(Action? onCreated = default(Action?)) where T : class, IModel
+ {
+ throw new NotImplementedException();
+ }
+
+ public void RegisterSystem(Action? onCreated = default(Action?)) where T : class, ISystem
+ {
+ throw new NotImplementedException();
+ }
+
+ public void Initialize()
+ {
+ }
+
+ public Task InitializeAsync()
+ {
+ throw new NotImplementedException();
+ }
+
+ public ValueTask DestroyAsync()
+ {
+ throw new NotImplementedException();
+ }
+
+ public void Destroy()
+ {
+ throw new NotImplementedException();
+ }
+
+ public void RegisterLifecycleHook(IArchitectureLifecycleHook hook)
+ {
+ }
+}
\ No newline at end of file
diff --git a/GFramework.SourceGenerators.Tests/rule/ContextAwareGeneratorSnapshotTests.cs b/GFramework.SourceGenerators.Tests/rule/ContextAwareGeneratorSnapshotTests.cs
index 38a15a6..a91a721 100644
--- a/GFramework.SourceGenerators.Tests/rule/ContextAwareGeneratorSnapshotTests.cs
+++ b/GFramework.SourceGenerators.Tests/rule/ContextAwareGeneratorSnapshotTests.cs
@@ -44,6 +44,32 @@ public class ContextAwareGeneratorSnapshotTests
namespace GFramework.Core.Abstractions.architecture
{
public interface IArchitectureContext { }
+
+ public interface IArchitectureContextProvider
+ {
+ IArchitectureContext GetContext();
+ bool TryGetContext(out T? context) where T : class, IArchitectureContext;
+ }
+ }
+
+ namespace GFramework.Core.architecture
+ {
+ using GFramework.Core.Abstractions.architecture;
+
+ public sealed class GameContextProvider : IArchitectureContextProvider
+ {
+ public IArchitectureContext GetContext() => null;
+ public bool TryGetContext(out T? context) where T : class, IArchitectureContext
+ {
+ context = null;
+ return false;
+ }
+ }
+
+ public static class GameContext
+ {
+ public static IArchitectureContext GetFirstArchitectureContext() => null;
+ }
}
namespace TestApp
@@ -56,21 +82,6 @@ public class ContextAwareGeneratorSnapshotTests
{
}
}
- namespace GFramework.Core.architecture
- {
- using GFramework.Core.Abstractions.architecture;
- public static class GameContext{
- ///
- /// 获取字典中的第一个架构上下文
- ///
- /// 返回字典中的第一个架构上下文实例
- /// 当字典为空时抛出
- public static IArchitectureContext GetFirstArchitectureContext()
- {
- return null;
- }
- }
- }
""";
// 执行生成器快照测试,将生成的代码与预期快照进行比较