< 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@ca54e35c77799b76774b3805b6f075cdbc0c5fbe
Line coverage
99%
Covered lines: 113
Uncovered lines: 1
Coverable lines: 114
Total lines: 230
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/08/2025 - 20:34:03 Line coverage: 97.3% (112/115) Branch coverage: 97.5% (39/40) Total lines: 233 Tag: Kestrun/Kestrun@3790ee5884494a7a2a829344a47743e0bf492e7209/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@5e12b09a6838e68e704cd3dc975331b9e680a62601/02/2026 - 00:16:25 Line coverage: 99.1% (113/114) Branch coverage: 97.5% (39/40) Total lines: 230 Tag: Kestrun/Kestrun@8405dc23b786b9d436fba0d65fb80baa4171e1d0 09/08/2025 - 20:34:03 Line coverage: 97.3% (112/115) Branch coverage: 97.5% (39/40) Total lines: 233 Tag: Kestrun/Kestrun@3790ee5884494a7a2a829344a47743e0bf492e7209/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@5e12b09a6838e68e704cd3dc975331b9e680a62601/02/2026 - 00:16:25 Line coverage: 99.1% (113/114) Branch coverage: 97.5% (39/40) Total lines: 230 Tag: Kestrun/Kestrun@8405dc23b786b9d436fba0d65fb80baa4171e1d0

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
PrepareExecutionAsync()92.85%141494.11%
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 Context = new KestrunContext(host, ctx);
 1928        if (log.IsEnabled(LogEventLevel.Debug))
 29        {
 530            log.DebugSanitized("Kestrun context created for {Path}", ctx.Request.Path);
 31        }
 32
 33        // Create a shared state dictionary that will be used to store global variables
 34        // This will be shared across all requests and can be used to store state
 35        // that needs to persist across multiple requests
 1936        if (log.IsEnabled(LogEventLevel.Debug))
 37        {
 538            log.Debug("Creating shared state store for Kestrun context");
 39        }
 40
 1941        var glob = new Dictionary<string, object?>(host.SharedState.Snapshot());
 1942        if (log.IsEnabled(LogEventLevel.Debug))
 43        {
 544            log.Debug("Shared state store created with {Count} items", glob.Count);
 45        }
 46
 47        // Inject the provided arguments into the globals so the script can access them
 1948        if (args != null && args.Count > 0)
 49        {
 150            if (log.IsEnabled(LogEventLevel.Debug))
 51            {
 052                log.Debug("Setting variables from arguments: {Count}", args.Count);
 53            }
 54
 455            foreach (var kv in args)
 56            {
 157                glob[kv.Key] = kv.Value; // add args to globals
 58            }
 59        }
 60
 61        // Create a new CsGlobals instance with the current context and shared state
 1962        var globals = new CsGlobals(glob, Context);
 1963        return (globals, Context.Response, Context);
 1964    }
 65
 66    /// <summary>
 67    /// Decides the VB return type string that matches TResult.
 68    /// </summary>
 69    /// <param name="ctx">The current HTTP context.</param>
 70    /// <param name="response">The Kestrun response to apply.</param>
 71    /// <param name="log">The logger to use for logging.</param>
 72    /// <returns>A task representing the asynchronous operation.</returns>
 73    internal static async Task ApplyResponseAsync(HttpContext ctx, KestrunResponse response, Serilog.ILogger log)
 74    {
 1475        if (log.IsEnabled(LogEventLevel.Debug))
 76        {
 577            log.DebugSanitized("Applying response to Kestrun context for {Path}", ctx.Request.Path);
 78        }
 79
 1480        if (!string.IsNullOrEmpty(response.RedirectUrl))
 81        {
 282            ctx.Response.Redirect(response.RedirectUrl);
 283            return;
 84        }
 85
 1286        await response.ApplyTo(ctx.Response).ConfigureAwait(false);
 87
 1288        if (log.IsEnabled(LogEventLevel.Debug))
 89        {
 490            log.DebugSanitized("Response applied to Kestrun context for {Path}", ctx.Request.Path);
 91        }
 1492    }
 93
 94    /// <summary>
 95    /// Common baseline references shared across script compilations.
 96    /// </summary>
 97    /// <returns> MetadataReference[] </returns>
 98    internal static MetadataReference[] BuildBaselineReferences()
 99    {
 100        // Collect unique assembly locations
 76101        var locations = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
 102
 103        void Add(Type t)
 104        {
 1140105            var loc = t.Assembly.Location;
 1140106            if (!string.IsNullOrWhiteSpace(loc))
 107            {
 1140108                _ = locations.Add(loc); // capture return to satisfy analyzer
 109            }
 1140110        }
 111
 112        // Seed core & always-required assemblies
 76113        Add(typeof(object));                                                              // System.Private.CoreLib
 76114        Add(typeof(Enumerable));                                                          // System.Linq
 76115        Add(typeof(HttpContext));                                                         // Microsoft.AspNetCore.Http
 76116        Add(typeof(Console));                                                             // System.Console
 76117        Add(typeof(StringBuilder));                                                       // System.Text
 76118        Add(typeof(Serilog.Log));                                                         // Serilog
 76119        Add(typeof(ClaimsPrincipal));                                                     // System.Security.Claims
 76120        Add(typeof(ClaimsIdentity));                                                      // System.Security.Claims
 76121        Add(typeof(System.Security.Cryptography.X509Certificates.X509Certificate2));      // X509 Certificates
 122
 123        // Snapshot loaded assemblies once
 76124        var loadedAssemblies = AppDomain.CurrentDomain
 76125            .GetAssemblies()
 23289126            .Where(a => !a.IsDynamic && !string.IsNullOrWhiteSpace(a.Location))
 76127            .ToArray();
 128
 129        // Attempt to bind each namespace in PlatformImports to a loaded assembly
 6688130        foreach (var ns in PlatformImports)
 131        {
 1697210132            foreach (var asm in loadedAssemblies)
 133            {
 845337134                if (locations.Contains(asm.Location))
 135                {
 136                    continue; // already referenced
 137                }
 504008138                if (NamespaceExistsInAssembly(asm, ns))
 139                {
 13457140                    _ = locations.Add(asm.Location); // capture return to satisfy analyzer
 141                }
 142            }
 143        }
 144
 145        // Explicitly ensure critical assemblies needed for dynamic auth / razor / encodings even if not yet scanned
 76146        Add(typeof(Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerDefaults));
 76147        Add(typeof(Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationDefaults));
 76148        Add(typeof(Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectDefaults));
 76149        Add(typeof(Microsoft.AspNetCore.Authentication.Negotiate.NegotiateDefaults));
 76150        Add(typeof(Microsoft.AspNetCore.Mvc.Razor.RazorPageBase));
 76151        Add(typeof(System.Text.Encodings.Web.HtmlEncoder));
 152
 76153        return [.. locations
 76154            .Distinct(StringComparer.OrdinalIgnoreCase)
 14065155            .Select(loc => MetadataReference.CreateFromFile(loc))];
 156    }
 157
 158    private static bool NamespaceExistsInAssembly(Assembly asm, string @namespace)
 159    {
 160        try
 161        {
 162            // Using DefinedTypes to avoid loading reflection-only contexts; guard against type load issues.
 120119344163            foreach (var t in asm.DefinedTypes)
 164            {
 59563962165                var ns = t.Namespace;
 59563962166                if (ns == null)
 167                {
 168                    continue;
 169                }
 57663262170                if (ns.Equals(@namespace, StringComparison.Ordinal) || ns.StartsWith(@namespace + ".", StringComparison.
 171                {
 13457172                    return true;
 173                }
 174            }
 487412175        }
 3139176        catch (ReflectionTypeLoadException)
 177        {
 178            // Ignore partially loadable assemblies; namespace absence treated as false.
 3139179        }
 490551180        return false;
 13457181    }
 182
 183    // Ordered & de-duplicated platform / framework imports used for dynamic script compilation.
 1184    internal static string[] PlatformImports = [
 1185        "Kestrun.Languages",
 1186        "Microsoft.AspNetCore.Authentication",
 1187        "Microsoft.AspNetCore.Authentication.Cookies",
 1188        "Microsoft.AspNetCore.Authentication.JwtBearer",
 1189        "Microsoft.AspNetCore.Authentication.Negotiate",
 1190        "Microsoft.AspNetCore.Authentication.OpenIdConnect",
 1191        "Microsoft.AspNetCore.Authorization",
 1192        "Microsoft.AspNetCore.Http",
 1193        "Microsoft.AspNetCore.Mvc",
 1194        "Microsoft.AspNetCore.Mvc.RazorPages",
 1195        // "Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation".
 1196        "Microsoft.AspNetCore.Server.Kestrel.Core",
 1197        "Microsoft.AspNetCore.SignalR",
 1198        "Microsoft.CodeAnalysis",
 1199        "Microsoft.CodeAnalysis.CSharp",
 1200        "Microsoft.CodeAnalysis.CSharp.Scripting",
 1201        "Microsoft.CodeAnalysis.Scripting",
 1202        "Microsoft.Extensions.FileProviders",
 1203        "Microsoft.Extensions.Logging",
 1204        "Microsoft.Extensions.Options",
 1205        "Microsoft.Extensions.Primitives",
 1206        "Microsoft.IdentityModel.Tokens",
 1207        "Microsoft.PowerShell",
 1208        "Microsoft.VisualBasic",
 1209        "Serilog",
 1210        "Serilog.Events",
 1211        "System",
 1212        "System.Collections",
 1213        "System.Collections.Generic",
 1214        "System.Collections.Immutable",
 1215        "System.IO",
 1216        "System.Linq",
 1217        "System.Management.Automation",
 1218        "System.Management.Automation.Runspaces",
 1219        "System.Net",
 1220        "System.Net.Http.Headers",
 1221        "System.Reflection",
 1222        "System.Runtime.InteropServices",
 1223        "System.Security.Claims",
 1224        "System.Security.Cryptography.X509Certificates",
 1225        "System.Text",
 1226        "System.Text.Encodings.Web",
 1227        "System.Text.RegularExpressions",
 1228        "System.Threading.Tasks"
 1229    ];
 230}