using System;
using System.Threading;
using System.Threading.Tasks;
using Shouldly;
using Xunit;
using ZB.MOM.WW.LmxOpcUa.Host.MxAccess;
namespace ZB.MOM.WW.LmxOpcUa.Tests.MxAccess
{
///
/// Verifies the single-threaded apartment worker used to marshal COM calls for the MXAccess bridge.
///
public class StaComThreadTests : IDisposable
{
private readonly StaComThread _thread;
///
/// Starts a fresh STA thread instance for each test.
///
public StaComThreadTests()
{
_thread = new StaComThread();
_thread.Start();
}
///
/// Disposes the STA thread after each test.
///
public void Dispose() => _thread.Dispose();
///
/// Confirms that queued work runs on a thread configured for STA apartment state.
///
[Fact]
public async Task RunAsync_ExecutesOnStaThread()
{
var apartmentState = await _thread.RunAsync(() => Thread.CurrentThread.GetApartmentState());
apartmentState.ShouldBe(ApartmentState.STA);
}
///
/// Confirms that action delegates run to completion on the STA thread.
///
[Fact]
public async Task RunAsync_Action_Completes()
{
var executed = false;
await _thread.RunAsync(() => executed = true);
executed.ShouldBe(true);
}
///
/// Confirms that function delegates can return results from the STA thread.
///
[Fact]
public async Task RunAsync_Func_ReturnsResult()
{
var result = await _thread.RunAsync(() => 42);
result.ShouldBe(42);
}
///
/// Confirms that exceptions thrown on the STA thread propagate back to the caller.
///
[Fact]
public async Task RunAsync_PropagatesException()
{
await Should.ThrowAsync(
_thread.RunAsync(() => throw new InvalidOperationException("test error")));
}
///
/// Confirms that disposing the STA thread stops it from accepting additional work.
///
[Fact]
public void Dispose_Stops_Thread()
{
var thread = new StaComThread();
thread.Start();
thread.IsRunning.ShouldBe(true);
thread.Dispose();
// After dispose, should not accept new work
Should.Throw(() => thread.RunAsync(() => { }).GetAwaiter().GetResult());
}
///
/// Confirms that multiple queued work items all execute successfully on the STA thread.
///
[Fact]
public async Task MultipleWorkItems_ExecuteInOrder()
{
var results = new System.Collections.Concurrent.ConcurrentBag();
await Task.WhenAll(
_thread.RunAsync(() => results.Add(1)),
_thread.RunAsync(() => results.Add(2)),
_thread.RunAsync(() => results.Add(3)));
results.Count.ShouldBe(3);
}
}
}