diff --git a/src/WireMock.Net/Matchers/Request/RequestMessageParamMatcher.cs b/src/WireMock.Net/Matchers/Request/RequestMessageParamMatcher.cs index 03f0c93b4..b22ea5656 100644 --- a/src/WireMock.Net/Matchers/Request/RequestMessageParamMatcher.cs +++ b/src/WireMock.Net/Matchers/Request/RequestMessageParamMatcher.cs @@ -142,6 +142,6 @@ private static double CalculateScore(IReadOnlyList matchers, Wir } } - return total.Any() ? MatchScores.ToScore(total, MatchOperator.Average) : default; + return total.Any() ? MatchScores.ToScore(total, MatchOperator.Average) : 0; } } \ No newline at end of file diff --git a/src/WireMock.Net/Util/QueryStringParser.cs b/src/WireMock.Net/Util/QueryStringParser.cs index 9a0c933fd..c10f02b7b 100644 --- a/src/WireMock.Net/Util/QueryStringParser.cs +++ b/src/WireMock.Net/Util/QueryStringParser.cs @@ -20,12 +20,12 @@ public static bool TryParse(string? queryString, bool caseIgnore, [NotNullWhen(t { if (queryString is null) { - nameValueCollection = default; + nameValueCollection = null; return false; } var parts = queryString! - .Split(new[] { "&" }, StringSplitOptions.RemoveEmptyEntries) + .Split(["&"], StringSplitOptions.RemoveEmptyEntries) .Select(parameter => parameter.Split('=')) .Distinct(); @@ -50,18 +50,6 @@ public static IDictionary> Parse(string? queryStrin var queryParameterMultipleValueSupport = support ?? QueryParameterMultipleValueSupport.All; - string[] JoinParts(string[] parts) - { - if (parts.Length > 1) - { - return queryParameterMultipleValueSupport.HasFlag(QueryParameterMultipleValueSupport.Comma) ? - parts[1].Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries) : // Support "?key=1,2" - new[] { parts[1] }; - } - - return new string[0]; - } - var splitOn = new List(); if (queryParameterMultipleValueSupport.HasFlag(QueryParameterMultipleValueSupport.Ampersand)) { @@ -74,8 +62,24 @@ string[] JoinParts(string[] parts) return queryString!.TrimStart('?') .Split(splitOn.ToArray(), StringSplitOptions.RemoveEmptyEntries) - .Select(parameter => parameter.Split(new[] { '=' }, 2, StringSplitOptions.RemoveEmptyEntries)) - .GroupBy(parts => parts[0], JoinParts) - .ToDictionary(grouping => grouping.Key, grouping => new WireMockList(grouping.SelectMany(x => x).Select(WebUtility.UrlDecode))); + .Select(parameter => new { hasEqualSign = parameter.Contains('='), parts = parameter.Split(['='], 2, StringSplitOptions.RemoveEmptyEntries) }) + .GroupBy(x => x.parts[0], y => JoinParts(y.hasEqualSign, y.parts)) + .ToDictionary + ( + grouping => grouping.Key, + grouping => new WireMockList(grouping.SelectMany(x => x).Select(WebUtility.UrlDecode).OfType()) + ); + + string[] JoinParts(bool hasEqualSign, string[] parts) + { + if (parts.Length > 1) + { + return queryParameterMultipleValueSupport.HasFlag(QueryParameterMultipleValueSupport.Comma) ? + parts[1].Split([","], StringSplitOptions.RemoveEmptyEntries) : // Support "?key=1,2" + [parts[1]]; + } + + return hasEqualSign ? [string.Empty] : []; // Return empty string if equal sign with no value (#1247) + } } } \ No newline at end of file diff --git a/test/WireMock.Net.Tests/RequestMatchers/RequestMessageParamMatcherTests.cs b/test/WireMock.Net.Tests/RequestMatchers/RequestMessageParamMatcherTests.cs index e8f737bb0..a0b46a358 100644 --- a/test/WireMock.Net.Tests/RequestMatchers/RequestMessageParamMatcherTests.cs +++ b/test/WireMock.Net.Tests/RequestMatchers/RequestMessageParamMatcherTests.cs @@ -43,6 +43,21 @@ public void RequestMessageParamMatcher_GetMatchingScore_KeyWith1ValuePresentInUr Check.That(score).IsEqualTo(0.5d); } + [Fact] + public void RequestMessageParamMatcher_GetMatchingScore_KeyWithNoValuePresentInUrl_Returns1_0() + { + // Assign + var requestMessage = new RequestMessage(new UrlDetails("http://localhost?key="), "GET", "127.0.0.1"); + var matcher = new RequestMessageParamMatcher(MatchBehaviour.AcceptOnMatch, "key", false, ""); + + // Act + var result = new RequestMatchResult(); + var score = matcher.GetMatchingScore(requestMessage, result); + + // Assert + Check.That(score).IsEqualTo(1.0d); + } + [Fact] public void RequestMessageParamMatcher_GetMatchingScore_KeyWith3ValuesPresentInUrl_And_With1ExactStringWith2Patterns_Returns0_66() { diff --git a/test/WireMock.Net.Tests/Util/QueryStringParserTests.cs b/test/WireMock.Net.Tests/Util/QueryStringParserTests.cs index 52287f51d..e94bfb495 100644 --- a/test/WireMock.Net.Tests/Util/QueryStringParserTests.cs +++ b/test/WireMock.Net.Tests/Util/QueryStringParserTests.cs @@ -148,7 +148,7 @@ public void Parse_With1ParamNoValueWithEqualSign() // Assert result.Count.Should().Be(1); - result["empty"].Should().Equal(new WireMockList()); + result["empty"].Should().Equal(new WireMockList("")); } [Fact] @@ -354,18 +354,19 @@ public void Parse_With1ParamContainingComma_Using_QueryParameterMultipleValueSup public void Parse_WithComplex() { // Assign - string query = "?q=energy+edge&rls=com.microsoft:en-au&ie=UTF-8&oe=UTF-8&startIndex=&startPage=1%22"; + string query = "?q=energy+edge&rls=com.microsoft:en-au&ie=UTF-8&oe=UTF-8&startIndex=&startPage=1%22&x"; // Act var result = QueryStringParser.Parse(query); // Assert - result.Count.Should().Be(6); + result.Count.Should().Be(7); result["q"].Should().Equal(new WireMockList("energy edge")); result["rls"].Should().Equal(new WireMockList("com.microsoft:en-au")); result["ie"].Should().Equal(new WireMockList("UTF-8")); result["oe"].Should().Equal(new WireMockList("UTF-8")); - result["startIndex"].Should().Equal(new WireMockList()); + result["startIndex"].Should().Equal(new WireMockList("")); result["startPage"].Should().Equal(new WireMockList("1\"")); + result["x"].Should().Equal(new WireMockList()); } } \ No newline at end of file