0038790902
- KompasDispatcher: выделенный STA-поток + очередь задач, InvokeAsync<T>, inline-выполнение вложенных вызовов, корректный Dispose - NativeMethods: attach к запущенному COM (CLSIDFromProgID + GetActiveObject, замена отсутствующего в .NET 8 Marshal.GetActiveObject) - KompasSession: подключение через API5 (KompasObject) -> API7 (IApplication), attach/launch, версия/редакция, освобождение COM на STA-потоке - tests: 5 unit-тестов диспетчера + 3 интеграционных теста подключения (зелёные) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
55 lines
1.8 KiB
C#
55 lines
1.8 KiB
C#
using Kompas.Mcp.Core.Threading;
|
|
|
|
namespace Kompas.Mcp.Tests;
|
|
|
|
/// <summary>Юнит-тесты STA-диспетчера. COM не требуется.</summary>
|
|
[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<InvalidOperationException>(
|
|
() => d.InvokeAsync<int>(() => throw new InvalidOperationException("boom")));
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Throws_ObjectDisposed_after_dispose()
|
|
{
|
|
var d = new KompasDispatcher();
|
|
d.Dispose();
|
|
await Assert.ThrowsAsync<ObjectDisposedException>(() => 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);
|
|
}
|
|
}
|