SafeSynchronizationContext
This context is used to protect test execution from any exceptions
using NUnit.Framework.Interfaces;
using System;
using System.Runtime.CompilerServices;
using System.Threading;
namespace NUnit.Framework.Internal
{
[System.Runtime.CompilerServices.NullableContext(1)]
[System.Runtime.CompilerServices.Nullable(0)]
public class SafeSynchronizationContext : SynchronizationContext
{
private static readonly Logger Log = InternalTrace.GetLogger("SafeSynchronizationContext");
internal TestExecutionContext ExecutionContext { get; }
internal SafeSynchronizationContext(TestExecutionContext executionContext)
{
ExecutionContext = executionContext;
}
public override void Send(SendOrPostCallback d, [System.Runtime.CompilerServices.Nullable(2)] object state)
{
ExecuteSafely(d, state);
}
public override void Post(SendOrPostCallback d, [System.Runtime.CompilerServices.Nullable(2)] object state)
{
ExecuteSafely(d, state);
}
protected void ExecuteSafely(SendOrPostCallback d, [System.Runtime.CompilerServices.Nullable(2)] object state)
{
try {
d(state);
} catch (Exception ex) {
TestExecutionContext executionContext = ExecutionContext;
Log.Error("Unexpected exception from SynchronizationContext in test " + executionContext.CurrentTest.FullName + ": " + ex.Message);
lock (executionContext) {
executionContext.CurrentResult.RecordException(ex, FailureSite.Test);
executionContext.CurrentResult.RecordTestCompletion();
}
}
}
public static SafeSynchronizationContext Create([System.Runtime.CompilerServices.Nullable(2)] SynchronizationContext synchronizationContext, TestExecutionContext executionContext)
{
if (synchronizationContext != null && !(synchronizationContext is SafeSynchronizationContext))
return new SafeIndirectSynchronizationContext(synchronizationContext, executionContext);
return new SafeSynchronizationContext(executionContext);
}
}
}