< Summary

Information
Class: NexusLabs.Needlr.VerificationResult
Assembly: NexusLabs.Needlr
File(s): /home/runner/work/needlr/needlr/src/NexusLabs.Needlr/ServiceCollectionVerificationExtensions.cs
Line coverage
75%
Covered lines: 12
Uncovered lines: 4
Coverable lines: 16
Total lines: 170
Line coverage: 75%
Branch coverage
62%
Covered branches: 5
Total branches: 8
Branch coverage: 62.5%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
get_Issues()100%11100%
get_IsValid()100%11100%
ThrowIfInvalid()0%620%
ToDetailedReport()83.33%6690.9%

File(s)

/home/runner/work/needlr/needlr/src/NexusLabs.Needlr/ServiceCollectionVerificationExtensions.cs

#LineLine coverage
 1using Microsoft.Extensions.DependencyInjection;
 2
 3namespace NexusLabs.Needlr;
 4
 5/// <summary>
 6/// Extension methods for verifying service collection configuration.
 7/// </summary>
 8public static class ServiceCollectionVerificationExtensions
 9{
 10    /// <summary>
 11    /// Verifies the service collection configuration and throws if issues are configured to throw.
 12    /// </summary>
 13    /// <param name="services">The service collection to verify.</param>
 14    /// <param name="options">The verification options. Defaults to <see cref="VerificationOptions.Default"/>.</param>
 15    /// <returns>The same service collection for chaining.</returns>
 16    /// <exception cref="ContainerVerificationException">
 17    /// Thrown if verification issues are detected and the configured behavior is <see cref="VerificationBehavior.Throw"
 18    /// </exception>
 19    public static IServiceCollection Verify(
 20        this IServiceCollection services,
 21        VerificationOptions? options = null)
 22    {
 23        ArgumentNullException.ThrowIfNull(services);
 24        options ??= VerificationOptions.Default;
 25
 26        var issues = new List<VerificationIssue>();
 27
 28        // Check for lifetime mismatches
 29        if (options.LifetimeMismatchBehavior != VerificationBehavior.Silent)
 30        {
 31            var mismatches = services.DetectLifetimeMismatches();
 32            foreach (var mismatch in mismatches)
 33            {
 34                issues.Add(new VerificationIssue(
 35                    Type: VerificationIssueType.LifetimeMismatch,
 36                    Message: $"Lifetime mismatch: {mismatch.ConsumerServiceType.Name} ({mismatch.ConsumerLifetime}) depe
 37                    DetailedMessage: mismatch.ToDetailedString(),
 38                    ConfiguredBehavior: options.LifetimeMismatchBehavior)
 39                {
 40                    InvolvedTypes = [mismatch.ConsumerServiceType, mismatch.DependencyServiceType]
 41                });
 42            }
 43        }
 44
 45        // Process issues based on configured behavior
 46        ProcessVerificationIssues(issues, options);
 47
 48        return services;
 49    }
 50
 51    /// <summary>
 52    /// Verifies the service collection and returns detailed diagnostic results.
 53    /// </summary>
 54    /// <param name="services">The service collection to verify.</param>
 55    /// <param name="options">The verification options. Defaults to <see cref="VerificationOptions.Default"/>.</param>
 56    /// <returns>A <see cref="VerificationResult"/> containing all detected issues.</returns>
 57    public static VerificationResult VerifyWithDiagnostics(
 58        this IServiceCollection services,
 59        VerificationOptions? options = null)
 60    {
 61        ArgumentNullException.ThrowIfNull(services);
 62        options ??= VerificationOptions.Default;
 63
 64        var issues = new List<VerificationIssue>();
 65
 66        // Check for lifetime mismatches
 67        if (options.LifetimeMismatchBehavior != VerificationBehavior.Silent)
 68        {
 69            var mismatches = services.DetectLifetimeMismatches();
 70            foreach (var mismatch in mismatches)
 71            {
 72                issues.Add(new VerificationIssue(
 73                    Type: VerificationIssueType.LifetimeMismatch,
 74                    Message: $"Lifetime mismatch: {mismatch.ConsumerServiceType.Name} ({mismatch.ConsumerLifetime}) depe
 75                    DetailedMessage: mismatch.ToDetailedString(),
 76                    ConfiguredBehavior: options.LifetimeMismatchBehavior)
 77                {
 78                    InvolvedTypes = [mismatch.ConsumerServiceType, mismatch.DependencyServiceType]
 79                });
 80            }
 81        }
 82
 83        return new VerificationResult(issues);
 84    }
 85
 86    private static void ProcessVerificationIssues(List<VerificationIssue> issues, VerificationOptions options)
 87    {
 88        var issuesByBehavior = issues.GroupBy(i => i.ConfiguredBehavior);
 89
 90        foreach (var group in issuesByBehavior)
 91        {
 92            switch (group.Key)
 93            {
 94                case VerificationBehavior.Warn:
 95                    foreach (var issue in group)
 96                    {
 97                        if (options.IssueReporter is not null)
 98                        {
 99                            options.IssueReporter(issue);
 100                        }
 101                        else
 102                        {
 103                            Console.Error.WriteLine($"[Needlr Warning] {issue.Message}");
 104                            Console.Error.WriteLine(issue.DetailedMessage);
 105                            Console.Error.WriteLine();
 106                        }
 107                    }
 108                    break;
 109
 110                case VerificationBehavior.Throw:
 111                    var throwableIssues = group.ToList();
 112                    if (throwableIssues.Count > 0)
 113                    {
 114                        throw new ContainerVerificationException(throwableIssues);
 115                    }
 116                    break;
 117            }
 118        }
 119    }
 120}
 121
 122/// <summary>
 123/// Result of container verification containing all detected issues.
 124/// </summary>
 125/// <param name="Issues">The list of verification issues detected.</param>
 7126public sealed record VerificationResult(IReadOnlyList<VerificationIssue> Issues)
 127{
 128    /// <summary>
 129    /// Gets whether the container configuration is valid (no errors).
 130    /// </summary>
 2131    public bool IsValid => !Issues.Any(i => i.ConfiguredBehavior == VerificationBehavior.Throw);
 132
 133    /// <summary>
 134    /// Throws <see cref="ContainerVerificationException"/> if any issues are present.
 135    /// </summary>
 136    public void ThrowIfInvalid()
 137    {
 0138        if (Issues.Count > 0)
 139        {
 0140            throw new ContainerVerificationException(Issues.ToList());
 141        }
 0142    }
 143
 144    /// <summary>
 145    /// Generates a detailed diagnostic report of all issues.
 146    /// </summary>
 147    public string ToDetailedReport()
 148    {
 1149        if (Issues.Count == 0)
 150        {
 0151            return "✅ Container verification passed. No issues detected.";
 152        }
 153
 1154        var sb = new System.Text.StringBuilder();
 1155        sb.AppendLine($"❌ Container verification found {Issues.Count} issue(s):");
 1156        sb.AppendLine();
 157
 4158        foreach (var issue in Issues)
 159        {
 1160            sb.AppendLine($"[{issue.Type}] {issue.Message}");
 1161            if (!string.IsNullOrWhiteSpace(issue.DetailedMessage))
 162            {
 1163                sb.AppendLine(issue.DetailedMessage);
 164            }
 1165            sb.AppendLine();
 166        }
 167
 1168        return sb.ToString();
 169    }
 170}