< Summary

Line coverage
34%
Covered lines: 37
Uncovered lines: 70
Coverable lines: 107
Total lines: 186
Line coverage: 34.5%
Branch coverage
33%
Covered branches: 14
Total branches: 42
Branch coverage: 33.3%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.ctor(...)100%11100%
.ctor(...)100%110%
.ctor(...)100%110%
ToString()50%22100%
Equals(...)0%440%
GetHashCode()100%110%
Parse(...)100%110%
TryParse(...)0%220%
GetStringWithQualityLength(...)75%121284%
TryReadQuality(...)20%202021.87%
System.ICloneable.Clone()100%110%

File(s)

https://raw.githubusercontent.com/dotnet/runtime/811a7eabb75c42db53440e8ba3f60c07511cfd1f/src/libraries/System.Net.Http/src/System/Net/Http/Headers/StringWithQualityHeaderValue.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;
 6using System.Globalization;
 7
 8namespace System.Net.Http.Headers
 9{
 10    public class StringWithQualityHeaderValue : ICloneable
 11    {
 12        private const double NotSetSentinel = double.PositiveInfinity;
 13
 14        private readonly string _value;
 15        private readonly double _quality;
 16
 017        public string Value => _value;
 18
 019        public double? Quality => _quality == NotSetSentinel ? null : _quality;
 20
 202821        public StringWithQualityHeaderValue(string value)
 202822        {
 202823            HeaderUtilities.CheckValidToken(value);
 24
 202825            _value = value;
 202826            _quality = NotSetSentinel;
 202827        }
 28
 029        public StringWithQualityHeaderValue(string value, double quality)
 030        {
 031            HeaderUtilities.CheckValidToken(value);
 32
 033            ArgumentOutOfRangeException.ThrowIfNegative(quality);
 034            ArgumentOutOfRangeException.ThrowIfGreaterThan(quality, 1.0);
 35
 036            _value = value;
 037            _quality = quality;
 038        }
 39
 040        private StringWithQualityHeaderValue(StringWithQualityHeaderValue source)
 041        {
 042            Debug.Assert(source != null);
 43
 044            _value = source._value;
 045            _quality = source._quality;
 046        }
 47
 48        public override string ToString() =>
 304049            _quality == NotSetSentinel
 304050                ? _value
 304051                : string.Create(CultureInfo.InvariantCulture, stackalloc char[128], $"{_value}; q={_quality:0.0##}");
 52
 53        public override bool Equals([NotNullWhen(true)] object? obj) =>
 054            obj is StringWithQualityHeaderValue other &&
 055            string.Equals(_value, other._value, StringComparison.OrdinalIgnoreCase) &&
 056            // Note that we don't consider double.Epsilon here. We really consider two values equal if they're
 057            // actually equal. This makes sure that we also get the same hashcode for two values considered equal
 058            // by Equals().
 059            _quality == other._quality;
 60
 61        public override int GetHashCode() =>
 062            HashCode.Combine(StringComparer.OrdinalIgnoreCase.GetHashCode(_value), _quality);
 63
 64        public static StringWithQualityHeaderValue Parse(string input)
 065        {
 066            int index = 0;
 067            return (StringWithQualityHeaderValue)GenericHeaderParser.SingleValueStringWithQualityParser.ParseValue(
 068                input, null, ref index);
 069        }
 70
 71        public static bool TryParse([NotNullWhen(true)] string? input, [NotNullWhen(true)] out StringWithQualityHeaderVa
 072        {
 073            int index = 0;
 074            parsedValue = null;
 75
 076            if (GenericHeaderParser.SingleValueStringWithQualityParser.TryParseValue(
 077                input, null, ref index, out object? output))
 078            {
 079                parsedValue = (StringWithQualityHeaderValue)output!;
 080                return true;
 81            }
 082            return false;
 083        }
 84
 85        internal static int GetStringWithQualityLength(string? input, int startIndex, out object? parsedValue)
 210086        {
 210087            Debug.Assert(startIndex >= 0);
 88
 210089            parsedValue = null;
 90
 210091            if (string.IsNullOrEmpty(input) || (startIndex >= input.Length))
 092            {
 093                return 0;
 94            }
 95
 96            // Parse the value string: <value> in '<value>; q=<quality>'
 210097            int valueLength = HttpRuleParser.GetTokenLength(input, startIndex);
 98
 210099            if (valueLength == 0)
 54100            {
 54101                return 0;
 102            }
 103
 2046104            string value = input.Substring(startIndex, valueLength);
 2046105            int current = startIndex + valueLength;
 2046106            current += HttpRuleParser.GetWhitespaceLength(input, current);
 107
 2046108            if ((current == input.Length) || (input[current] != ';'))
 2028109            {
 2028110                parsedValue = new StringWithQualityHeaderValue(value);
 2028111                return current - startIndex; // we have a valid token, but no quality.
 112            }
 113
 18114            current++; // skip ';' separator
 18115            current += HttpRuleParser.GetWhitespaceLength(input, current);
 116
 117            // If we found a ';' separator, it must be followed by a quality information
 18118            if (!TryReadQuality(input, out double quality, ref current))
 18119            {
 18120                return 0;
 121            }
 122
 0123            parsedValue = new StringWithQualityHeaderValue(value, quality);
 0124            return current - startIndex;
 2100125        }
 126
 127        private static bool TryReadQuality(string input, out double quality, ref int index)
 18128        {
 18129            int current = index;
 18130            quality = default;
 131
 132            // See if we have a quality value by looking for "q"
 18133            if ((current == input.Length) || ((input[current] != 'q') && (input[current] != 'Q')))
 18134            {
 18135                return false;
 136            }
 137
 0138            current++; // skip 'q' identifier
 0139            current += HttpRuleParser.GetWhitespaceLength(input, current);
 140
 141            // If we found "q" it must be followed by "="
 0142            if ((current == input.Length) || (input[current] != '='))
 0143            {
 0144                return false;
 145            }
 146
 0147            current++; // skip '=' separator
 0148            current += HttpRuleParser.GetWhitespaceLength(input, current);
 149
 0150            if (current == input.Length)
 0151            {
 0152                return false;
 153            }
 154
 0155            int qualityLength = HttpRuleParser.GetNumberLength(input, current, true);
 156
 0157            if (qualityLength == 0)
 0158            {
 0159                return false;
 160            }
 161
 0162            if (!double.TryParse(input.AsSpan(current, qualityLength), NumberStyles.AllowDecimalPoint,
 0163                NumberFormatInfo.InvariantInfo, out quality))
 0164            {
 0165                return false;
 166            }
 167
 0168            if ((quality < 0) || (quality > 1))
 0169            {
 0170                return false;
 171            }
 172
 0173            current += qualityLength;
 0174            current += HttpRuleParser.GetWhitespaceLength(input, current);
 175
 0176            index = current;
 0177            return true;
 18178        }
 179
 180        object ICloneable.Clone()
 0181        {
 0182            return new StringWithQualityHeaderValue(this);
 0183        }
 184    }
 185}
 186