< Summary - Combined Code Coverage

Information
Class: NLightning.Bolt11.Models.TaggedFieldList
Assembly: NLightning.Bolt11
File(s): /home/runner/work/nlightning/nlightning/src/NLightning.Bolt11/Models/TaggedFieldList.cs
Tag: 36_15743069263
Line coverage
96%
Covered lines: 77
Uncovered lines: 3
Coverable lines: 80
Total lines: 244
Line coverage: 96.2%
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

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor()100%11100%
Add(...)93.75%16.051694.12%
AddRange(...)100%22100%
Remove(...)100%22100%
RemoveAt(...)100%11100%
RemoveAll(...)100%22100%
RemoveRange(...)100%11100%
TryGet(...)100%22100%
TryGetAll(...)100%22100%
FromBitReader(...)100%8.1888.24%
WriteToBitWriter(...)100%22100%
CalculateSizeInBits()100%11100%
Get(...)100%11100%
GetAll(...)100%22100%
OnChanged()100%22100%

File(s)

/home/runner/work/nlightning/nlightning/src/NLightning.Bolt11/Models/TaggedFieldList.cs

#LineLine coverage
 1using System.Diagnostics;
 2using System.Diagnostics.CodeAnalysis;
 3
 4namespace NLightning.Bolt11.Models;
 5
 6using Domain.Protocol.ValueObjects;
 7using Domain.Utils;
 8using Enums;
 9using Factories;
 10using Interfaces;
 11
 12/// <summary>
 13/// A list of tagged fields
 14/// </summary>
 15internal class TaggedFieldList : List<ITaggedField>
 16{
 46017    private bool _shouldInvokeChangedEvent = true;
 18    public event EventHandler? Changed;
 19
 20    /// <summary>
 21    /// Add a tagged field to the list
 22    /// </summary>
 23    /// <param name="taggedField">The tagged field to add</param>
 24    /// <exception cref="ArgumentException">If the tagged field is not unique</exception>
 25    internal new void Add(ITaggedField taggedField)
 26    {
 27        // Individual field validation
 101228        if (!taggedField.IsValid())
 029            throw new ArgumentException($"Invalid {taggedField.Type} field: field validation failed");
 30
 31        // Check for uniqueness
 273632        if (this.Any(x => x.Type.Equals(taggedField.Type)) && taggedField.Type != TaggedFieldTypes.FallbackAddress)
 433            throw new ArgumentException(
 434                $"TaggedFieldDictionary already contains a tagged field of type {taggedField.Type}");
 35
 36        // Mutual exclusivity validation
 100837        if (taggedField.Type == TaggedFieldTypes.Description
 114838         && this.Any(x => x.Type.Equals(TaggedFieldTypes.DescriptionHash)))
 439            throw new ArgumentException(
 440                $"TaggedFieldDictionary already contains a tagged field of type {taggedField.Type}");
 41
 100442        if (taggedField.Type == TaggedFieldTypes.DescriptionHash
 108443         && this.Any(x => x.Type.Equals(TaggedFieldTypes.Description)))
 444            throw new ArgumentException(
 445                $"TaggedFieldDictionary already contains a tagged field of type {taggedField.Type}");
 46
 47        // Add the tagged field
 100048        base.Add(taggedField);
 100049        if (_shouldInvokeChangedEvent)
 96450            OnChanged();
 100051    }
 52
 53    /// <summary>
 54    /// Add a range of tagged fields to the list
 55    /// </summary>
 56    /// <param name="taggedFields">The tagged fields to add</param>
 57    internal new void AddRange(IEnumerable<ITaggedField> taggedFields)
 58    {
 2859        _shouldInvokeChangedEvent = false;
 60
 12861        foreach (var taggedField in taggedFields)
 3662            Add(taggedField);
 63
 2864        _shouldInvokeChangedEvent = true;
 2865        OnChanged();
 2866    }
 67
 68    internal new bool Remove(ITaggedField item)
 69    {
 870        if (!base.Remove(item))
 471            return false;
 72
 473        OnChanged();
 474        return true;
 75    }
 76
 77    internal new void RemoveAt(int index)
 78    {
 479        base.RemoveAt(index);
 480        OnChanged();
 481    }
 82
 83    internal new int RemoveAll(Predicate<ITaggedField> match)
 84    {
 485        var removed = base.RemoveAll(match);
 486        if (removed > 0)
 487            OnChanged();
 88
 489        return removed;
 90    }
 91
 92    internal new void RemoveRange(int index, int count)
 93    {
 494        base.RemoveRange(index, count);
 495        OnChanged();
 496    }
 97
 98    /// <summary>
 99    /// Attempts to retrieve a tagged field of the specified type from the list.
 100    /// </summary>
 101    /// <typeparam name="T">The type of the tagged field to retrieve.</typeparam>
 102    /// <param name="taggedFieldType">The type of the tagged field being searched for.</param>
 103    /// <param name="taggedField">The output parameter to hold the retrieved tagged field if found; otherwise, the defau
 104    /// <returns>True if the tagged field of the specified type is found; otherwise, false.</returns>
 105    internal bool TryGet<T>(TaggedFieldTypes taggedFieldType, [MaybeNullWhen(false)] out T taggedField)
 106        where T : ITaggedField
 107    {
 1168108        var value = Get<T>(taggedFieldType);
 1168109        if (value != null)
 110        {
 872111            taggedField = value;
 872112            return true;
 113        }
 114
 296115        taggedField = default;
 296116        return false;
 117    }
 118
 119    /// <summary>
 120    /// Try to get all tagged fields of a specific type
 121    /// </summary>
 122    /// <param name="taggedFieldType">The type of the tagged field</param>
 123    /// <param name="taggedFieldList">A list containing the tagged fields</param>
 124    /// <typeparam name="T">The type of the tagged field</typeparam>
 125    /// <returns>True if the tagged fields were found, false otherwise</returns>
 126    internal bool TryGetAll<T>(TaggedFieldTypes taggedFieldType, [MaybeNullWhen(false)] out List<T> taggedFieldList)
 127        where T : ITaggedField
 128    {
 44129        var value = GetAll<T>(taggedFieldType);
 44130        if (value != null)
 131        {
 40132            taggedFieldList = value;
 40133            return true;
 134        }
 135
 4136        taggedFieldList = null;
 4137        return false;
 138    }
 139
 140    /// <summary>
 141    /// Get a new TaggedFieldList from a BitReader
 142    /// </summary>
 143    /// <param name="bitReader">The BitReader to read from</param>
 144    /// <param name="bitcoinNetwork">The network type</param>
 145    /// <returns>A new TaggedFieldList</returns>
 146    internal static TaggedFieldList FromBitReader(BitReader bitReader, BitcoinNetwork bitcoinNetwork)
 147    {
 72148        var taggedFields = new TaggedFieldList();
 948149        while (bitReader.HasMoreBits(15))
 150        {
 876151            var type = (TaggedFieldTypes)bitReader.ReadByteFromBits(5);
 876152            var length = bitReader.ReadInt16FromBits(10);
 876153            if (length == 0 || !bitReader.HasMoreBits(length * 5))
 154                continue;
 155
 348156            if (!Enum.IsDefined(typeof(TaggedFieldTypes), type))
 157            {
 12158                bitReader.SkipBits(length * 5);
 159            }
 160            else
 161            {
 162                try
 163                {
 336164                    var taggedField =
 336165                        TaggedFieldFactory.CreateTaggedFieldFromBitReader(type, bitReader, length, bitcoinNetwork);
 166
 167                    try
 168                    {
 316169                        taggedFields.Add(taggedField);
 316170                    }
 0171                    catch (Exception e)
 172                    {
 173                        Debug.WriteLine(e.Message);
 174                        // Skip for now, log latter
 0175                    }
 316176                }
 20177                catch (Exception e)
 178                {
 179                    Debug.WriteLine(e.Message);
 180                    // Skip for now, log latter
 20181                }
 182            }
 183        }
 184
 72185        return taggedFields;
 186    }
 187
 188    /// <summary>
 189    /// Write the TaggedFieldList to a BitWriter
 190    /// </summary>
 191    /// <param name="bitWriter">The BitWriter to write to</param>
 192    internal void WriteToBitWriter(BitWriter bitWriter)
 193    {
 736194        foreach (var taggedField in this)
 195        {
 196            // Write type
 292197            bitWriter.WriteByteAsBits((byte)taggedField.Type, 5);
 198
 199            // Write length
 292200            bitWriter.WriteInt16AsBits(taggedField.Length, 10);
 201
 292202            taggedField.WriteToBitWriter(bitWriter);
 203        }
 76204    }
 205
 206    /// <summary>
 207    /// Calculate the size of the TaggedFieldList in bits
 208    /// </summary>
 209    /// <returns>The size of the TaggedFieldList in bits</returns>
 210    internal int CalculateSizeInBits()
 211    {
 368212        return this.Sum(x => x.Length);
 213    }
 214
 215    /// <summary>
 216    /// Get a tagged field of a specific type
 217    /// </summary>
 218    /// <param name="taggedFieldType">The type of the tagged field</param>
 219    /// <typeparam name="T">The type of the tagged field</typeparam>
 220    /// <returns>The tagged field</returns>
 221    private T? Get<T>(TaggedFieldTypes taggedFieldType) where T : ITaggedField
 222    {
 4848223        return (T?)this.FirstOrDefault(x => x.Type.Equals(taggedFieldType));
 224    }
 225
 226    /// <summary>
 227    /// Get all tagged fields of a specific type
 228    /// </summary>
 229    /// <param name="taggedFieldType">The type of the tagged field</param>
 230    /// <typeparam name="T">The type of the tagged field</typeparam>
 231    /// <returns>A list containing the tagged fields</returns>
 232    private List<T>? GetAll<T>(TaggedFieldTypes taggedFieldType) where T : ITaggedField
 233    {
 208234        var taggedFields = this.Where(x => x.Type.Equals(taggedFieldType)).ToList();
 44235        return taggedFields.Count == 0
 44236                   ? null
 44237                   : taggedFields.Cast<T>().ToList();
 238    }
 239
 240    private void OnChanged()
 241    {
 1008242        Changed?.Invoke(this, EventArgs.Empty);
 500243    }
 244}