diff --git a/Directory.Build.props b/Directory.Build.props
index 5438effc..1efbb2df 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -4,7 +4,7 @@
- 1.0.7
+ 1.0.8
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index ac816e65..7a56d892 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -24,7 +24,7 @@ steps:
# - https://github.com/Microsoft/vsts-tasks/issues/8291
#
- script: |
- %USERPROFILE%\.dotnet\tools\dotnet-sonarscanner begin /k:"wiremock" /d:sonar.organization="stefh-github" /d:sonar.host.url="https://sonarcloud.io" /d:sonar.login="$(SONAR_TOKEN)" /v:"$(buildId)" /d:sonar.cs.opencover.reportsPaths="**\coverage.opencover.xml"
+ %USERPROFILE%\.dotnet\tools\dotnet-sonarscanner begin /k:"wiremock" /o:"stefh-github" /d:sonar.host.url="https://sonarcloud.io" /d:sonar.login="$(SONAR_TOKEN)" /v:"$(buildId)" /d:sonar.cs.opencover.reportsPaths="**\coverage.opencover.xml"
displayName: Begin SonarScanner
# Build source, tests and run tests for net452 and netcoreapp2.1 (with coverage)
diff --git a/src/WireMock.Net/Admin/Mappings/ParamModel.cs b/src/WireMock.Net/Admin/Mappings/ParamModel.cs
index 8b4ca0b1..90d263a5 100644
--- a/src/WireMock.Net/Admin/Mappings/ParamModel.cs
+++ b/src/WireMock.Net/Admin/Mappings/ParamModel.cs
@@ -10,6 +10,11 @@
///
public string Name { get; set; }
+ ///
+ /// Defines if the key should be matched using case-ignore.
+ ///
+ public bool? IgnoreCase { get; set; }
+
///
/// Gets or sets the matchers.
///
diff --git a/src/WireMock.Net/Matchers/Request/RequestMessageParamMatcher.cs b/src/WireMock.Net/Matchers/Request/RequestMessageParamMatcher.cs
index 47b4fe74..e74e9303 100644
--- a/src/WireMock.Net/Matchers/Request/RequestMessageParamMatcher.cs
+++ b/src/WireMock.Net/Matchers/Request/RequestMessageParamMatcher.cs
@@ -24,6 +24,11 @@ namespace WireMock.Matchers.Request
///
public string Key { get; }
+ ///
+ /// Defines if the key should be matched using case-ignore.
+ ///
+ public bool? IgnoreCase { get; private set; }
+
///
/// The matchers.
///
@@ -34,7 +39,8 @@ namespace WireMock.Matchers.Request
///
/// The match behaviour.
/// The key.
- public RequestMessageParamMatcher(MatchBehaviour matchBehaviour, [NotNull] string key) : this(matchBehaviour, key, (IStringMatcher[])null)
+ /// Defines if the key should be matched using case-ignore.
+ public RequestMessageParamMatcher(MatchBehaviour matchBehaviour, [NotNull] string key, bool ignoreCase) : this(matchBehaviour, key, ignoreCase, (IStringMatcher[])null)
{
}
@@ -43,8 +49,9 @@ namespace WireMock.Matchers.Request
///
/// The match behaviour.
/// The key.
+ /// Defines if the key should be matched using case-ignore.
/// The values.
- public RequestMessageParamMatcher(MatchBehaviour matchBehaviour, [NotNull] string key, [CanBeNull] string[] values) : this(matchBehaviour, key, values?.Select(value => new ExactMatcher(matchBehaviour, value)).Cast().ToArray())
+ public RequestMessageParamMatcher(MatchBehaviour matchBehaviour, [NotNull] string key, bool ignoreCase, [CanBeNull] string[] values) : this(matchBehaviour, key, ignoreCase, values?.Select(value => new ExactMatcher(matchBehaviour, value)).Cast().ToArray())
{
}
@@ -53,13 +60,15 @@ namespace WireMock.Matchers.Request
///
/// The match behaviour.
/// The key.
+ /// Defines if the key should be matched using case-ignore.
/// The matchers.
- public RequestMessageParamMatcher(MatchBehaviour matchBehaviour, [NotNull] string key, [CanBeNull] IStringMatcher[] matchers)
+ public RequestMessageParamMatcher(MatchBehaviour matchBehaviour, [NotNull] string key, bool ignoreCase, [CanBeNull] IStringMatcher[] matchers)
{
Check.NotNull(key, nameof(key));
_matchBehaviour = matchBehaviour;
Key = key;
+ IgnoreCase = ignoreCase;
Matchers = matchers;
}
@@ -88,7 +97,7 @@ namespace WireMock.Matchers.Request
return MatchScores.ToScore(requestMessage.Query != null && Funcs.Any(f => f(requestMessage.Query)));
}
- WireMockList valuesPresentInRequestMessage = requestMessage.GetParameter(Key);
+ WireMockList valuesPresentInRequestMessage = requestMessage.GetParameter(Key, IgnoreCase ?? false);
if (valuesPresentInRequestMessage == null)
{
// Key is not present at all, just return Mismatch
diff --git a/src/WireMock.Net/RequestBuilders/IParamsRequestBuilder.cs b/src/WireMock.Net/RequestBuilders/IParamsRequestBuilder.cs
index ddb21610..06bb0a3b 100644
--- a/src/WireMock.Net/RequestBuilders/IParamsRequestBuilder.cs
+++ b/src/WireMock.Net/RequestBuilders/IParamsRequestBuilder.cs
@@ -1,6 +1,6 @@
-using System;
+using JetBrains.Annotations;
+using System;
using System.Collections.Generic;
-using JetBrains.Annotations;
using WireMock.Matchers;
using WireMock.Util;
@@ -19,6 +19,15 @@ namespace WireMock.RequestBuilders
/// The .
IRequestBuilder WithParam([NotNull] string key, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch);
+ ///
+ /// WithParam: matching on key only.
+ ///
+ /// The key.
+ /// Defines if the key should be matched using case-ignore.
+ /// The match behaviour (optional).
+ /// The .
+ IRequestBuilder WithParam([NotNull] string key, bool ignoreCase, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch);
+
///
/// WithParam: matching on key and values.
///
@@ -27,6 +36,15 @@ namespace WireMock.RequestBuilders
/// The .
IRequestBuilder WithParam([NotNull] string key, [CanBeNull] params string[] values);
+ ///
+ /// WithParam: matching on key and values.
+ ///
+ /// The key.
+ /// Defines if the key should be matched using case-ignore.
+ /// The values.
+ /// The .
+ IRequestBuilder WithParam([NotNull] string key, bool ignoreCase, [CanBeNull] params string[] values);
+
///
/// WithParam: matching on key and matchers.
///
@@ -35,6 +53,15 @@ namespace WireMock.RequestBuilders
/// The .
IRequestBuilder WithParam([NotNull] string key, [CanBeNull] params IStringMatcher[] matchers);
+ ///
+ /// WithParam: matching on key and matchers.
+ ///
+ /// The key.
+ /// Defines if the key should be matched using case-ignore.
+ /// The matchers.
+ /// The .
+ IRequestBuilder WithParam([NotNull] string key, bool ignoreCase, [CanBeNull] params IStringMatcher[] matchers);
+
///
/// WithParam: matching on key, values and matchBehaviour.
///
@@ -44,6 +71,16 @@ namespace WireMock.RequestBuilders
/// The .
IRequestBuilder WithParam([NotNull] string key, MatchBehaviour matchBehaviour, [CanBeNull] params string[] values);
+ ///
+ /// WithParam: matching on key, values and matchBehaviour.
+ ///
+ /// The key.
+ /// Defines if the key should be matched using case-ignore.
+ /// The values.
+ /// The match behaviour.
+ /// The .
+ IRequestBuilder WithParam([NotNull] string key, MatchBehaviour matchBehaviour, bool ignoreCase = false, [CanBeNull] params string[] values);
+
///
/// WithParam: matching on key, matchers and matchBehaviour.
///
@@ -53,6 +90,16 @@ namespace WireMock.RequestBuilders
/// The .
IRequestBuilder WithParam([NotNull] string key, MatchBehaviour matchBehaviour, [CanBeNull] params IStringMatcher[] matchers);
+ ///
+ /// WithParam: matching on key, matchers and matchBehaviour.
+ ///
+ /// The key.
+ /// Defines if the key should be matched using case-ignore.
+ /// The matchers.
+ /// The match behaviour.
+ /// The .
+ IRequestBuilder WithParam([NotNull] string key, MatchBehaviour matchBehaviour, bool ignoreCase = false, [CanBeNull] params IStringMatcher[] matchers);
+
///
/// WithParam: matching on functions.
///
diff --git a/src/WireMock.Net/RequestBuilders/Request.Params.cs b/src/WireMock.Net/RequestBuilders/Request.Params.cs
new file mode 100644
index 00000000..94dcd6bd
--- /dev/null
+++ b/src/WireMock.Net/RequestBuilders/Request.Params.cs
@@ -0,0 +1,89 @@
+using System;
+using System.Collections.Generic;
+using WireMock.Matchers;
+using WireMock.Matchers.Request;
+using WireMock.Util;
+using WireMock.Validation;
+
+namespace WireMock.RequestBuilders
+{
+ public partial class Request
+ {
+ ///
+ public IRequestBuilder WithParam(string key, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch)
+ {
+ return WithParam(key, false, matchBehaviour);
+ }
+
+ ///
+ public IRequestBuilder WithParam(string key, bool ignoreCase, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch)
+ {
+ Check.NotNull(key, nameof(key));
+
+ _requestMatchers.Add(new RequestMessageParamMatcher(matchBehaviour, key, ignoreCase));
+ return this;
+ }
+
+ ///
+ public IRequestBuilder WithParam(string key, params string[] values)
+ {
+ return WithParam(key, MatchBehaviour.AcceptOnMatch, false, values);
+ }
+
+ ///
+ public IRequestBuilder WithParam(string key, bool ignoreCase, params string[] values)
+ {
+ return WithParam(key, MatchBehaviour.AcceptOnMatch, ignoreCase, values);
+ }
+
+ ///
+ public IRequestBuilder WithParam(string key, params IStringMatcher[] matchers)
+ {
+ return WithParam(key, MatchBehaviour.AcceptOnMatch, false, matchers);
+ }
+
+ ///
+ public IRequestBuilder WithParam(string key, bool ignoreCase, params IStringMatcher[] matchers)
+ {
+ return WithParam(key, MatchBehaviour.AcceptOnMatch, ignoreCase, matchers);
+ }
+
+ ///
+ public IRequestBuilder WithParam(string key, MatchBehaviour matchBehaviour, params string[] values)
+ {
+ return WithParam(key, matchBehaviour, false, values);
+ }
+
+ ///
+ public IRequestBuilder WithParam(string key, MatchBehaviour matchBehaviour, bool ignoreCase = false, params string[] values)
+ {
+ Check.NotNull(key, nameof(key));
+
+ _requestMatchers.Add(new RequestMessageParamMatcher(matchBehaviour, key, ignoreCase, values));
+ return this;
+ }
+
+ public IRequestBuilder WithParam(string key, MatchBehaviour matchBehaviour, params IStringMatcher[] matchers)
+ {
+ return WithParam(key, matchBehaviour, false, matchers);
+ }
+
+ ///
+ public IRequestBuilder WithParam(string key, MatchBehaviour matchBehaviour, bool ignoreCase, params IStringMatcher[] matchers)
+ {
+ Check.NotNull(key, nameof(key));
+
+ _requestMatchers.Add(new RequestMessageParamMatcher(matchBehaviour, key, ignoreCase, matchers));
+ return this;
+ }
+
+ ///
+ public IRequestBuilder WithParam(params Func>, bool>[] funcs)
+ {
+ Check.NotNullOrEmpty(funcs, nameof(funcs));
+
+ _requestMatchers.Add(new RequestMessageParamMatcher(funcs));
+ return this;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/WireMock.Net/RequestBuilders/Request.cs b/src/WireMock.Net/RequestBuilders/Request.cs
index cd32f121..054f8d2d 100644
--- a/src/WireMock.Net/RequestBuilders/Request.cs
+++ b/src/WireMock.Net/RequestBuilders/Request.cs
@@ -12,7 +12,7 @@ namespace WireMock.RequestBuilders
///
/// The requests.
///
- public class Request : RequestMessageCompositeMatcher, IRequestBuilder
+ public partial class Request : RequestMessageCompositeMatcher, IRequestBuilder
{
private readonly IList _requestMatchers;
@@ -291,54 +291,6 @@ namespace WireMock.RequestBuilders
return this;
}
- ///
- public IRequestBuilder WithParam(string key, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch)
- {
- Check.NotNull(key, nameof(key));
-
- _requestMatchers.Add(new RequestMessageParamMatcher(matchBehaviour, key));
- return this;
- }
-
- ///
- public IRequestBuilder WithParam(string key, params string[] values)
- {
- return WithParam(key, MatchBehaviour.AcceptOnMatch, values);
- }
-
- ///
- public IRequestBuilder WithParam(string key, params IStringMatcher[] matchers)
- {
- return WithParam(key, MatchBehaviour.AcceptOnMatch, matchers);
- }
-
- ///
- public IRequestBuilder WithParam(string key, MatchBehaviour matchBehaviour, params string[] values)
- {
- Check.NotNull(key, nameof(key));
-
- _requestMatchers.Add(new RequestMessageParamMatcher(matchBehaviour, key, values));
- return this;
- }
-
- ///
- public IRequestBuilder WithParam(string key, MatchBehaviour matchBehaviour, params IStringMatcher[] matchers)
- {
- Check.NotNull(key, nameof(key));
-
- _requestMatchers.Add(new RequestMessageParamMatcher(matchBehaviour, key, matchers));
- return this;
- }
-
- ///
- public IRequestBuilder WithParam(params Func>, bool>[] funcs)
- {
- Check.NotNullOrEmpty(funcs, nameof(funcs));
-
- _requestMatchers.Add(new RequestMessageParamMatcher(funcs));
- return this;
- }
-
///
public IRequestBuilder WithHeader(string name, string pattern, MatchBehaviour matchBehaviour)
{
diff --git a/src/WireMock.Net/RequestMessage.cs b/src/WireMock.Net/RequestMessage.cs
index 5a7262fe..46583b43 100644
--- a/src/WireMock.Net/RequestMessage.cs
+++ b/src/WireMock.Net/RequestMessage.cs
@@ -1,8 +1,8 @@
-using System;
+using JetBrains.Annotations;
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
-using JetBrains.Annotations;
using WireMock.Models;
using WireMock.Util;
using WireMock.Validation;
@@ -211,15 +211,18 @@ namespace WireMock
/// Get a query parameter.
///
/// The key.
+ /// Defines if the key should be matched using case-ignore.
/// The query parameter.
- public WireMockList GetParameter(string key)
+ public WireMockList GetParameter(string key, bool ignoreCase = false)
{
if (Query == null)
{
return null;
}
- return Query.ContainsKey(key) ? Query[key] : null;
+ var query = !ignoreCase ? Query : new Dictionary>(Query, StringComparer.OrdinalIgnoreCase);
+
+ return query.ContainsKey(key) ? query[key] : null;
}
}
}
\ No newline at end of file
diff --git a/src/WireMock.Net/Serialization/MappingConverter.cs b/src/WireMock.Net/Serialization/MappingConverter.cs
index 46b5af01..0ad9f9ec 100644
--- a/src/WireMock.Net/Serialization/MappingConverter.cs
+++ b/src/WireMock.Net/Serialization/MappingConverter.cs
@@ -66,6 +66,7 @@ namespace WireMock.Serialization
Params = paramsMatchers != null && paramsMatchers.Any() ? paramsMatchers.Select(pm => new ParamModel
{
Name = pm.Key,
+ IgnoreCase = pm.IgnoreCase,
Matchers = MatcherMapper.Map(pm.Matchers)
}).ToList() : null,
diff --git a/src/WireMock.Net/Server/FluentMockServer.Admin.cs b/src/WireMock.Net/Server/FluentMockServer.Admin.cs
index e7a8011d..84fa0057 100644
--- a/src/WireMock.Net/Server/FluentMockServer.Admin.cs
+++ b/src/WireMock.Net/Server/FluentMockServer.Admin.cs
@@ -265,7 +265,7 @@ namespace WireMock.Server
request.WithPath(requestMessage.Path);
request.UsingMethod(requestMessage.Method);
- requestMessage.Query.Loop((key, value) => request.WithParam(key, value.ToArray()));
+ requestMessage.Query.Loop((key, value) => request.WithParam(key, false, value.ToArray()));
requestMessage.Cookies.Loop((key, value) => request.WithCookie(key, value));
var allBlackListedHeaders = new List(blacklistedHeaders) { "Cookie" };
@@ -685,7 +685,8 @@ namespace WireMock.Server
{
foreach (var paramModel in requestModel.Params.Where(c => c.Matchers != null))
{
- requestBuilder = requestBuilder.WithParam(paramModel.Name, paramModel.Matchers.Select(MatcherMapper.Map).Cast().ToArray());
+ bool ignoreCase = paramModel?.IgnoreCase ?? false;
+ requestBuilder = requestBuilder.WithParam(paramModel.Name, ignoreCase, paramModel.Matchers.Select(MatcherMapper.Map).Cast().ToArray());
}
}
diff --git a/test/WireMock.Net.Tests/RequestMatchers/RequestMessageParamMatcherTests.cs b/test/WireMock.Net.Tests/RequestMatchers/RequestMessageParamMatcherTests.cs
index 78585e4c..4e73db18 100644
--- a/test/WireMock.Net.Tests/RequestMatchers/RequestMessageParamMatcherTests.cs
+++ b/test/WireMock.Net.Tests/RequestMatchers/RequestMessageParamMatcherTests.cs
@@ -8,12 +8,27 @@ namespace WireMock.Net.Tests.RequestMatchers
{
public class RequestMessageParamMatcherTests
{
+ [Fact]
+ public void RequestMessageParamMatcher_GetMatchingScore_IgnoreCaseKeyWithValuesPresentInUrl_MatchExactOnStringValues()
+ {
+ // Assign
+ var requestMessage = new RequestMessage(new UrlDetails("http://localhost?key=test1"), "GET", "127.0.0.1");
+ var matcher = new RequestMessageParamMatcher(MatchBehaviour.AcceptOnMatch, "KeY", true, new[] { "test1" });
+
+ // Act
+ var result = new RequestMatchResult();
+ double score = matcher.GetMatchingScore(requestMessage, result);
+
+ // Assert
+ Check.That(score).IsEqualTo(1.0d);
+ }
+
[Fact]
public void RequestMessageParamMatcher_GetMatchingScore_KeyWithValuesPresentInUrl_MatchExactOnStringValues()
{
// Assign
var requestMessage = new RequestMessage(new UrlDetails("http://localhost?key=test1,test2"), "GET", "127.0.0.1");
- var matcher = new RequestMessageParamMatcher(MatchBehaviour.AcceptOnMatch, "key", new[] { "test1", "test2" });
+ var matcher = new RequestMessageParamMatcher(MatchBehaviour.AcceptOnMatch, "key", false, new[] { "test1", "test2" });
// Act
var result = new RequestMatchResult();
@@ -28,7 +43,7 @@ namespace WireMock.Net.Tests.RequestMatchers
{
// Assign
var requestMessage = new RequestMessage(new UrlDetails("http://localhost?key=test1,test2"), "GET", "127.0.0.1");
- var matcher = new RequestMessageParamMatcher(MatchBehaviour.AcceptOnMatch, "key", new IStringMatcher[] { new ExactMatcher("test1"), new ExactMatcher("test2") });
+ var matcher = new RequestMessageParamMatcher(MatchBehaviour.AcceptOnMatch, "key", false, new IStringMatcher[] { new ExactMatcher("test1"), new ExactMatcher("test2") });
// Act
var result = new RequestMatchResult();
@@ -43,7 +58,7 @@ namespace WireMock.Net.Tests.RequestMatchers
{
// Assign
var requestMessage = new RequestMessage(new UrlDetails("http://localhost?key=test0,test2"), "GET", "127.0.0.1");
- var matcher = new RequestMessageParamMatcher(MatchBehaviour.AcceptOnMatch, "key", new[] { "test1", "test2" });
+ var matcher = new RequestMessageParamMatcher(MatchBehaviour.AcceptOnMatch, "key", false, new[] { "test1", "test2" });
// Act
var result = new RequestMatchResult();
@@ -58,7 +73,7 @@ namespace WireMock.Net.Tests.RequestMatchers
{
// Assign
var requestMessage = new RequestMessage(new UrlDetails("http://localhost?key"), "GET", "127.0.0.1");
- var matcher = new RequestMessageParamMatcher(MatchBehaviour.AcceptOnMatch, "key", new[] { "test1", "test2" });
+ var matcher = new RequestMessageParamMatcher(MatchBehaviour.AcceptOnMatch, "key", false, new[] { "test1", "test2" });
// Act
var result = new RequestMatchResult();
@@ -73,7 +88,7 @@ namespace WireMock.Net.Tests.RequestMatchers
{
// Assign
var requestMessage = new RequestMessage(new UrlDetails("http://localhost?key"), "GET", "127.0.0.1");
- var matcher = new RequestMessageParamMatcher(MatchBehaviour.AcceptOnMatch, "key");
+ var matcher = new RequestMessageParamMatcher(MatchBehaviour.AcceptOnMatch, "key", false);
// Act
var result = new RequestMatchResult();
@@ -88,7 +103,7 @@ namespace WireMock.Net.Tests.RequestMatchers
{
// Assign
var requestMessage = new RequestMessage(new UrlDetails("http://localhost?key"), "GET", "127.0.0.1");
- var matcher = new RequestMessageParamMatcher(MatchBehaviour.AcceptOnMatch, "key", new string[] { });
+ var matcher = new RequestMessageParamMatcher(MatchBehaviour.AcceptOnMatch, "key", false, new string[] { });
// Act
var result = new RequestMatchResult();
@@ -103,7 +118,7 @@ namespace WireMock.Net.Tests.RequestMatchers
{
// Assign
var requestMessage = new RequestMessage(new UrlDetails("http://localhost?key=frank@contoso.com"), "GET", "127.0.0.1");
- var matcher = new RequestMessageParamMatcher(MatchBehaviour.AcceptOnMatch, "key");
+ var matcher = new RequestMessageParamMatcher(MatchBehaviour.AcceptOnMatch, "key", false);
// Act
var result = new RequestMatchResult();
diff --git a/test/WireMock.Net.Tests/RequestMessageTests.cs b/test/WireMock.Net.Tests/RequestMessageTests.cs
index 8d04bece..f4828818 100644
--- a/test/WireMock.Net.Tests/RequestMessageTests.cs
+++ b/test/WireMock.Net.Tests/RequestMessageTests.cs
@@ -39,6 +39,16 @@ namespace WireMock.Net.Tests
Check.That(request.GetParameter("foo")).ContainsExactly("bar");
}
+ [Fact]
+ public void RequestMessage_ParseQuery_SingleKey_SingleValue_WithIgnoreCase()
+ {
+ // Assign
+ var request = new RequestMessage(new UrlDetails("http://localhost?foo=bar"), "POST", ClientIp);
+
+ // Assert
+ Check.That(request.GetParameter("FoO", true)).ContainsExactly("bar");
+ }
+
[Fact]
public void RequestMessage_ParseQuery_MultipleKeys_MultipleValues()
{