From 2cadfd858291a180fd706fcbf14822bc22cb2a38 Mon Sep 17 00:00:00 2001 From: ZLoo Date: Mon, 22 Jul 2024 22:26:42 +0300 Subject: [PATCH 1/3] Fix warning CA1062#CachePolicy --- src/Polly/Caching/CachePolicy.cs | 36 ++++++++++--- test/Polly.Specs/Caching/CacheSpecs.cs | 53 +++++++++++++++++++ test/Polly.Specs/Caching/CacheTResultSpecs.cs | 43 +++++++++++++++ 3 files changed, 124 insertions(+), 8 deletions(-) diff --git a/src/Polly/Caching/CachePolicy.cs b/src/Polly/Caching/CachePolicy.cs index e36ccf0d072..e1eed65bd77 100644 --- a/src/Polly/Caching/CachePolicy.cs +++ b/src/Polly/Caching/CachePolicy.cs @@ -4,7 +4,6 @@ namespace Polly.Caching; /// /// A cache policy that can be applied to the results of delegate executions. /// -#pragma warning disable CA1062 // Validate arguments of public methods public class CachePolicy : Policy, ICachePolicy { private readonly ISyncCacheProvider _syncCacheProvider; @@ -39,14 +38,27 @@ internal CachePolicy( } /// - protected override void Implementation(Action action, Context context, CancellationToken cancellationToken) // Pass-through/NOOP policy action, for void-returning calls through a cache policy. - => - action(context, cancellationToken); + protected override void Implementation(Action action, Context context, CancellationToken cancellationToken) + { + // Pass-through/NOOP policy action, for void-returning calls through a cache policy. + if (action is null) + { + throw new ArgumentNullException(nameof(action)); + } + + action(context, cancellationToken); + } /// [DebuggerStepThrough] - protected override TResult Implementation(Func action, Context context, CancellationToken cancellationToken) => - CacheEngine.Implementation( + protected override TResult Implementation(Func action, Context context, CancellationToken cancellationToken) + { + if (action is null) + { + throw new ArgumentNullException(nameof(action)); + } + + return CacheEngine.Implementation( _syncCacheProvider.For(), _ttlStrategy.For(), _cacheKeyStrategy, @@ -58,6 +70,7 @@ protected override TResult Implementation(Func @@ -99,8 +112,14 @@ internal CachePolicy( /// [DebuggerStepThrough] - protected override TResult Implementation(Func action, Context context, CancellationToken cancellationToken) => - CacheEngine.Implementation( + protected override TResult Implementation(Func action, Context context, CancellationToken cancellationToken) + { + if (action is null) + { + throw new ArgumentNullException(nameof(action)); + } + + return CacheEngine.Implementation( _syncCacheProvider, _ttlStrategy, _cacheKeyStrategy, @@ -112,4 +131,5 @@ protected override TResult Implementation(Func action = null!; + Action actionVoid = null; + + ISyncCacheProvider syncCacheProvider = new StubCacheProvider(); + ITtlStrategy ttlStrategy = new ContextualTtl(); + Func cacheKeyStrategy = (_) => string.Empty; + Action onCacheGet = (_, _) => { }; + Action onCacheMiss = (_, _) => { }; + Action onCachePut = (_, _) => { }; + Action? onCacheGetError = null; + Action? onCachePutError = null; + + var instance = Activator.CreateInstance( + typeof(CachePolicy), + flags, + null, + [ + syncCacheProvider, + ttlStrategy, + cacheKeyStrategy, + onCacheGet, + onCacheMiss, + onCachePut, + onCacheGetError, + onCachePutError, + ], + null)!; + var instanceType = instance.GetType(); + var methods = instanceType.GetMethods(flags); + var methodInfo = methods.First(method => method is { Name: "Implementation", ReturnType.Name: "TResult" }); + var generic = methodInfo.MakeGenericMethod(typeof(EmptyStruct)); + + var func = () => generic.Invoke(instance, [action, new Context(), CancellationToken.None]); + + var exceptionAssertions = func.Should().Throw(); + exceptionAssertions.And.Message.Should().Be("Exception has been thrown by the target of an invocation."); + exceptionAssertions.And.InnerException.Should().BeOfType() + .Which.ParamName.Should().Be("action"); + + methodInfo = methods.First(method => method is { Name: "Implementation", ReturnType.Name: "Void" }); + + func = () => methodInfo.Invoke(instance, [actionVoid, new Context(), CancellationToken.None]); + + exceptionAssertions = func.Should().Throw(); + exceptionAssertions.And.Message.Should().Be("Exception has been thrown by the target of an invocation."); + exceptionAssertions.And.InnerException.Should().BeOfType() + .Which.ParamName.Should().Be("action"); + } + [Fact] public void Should_throw_when_cache_provider_is_null() { diff --git a/test/Polly.Specs/Caching/CacheTResultSpecs.cs b/test/Polly.Specs/Caching/CacheTResultSpecs.cs index ab4227531a9..755772d6c02 100644 --- a/test/Polly.Specs/Caching/CacheTResultSpecs.cs +++ b/test/Polly.Specs/Caching/CacheTResultSpecs.cs @@ -5,6 +5,49 @@ public class CacheTResultSpecs : IDisposable { #region Configuration + [Fact] + public void Should_throw_when_action_is_null() + { + var flags = BindingFlags.NonPublic | BindingFlags.Instance; + Func action = null!; + Action actionVoid = null; + + ISyncCacheProvider syncCacheProvider = new StubCacheProvider().For(); + ITtlStrategy ttlStrategy = new ContextualTtl().For(); + Func cacheKeyStrategy = (_) => string.Empty; + Action onCacheGet = (_, _) => { }; + Action onCacheMiss = (_, _) => { }; + Action onCachePut = (_, _) => { }; + Action? onCacheGetError = null; + Action? onCachePutError = null; + + var instance = Activator.CreateInstance( + typeof(CachePolicy), + flags, + null, + [ + syncCacheProvider, + ttlStrategy, + cacheKeyStrategy, + onCacheGet, + onCacheMiss, + onCachePut, + onCacheGetError, + onCachePutError, + ], + null)!; + var instanceType = instance.GetType(); + var methods = instanceType.GetMethods(flags); + var methodInfo = methods.First(method => method is { Name: "Implementation", ReturnType.Name: "EmptyStruct" }); + + var func = () => methodInfo.Invoke(instance, [action, new Context(), CancellationToken.None]); + + var exceptionAssertions = func.Should().Throw(); + exceptionAssertions.And.Message.Should().Be("Exception has been thrown by the target of an invocation."); + exceptionAssertions.And.InnerException.Should().BeOfType() + .Which.ParamName.Should().Be("action"); + } + [Fact] public void Should_throw_when_cache_provider_is_null() { From 0568e5033a4c7f9db1ca527a19b3999b7b44d698 Mon Sep 17 00:00:00 2001 From: ZLoo Date: Mon, 22 Jul 2024 23:26:20 +0300 Subject: [PATCH 2/3] Fix PR --- test/Polly.Specs/Caching/CacheSpecs.cs | 2 +- test/Polly.Specs/Caching/CacheTResultSpecs.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Polly.Specs/Caching/CacheSpecs.cs b/test/Polly.Specs/Caching/CacheSpecs.cs index 16bab3cd6b4..69f88b5af3d 100644 --- a/test/Polly.Specs/Caching/CacheSpecs.cs +++ b/test/Polly.Specs/Caching/CacheSpecs.cs @@ -10,7 +10,7 @@ public void Should_throw_when_action_is_null() { var flags = BindingFlags.NonPublic | BindingFlags.Instance; Func action = null!; - Action actionVoid = null; + Action actionVoid = null!; ISyncCacheProvider syncCacheProvider = new StubCacheProvider(); ITtlStrategy ttlStrategy = new ContextualTtl(); diff --git a/test/Polly.Specs/Caching/CacheTResultSpecs.cs b/test/Polly.Specs/Caching/CacheTResultSpecs.cs index 755772d6c02..490a1b87463 100644 --- a/test/Polly.Specs/Caching/CacheTResultSpecs.cs +++ b/test/Polly.Specs/Caching/CacheTResultSpecs.cs @@ -10,7 +10,7 @@ public void Should_throw_when_action_is_null() { var flags = BindingFlags.NonPublic | BindingFlags.Instance; Func action = null!; - Action actionVoid = null; + Action actionVoid = null!; ISyncCacheProvider syncCacheProvider = new StubCacheProvider().For(); ITtlStrategy ttlStrategy = new ContextualTtl().For(); From 849123af3a3e8b82a65c3d7871b7c628ae108955 Mon Sep 17 00:00:00 2001 From: ZLoo Date: Tue, 23 Jul 2024 00:56:29 +0300 Subject: [PATCH 3/3] Fix PR --- test/Polly.Specs/Caching/CacheTResultSpecs.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/test/Polly.Specs/Caching/CacheTResultSpecs.cs b/test/Polly.Specs/Caching/CacheTResultSpecs.cs index 490a1b87463..15e7f278ce0 100644 --- a/test/Polly.Specs/Caching/CacheTResultSpecs.cs +++ b/test/Polly.Specs/Caching/CacheTResultSpecs.cs @@ -10,7 +10,6 @@ public void Should_throw_when_action_is_null() { var flags = BindingFlags.NonPublic | BindingFlags.Instance; Func action = null!; - Action actionVoid = null!; ISyncCacheProvider syncCacheProvider = new StubCacheProvider().For(); ITtlStrategy ttlStrategy = new ContextualTtl().For();