diff --git a/test/Castle.Core.AsyncInterceptor.Tests/InterfaceProxies/ClassWithAlwaysCompletedAsync.cs b/test/Castle.Core.AsyncInterceptor.Tests/InterfaceProxies/ClassWithAlwaysCompletedAsync.cs index 3609436..db75db1 100644 --- a/test/Castle.Core.AsyncInterceptor.Tests/InterfaceProxies/ClassWithAlwaysCompletedAsync.cs +++ b/test/Castle.Core.AsyncInterceptor.Tests/InterfaceProxies/ClassWithAlwaysCompletedAsync.cs @@ -57,4 +57,25 @@ public Task AsynchronousResultMethod() _log.Add(nameof(AsynchronousResultMethod) + ":End"); return Task.FromResult(Guid.NewGuid()); } + +#if NET5_0_OR_GREATER + public async IAsyncEnumerable AsynchronousEnumerableMethod() + { + _log.Add(nameof(AsynchronousEnumerableMethod) + ":Start"); + yield return "a"; + _log.Add(nameof(AsynchronousEnumerableMethod) + ":Yield a"); + await Task.Delay(10).ConfigureAwait(false); + yield return "b"; + _log.Add(nameof(AsynchronousEnumerableMethod) + ":Yield b"); + } + + public async IAsyncEnumerable AsynchronousEnumerableExceptionMethod() + { + _log.Add(nameof(AsynchronousEnumerableExceptionMethod) + ":Start"); + yield return "a"; + _log.Add(nameof(AsynchronousEnumerableExceptionMethod) + ":Yield a"); + await Task.Delay(10).ConfigureAwait(false); + throw new InvalidOperationException(nameof(AsynchronousEnumerableExceptionMethod) + ":Exception"); + } +#endif } diff --git a/test/Castle.Core.AsyncInterceptor.Tests/InterfaceProxies/ClassWithAlwaysIncompleteAsync.cs b/test/Castle.Core.AsyncInterceptor.Tests/InterfaceProxies/ClassWithAlwaysIncompleteAsync.cs index 7c4b345..5bc9e2e 100644 --- a/test/Castle.Core.AsyncInterceptor.Tests/InterfaceProxies/ClassWithAlwaysIncompleteAsync.cs +++ b/test/Castle.Core.AsyncInterceptor.Tests/InterfaceProxies/ClassWithAlwaysIncompleteAsync.cs @@ -58,4 +58,26 @@ public async Task AsynchronousResultMethod() _log.Add(nameof(AsynchronousResultMethod) + ":End"); return Guid.NewGuid(); } + +#if NET5_0_OR_GREATER + public async IAsyncEnumerable AsynchronousEnumerableMethod() + { + _log.Add(nameof(AsynchronousEnumerableMethod) + ":Start"); + yield return "a"; + _log.Add(nameof(AsynchronousEnumerableMethod) + ":Yield a"); + await Task.Delay(10).ConfigureAwait(false); + yield return "b"; + _log.Add(nameof(AsynchronousEnumerableMethod) + ":Yield b"); + } + + public async IAsyncEnumerable AsynchronousEnumerableExceptionMethod() + { + _log.Add(nameof(AsynchronousEnumerableExceptionMethod) + ":Start"); + yield return "a"; + _log.Add(nameof(AsynchronousEnumerableExceptionMethod) + ":Yield a"); + await Task.Delay(10).ConfigureAwait(false); + throw new InvalidOperationException(nameof(AsynchronousEnumerableExceptionMethod) + ":Exception"); + } +#endif + } diff --git a/test/Castle.Core.AsyncInterceptor.Tests/InterfaceProxies/ClassWithInterfaceToProxy.cs b/test/Castle.Core.AsyncInterceptor.Tests/InterfaceProxies/ClassWithInterfaceToProxy.cs index d398c4a..32c9029 100644 --- a/test/Castle.Core.AsyncInterceptor.Tests/InterfaceProxies/ClassWithInterfaceToProxy.cs +++ b/test/Castle.Core.AsyncInterceptor.Tests/InterfaceProxies/ClassWithInterfaceToProxy.cs @@ -73,4 +73,25 @@ public async Task AsynchronousResultExceptionMethod() await Task.Delay(10).ConfigureAwait(false); throw new InvalidOperationException(nameof(AsynchronousResultExceptionMethod) + ":Exception"); } + +#if NET5_0_OR_GREATER + public async IAsyncEnumerable AsynchronousEnumerableMethod() + { + _log.Add(nameof(AsynchronousEnumerableMethod) + ":Start"); + yield return "a"; + _log.Add(nameof(AsynchronousEnumerableMethod) + ":Yield a"); + await Task.Delay(10).ConfigureAwait(false); + yield return "b"; + _log.Add(nameof(AsynchronousEnumerableMethod) + ":Yield b"); + } + + public async IAsyncEnumerable AsynchronousEnumerableExceptionMethod() + { + _log.Add(nameof(AsynchronousEnumerableExceptionMethod) + ":Start"); + yield return "a"; + _log.Add(nameof(AsynchronousEnumerableExceptionMethod) + ":Yield a"); + await Task.Delay(10).ConfigureAwait(false); + throw new InvalidOperationException(nameof(AsynchronousEnumerableExceptionMethod) + ":Exception"); + } +#endif } diff --git a/test/Castle.Core.AsyncInterceptor.Tests/InterfaceProxies/IInterfaceToProxy.cs b/test/Castle.Core.AsyncInterceptor.Tests/InterfaceProxies/IInterfaceToProxy.cs index f09c524..2fe49a6 100644 --- a/test/Castle.Core.AsyncInterceptor.Tests/InterfaceProxies/IInterfaceToProxy.cs +++ b/test/Castle.Core.AsyncInterceptor.Tests/InterfaceProxies/IInterfaceToProxy.cs @@ -22,4 +22,10 @@ public interface IInterfaceToProxy Task AsynchronousResultMethod(); Task AsynchronousResultExceptionMethod(); + +#if NET5_0_OR_GREATER + IAsyncEnumerable AsynchronousEnumerableMethod(); + + IAsyncEnumerable AsynchronousEnumerableExceptionMethod(); +#endif } diff --git a/test/Castle.Core.AsyncInterceptor.Tests/ProcessingAsyncInterceptorWithAsyncEnumerableShould.cs b/test/Castle.Core.AsyncInterceptor.Tests/ProcessingAsyncInterceptorWithAsyncEnumerableShould.cs new file mode 100644 index 0000000..c26d6c2 --- /dev/null +++ b/test/Castle.Core.AsyncInterceptor.Tests/ProcessingAsyncInterceptorWithAsyncEnumerableShould.cs @@ -0,0 +1,172 @@ +// Copyright (c) 2016-2023 James Skimming. All rights reserved. +// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. +#if NET5_0_OR_GREATER + +namespace Castle.DynamicProxy; + +using System; +using Castle.DynamicProxy.InterfaceProxies; +using Xunit; +using Xunit.Abstractions; + +public class WhenProcessingAsynchronousEnumerableMethods +{ + private const string MethodName = nameof(IInterfaceToProxy.AsynchronousEnumerableMethod); + private readonly ListLogger _log; + private readonly IInterfaceToProxy _proxy; + + public WhenProcessingAsynchronousEnumerableMethods(ITestOutputHelper output) + { + _log = new ListLogger(output); + var interceptor = new TestProcessingReturnValueAsyncInterceptor(_log); + _proxy = ProxyGen.CreateProxy(_log, interceptor); + } + + [Fact] + public async Task ShouldLog4Entries() + { + // Arrange + var messages = new List(); + + // Act + await foreach (string msg in _proxy.AsynchronousEnumerableMethod().ConfigureAwait(false)) + { + messages.Add(msg); + } + + // Assert + Assert.Equal(2, messages.Count); + Assert.Equal("a", messages[0]); + Assert.Equal("b", messages[1]); + Assert.Equal(5, _log.Count); + } + + [Fact] + public async Task ShouldAllowProcessingPriorToInvocation() + { + // Arrange + var messages = new List(); + + // Act + await foreach (string msg in _proxy.AsynchronousEnumerableMethod().ConfigureAwait(false)) + { + messages.Add(msg); + } + + // Assert + Assert.Equal($"{MethodName}:StartingInvocation", _log[0]); + } + + [Fact] + public async Task ShouldAllowProcessingAfterInvocation() + { + // Arrange + var messages = new List(); + + // Act + await foreach (string msg in _proxy.AsynchronousEnumerableMethod().ConfigureAwait(false)) + { + messages.Add(msg); + } + + // Assert + Assert.Equal($"{MethodName}:Yield b", _log[4]); + } +} + +public class WhenProcessingAsynchronousEnumerableMethodsThatThrowExceptions +{ + private const string MethodName = nameof(IInterfaceToProxy.AsynchronousEnumerableExceptionMethod); + private readonly ListLogger _log; + private readonly IInterfaceToProxy _proxy; + + public WhenProcessingAsynchronousEnumerableMethodsThatThrowExceptions(ITestOutputHelper output) + { + _log = new ListLogger(output); + var interceptor = new TestProcessingReturnValueAsyncInterceptor(_log); + _proxy = ProxyGen.CreateProxy(_log, interceptor); + } + + [Fact] + public async Task ShouldLog4Entries() + { + // Arrange + var messages = new List(); + InvalidOperationException? exception = null; + + // Act + try + { + await foreach (string msg in _proxy.AsynchronousEnumerableExceptionMethod().ConfigureAwait(false)) + { + messages.Add(msg); + } + } + catch (InvalidOperationException ioe) + { + exception = ioe; + } + + // Assert + Assert.Single(messages); + Assert.Equal("a", messages[0]); + Assert.NotNull(exception); + Assert.Equal(4, _log.Count); + } + + [Fact] + public async Task ShouldAllowProcessingPriorToInvocation() + { + // Arrange + var messages = new List(); + InvalidOperationException? exception = null; + + // Act + try + { + await foreach (string msg in _proxy.AsynchronousEnumerableExceptionMethod().ConfigureAwait(false)) + { + messages.Add(msg); + } + } + catch (InvalidOperationException ioe) + { + exception = ioe; + } + + // Assert + Assert.Single(messages); + Assert.Equal("a", messages[0]); + Assert.NotNull(exception); + Assert.Equal($"{MethodName}:StartingInvocation", _log[0]); + } + + [Fact] + public async Task ShouldAllowProcessingAfterInvocation() + { + // Arrange + var messages = new List(); + InvalidOperationException? exception = null; + + // Act + try + { + await foreach (string msg in _proxy.AsynchronousEnumerableExceptionMethod().ConfigureAwait(false)) + { + messages.Add(msg); + } + } + catch (InvalidOperationException ioe) + { + exception = ioe; + } + + // Assert + Assert.Single(messages); + Assert.Equal("a", messages[0]); + Assert.NotNull(exception); + Assert.Equal($"{MethodName}:Yield a", _log[3]); + } +} + +#endif