<PackageReference Include="NUnit" Version="3.11.0" />

SingleThreadedTestSynchronizationContext

using System; using System.Collections.Generic; using System.Threading; namespace NUnit.Framework.Internal { internal sealed class SingleThreadedTestSynchronizationContext : SynchronizationContext, IDisposable { private enum Status { NotStarted, Running, ShutDown } private struct ScheduledWork { private readonly SendOrPostCallback _callback; private readonly object _state; private readonly System.Threading.ManualResetEventSlim _finished; public ScheduledWork(SendOrPostCallback callback, object state, System.Threading.ManualResetEventSlim finished) { _callback = callback; _state = state; _finished = finished; } public void Execute() { _callback(_state); _finished?.Set(); } } private readonly Queue<ScheduledWork> _queue = new Queue<ScheduledWork>(); private Status status; public override void Post(SendOrPostCallback d, object state) { Guard.ArgumentNotNull(d, "d"); AddWork(new ScheduledWork(d, state, null)); } public override void Send(SendOrPostCallback d, object state) { Guard.ArgumentNotNull(d, "d"); if (SynchronizationContext.Current == this) d(state); else { using (System.Threading.ManualResetEventSlim manualResetEventSlim = new System.Threading.ManualResetEventSlim()) { AddWork(new ScheduledWork(d, state, manualResetEventSlim)); manualResetEventSlim.Wait(); } } } private void AddWork(ScheduledWork work) { lock (_queue) { if (status == Status.ShutDown) throw CreateInvalidWhenShutDownException(); _queue.Enqueue(work); Monitor.Pulse(_queue); } } public void ShutDown() { lock (_queue) { status = Status.ShutDown; Monitor.Pulse(_queue); if (_queue.Count != 0) throw new InvalidOperationException("Shutting down SingleThreadedTestSynchronizationContext with work still in the queue."); } } private static InvalidOperationException CreateInvalidWhenShutDownException() { return new InvalidOperationException("This SingleThreadedTestSynchronizationContext has been shut down."); } public void Run() { lock (_queue) { switch (status) { case Status.Running: throw new InvalidOperationException("SingleThreadedTestSynchronizationContext.Run may not be reentered."); case Status.ShutDown: throw CreateInvalidWhenShutDownException(); } status = Status.Running; } ScheduledWork scheduledWork; while (TryTake(out scheduledWork)) { scheduledWork.Execute(); } } private bool TryTake(out ScheduledWork scheduledWork) { lock (_queue) { while (true) { if (status == Status.ShutDown) { scheduledWork = default(ScheduledWork); return false; } if (_queue.Count != 0) break; Monitor.Wait(_queue); } scheduledWork = _queue.Dequeue(); } return true; } public void Dispose() { ShutDown(); } } }