// Copyright (c) 2025-2026 GeWuYou
// SPDX-License-Identifier: Apache-2.0
using GFramework.Core.Command;
using GFramework.Core.Tests.Architectures;
namespace GFramework.Core.Tests.Command;
///
/// CommandBus类的单元测试
/// 测试内容包括:
/// - Send方法执行命令
/// - Send方法处理null命令
/// - Send方法(带返回值)返回值
/// - Send方法(带返回值)处理null命令
/// - SendAsync方法执行异步命令
/// - SendAsync方法处理null异步命令
/// - SendAsync方法(带返回值)返回值
/// - SendAsync方法(带返回值)处理null异步命令
///
[TestFixture]
public class CommandExecutorTests
{
[SetUp]
public void SetUp()
{
_commandExecutor = new CommandExecutor();
}
private CommandExecutor _commandExecutor = null!;
///
/// 测试Send方法执行命令
///
[Test]
public void Send_Should_Execute_Command()
{
var input = new TestCommandInput { Value = 42 };
var command = new TestCommand(input);
Assert.DoesNotThrow(() => _commandExecutor.Send(command));
Assert.That(command.Executed, Is.True);
Assert.That(command.ExecutedValue, Is.EqualTo(42));
}
///
/// 测试Send方法处理null命令时抛出ArgumentNullException异常
///
[Test]
public void Send_WithNullCommand_Should_ThrowArgumentNullException()
{
Assert.Throws(() => _commandExecutor.Send(null!));
}
///
/// 测试Send方法(带返回值)正确返回值
///
[Test]
public void Send_WithResult_Should_Return_Value()
{
var input = new TestCommandInput { Value = 100 };
var command = new TestCommandWithResult(input);
var result = _commandExecutor.Send(command);
Assert.That(command.Executed, Is.True);
Assert.That(result, Is.EqualTo(200));
}
///
/// 测试Send方法(带返回值)处理null命令时抛出ArgumentNullException异常
///
[Test]
public void Send_WithResult_AndNullCommand_Should_ThrowArgumentNullException()
{
Assert.Throws(() => _commandExecutor.Send(null!));
}
///
/// 验证 legacy 同步命令桥接会在线程池上等待 runtime,
/// 避免直接继承调用方当前的同步上下文。
///
[Test]
public void Send_Should_Bridge_Through_Runtime_Without_Reusing_Caller_SynchronizationContext()
{
var runtime = new RecordingCqrsRuntime();
var executor = new CommandExecutor(runtime);
var command = new ContextAwareLegacyCommand();
var expectedContext = new TestArchitectureContextBaseStub();
((GFramework.Core.Abstractions.Rule.IContextAware)command).SetContext(expectedContext);
var originalContext = SynchronizationContext.Current;
try
{
SynchronizationContext.SetSynchronizationContext(new TestLegacySynchronizationContext());
executor.Send(command);
Assert.Multiple(() =>
{
Assert.That(runtime.LastRequest, Is.TypeOf());
Assert.That(runtime.ObservedSynchronizationContextType, Is.Null);
});
}
finally
{
SynchronizationContext.SetSynchronizationContext(originalContext);
}
}
///
/// 验证 legacy 带返回值命令桥接也会保留上下文注入与返回值语义。
///
[Test]
public void Send_WithResult_Should_Bridge_Through_Runtime_And_Preserve_Context()
{
var runtime = new RecordingCqrsRuntime(static _ => 123);
var executor = new CommandExecutor(runtime);
var command = new ContextAwareLegacyCommandWithResult(123);
var expectedContext = new TestArchitectureContextBaseStub();
((GFramework.Core.Abstractions.Rule.IContextAware)command).SetContext(expectedContext);
var result = executor.Send(command);
Assert.Multiple(() =>
{
Assert.That(result, Is.EqualTo(123));
Assert.That(runtime.LastRequest, Is.TypeOf());
Assert.That(command.ObservedContext, Is.SameAs(expectedContext));
});
}
///
/// 测试SendAsync方法执行异步命令
///
[Test]
public async Task SendAsync_Should_Execute_AsyncCommand()
{
var input = new TestCommandInput { Value = 42 };
var command = new TestAsyncCommand(input);
await _commandExecutor.SendAsync(command);
Assert.That(command.Executed, Is.True);
Assert.That(command.ExecutedValue, Is.EqualTo(42));
}
///
/// 测试SendAsync方法处理null异步命令时抛出ArgumentNullException异常
///
[Test]
public void SendAsync_WithNullCommand_Should_ThrowArgumentNullException()
{
Assert.ThrowsAsync(() => _commandExecutor.SendAsync(null!));
}
///
/// 测试SendAsync方法(带返回值)正确返回值
///
[Test]
public async Task SendAsync_WithResult_Should_Return_Value()
{
var input = new TestCommandInput { Value = 100 };
var command = new TestAsyncCommandWithResult(input);
var result = await _commandExecutor.SendAsync(command);
Assert.That(command.Executed, Is.True);
Assert.That(result, Is.EqualTo(200));
}
///
/// 测试SendAsync方法(带返回值)处理null异步命令时抛出ArgumentNullException异常
///
[Test]
public void SendAsync_WithResult_AndNullCommand_Should_ThrowArgumentNullException()
{
Assert.ThrowsAsync(() => _commandExecutor.SendAsync(null!));
}
///
/// 为同步 bridge 测试提供最小架构上下文替身。
///
private sealed class TestArchitectureContextBaseStub : TestArchitectureContextBase
{
}
}