< Summary

Information
Class: NexusLabs.Needlr.Injection.ServiceCollectionPopulator
Assembly: NexusLabs.Needlr.Injection
File(s): /home/runner/work/needlr/needlr/src/NexusLabs.Needlr.Injection/ServiceCollectionPopulator.cs
Line coverage
95%
Covered lines: 44
Uncovered lines: 2
Coverable lines: 46
Total lines: 110
Line coverage: 95.6%
Branch coverage
100%
Covered branches: 6
Total branches: 6
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
RegisterToServiceCollection(...)100%66100%
.ctor(...)100%11100%
.ctor(...)100%11100%
get_Item(...)100%210%
get_Count()100%210%
GetEnumerator()100%11100%
System.Collections.IEnumerable.GetEnumerator()100%11100%

File(s)

/home/runner/work/needlr/needlr/src/NexusLabs.Needlr.Injection/ServiceCollectionPopulator.cs

#LineLine coverage
 1using Microsoft.Extensions.Configuration;
 2using Microsoft.Extensions.DependencyInjection;
 3
 4using System.Diagnostics.CodeAnalysis;
 5using System.Reflection;
 6
 7namespace NexusLabs.Needlr.Injection;
 8
 9/// <summary>
 10/// Default implementation of <see cref="IServiceCollectionPopulator"/> that registers discovered types into a service c
 11/// Handles type registration, plugin execution, and built-in service factory registration.
 12/// </summary>
 13[DoNotAutoRegister]
 14public sealed class ServiceCollectionPopulator : IServiceCollectionPopulator
 15{
 16    private readonly ITypeRegistrar _typeRegistrar;
 17    private readonly ITypeFilterer _typeFilterer;
 18    private readonly IPluginFactory _pluginFactory;
 19
 20    /// <summary>
 21    /// Initializes a new instance of the <see cref="ServiceCollectionPopulator"/> class.
 22    /// </summary>
 23    /// <param name="typeRegistrar">The type registrar to use for service registration.</param>
 24    /// <param name="typeFilterer">The type filterer to determine service lifetimes.</param>
 25    /// <param name="pluginFactory">The plugin factory to use for plugin discovery and instantiation.</param>
 80026    public ServiceCollectionPopulator(
 80027        ITypeRegistrar typeRegistrar,
 80028        ITypeFilterer typeFilterer,
 80029        IPluginFactory pluginFactory)
 30    {
 80031        ArgumentNullException.ThrowIfNull(typeRegistrar);
 80032        ArgumentNullException.ThrowIfNull(typeFilterer);
 80033        ArgumentNullException.ThrowIfNull(pluginFactory);
 34
 80035        _typeRegistrar = typeRegistrar;
 80036        _typeFilterer = typeFilterer;
 80037        _pluginFactory = pluginFactory;
 80038    }
 39
 40    /// <inheritdoc />
 41    public IServiceCollection RegisterToServiceCollection(
 42        IServiceCollection services,
 43        IConfiguration config,
 44        IReadOnlyList<Assembly> candidateAssemblies)
 45    {
 80046        ArgumentNullException.ThrowIfNull(services);
 80047        ArgumentNullException.ThrowIfNull(config);
 80048        ArgumentNullException.ThrowIfNull(candidateAssemblies);
 49
 80050        services.AddSingleton(services);
 80051        services.AddSingleton(provider => provider);
 80052        services.AddSingleton(typeof(Lazy<>), typeof(LazyFactory<>));
 80053        services.AddSingleton(typeof(IReadOnlyList<>), typeof(ReadOnlyListFactory<>));
 80054        services.AddSingleton(typeof(IReadOnlyCollection<>), typeof(ReadOnlyListFactory<>));
 80055        services.AddSingleton(_pluginFactory);
 56
 580057        foreach (var assembly in candidateAssemblies)
 58        {
 210059            services.AddSingleton(assembly);
 60        }
 61
 80062        _typeRegistrar.RegisterTypesFromAssemblies(
 80063            services,
 80064            _typeFilterer,
 80065            candidateAssemblies);
 66
 80067        ServiceCollectionPluginOptions options = new(
 80068            services,
 80069            config,
 80070            candidateAssemblies,
 80071            _pluginFactory);
 72
 80073        var executedPluginTypes = new HashSet<Type>();
 949874        foreach (var serviceCollectionPlugin in _pluginFactory.CreatePluginsFromAssemblies<IServiceCollectionPlugin>(can
 75        {
 394976            var pluginType = serviceCollectionPlugin.GetType();
 394977            if (!executedPluginTypes.Add(pluginType))
 78            {
 79                // Skip duplicate plugin instances of the same type
 80                continue;
 81            }
 82
 394983            serviceCollectionPlugin.Configure(options);
 84        }
 85
 80086        return services;
 87    }
 88
 89    private sealed class LazyFactory<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConst
 2090        Lazy<T>(() => provider.GetRequiredService<T>())
 91        where T : notnull
 92    {
 93    }
 94
 3495    private sealed class ReadOnlyListFactory<T>(IServiceProvider provider) : IReadOnlyList<T>
 96        where T : notnull
 97    {
 6898        private readonly Lazy<IReadOnlyList<T>> _lazyItems = new(() => provider
 6899            .GetServices<T>()
 68100            .ToArray());
 101
 0102        public T this[int index] => _lazyItems.Value[index];
 103
 0104        public int Count => _lazyItems.Value.Count;
 105
 43106        public IEnumerator<T> GetEnumerator() => _lazyItems.Value.GetEnumerator();
 107
 4108        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => GetEnumerator();
 109    }
 110}