// Copyright (c) 2025-2026 GeWuYou
// SPDX-License-Identifier: Apache-2.0
using System.Reflection;
using GFramework.Core.Abstractions.Logging;
using GFramework.Core.Architectures;
using GFramework.Core.Logging;
using GFramework.Cqrs;
using GFramework.Cqrs.Abstractions.Cqrs;
namespace GFramework.Core.Tests.Architectures;
///
/// 验证架构初始化阶段可以显式接入默认程序集之外的 CQRS handlers。
///
[TestFixture]
public sealed class ArchitectureAdditionalCqrsHandlersTests
{
///
/// 初始化日志工厂和共享测试状态。
///
[SetUp]
public void SetUp()
{
_previousLoggerFactoryProvider = LoggerFactoryResolver.Provider;
LoggerFactoryResolver.Provider = new ConsoleLoggerFactoryProvider();
GameContext.Clear();
AdditionalAssemblyNotificationHandlerState.Reset();
}
///
/// 清理测试过程中写入的共享状态。
///
[TearDown]
public void TearDown()
{
AdditionalAssemblyNotificationHandlerState.Reset();
GameContext.Clear();
LoggerFactoryResolver.Provider = _previousLoggerFactoryProvider
?? throw new InvalidOperationException(
"LoggerFactoryResolver.Provider should be captured during setup.");
}
private ILoggerFactoryProvider? _previousLoggerFactoryProvider;
///
/// 验证显式声明的额外程序集会在初始化阶段接入当前架构容器。
///
/// The asynchronous test task.
[Test]
public async Task RegisterCqrsHandlersFromAssembly_Should_Register_Handlers_From_Explicit_Assembly()
{
var generatedAssembly = CreateGeneratedHandlerAssembly();
var architecture = CreateArchitecture(target =>
target.RegisterCqrsHandlersFromAssembly(generatedAssembly.Object));
await architecture.InitializeAsync();
try
{
await architecture.Context.PublishAsync(new AdditionalAssemblyNotification());
Assert.That(AdditionalAssemblyNotificationHandlerState.InvocationCount, Is.EqualTo(1));
}
finally
{
await architecture.DestroyAsync();
}
}
///
/// 验证不同 实例只要解析到相同程序集键,就不会向容器重复写入相同 handler 映射。
///
/// The asynchronous test task.
[Test]
public async Task RegisterCqrsHandlersFromAssembly_Should_Deduplicate_Repeated_Assembly_Registration()
{
var generatedAssemblyA = CreateGeneratedHandlerAssembly();
var generatedAssemblyB = CreateGeneratedHandlerAssembly();
var architecture = CreateArchitecture(target =>
{
target.RegisterCqrsHandlersFromAssembly(generatedAssemblyA.Object);
target.RegisterCqrsHandlersFromAssemblies([generatedAssemblyB.Object]);
});
await architecture.InitializeAsync();
try
{
await architecture.Context.PublishAsync(new AdditionalAssemblyNotification());
Assert.That(AdditionalAssemblyNotificationHandlerState.InvocationCount, Is.EqualTo(1));
}
finally
{
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;
}
///
/// 创建复用现有测试架构基建的测试架构,并在注册阶段后执行额外程序集接入逻辑。
///
/// 初始化阶段执行的额外 CQRS 程序集接入逻辑。
/// 带有注册后钩子的测试架构实例。
private static SyncTestArchitecture CreateArchitecture(Action configure)
{
var architecture = new SyncTestArchitecture();
architecture.AddPostRegistrationHook(configure);
return architecture;
}
}