From 85cd19d356c211b4921e814a2de24e13a6c7d4e9 Mon Sep 17 00:00:00 2001 From: ZLoo Date: Tue, 23 Jul 2024 10:09:56 +0300 Subject: [PATCH] Fix CA1062 warnings (#2238) Fix CA1062 warnings for `CachePolicy`. --- src/Polly/Caching/CachePolicy.cs | 36 ++++++++++--- test/Polly.Specs/Caching/CacheSpecs.cs | 53 +++++++++++++++++++ test/Polly.Specs/Caching/CacheTResultSpecs.cs | 42 +++++++++++++++ 3 files changed, 123 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..15e7f278ce0 100644 --- a/test/Polly.Specs/Caching/CacheTResultSpecs.cs +++ b/test/Polly.Specs/Caching/CacheTResultSpecs.cs @@ -5,6 +5,48 @@ public class CacheTResultSpecs : IDisposable { #region Configuration + [Fact] + public void Should_throw_when_action_is_null() + { + var flags = BindingFlags.NonPublic | BindingFlags.Instance; + Func action = 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() {