< 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@5f1d2b981c9d7292c11fd448428c6ab6c811c5de
Line coverage
97%
Covered lines: 111
Uncovered lines: 3
Coverable lines: 114
Total lines: 230
Line coverage: 97.3%
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 11/19/2025 - 17:40:50 Line coverage: 99.1% (115/116) Branch coverage: 97.5% (39/40) Total lines: 233 Tag: Kestrun/Kestrun@fcf33342333cef0516fe0d0912a86709874fd02601/02/2026 - 00:16:25 Line coverage: 99.1% (113/114) Branch coverage: 97.5% (39/40) Total lines: 230 Tag: Kestrun/Kestrun@8405dc23b786b9d436fba0d65fb80baa4171e1d003/26/2026 - 03:54:59 Line coverage: 97.3% (111/114) Branch coverage: 97.5% (39/40) Total lines: 230 Tag: Kestrun/Kestrun@844b5179fb0492dc6b1182bae3ff65fa7365521d 11/19/2025 - 17:40:50 Line coverage: 99.1% (115/116) Branch coverage: 97.5% (39/40) Total lines: 233 Tag: Kestrun/Kestrun@fcf33342333cef0516fe0d0912a86709874fd02601/02/2026 - 00:16:25 Line coverage: 99.1% (113/114) Branch coverage: 97.5% (39/40) Total lines: 230 Tag: Kestrun/Kestrun@8405dc23b786b9d436fba0d65fb80baa4171e1d003/26/2026 - 03:54:59 Line coverage: 97.3% (111/114) Branch coverage: 97.5% (39/40) Total lines: 230 Tag: Kestrun/Kestrun@844b5179fb0492dc6b1182bae3ff65fa7365521d

Coverage delta

Coverage delta 2 -2

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
PrepareExecutionAsync()92.86%141494.12%
ApplyResponseAsync()100%66100%
BuildBaselineReferences()100%1010100%
Add()100%22100%
NamespaceExistsInAssembly(...)100%9880%
.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        {
 230            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        {
 238            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        {
 244            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        {
 277            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        {
 290            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
 80101        var locations = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
 102
 103        void Add(Type t)
 104        {
 1200105            var loc = t.Assembly.Location;
 1200106            if (!string.IsNullOrWhiteSpace(loc))
 107            {
 1200108                _ = locations.Add(loc); // capture return to satisfy analyzer
 109            }
 1200110        }
 111
 112        // Seed core & always-required assemblies
 80113        Add(typeof(object));                                                              // System.Private.CoreLib
 80114        Add(typeof(Enumerable));                                                          // System.Linq
 80115        Add(typeof(HttpContext));                                                         // Microsoft.AspNetCore.Http
 80116        Add(typeof(Console));                                                             // System.Console
 80117        Add(typeof(StringBuilder));                                                       // System.Text
 80118        Add(typeof(Serilog.Log));                                                         // Serilog
 80119        Add(typeof(ClaimsPrincipal));                                                     // System.Security.Claims
 80120        Add(typeof(ClaimsIdentity));                                                      // System.Security.Claims
 80121        Add(typeof(System.Security.Cryptography.X509Certificates.X509Certificate2));      // X509 Certificates
 122
 123        // Snapshot loaded assemblies once
 80124        var loadedAssemblies = AppDomain.CurrentDomain
 80125            .GetAssemblies()
 27629126            .Where(a => !a.IsDynamic && !string.IsNullOrWhiteSpace(a.Location))
 80127            .ToArray();
 128
 129        // Attempt to bind each namespace in PlatformImports to a loaded assembly
 7040130        foreach (var ns in PlatformImports)
 131        {
 2044306132            foreach (var asm in loadedAssemblies)
 133            {
 1018713134                if (locations.Contains(asm.Location))
 135                {
 136                    continue; // already referenced
 137                }
 594369138                if (NamespaceExistsInAssembly(asm, ns))
 139                {
 16616140                    _ = 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
 80146        Add(typeof(Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerDefaults));
 80147        Add(typeof(Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationDefaults));
 80148        Add(typeof(Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectDefaults));
 80149        Add(typeof(Microsoft.AspNetCore.Authentication.Negotiate.NegotiateDefaults));
 80150        Add(typeof(Microsoft.AspNetCore.Mvc.Razor.RazorPageBase));
 80151        Add(typeof(System.Text.Encodings.Web.HtmlEncoder));
 152
 80153        return [.. locations
 80154            .Distinct(StringComparer.OrdinalIgnoreCase)
 17256155            .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.
 129460072163            foreach (var t in asm.DefinedTypes)
 164            {
 64143975165                var ns = t.Namespace;
 64143975166                if (ns == null)
 167                {
 168                    continue;
 169                }
 61327444170                if (ns.Equals(@namespace, StringComparison.Ordinal) || ns.StartsWith(@namespace + ".", StringComparison.
 171                {
 16616172                    return true;
 173                }
 174            }
 577753175        }
 0176        catch (ReflectionTypeLoadException)
 177        {
 178            // Ignore partially loadable assemblies; namespace absence treated as false.
 0179        }
 577753180        return false;
 16616181    }
 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}