using System.Reflection;
using GFramework.Core.Abstractions.Cqrs;
using GFramework.Core.Abstractions.Logging;
using GFramework.Core.Architectures;
using GFramework.Core.Logging;
namespace GFramework.Core.Tests.Architectures;
///
/// 验证架构初始化阶段可以显式接入默认程序集之外的 CQRS handlers。
///
[TestFixture]
public sealed class ArchitectureAdditionalCqrsHandlersTests
{
///
/// 初始化日志工厂和共享测试状态。
///
[SetUp]
public void SetUp()
{
LoggerFactoryResolver.Provider = new ConsoleLoggerFactoryProvider();
GameContext.Clear();
AdditionalAssemblyNotificationHandler.Reset();
}
///
/// 清理测试过程中写入的共享状态。
///
[TearDown]
public void TearDown()
{
AdditionalAssemblyNotificationHandler.Reset();
GameContext.Clear();
}
///
/// 验证显式声明的额外程序集会在初始化阶段接入当前架构容器。
///
[Test]
public async Task RegisterCqrsHandlersFromAssembly_Should_Register_Handlers_From_Explicit_Assembly()
{
var generatedAssembly = CreateGeneratedHandlerAssembly();
var architecture = new AdditionalHandlersTestArchitecture(target =>
target.RegisterCqrsHandlersFromAssembly(generatedAssembly.Object));
await architecture.InitializeAsync();
await architecture.Context.PublishAsync(new AdditionalAssemblyNotification());
Assert.That(AdditionalAssemblyNotificationHandler.InvocationCount, Is.EqualTo(1));
await architecture.DestroyAsync();
}
///
/// 验证同一额外程序集被重复声明时,不会向容器重复写入相同 handler 映射。
///
[Test]
public async Task RegisterCqrsHandlersFromAssembly_Should_Deduplicate_Repeated_Assembly_Registration()
{
var generatedAssembly = CreateGeneratedHandlerAssembly();
var architecture = new AdditionalHandlersTestArchitecture(target =>
{
target.RegisterCqrsHandlersFromAssembly(generatedAssembly.Object);
target.RegisterCqrsHandlersFromAssemblies([generatedAssembly.Object]);
});
await architecture.InitializeAsync();
await architecture.Context.PublishAsync(new AdditionalAssemblyNotification());
Assert.That(AdditionalAssemblyNotificationHandler.InvocationCount, Is.EqualTo(1));
await architecture.DestroyAsync();
}
///
/// 创建一个仅暴露程序集级 CQRS registry 元数据的 mocked Assembly。
/// 该测试替身模拟“扩展程序集已经挂接 source-generator,运行时只需显式接入该程序集”的真实路径。
///
/// 包含程序集级 handler registry 元数据的 mocked Assembly。
private static Mock CreateGeneratedHandlerAssembly()
{
var generatedAssembly = new Mock();
generatedAssembly
.SetupGet(static assembly => assembly.FullName)
.Returns("GFramework.Core.Tests.Architectures.ExplicitAdditionalHandlers, Version=1.0.0.0");
generatedAssembly
.Setup(static assembly => assembly.GetCustomAttributes(typeof(CqrsHandlerRegistryAttribute), false))
.Returns([new CqrsHandlerRegistryAttribute(typeof(AdditionalAssemblyNotificationHandlerRegistry))]);
return generatedAssembly;
}
///
/// 用于测试额外程序集注册入口的最小架构实现。
///
private sealed class AdditionalHandlersTestArchitecture(Action configure) :
Architecture
{
///
/// 在初始化阶段执行测试注入的额外 CQRS 程序集接入逻辑。
///
protected override void OnInitialize()
{
configure(this);
}
}
}
///
/// 用于验证额外程序集接入是否成功的测试通知。
///
public sealed record AdditionalAssemblyNotification : INotification;
///
/// 由模拟扩展程序集的生成注册器挂入当前容器的通知处理器。
///
public sealed class AdditionalAssemblyNotificationHandler : INotificationHandler
{
///
/// 获取当前测试进程中该处理器的执行次数。
///
public static int InvocationCount { get; private set; }
///
/// 记录一次通知处理,供测试断言显式程序集接入后的运行时行为。
///
/// 通知实例。
/// 取消令牌。
/// 已完成任务。
public ValueTask Handle(AdditionalAssemblyNotification notification, CancellationToken cancellationToken)
{
InvocationCount++;
return ValueTask.CompletedTask;
}
///
/// 清理共享计数器,避免测试间相互污染。
///
public static void Reset()
{
InvocationCount = 0;
}
}
///
/// 模拟由 source-generator 为扩展程序集生成的 CQRS handler registry。
///
internal sealed class AdditionalAssemblyNotificationHandlerRegistry : ICqrsHandlerRegistry
{
///
/// 将扩展程序集中的通知处理器映射写入服务集合。
///
/// 目标服务集合。
/// 日志记录器。
public void Register(IServiceCollection services, ILogger logger)
{
ArgumentNullException.ThrowIfNull(services);
ArgumentNullException.ThrowIfNull(logger);
services
.AddTransient,
AdditionalAssemblyNotificationHandler>();
logger.Debug(
$"Registered CQRS handler {typeof(AdditionalAssemblyNotificationHandler).FullName} as {typeof(INotificationHandler).FullName}.");
}
}