using Kompas.Mcp.Core.Threading;
namespace Kompas.Mcp.Tests;
/// Юнит-тесты STA-диспетчера. COM не требуется.
[Trait("Category", "Unit")]
public sealed class DispatcherTests
{
[Fact]
public async Task Runs_work_on_STA_thread()
{
using var d = new KompasDispatcher();
var state = await d.InvokeAsync(() => Thread.CurrentThread.GetApartmentState());
Assert.Equal(ApartmentState.STA, state);
}
[Fact]
public async Task Serializes_all_work_on_one_thread()
{
using var d = new KompasDispatcher();
var id1 = await d.InvokeAsync(() => Environment.CurrentManagedThreadId);
var id2 = await d.InvokeAsync(() => Environment.CurrentManagedThreadId);
Assert.Equal(id1, id2);
Assert.NotEqual(Environment.CurrentManagedThreadId, id1);
}
[Fact]
public async Task Propagates_exceptions_to_caller()
{
using var d = new KompasDispatcher();
await Assert.ThrowsAsync(
() => d.InvokeAsync(() => throw new InvalidOperationException("boom")));
}
[Fact]
public async Task Throws_ObjectDisposed_after_dispose()
{
var d = new KompasDispatcher();
d.Dispose();
await Assert.ThrowsAsync(() => d.InvokeAsync(() => { }));
}
[Fact]
public async Task Nested_invoke_runs_inline_without_deadlock()
{
using var d = new KompasDispatcher();
var result = await d.InvokeAsync(() =>
{
// Вложенный вызов на том же потоке должен выполниться синхронно, без дедлока.
return d.InvokeAsync(() => 42).GetAwaiter().GetResult();
});
Assert.Equal(42, result);
}
}