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 { public class StaComThreadTests : IDisposable { private readonly StaComThread _thread; public StaComThreadTests() { _thread = new StaComThread(); _thread.Start(); } public void Dispose() => _thread.Dispose(); [Fact] public async Task RunAsync_ExecutesOnStaThread() { var apartmentState = await _thread.RunAsync(() => Thread.CurrentThread.GetApartmentState()); apartmentState.ShouldBe(ApartmentState.STA); } [Fact] public async Task RunAsync_Action_Completes() { var executed = false; await _thread.RunAsync(() => executed = true); executed.ShouldBe(true); } [Fact] public async Task RunAsync_Func_ReturnsResult() { var result = await _thread.RunAsync(() => 42); result.ShouldBe(42); } [Fact] public async Task RunAsync_PropagatesException() { await Should.ThrowAsync( _thread.RunAsync(() => throw new InvalidOperationException("test error"))); } [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()); } [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); } } }