< Summary

Line coverage
62%
Covered lines: 52
Uncovered lines: 31
Coverable lines: 83
Total lines: 143
Line coverage: 62.6%
Branch coverage
61%
Covered branches: 21
Total branches: 34
Branch coverage: 61.7%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.ctor(...)100%22100%
.ctor(...)100%110%
.ctor(...)100%11100%
.ctor(...)100%110%
ToString()50%22100%
Equals(...)0%440%
GetHashCode()100%110%
Parse(...)100%110%
TryParse(...)0%220%
GetEntityTagLength(...)81.81%222294.28%
System.ICloneable.Clone()0%220%

File(s)

https://raw.githubusercontent.com/dotnet/runtime/811a7eabb75c42db53440e8ba3f60c07511cfd1f/src/libraries/System.Net.Http/src/System/Net/Http/Headers/EntityTagHeaderValue.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System.Diagnostics;
 5using System.Diagnostics.CodeAnalysis;
 6
 7namespace System.Net.Http.Headers
 8{
 9    public class EntityTagHeaderValue : ICloneable
 10    {
 125311        public string Tag { get; private init; }
 12
 125313        public bool IsWeak { get; private init; }
 14
 3215        public static EntityTagHeaderValue Any { get; } = new EntityTagHeaderValue("*", isWeak: false, false);
 16
 53917        private EntityTagHeaderValue(string tag, bool isWeak, bool _)
 53918        {
 19#if DEBUG
 20            // This constructor should only be used with already validated values.
 21            // "*" is a special case that can only be created via the static Any property.
 53922            if (tag != "*")
 53823            {
 53824                new EntityTagHeaderValue(tag, isWeak);
 53825            }
 26#endif
 27
 53928            Tag = tag;
 53929            IsWeak = isWeak;
 53930        }
 31
 32        public EntityTagHeaderValue(string tag)
 033            : this(tag, false)
 034        {
 035        }
 36
 53837        public EntityTagHeaderValue(string tag, bool isWeak)
 53838        {
 53839            HeaderUtilities.CheckValidQuotedString(tag);
 40
 53841            Tag = tag;
 53842            IsWeak = isWeak;
 53843        }
 44
 045        private EntityTagHeaderValue(EntityTagHeaderValue source)
 046        {
 047            Debug.Assert(source != null);
 48
 049            Tag = source.Tag;
 050            IsWeak = source.IsWeak;
 051        }
 52
 53        public override string ToString() =>
 17654            IsWeak ? $"W/{Tag}" : Tag;
 55
 56        public override bool Equals([NotNullWhen(true)] object? obj) =>
 057            obj is EntityTagHeaderValue other &&
 058            IsWeak == other.IsWeak &&
 059            // Since the tag is a quoted-string we treat it case-sensitive.
 060            string.Equals(Tag, other.Tag, StringComparison.Ordinal);
 61
 62        public override int GetHashCode() =>
 063            HashCode.Combine(Tag, IsWeak);
 64
 65        public static EntityTagHeaderValue Parse(string input)
 066        {
 067            int index = 0;
 068            return (EntityTagHeaderValue)GenericHeaderParser.SingleValueEntityTagParser.ParseValue(
 069                input, null, ref index);
 070        }
 71
 72        public static bool TryParse([NotNullWhen(true)] string? input, [NotNullWhen(true)] out EntityTagHeaderValue? par
 073        {
 074            int index = 0;
 075            parsedValue = null;
 76
 077            if (GenericHeaderParser.SingleValueEntityTagParser.TryParseValue(input, null, ref index, out object? output)
 078            {
 079                parsedValue = (EntityTagHeaderValue)output!;
 080                return true;
 81            }
 082            return false;
 083        }
 84
 85        internal static int GetEntityTagLength(string? input, int startIndex, out EntityTagHeaderValue? parsedValue)
 107386        {
 107387            Debug.Assert(startIndex >= 0);
 88
 107389            parsedValue = null;
 90
 107391            if (string.IsNullOrEmpty(input) || (startIndex >= input.Length))
 092            {
 093                return 0;
 94            }
 95
 96            // Caller must remove leading whitespace. If not, we'll return 0.
 107397            bool isWeak = false;
 107398            int current = startIndex;
 99
 1073100            char firstChar = input[startIndex];
 1073101            if (firstChar == '*')
 9102            {
 103                // We have '*' value, indicating "any" ETag.
 9104                parsedValue = Any;
 9105                current++;
 9106            }
 107            else
 1064108            {
 109                // The RFC defines 'W/' as prefix, but we'll be flexible and also accept lower-case 'w'.
 1064110                if ((firstChar == 'W') || (firstChar == 'w'))
 34111                {
 34112                    current++;
 113                    // We need at least 3 more chars: the '/' character followed by two quotes.
 34114                    if ((current + 2 >= input.Length) || (input[current] != '/'))
 18115                    {
 18116                        return 0;
 117                    }
 16118                    isWeak = true;
 16119                    current++; // we have a weak-entity tag.
 16120                    current += HttpRuleParser.GetWhitespaceLength(input, current);
 16121                }
 122
 1046123                if (current == input.Length || HttpRuleParser.GetQuotedStringLength(input, current, out int tagLength) !
 508124                {
 508125                    return 0;
 126                }
 127
 128                // Most of the time we'll have strong ETags without leading/trailing whitespace.
 538129                Debug.Assert(tagLength != input.Length || (startIndex == 0 && !isWeak));
 130
 538131                parsedValue = new EntityTagHeaderValue(input.Substring(current, tagLength), isWeak, false);
 132
 538133                current += tagLength;
 538134            }
 547135            current += HttpRuleParser.GetWhitespaceLength(input, current);
 136
 547137            return current - startIndex;
 1073138        }
 139
 0140        object ICloneable.Clone() => ReferenceEquals(this, Any) ? Any : new EntityTagHeaderValue(this);
 141    }
 142}
 143