< Summary - Kestrun — Combined Coverage

Information
Class: DelegateBuilder
Assembly: Kestrun
File(s): /home/runner/work/Kestrun/Kestrun/src/CSharp/Kestrun/Languages/DelegateBuilder.cs
Tag: Kestrun/Kestrun@0d738bf294e6281b936d031e1979d928007495ff
Line coverage
99%
Covered lines: 115
Uncovered lines: 1
Coverable lines: 116
Total lines: 233
Line coverage: 99.1%
Branch coverage
97%
Covered branches: 39
Total branches: 40
Branch coverage: 97.5%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100 09/04/2025 - 17:02:01 Line coverage: 93% (107/115) Branch coverage: 85% (34/40) Total lines: 233 Tag: Kestrun/Kestrun@f3880b25ea131298aa2f8b1e0d0a8d55eb160bc009/06/2025 - 18:30:33 Line coverage: 97.3% (112/115) Branch coverage: 97.5% (39/40) Total lines: 233 Tag: Kestrun/Kestrun@aeddbedb8a96e9137aac94c2d5edd011b57ac87109/12/2025 - 03:43:11 Line coverage: 97.3% (112/115) Branch coverage: 97.5% (39/40) Total lines: 232 Tag: Kestrun/Kestrun@d160286e3020330b1eb862d66a37db2e26fc904210/13/2025 - 16:52:37 Line coverage: 99.1% (115/116) Branch coverage: 97.5% (39/40) Total lines: 234 Tag: Kestrun/Kestrun@10d476bee71c71ad215bb8ab59f219887b5b4a5e11/14/2025 - 12:29:34 Line coverage: 99.1% (115/116) Branch coverage: 97.5% (39/40) Total lines: 233 Tag: Kestrun/Kestrun@5e12b09a6838e68e704cd3dc975331b9e680a626 09/04/2025 - 17:02:01 Line coverage: 93% (107/115) Branch coverage: 85% (34/40) Total lines: 233 Tag: Kestrun/Kestrun@f3880b25ea131298aa2f8b1e0d0a8d55eb160bc009/06/2025 - 18:30:33 Line coverage: 97.3% (112/115) Branch coverage: 97.5% (39/40) Total lines: 233 Tag: Kestrun/Kestrun@aeddbedb8a96e9137aac94c2d5edd011b57ac87109/12/2025 - 03:43:11 Line coverage: 97.3% (112/115) Branch coverage: 97.5% (39/40) Total lines: 232 Tag: Kestrun/Kestrun@d160286e3020330b1eb862d66a37db2e26fc904210/13/2025 - 16:52:37 Line coverage: 99.1% (115/116) Branch coverage: 97.5% (39/40) Total lines: 234 Tag: Kestrun/Kestrun@10d476bee71c71ad215bb8ab59f219887b5b4a5e11/14/2025 - 12:29:34 Line coverage: 99.1% (115/116) Branch coverage: 97.5% (39/40) Total lines: 233 Tag: Kestrun/Kestrun@5e12b09a6838e68e704cd3dc975331b9e680a626

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
PrepareExecutionAsync()92.85%141494.73%
ApplyResponseAsync()100%66100%
BuildBaselineReferences()100%1010100%
Add()100%22100%
NamespaceExistsInAssembly(...)100%88100%
.cctor()100%11100%

File(s)

/home/runner/work/Kestrun/Kestrun/src/CSharp/Kestrun/Languages/DelegateBuilder.cs

