< Summary - Kestrun — Combined Coverage

Information
Class: Kestrun.Utilities.RateLimiterOptionsExtensions
Assembly: Kestrun
File(s): /home/runner/work/Kestrun/Kestrun/src/CSharp/Kestrun/Utilities/RateLimiterOptionsExtensions.cs
Tag: Kestrun/Kestrun@0d738bf294e6281b936d031e1979d928007495ff
Line coverage
30%
Covered lines: 13
Uncovered lines: 29
Coverable lines: 42
Total lines: 119
Line coverage: 30.9%
Branch coverage
11%
Covered branches: 4
Total branches: 34
Branch coverage: 11.7%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100 08/26/2025 - 14:53:17 Line coverage: 0% (0/21) Branch coverage: 0% (0/6) Total lines: 53 Tag: Kestrun/Kestrun@78d1e497d8ba989d121b57aa39aa3c6b22de743112/15/2025 - 04:25:23 Line coverage: 30.9% (13/42) Branch coverage: 11.7% (4/34) Total lines: 119 Tag: Kestrun/Kestrun@e333660af9731cab5ae4c14a12f3bb84a8fabc7d 08/26/2025 - 14:53:17 Line coverage: 0% (0/21) Branch coverage: 0% (0/6) Total lines: 53 Tag: Kestrun/Kestrun@78d1e497d8ba989d121b57aa39aa3c6b22de743112/15/2025 - 04:25:23 Line coverage: 30.9% (13/42) Branch coverage: 11.7% (4/34) Total lines: 119 Tag: Kestrun/Kestrun@e333660af9731cab5ae4c14a12f3bb84a8fabc7d

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
CopyFrom(...)25%521648.14%
GetAddPolicyMethod(...)0%342180%

File(s)

/home/runner/work/Kestrun/Kestrun/src/CSharp/Kestrun/Utilities/RateLimiterOptionsExtensions.cs

#LineLine coverage
 1using System.Reflection;
 2using Microsoft.AspNetCore.RateLimiting;
 3namespace Kestrun.Utilities;
 4/// <summary>
 5/// Provides extension methods for copying rate limiter options and policies.
 6/// </summary>
 7public static class RateLimiterOptionsExtensions
 8{
 9    /// <summary>
 10    /// Copies all rate limiter options and policies from the source to the target <see cref="RateLimiterOptions"/>.
 11    /// </summary>
 12    /// <param name="target">The target <see cref="RateLimiterOptions"/> to copy to.</param>
 13    /// <param name="source">The source <see cref="RateLimiterOptions"/> to copy from.</param>
 14    public static void CopyFrom(this RateLimiterOptions target, RateLimiterOptions source)
 15    {
 316        ArgumentNullException.ThrowIfNull(source);
 17
 18        // ───── scalar props ─────
 219        target.GlobalLimiter = source.GlobalLimiter;
 220        target.OnRejected = source.OnRejected;
 221        target.RejectionStatusCode = source.RejectionStatusCode;
 22
 23        // ───── activated policies ─────
 24        try
 25        {
 226            var policyMapField = typeof(RateLimiterOptions).GetField("PolicyMap",
 227                BindingFlags.Instance | BindingFlags.NonPublic);
 228            if (policyMapField != null)
 29            {
 030                var policyMap = (IDictionary<string, object>?)policyMapField.GetValue(source);
 031                if (policyMap != null)
 32                {
 33                    // Find the AddPolicy method that takes an IRateLimiterPolicy<HttpContext>
 034                    var addPolicyMethod = GetAddPolicyMethod(true);
 035                    foreach (var kvp in policyMap)
 36                    {
 037                        _ = (addPolicyMethod?.Invoke(target, [kvp.Key, kvp.Value]));
 38                    }
 39                }
 40            }
 241        }
 042        catch
 43        {
 44            // Silently ignore if PolicyMap field doesn't exist in this version
 045        }
 46
 47        // ───── factories awaiting DI (un-activated) ─────
 48        try
 49        {
 250            var factoryMapField = typeof(RateLimiterOptions).GetField("UnactivatedPolicyMap",
 251                BindingFlags.Instance | BindingFlags.NonPublic);
 252            if (factoryMapField != null)
 53            {
 054                var factoryMap = (IDictionary<string, object>?)factoryMapField.GetValue(source);
 055                if (factoryMap != null)
 56                {
 57                    // Find the AddPolicy method that takes a Func<IServiceProvider, IRateLimiterPolicy<HttpContext>>
 058                    var addPolicyMethod = GetAddPolicyMethod(false);
 059                    foreach (var kvp in factoryMap)
 60                    {
 061                        _ = (addPolicyMethod?.Invoke(target, [kvp.Key, kvp.Value]));
 62                    }
 63                }
 64            }
 265        }
 066        catch
 67        {
 68            // Silently ignore if UnactivatedPolicyMap field doesn't exist in this version
 069        }
 270    }
 71
 72    private static MethodInfo? GetAddPolicyMethod(bool forDirectPolicy)
 73    {
 074        var methods = typeof(RateLimiterOptions).GetMethods();
 075        foreach (var method in methods)
 76        {
 077            if (method.Name != "AddPolicy")
 78            {
 79                continue;
 80            }
 81
 082            var parameters = method.GetParameters();
 083            if (parameters.Length != 2)
 84            {
 85                continue;
 86            }
 87
 088            if (parameters[0].ParameterType != typeof(string))
 89            {
 90                continue;
 91            }
 92
 093            var secondParamType = parameters[1].ParameterType;
 94
 095            if (forDirectPolicy)
 96            {
 97                // Looking for AddPolicy(string, IRateLimiterPolicy<HttpContext>)
 98                // The parameter should be an interface that is IRateLimiterPolicy<T>
 099                if (secondParamType.IsGenericType &&
 0100                    secondParamType.GetGenericTypeDefinition().Name.Contains("IRateLimiterPolicy"))
 101                {
 0102                    return method;
 103                }
 104            }
 105            else
 106            {
 107                // Looking for AddPolicy(string, Func<IServiceProvider, IRateLimiterPolicy<HttpContext>>)
 108                // The parameter should be a Func delegate
 0109                if (secondParamType.IsGenericType &&
 0110                    secondParamType.GetGenericTypeDefinition() == typeof(Func<,>))
 111                {
 0112                    return method;
 113                }
 114            }
 115        }
 116
 0117        return null;
 118    }
 119}