diff --git a/Directory.Build.props b/Directory.Build.props index 6025539..a657aac 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -2,4 +2,7 @@ latest + + $(DefineConstants);HAS_ASYNC_ENUMERATOR + diff --git a/src/Ben.Demystifier/EnhancedStackTrace.Frames.cs b/src/Ben.Demystifier/EnhancedStackTrace.Frames.cs index 933b88c..e5084c8 100644 --- a/src/Ben.Demystifier/EnhancedStackTrace.Frames.cs +++ b/src/Ben.Demystifier/EnhancedStackTrace.Frames.cs @@ -845,7 +845,7 @@ namespace System.Diagnostics { foundAttribute = true; foundIteratorAttribute |= asma is IteratorStateMachineAttribute -#if NETSTANDARD2_1 +#if HAS_ASYNC_ENUMERATOR || asma is AsyncIteratorStateMachineAttribute #endif ; diff --git a/test/Ben.Demystifier.Test/AsyncEnumerableTests.cs b/test/Ben.Demystifier.Test/AsyncEnumerableTests.cs new file mode 100644 index 0000000..d9469a4 --- /dev/null +++ b/test/Ben.Demystifier.Test/AsyncEnumerableTests.cs @@ -0,0 +1,68 @@ +#if HAS_ASYNC_ENUMERATOR +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Threading; +using System.Threading.Tasks; +using Xunit; + +namespace Ben.Demystifier.Test +{ + public class AsyncEnumerableTests + { + [Fact] + public async Task DemystifiesAsyncEnumerable() + { + Exception demystifiedException = null; + + try + { + await foreach (var val in Start(CancellationToken.None)) + { + _ = val; + } + } + catch (Exception ex) + { + demystifiedException = ex.Demystify(); + } + + // Assert + var stackTrace = demystifiedException.ToString(); + stackTrace = LineEndingsHelper.RemoveLineEndings(stackTrace); + var trace = string.Join("", stackTrace.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries) + .Skip(1) + .ToArray()); + var expected = string.Join("", new[] { + " at async IAsyncEnumerable Ben.Demystifier.Test.AsyncEnumerableTests.Throw(CancellationToken cancellationToken)+MoveNext()", + " at async IAsyncEnumerable Ben.Demystifier.Test.AsyncEnumerableTests.Throw(CancellationToken cancellationToken)+System.Threading.Tasks.Sources.IValueTaskSource.GetResult(short token)", + " at async IAsyncEnumerable Ben.Demystifier.Test.AsyncEnumerableTests.Start(CancellationToken cancellationToken)+MoveNext()", + " at async IAsyncEnumerable Ben.Demystifier.Test.AsyncEnumerableTests.Start(CancellationToken cancellationToken)+MoveNext()", + " at async IAsyncEnumerable Ben.Demystifier.Test.AsyncEnumerableTests.Start(CancellationToken cancellationToken)+System.Threading.Tasks.Sources.IValueTaskSource.GetResult(short token)", + " at async Task Ben.Demystifier.Test.AsyncEnumerableTests.DemystifiesAsyncEnumerable()", + " at async Task Ben.Demystifier.Test.AsyncEnumerableTests.DemystifiesAsyncEnumerable()" + }); + Assert.Equal(expected, trace); + } + + async IAsyncEnumerable Start([EnumeratorCancellation] CancellationToken cancellationToken) + { + await Task.Delay(1, cancellationToken).ConfigureAwait(false); + yield return 1; + await foreach (var @throw in Throw(cancellationToken)) + { + yield return @throw; + } + } + + async IAsyncEnumerable Throw([EnumeratorCancellation] CancellationToken cancellationToken) + { + yield return 2; + await Task.Delay(1, cancellationToken).ConfigureAwait(false); + throw new InvalidOperationException(); + } + } +} +#endif