< Summary

Information
Class: TeleFlow.Telegram.Internal.Handlers.TelegramHandlerRegistrationValidator
Assembly: TeleFlow.Framework
File(s): /_/src/TeleFlow.Framework/Internal/Handlers/TelegramHandlerRegistrationValidator.cs
Line coverage
94%
Covered lines: 65
Uncovered lines: 4
Coverable lines: 69
Total lines: 139
Line coverage: 94.2%
Branch coverage
88%
Covered branches: 23
Total branches: 26
Branch coverage: 88.4%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
EnsureAssemblyCanRegister(...)100%22100%
EnsureHandlerTypesCanRegister(...)83.33%6689.47%
EnsureNoDuplicateCommands(...)100%22100%
CreateDuplicateKeys()91.66%121291.66%
FormatMode(...)75%4485.71%

File(s)

/_/src/TeleFlow.Framework/Internal/Handlers/TelegramHandlerRegistrationValidator.cs

#LineLine coverage
 1using System.Reflection;
 2using Microsoft.Extensions.DependencyInjection;
 3using TeleFlow.Annotations;
 4
 5namespace TeleFlow.Telegram.Internal.Handlers;
 6
 7internal static class TelegramHandlerRegistrationValidator
 8{
 9    public static void EnsureAssemblyCanRegister(
 10        IServiceCollection services,
 11        Assembly assembly,
 12        TelegramHandlerRegistrationMode requestedMode)
 13    {
 5414        ArgumentNullException.ThrowIfNull(services);
 5415        ArgumentNullException.ThrowIfNull(assembly);
 16
 5417        var existing = services
 142618            .Where(static descriptor => descriptor.ServiceType == typeof(TelegramHandlerAssemblyRegistrationMarker))
 219            .Select(static descriptor => descriptor.ImplementationInstance)
 5420            .OfType<TelegramHandlerAssemblyRegistrationMarker>()
 5621            .FirstOrDefault(marker => marker.Assembly == assembly);
 22
 5423        if (existing is null)
 24        {
 5225            return;
 26        }
 27
 228        throw new InvalidOperationException(
 229            $"Telegram handler assembly '{assembly.FullName}' is already registered through {FormatMode(existing.Mode)} 
 30    }
 31
 32    public static void EnsureHandlerTypesCanRegister(
 33        IServiceCollection services,
 34        IReadOnlyList<Type> handlerTypes,
 35        TelegramHandlerRegistrationMode requestedMode)
 36    {
 38137        ArgumentNullException.ThrowIfNull(services);
 38138        ArgumentNullException.ThrowIfNull(handlerTypes);
 39
 38140        var duplicateInRequest = handlerTypes
 129041            .GroupBy(static type => type)
 167142            .FirstOrDefault(static group => group.Count() > 1);
 43
 38144        if (duplicateInRequest is not null)
 45        {
 046            throw new InvalidOperationException(
 047                $"Telegram handler type '{duplicateInRequest.Key.FullName}' is listed more than once for {FormatMode(req
 48        }
 49
 38150        var existingMarkers = services
 1111951            .Where(static descriptor => descriptor.ServiceType == typeof(TelegramHandlerTypeRegistrationMarker))
 23152            .Select(static descriptor => descriptor.ImplementationInstance)
 38153            .OfType<TelegramHandlerTypeRegistrationMarker>()
 38154            .ToArray();
 55
 334056        foreach (var handlerType in handlerTypes)
 57        {
 152158            var existing = existingMarkers.FirstOrDefault(marker => marker.HandlerType == handlerType);
 59
 129060            if (existing is null)
 61            {
 62                continue;
 63            }
 64
 265            throw new InvalidOperationException(
 266                $"Telegram handler type '{handlerType.FullName}' is already registered through {FormatMode(existing.Mode
 67        }
 37968    }
 69
 70    public static void EnsureNoDuplicateCommands(
 71        IServiceCollection services,
 72        IReadOnlyList<TelegramHandlerDescriptor> newDescriptors)
 73    {
 35474        ArgumentNullException.ThrowIfNull(services);
 35475        ArgumentNullException.ThrowIfNull(newDescriptors);
 76
 35477        var existingCommandHandlers = services
 1043478            .Where(static descriptor => descriptor.ServiceType == typeof(TelegramHandlerDescriptor))
 22679            .Select(static descriptor => descriptor.ImplementationInstance)
 35480            .OfType<TelegramHandlerDescriptor>()
 22681            .Where(static descriptor => descriptor.Route.RouteKind == TelegramRouteKind.CommandExact)
 35482            .ToArray();
 83
 35484        var allCommandHandlers = existingCommandHandlers
 115185            .Concat(newDescriptors.Where(static descriptor => descriptor.Route.RouteKind == TelegramRouteKind.CommandExa
 35486            .SelectMany(CreateDuplicateKeys)
 35487            .ToArray();
 88
 35489        var duplicate = allCommandHandlers
 39190            .GroupBy(static item => item.Key, StringComparer.Ordinal)
 74391            .FirstOrDefault(static group => group.Count() > 1);
 92
 35493        if (duplicate is not null)
 94        {
 295            var display = duplicate.First().Display;
 96
 297            throw new InvalidOperationException(
 298                $"Duplicate Telegram command handler registration for command '{display}'.");
 99        }
 352100    }
 101
 102    private static IEnumerable<DuplicateCommandCandidate> CreateDuplicateKeys(TelegramHandlerDescriptor descriptor)
 103    {
 334104        if (string.IsNullOrWhiteSpace(descriptor.Command))
 105        {
 0106            yield break;
 107        }
 108
 334109        if (descriptor.Route.CommandPolicy.PrefixMode is CommandPrefixMode.Required or CommandPrefixMode.Optional)
 110        {
 1386111            foreach (var prefix in descriptor.Route.CommandPolicy.Prefixes)
 112            {
 361113                yield return new DuplicateCommandCandidate(
 361114                    $"{prefix.ToUpperInvariant()}\u001F{descriptor.Route.CommandPolicy.AllowSpaceAfterPrefix}\u001FPREFI
 361115                    $"{prefix}{descriptor.Command}");
 116            }
 117        }
 118
 334119        if (descriptor.Route.CommandPolicy.PrefixMode is CommandPrefixMode.Optional or CommandPrefixMode.NoPrefix)
 120        {
 30121            yield return new DuplicateCommandCandidate(
 30122                $"NO_PREFIX\u001F{descriptor.Command.ToUpperInvariant()}",
 30123                descriptor.Command);
 124        }
 334125    }
 126
 127    private static string FormatMode(TelegramHandlerRegistrationMode mode)
 128    {
 8129        return mode switch
 8130        {
 2131            TelegramHandlerRegistrationMode.Direct => "direct",
 2132            TelegramHandlerRegistrationMode.Generated => "generated",
 4133            TelegramHandlerRegistrationMode.Reflection => "reflection",
 0134            _ => mode.ToString()
 8135        };
 136    }
 137
 138    private sealed record DuplicateCommandCandidate(string Key, string Display);
 139}