From 871cef47e591205d511a64a945eaf73fc528833d Mon Sep 17 00:00:00 2001 From: ZLoo Date: Sun, 21 Jul 2024 23:22:01 +0300 Subject: [PATCH] Fix warning CA1062#RateLimitPolicy --- src/Polly/RateLimit/RateLimitPolicy.cs | 23 ++++++++++++---- .../RateLimit/RateLimitPolicySpecs.cs | 26 +++++++++++++++++++ .../RateLimit/RateLimitPolicyTResultSpecs.cs | 26 +++++++++++++++++++ 3 files changed, 70 insertions(+), 5 deletions(-) diff --git a/src/Polly/RateLimit/RateLimitPolicy.cs b/src/Polly/RateLimit/RateLimitPolicy.cs index 95c891fc14a..34a540cf8d2 100644 --- a/src/Polly/RateLimit/RateLimitPolicy.cs +++ b/src/Polly/RateLimit/RateLimitPolicy.cs @@ -4,7 +4,6 @@ namespace Polly.RateLimit; /// /// A rate-limit policy that can be applied to synchronous delegates. /// -#pragma warning disable CA1062 // Validate arguments of public methods public class RateLimitPolicy : Policy, IRateLimitPolicy { private readonly IRateLimiter _rateLimiter; @@ -14,8 +13,15 @@ internal RateLimitPolicy(IRateLimiter rateLimiter) => /// [DebuggerStepThrough] - protected override TResult Implementation(Func action, Context context, CancellationToken cancellationToken) => - RateLimitEngine.Implementation(_rateLimiter, null, action, context, cancellationToken); + protected override TResult Implementation(Func action, Context context, CancellationToken cancellationToken) + { + if (action is null) + { + throw new ArgumentNullException(nameof(action)); + } + + return RateLimitEngine.Implementation(_rateLimiter, null, action, context, cancellationToken); + } } /// @@ -37,6 +43,13 @@ internal RateLimitPolicy( /// [DebuggerStepThrough] - protected override TResult Implementation(Func action, Context context, CancellationToken cancellationToken) => - RateLimitEngine.Implementation(_rateLimiter, _retryAfterFactory, action, context, cancellationToken); + protected override TResult Implementation(Func action, Context context, CancellationToken cancellationToken) + { + if (action is null) + { + throw new ArgumentNullException(nameof(action)); + } + + return RateLimitEngine.Implementation(_rateLimiter, _retryAfterFactory, action, context, cancellationToken); + } } diff --git a/test/Polly.Specs/RateLimit/RateLimitPolicySpecs.cs b/test/Polly.Specs/RateLimit/RateLimitPolicySpecs.cs index eb7329856ef..d5b7a25ed63 100644 --- a/test/Polly.Specs/RateLimit/RateLimitPolicySpecs.cs +++ b/test/Polly.Specs/RateLimit/RateLimitPolicySpecs.cs @@ -31,4 +31,30 @@ protected override (bool, TimeSpan) TryExecuteThroughPolicy(IRateLimitPolicy pol throw new InvalidOperationException("Unexpected policy type in test construction."); } } + + [Fact] + public void Should_throw_when_action_is_null() + { + var flags = BindingFlags.NonPublic | BindingFlags.Instance; + Func action = null!; + IRateLimiter rateLimiter = RateLimiterFactory.Create(TimeSpan.FromSeconds(1), 1); + + var instance = Activator.CreateInstance( + typeof(RateLimitPolicy), + flags, + null, + [rateLimiter], + 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"); + } } diff --git a/test/Polly.Specs/RateLimit/RateLimitPolicyTResultSpecs.cs b/test/Polly.Specs/RateLimit/RateLimitPolicyTResultSpecs.cs index d94142b748b..99fc2a224c5 100644 --- a/test/Polly.Specs/RateLimit/RateLimitPolicyTResultSpecs.cs +++ b/test/Polly.Specs/RateLimit/RateLimitPolicyTResultSpecs.cs @@ -47,4 +47,30 @@ protected override TResult TryExecuteThroughPolicy(IRateLimitPolicy action = null!; + IRateLimiter rateLimiter = RateLimiterFactory.Create(TimeSpan.FromSeconds(1), 1); + Func? retryAfterFactory = null; + + var instance = Activator.CreateInstance( + typeof(RateLimitPolicy), + flags, + null, + [rateLimiter, retryAfterFactory], + 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"); + } }