From 1981464d9fefbcc3374151a55420c201b0c50e81 Mon Sep 17 00:00:00 2001 From: Robert Coltheart <13191652+robertcoltheart@users.noreply.github.com> Date: Mon, 24 Jun 2024 07:58:10 +1000 Subject: [PATCH] Capture stacktrace of exceptions thrown from async (#524) * Capture stacktrace of exceptions thrown from async * tidy --- .../Runner/AsyncDelegateRunnerSpecs.cs | 5 +++++ .../Runner/Impl/AsyncSynchronizationContext.cs | 17 +++++++++++++++++ .../Runner/Impl/DelegateRunner.cs | 4 ++++ 3 files changed, 26 insertions(+) diff --git a/src/Machine.Specifications.Specs/Runner/AsyncDelegateRunnerSpecs.cs b/src/Machine.Specifications.Specs/Runner/AsyncDelegateRunnerSpecs.cs index 51744149..246826a5 100644 --- a/src/Machine.Specifications.Specs/Runner/AsyncDelegateRunnerSpecs.cs +++ b/src/Machine.Specifications.Specs/Runner/AsyncDelegateRunnerSpecs.cs @@ -68,6 +68,11 @@ public class when_running_async_specifications_with_exceptions : RunnerSpecs It should_have_failures = () => results.Should().Match(x => x.All(y => !y.Passed)); + + It should_have_exception_details = () => + results.Should().Match(x => x.All(r => r.Exception.TypeName == nameof(InvalidOperationException) && + r.Exception.Message == "something went wrong" && + r.Exception.StackTrace.Contains(typeof(AsyncSpecificationsWithExceptions).FullName))); } #if NETCOREAPP diff --git a/src/Machine.Specifications/Runner/Impl/AsyncSynchronizationContext.cs b/src/Machine.Specifications/Runner/Impl/AsyncSynchronizationContext.cs index 994aeab4..0f34fbc4 100644 --- a/src/Machine.Specifications/Runner/Impl/AsyncSynchronizationContext.cs +++ b/src/Machine.Specifications/Runner/Impl/AsyncSynchronizationContext.cs @@ -1,5 +1,6 @@ #if !NET35 using System; +using System.Runtime.ExceptionServices; using System.Threading; using System.Threading.Tasks; @@ -13,7 +14,11 @@ internal class AsyncSynchronizationContext : SynchronizationContext private int callCount; +#if !NET40 + private ExceptionDispatchInfo exception; +#else private Exception exception; +#endif public AsyncSynchronizationContext(SynchronizationContext inner) { @@ -28,7 +33,11 @@ private void Execute(SendOrPostCallback callback, object state) } catch (Exception ex) { +#if !NET40 + exception = ExceptionDispatchInfo.Capture(ex); +#else exception = ex; +#endif } finally { @@ -89,11 +98,19 @@ public override void Send(SendOrPostCallback d, object state) } catch (Exception ex) { +#if !NET40 + exception = ExceptionDispatchInfo.Capture(ex); +#else exception = ex; +#endif } } +#if !NET40 + public ExceptionDispatchInfo WaitAsync() +#else public Exception WaitAsync() +#endif { events.Wait(); diff --git a/src/Machine.Specifications/Runner/Impl/DelegateRunner.cs b/src/Machine.Specifications/Runner/Impl/DelegateRunner.cs index abfb4b90..92adbd1e 100644 --- a/src/Machine.Specifications/Runner/Impl/DelegateRunner.cs +++ b/src/Machine.Specifications/Runner/Impl/DelegateRunner.cs @@ -44,7 +44,11 @@ public void Execute() if (exception != null) { +#if !NET40 + exception.Throw(); +#else throw exception; +#endif } } finally