< Summary

Information
Class: TeleFlow.Generators.TelegramChatTypeFacts
Assembly: TeleFlow.Generators
File(s): /_/src/TeleFlow.Generators/TelegramHandlerMetadataFacts.cs
Line coverage
81%
Covered lines: 9
Uncovered lines: 2
Coverable lines: 11
Total lines: 319
Line coverage: 81.8%
Branch coverage
71%
Covered branches: 5
Total branches: 7
Branch coverage: 71.4%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
IsKnown(...)50%22100%
TryMapToTelegramValue(...)80%5580%

File(s)

/_/src/TeleFlow.Generators/TelegramHandlerMetadataFacts.cs

#LineLine coverage
 1using System.Text;
 2using Microsoft.CodeAnalysis;
 3
 4namespace TeleFlow.Generators;
 5
 6internal enum TelegramHandlerMetadataRouteKind
 7{
 8    Command,
 9    Message,
 10    Callback,
 11    ChatMember
 12}
 13
 14internal enum TelegramBuiltInFilterTarget
 15{
 16    Message,
 17    Callback,
 18    Chat,
 19    MessageThread,
 20    SenderUser,
 21    SenderChat
 22}
 23
 24internal sealed record TelegramBuiltInFilterSpec(
 25    string AttributeMetadataName,
 26    string GeneratedKind,
 27    TelegramBuiltInFilterTarget Target,
 28    bool IsMarker);
 29
 30internal static class TelegramChatTypeFacts
 31{
 32    public static bool IsKnown(int value)
 33    {
 534        return value is >= 0 and <= 3;
 35    }
 36
 37    public static bool TryMapToTelegramValue(int value, out string telegramValue)
 38    {
 39        switch (value)
 40        {
 41            case 0:
 342                telegramValue = "private";
 343                return true;
 44            case 1:
 145                telegramValue = "group";
 146                return true;
 47            case 2:
 148                telegramValue = "supergroup";
 149                return true;
 50            case 3:
 251                telegramValue = "channel";
 252                return true;
 53            default:
 054                telegramValue = string.Empty;
 055                return false;
 56        }
 57    }
 58}
 59
 60internal static class TelegramMemberStatusFacts
 61{
 62    public const int Creator = 1 << 0;
 63    public const int Administrator = 1 << 1;
 64    public const int Member = 1 << 2;
 65    public const int RestrictedMember = 1 << 3;
 66    public const int RestrictedNotMember = 1 << 4;
 67    public const int Left = 1 << 5;
 68    public const int Banned = 1 << 6;
 69    public const int IsAdmin = Creator | Administrator;
 70    public const int IsMember = Creator | Administrator | Member | RestrictedMember;
 71    public const int IsNotMember = Left | Banned | RestrictedNotMember;
 72    public const int Any =
 73        Creator |
 74        Administrator |
 75        Member |
 76        RestrictedMember |
 77        RestrictedNotMember |
 78        Left |
 79        Banned;
 80
 81    private const int PromotedOldStatus =
 82        Member |
 83        RestrictedMember |
 84        RestrictedNotMember |
 85        Left |
 86        Banned;
 87
 88    public static bool IsValid(int value)
 89    {
 90        return value != 0 && (value & ~Any) == 0;
 91    }
 92
 93    public static bool TryMapTransition(
 94        int transition,
 95        out int oldStatus,
 96        out int newStatus)
 97    {
 98        switch (transition)
 99        {
 100            case 0:
 101                oldStatus = IsNotMember;
 102                newStatus = IsMember;
 103                return true;
 104            case 1:
 105                oldStatus = IsMember;
 106                newStatus = IsNotMember;
 107                return true;
 108            case 2:
 109                oldStatus = PromotedOldStatus;
 110                newStatus = IsAdmin;
 111                return true;
 112            case 3:
 113                oldStatus = IsAdmin;
 114                newStatus = PromotedOldStatus;
 115                return true;
 116            default:
 117                oldStatus = 0;
 118                newStatus = 0;
 119                return false;
 120        }
 121    }
 122
 123    public static bool TryGetRoleRequirementMask(
 124        AttributeData attribute,
 125        out int allowedStatuses)
 126    {
 127        allowedStatuses = 0;
 128
 129        if (attribute.ConstructorArguments.Length == 0)
 130        {
 131            return false;
 132        }
 133
 134        TypedConstant argument = attribute.ConstructorArguments[0];
 135
 136        if (argument.Kind == TypedConstantKind.Array)
 137        {
 138            foreach (TypedConstant value in argument.Values)
 139            {
 140                if (value.Value is not int status)
 141                {
 142                    return false;
 143                }
 144
 145                allowedStatuses |= status;
 146            }
 147
 148            return true;
 149        }
 150
 151        if (argument.Value is int singleStatus)
 152        {
 153            allowedStatuses = singleStatus;
 154            return true;
 155        }
 156
 157        return false;
 158    }
 159}
 160
 161internal static class TelegramCallbackDataFacts
 162{
 163    public const int MaxCallbackDataBytes = 64;
 164
 165    public static bool IsValidPayloadPrefix(string? prefix)
 166    {
 167        return prefix is not null &&
 168               !string.IsNullOrWhiteSpace(prefix) &&
 169               prefix.IndexOf(':') < 0 &&
 170               prefix.IndexOf('%') < 0 &&
 171               !prefix.Any(char.IsWhiteSpace) &&
 172               Encoding.UTF8.GetByteCount(prefix) <= MaxCallbackDataBytes;
 173    }
 174
 175    public static bool IsSupportedFieldType(ITypeSymbol type)
 176    {
 177        return type.SpecialType is SpecialType.System_String or
 178                   SpecialType.System_Int32 or
 179                   SpecialType.System_Int64 or
 180                   SpecialType.System_Boolean ||
 181               type.TypeKind == TypeKind.Enum;
 182    }
 183}
 184
 185internal static class TelegramBuiltInFilterFacts
 186{
 187    public static IReadOnlyList<TelegramBuiltInFilterSpec> All { get; } = new TelegramBuiltInFilterSpec[]
 188    {
 189        new(TelegramHandlerSymbols.ChatTypeAttribute, "ChatType", TelegramBuiltInFilterTarget.Chat, IsMarker: false),
 190        new(TelegramHandlerSymbols.SenderChatTypeAttribute, "SenderChatType", TelegramBuiltInFilterTarget.SenderChat, Is
 191        new(TelegramHandlerSymbols.ChatIdAttribute, "ChatId", TelegramBuiltInFilterTarget.Chat, IsMarker: false),
 192        new(TelegramHandlerSymbols.ChatUsernameAttribute, "ChatUsername", TelegramBuiltInFilterTarget.Chat, IsMarker: fa
 193        new(TelegramHandlerSymbols.FromUserAttribute, "FromUser", TelegramBuiltInFilterTarget.SenderUser, IsMarker: fals
 194        new(TelegramHandlerSymbols.HasTextAttribute, "HasText", TelegramBuiltInFilterTarget.Message, IsMarker: true),
 195        new(TelegramHandlerSymbols.HasPhotoAttribute, "HasPhoto", TelegramBuiltInFilterTarget.Message, IsMarker: true),
 196        new(TelegramHandlerSymbols.HasDocumentAttribute, "HasDocument", TelegramBuiltInFilterTarget.Message, IsMarker: t
 197        new(TelegramHandlerSymbols.HasCaptionAttribute, "HasCaption", TelegramBuiltInFilterTarget.Message, IsMarker: tru
 198        new(TelegramHandlerSymbols.HasVideoAttribute, "HasVideo", TelegramBuiltInFilterTarget.Message, IsMarker: true),
 199        new(TelegramHandlerSymbols.HasAnimationAttribute, "HasAnimation", TelegramBuiltInFilterTarget.Message, IsMarker:
 200        new(TelegramHandlerSymbols.HasAudioAttribute, "HasAudio", TelegramBuiltInFilterTarget.Message, IsMarker: true),
 201        new(TelegramHandlerSymbols.HasVoiceAttribute, "HasVoice", TelegramBuiltInFilterTarget.Message, IsMarker: true),
 202        new(TelegramHandlerSymbols.HasVideoNoteAttribute, "HasVideoNote", TelegramBuiltInFilterTarget.Message, IsMarker:
 203        new(TelegramHandlerSymbols.HasStickerAttribute, "HasSticker", TelegramBuiltInFilterTarget.Message, IsMarker: tru
 204        new(TelegramHandlerSymbols.HasContactAttribute, "HasContact", TelegramBuiltInFilterTarget.Message, IsMarker: tru
 205        new(TelegramHandlerSymbols.HasLocationAttribute, "HasLocation", TelegramBuiltInFilterTarget.Message, IsMarker: t
 206        new(TelegramHandlerSymbols.HasVenueAttribute, "HasVenue", TelegramBuiltInFilterTarget.Message, IsMarker: true),
 207        new(TelegramHandlerSymbols.HasPollAttribute, "HasPoll", TelegramBuiltInFilterTarget.Message, IsMarker: true),
 208        new(TelegramHandlerSymbols.HasDiceAttribute, "HasDice", TelegramBuiltInFilterTarget.Message, IsMarker: true),
 209        new(TelegramHandlerSymbols.FromBotAttribute, "FromBot", TelegramBuiltInFilterTarget.SenderUser, IsMarker: false)
 210        new(TelegramHandlerSymbols.FromPremiumUserAttribute, "FromPremiumUser", TelegramBuiltInFilterTarget.SenderUser, 
 211        new(TelegramHandlerSymbols.IsReplyAttribute, "IsReply", TelegramBuiltInFilterTarget.Message, IsMarker: true),
 212        new(TelegramHandlerSymbols.ReplyToBotAttribute, "ReplyToBot", TelegramBuiltInFilterTarget.Message, IsMarker: tru
 213        new(TelegramHandlerSymbols.MessageThreadIdAttribute, "MessageThreadId", TelegramBuiltInFilterTarget.MessageThrea
 214        new(TelegramHandlerSymbols.HasMessageThreadAttribute, "HasMessageThread", TelegramBuiltInFilterTarget.MessageThr
 215        new(TelegramHandlerSymbols.HasCallbackDataAttribute, "HasCallbackData", TelegramBuiltInFilterTarget.Callback, Is
 216        new(TelegramHandlerSymbols.CallbackDataPrefixAttribute, "CallbackDataPrefix", TelegramBuiltInFilterTarget.Callba
 217    };
 218
 219    public static IEnumerable<TelegramBuiltInFilterSpec> MarkerSpecs
 220    {
 221        get
 222        {
 223            return All.Where(static spec => spec.IsMarker);
 224        }
 225    }
 226
 227    public static IEnumerable<AttributeData> GetAttributes(ISymbol symbol)
 228    {
 229        foreach (TelegramBuiltInFilterSpec spec in All)
 230        {
 231            foreach (AttributeData attribute in TelegramHandlerSymbols.GetAttributes(
 232                         symbol,
 233                         spec.AttributeMetadataName,
 234                         inherit: true))
 235            {
 236                yield return attribute;
 237            }
 238        }
 239    }
 240
 241    public static bool TryGetSpec(
 242        AttributeData attribute,
 243        out TelegramBuiltInFilterSpec spec)
 244    {
 245        foreach (TelegramBuiltInFilterSpec candidate in All)
 246        {
 247            if (TelegramHandlerSymbols.IsAttribute(attribute, candidate.AttributeMetadataName))
 248            {
 249                spec = candidate;
 250                return true;
 251            }
 252        }
 253
 254        spec = null!;
 255        return false;
 256    }
 257
 258    public static bool TryGetSpecByGeneratedKind(
 259        string generatedKind,
 260        out TelegramBuiltInFilterSpec spec)
 261    {
 262        foreach (TelegramBuiltInFilterSpec candidate in All)
 263        {
 264            if (string.Equals(candidate.GeneratedKind, generatedKind, StringComparison.Ordinal))
 265            {
 266                spec = candidate;
 267                return true;
 268            }
 269        }
 270
 271        spec = null!;
 272        return false;
 273    }
 274
 275    public static bool SupportsRouteKind(
 276        TelegramBuiltInFilterTarget target,
 277        TelegramHandlerMetadataRouteKind routeKind)
 278    {
 279        return target switch
 280        {
 281            TelegramBuiltInFilterTarget.Chat => true,
 282            TelegramBuiltInFilterTarget.MessageThread => routeKind is TelegramHandlerMetadataRouteKind.Command or
 283                TelegramHandlerMetadataRouteKind.Message or
 284                TelegramHandlerMetadataRouteKind.Callback,
 285            TelegramBuiltInFilterTarget.Message => routeKind is TelegramHandlerMetadataRouteKind.Command or
 286                TelegramHandlerMetadataRouteKind.Message,
 287            TelegramBuiltInFilterTarget.SenderUser => routeKind is TelegramHandlerMetadataRouteKind.Command or
 288                TelegramHandlerMetadataRouteKind.Message or
 289                TelegramHandlerMetadataRouteKind.Callback,
 290            TelegramBuiltInFilterTarget.SenderChat => routeKind is TelegramHandlerMetadataRouteKind.Command or
 291                TelegramHandlerMetadataRouteKind.Message,
 292            TelegramBuiltInFilterTarget.Callback => routeKind == TelegramHandlerMetadataRouteKind.Callback,
 293            _ => false
 294        };
 295    }
 296
 297    public static string GetInvalidFilterMessage(
 298        TelegramBuiltInFilterTarget target,
 299        TelegramHandlerMetadataRouteKind routeKind)
 300    {
 301        string routeName = routeKind switch
 302        {
 303            TelegramHandlerMetadataRouteKind.Callback => "callback",
 304            TelegramHandlerMetadataRouteKind.ChatMember => "chat member update",
 305            _ => "message"
 306        };
 307
 308        return target switch
 309        {
 310            TelegramBuiltInFilterTarget.Chat => $"Chat filters cannot be used on {routeName} handlers.",
 311            TelegramBuiltInFilterTarget.MessageThread => $"Message thread filters cannot be used on {routeName} handlers
 312            TelegramBuiltInFilterTarget.Message => $"Message filters cannot be used on {routeName} handlers.",
 313            TelegramBuiltInFilterTarget.SenderUser => $"Sender user filters cannot be used on {routeName} handlers.",
 314            TelegramBuiltInFilterTarget.SenderChat => $"Sender chat filters cannot be used on {routeName} handlers.",
 315            TelegramBuiltInFilterTarget.Callback => $"Callback filters cannot be used on {routeName} handlers.",
 316            _ => $"Telegram filter cannot be used on {routeName} handlers."
 317        };
 318    }
 319}