#LineLine coverage
 1using System.Security.Claims;
 2using System.Text;
 3using Kestrun.Languages;
 4using Kestrun.Logging;
 5using Kestrun.Models;
 6using Microsoft.CodeAnalysis;
 7using Serilog.Events;
 8using System.Reflection;
 9using Kestrun.Hosting;
 10
 11internal static class DelegateBuilder
 12{
 13    /// <summary>
 14    /// Prepares the Kestrun context, response, and script globals for execution.
 15    /// Encapsulates request parsing, shared state snapshot, arg injection, and logging.
 16    /// </summary>
 17    /// <param name="host">The Kestrun host instance.</param>
 18    /// <param name="ctx">The current HTTP context.</param>
 19    /// <param name="args">Optional variables to inject into the globals.</param>
 20    /// <returns>Tuple containing the prepared CsGlobals, KestrunResponse, and KestrunContext.</returns>
 21    internal static async Task<(CsGlobals Globals, KestrunResponse Response, KestrunContext Context)> PrepareExecutionAs
 22        KestrunHost host,
 23        HttpContext ctx,
 24        Dictionary<string, object?>? args)
 25    {
 1926        var log = host.Logger;
 1927        var krRequest = await KestrunRequest.NewRequest(ctx).ConfigureAwait(false);
 1928        var krResponse = new KestrunResponse(krRequest);
 1929        var Context = new KestrunContext(host, krRequest, krResponse, ctx);
 1930        if (log.IsEnabled(LogEventLevel.Debug))
 31        {
 532            log.DebugSanitized("Kestrun context created for {Path}", ctx.Request.Path);
 33        }
 34
 35        // Create a shared state dictionary that will be used to store global variables
 36        // This will be shared across all requests and can be used to store state
 37        // that needs to persist across multiple requests
 1938        if (log.IsEnabled(LogEventLevel.Debug))
 39        {
 540            log.Debug("Creating shared state store for Kestrun context");
 41        }
 42
 1943        var glob = new Dictionary<string, object?>(host.SharedState.Snapshot());
 1944        if (log.IsEnabled(LogEventLevel.Debug))
 45        {
 546            log.Debug("Shared state store created with {Count} items", glob.Count);
 47        }
 48
 49        // Inject the provided arguments into the globals so the script can access them
 1950        if (args != null && args.Count > 0)
 51        {
 152            if (log.IsEnabled(LogEventLevel.Debug))
 53            {
 054                log.Debug("Setting variables from arguments: {Count}", args.Count);
 55            }
 56
 457            foreach (var kv in args)
 58            {
 159                glob[kv.Key] = kv.Value; // add args to globals
 60            }
 61        }
 62
 63        // Create a new CsGlobals instance with the current context and shared state
 1964        var globals = new CsGlobals(glob, Context);
 1965        return (globals, krResponse, Context);
 1966    }
 67
 68
 69    /// <summary>
 70    /// Decides the VB return type string that matches TResult.
 71    /// </summary>
 72    /// <param name="ctx">The current HTTP context.</param>
 73    /// <param name="response">The Kestrun response to apply.</param>
 74    /// <param name="log">The logger to use for logging.</param>
 75    /// <returns>A task representing the asynchronous operation.</returns>
 76    internal static async Task ApplyResponseAsync(HttpContext ctx, KestrunResponse response, Serilog.ILogger log)
 77    {
 1478        if (log.IsEnabled(LogEventLevel.Debug))
 79        {
 580            log.DebugSanitized("Applying response to Kestrun context for {Path}", ctx.Request.Path);
 81        }
 82
 1483        if (!string.IsNullOrEmpty(response.RedirectUrl))
 84        {
 285            ctx.Response.Redirect(response.RedirectUrl);
 286            return;
 87        }
 88
 1289        await response.ApplyTo(ctx.Response).ConfigureAwait(false);
 90
 1291        if (log.IsEnabled(LogEventLevel.Debug))
 92        {
 493            log.DebugSanitized("Response applied to Kestrun context for {Path}", ctx.Request.Path);
 94        }
 1495    }
 96
 97    /// <summary>
 98    /// Common baseline references shared across script compilations.
 99    /// </summary>
 100    /// <returns> MetadataReference[] </returns>
 101    internal static MetadataReference[] BuildBaselineReferences()
 102    {
 103        // Collect unique assembly locations
 72104        var locations = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
 105
 106        void Add(Type t)
 107        {
 1080108            var loc = t.Assembly.Location;
 1080109            if (!string.IsNullOrWhiteSpace(loc))
 110            {
 1080111                _ = locations.Add(loc); // capture return to satisfy analyzer
 112            }
 1080113        }
 114
 115        // Seed core & always-required assemblies
 72116        Add(typeof(object));                                                              // System.Private.CoreLib
 72117        Add(typeof(Enumerable));                                                          // System.Linq
 72118        Add(typeof(HttpContext));                                                         // Microsoft.AspNetCore.Http
 72119        Add(typeof(Console));                                                             // System.Console
 72120        Add(typeof(StringBuilder));                                                       // System.Text
 72121        Add(typeof(Serilog.Log));                                                         // Serilog
 72122        Add(typeof(ClaimsPrincipal));                                                     // System.Security.Claims
 72123        Add(typeof(ClaimsIdentity));                                                      // System.Security.Claims
 72124        Add(typeof(System.Security.Cryptography.X509Certificates.X509Certificate2));      // X509 Certificates
 125
 126        // Snapshot loaded assemblies once
 72127        var loadedAssemblies = AppDomain.CurrentDomain
 72128            .GetAssemblies()
 21380129            .Where(a => !a.IsDynamic && !string.IsNullOrWhiteSpace(a.Location))
 72130            .ToArray();
 131
 132        // Attempt to bind each namespace in PlatformImports to a loaded assembly
 6336133        foreach (var ns in PlatformImports)
 134        {
 1551096135            foreach (var asm in loadedAssemblies)
 136            {
 772452137                if (locations.Contains(asm.Location))
 138                {
 139                    continue; // already referenced
 140                }
 455414141                if (NamespaceExistsInAssembly(asm, ns))
 142                {
 12418143                    _ = locations.Add(asm.Location); // capture return to satisfy analyzer
 144                }
 145            }
 146        }
 147
 148        // Explicitly ensure critical assemblies needed for dynamic auth / razor / encodings even if not yet scanned
 72149        Add(typeof(Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerDefaults));
 72150        Add(typeof(Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationDefaults));
 72151        Add(typeof(Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectDefaults));
 72152        Add(typeof(Microsoft.AspNetCore.Authentication.Negotiate.NegotiateDefaults));
 72153        Add(typeof(Microsoft.AspNetCore.Mvc.Razor.RazorPageBase));
 72154        Add(typeof(System.Text.Encodings.Web.HtmlEncoder));
 155
 72156        return [.. locations
 72157            .Distinct(StringComparer.OrdinalIgnoreCase)
 12994158            .Select(loc => MetadataReference.CreateFromFile(loc))];
 159    }
 160
 161    private static bool NamespaceExistsInAssembly(Assembly asm, string @namespace)
 162    {
 163        try
 164        {
 165            // Using DefinedTypes to avoid loading reflection-only contexts; guard against type load issues.
 104238978166            foreach (var t in asm.DefinedTypes)
 167            {
 51671273168                var ns = t.Namespace;
 51671273169                if (ns == null)
 170                {
 171                    continue;
 172                }
 49991951173                if (ns.Equals(@namespace, StringComparison.Ordinal) || ns.StartsWith(@namespace + ".", StringComparison.
 174                {
 12418175                    return true;
 176                }
 177            }
 441018178        }
 1978179        catch (ReflectionTypeLoadException)
 180        {
 181            // Ignore partially loadable assemblies; namespace absence treated as false.
 1978182        }
 442996183        return false;
 12418184    }
 185
 186    // Ordered & de-duplicated platform / framework imports used for dynamic script compilation.
 1187    internal static string[] PlatformImports = [
 1188        "Kestrun.Languages",
 1189        "Microsoft.AspNetCore.Authentication",
 1190        "Microsoft.AspNetCore.Authentication.Cookies",
 1191        "Microsoft.AspNetCore.Authentication.JwtBearer",
 1192        "Microsoft.AspNetCore.Authentication.Negotiate",
 1193        "Microsoft.AspNetCore.Authentication.OpenIdConnect",
 1194        "Microsoft.AspNetCore.Authorization",
 1195        "Microsoft.AspNetCore.Http",
 1196        "Microsoft.AspNetCore.Mvc",
 1197        "Microsoft.AspNetCore.Mvc.RazorPages",
 1198        // "Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation".
 1199        "Microsoft.AspNetCore.Server.Kestrel.Core",
 1200        "Microsoft.AspNetCore.SignalR",
 1201        "Microsoft.CodeAnalysis",
 1202        "Microsoft.CodeAnalysis.CSharp",
 1203        "Microsoft.CodeAnalysis.CSharp.Scripting",
 1204        "Microsoft.CodeAnalysis.Scripting",
 1205        "Microsoft.Extensions.FileProviders",
 1206        "Microsoft.Extensions.Logging",
 1207        "Microsoft.Extensions.Options",
 1208        "Microsoft.Extensions.Primitives",
 1209        "Microsoft.IdentityModel.Tokens",
 1210        "Microsoft.PowerShell",
 1211        "Microsoft.VisualBasic",
 1212        "Serilog",
 1213        "Serilog.Events",
 1214        "System",
 1215        "System.Collections",
 1216        "System.Collections.Generic",
 1217        "System.Collections.Immutable",
 1218        "System.IO",
 1219        "System.Linq",
 1220        "System.Management.Automation",
 1221        "System.Management.Automation.Runspaces",
 1222        "System.Net",
 1223        "System.Net.Http.Headers",
 1224        "System.Reflection",
 1225        "System.Runtime.InteropServices",
 1226        "System.Security.Claims",
 1227        "System.Security.Cryptography.X509Certificates",
 1228        "System.Text",
 1229        "System.Text.Encodings.Web",
 1230        "System.Text.RegularExpressions",
 1231        "System.Threading.Tasks"
 1232    ];
 233}