diff --git a/src/WireMock.Net.Abstractions/Admin/Mappings/ParamModel.cs b/src/WireMock.Net.Abstractions/Admin/Mappings/ParamModel.cs index 7be363f1..d5559ec6 100644 --- a/src/WireMock.Net.Abstractions/Admin/Mappings/ParamModel.cs +++ b/src/WireMock.Net.Abstractions/Admin/Mappings/ParamModel.cs @@ -16,6 +16,11 @@ public class ParamModel /// public bool? IgnoreCase { get; set; } + /// + /// Gets or sets the Reject on match for the Param Name. + /// + public bool? RejectOnMatch { get; set; } + /// /// Gets or sets the matchers. /// diff --git a/src/WireMock.Net/Matchers/Request/RequestMessageCookieMatcher.cs b/src/WireMock.Net/Matchers/Request/RequestMessageCookieMatcher.cs index 4cacde4e..09ee75be 100644 --- a/src/WireMock.Net/Matchers/Request/RequestMessageCookieMatcher.cs +++ b/src/WireMock.Net/Matchers/Request/RequestMessageCookieMatcher.cs @@ -11,9 +11,15 @@ namespace WireMock.Matchers.Request; /// public class RequestMessageCookieMatcher : IRequestMatcher { - private readonly MatchBehaviour _matchBehaviour; + /// + /// MatchBehaviour + /// + public MatchBehaviour MatchBehaviour { get; } - private readonly bool _ignoreCase; + /// + /// IgnoreCase + /// + public bool IgnoreCase { get; } /// /// The functions @@ -39,8 +45,8 @@ public class RequestMessageCookieMatcher : IRequestMatcher /// The match behaviour. public RequestMessageCookieMatcher(MatchBehaviour matchBehaviour, string name, string pattern, bool ignoreCase) { - _matchBehaviour = matchBehaviour; - _ignoreCase = ignoreCase; + MatchBehaviour = matchBehaviour; + IgnoreCase = ignoreCase; Name = Guard.NotNull(name); Matchers = new IStringMatcher[] { new WildcardMatcher(matchBehaviour, Guard.NotNull(pattern), ignoreCase) }; } @@ -67,10 +73,10 @@ public class RequestMessageCookieMatcher : IRequestMatcher /// Ignore the case from the pattern. public RequestMessageCookieMatcher(MatchBehaviour matchBehaviour, string name, bool ignoreCase, params IStringMatcher[] matchers) { - _matchBehaviour = matchBehaviour; + MatchBehaviour = matchBehaviour; Name = Guard.NotNull(name); Matchers = Guard.NotNull(matchers); - _ignoreCase = ignoreCase; + IgnoreCase = ignoreCase; } /// @@ -96,11 +102,11 @@ public class RequestMessageCookieMatcher : IRequestMatcher { if (requestMessage.Cookies == null) { - return MatchBehaviourHelper.Convert(_matchBehaviour, MatchScores.Mismatch); + return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.Mismatch); } // Check if we want to use IgnoreCase to compare the Cookie-Name and Cookie-Value - var cookies = !_ignoreCase ? requestMessage.Cookies : new Dictionary(requestMessage.Cookies, StringComparer.OrdinalIgnoreCase); + var cookies = !IgnoreCase ? requestMessage.Cookies : new Dictionary(requestMessage.Cookies, StringComparer.OrdinalIgnoreCase); if (Funcs != null) { @@ -114,7 +120,7 @@ public class RequestMessageCookieMatcher : IRequestMatcher if (!cookies.ContainsKey(Name)) { - return MatchBehaviourHelper.Convert(_matchBehaviour, MatchScores.Mismatch); + return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.Mismatch); } return Matchers.Max(m => m.IsMatch(cookies[Name])); diff --git a/src/WireMock.Net/Matchers/Request/RequestMessageHeaderMatcher.cs b/src/WireMock.Net/Matchers/Request/RequestMessageHeaderMatcher.cs index cb7ec144..00e0c1da 100644 --- a/src/WireMock.Net/Matchers/Request/RequestMessageHeaderMatcher.cs +++ b/src/WireMock.Net/Matchers/Request/RequestMessageHeaderMatcher.cs @@ -12,8 +12,15 @@ namespace WireMock.Matchers.Request; /// public class RequestMessageHeaderMatcher : IRequestMatcher { - private readonly MatchBehaviour _matchBehaviour; - private readonly bool _ignoreCase; + /// + /// MatchBehaviour + /// + public MatchBehaviour MatchBehaviour { get; } + + /// + /// IgnoreCase + /// + public bool IgnoreCase { get; } /// /// The functions @@ -47,8 +54,8 @@ public class RequestMessageHeaderMatcher : IRequestMatcher Guard.NotNull(name); Guard.NotNull(pattern); - _matchBehaviour = matchBehaviour; - _ignoreCase = ignoreCase; + MatchBehaviour = matchBehaviour; + IgnoreCase = ignoreCase; Name = name; Matchers = new IStringMatcher[] { new WildcardMatcher(matchBehaviour, pattern, ignoreCase) }; } @@ -80,11 +87,11 @@ public class RequestMessageHeaderMatcher : IRequestMatcher Guard.NotNull(name); Guard.NotNull(matchers); - _matchBehaviour = matchBehaviour; + MatchBehaviour = matchBehaviour; MatchOperator = matchOperator; Name = name; Matchers = matchers; - _ignoreCase = ignoreCase; + IgnoreCase = ignoreCase; } /// @@ -108,11 +115,11 @@ public class RequestMessageHeaderMatcher : IRequestMatcher { if (requestMessage.Headers == null) { - return MatchBehaviourHelper.Convert(_matchBehaviour, MatchScores.Mismatch); + return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.Mismatch); } // Check if we want to use IgnoreCase to compare the Header-Name and Header-Value(s) - var headers = !_ignoreCase ? requestMessage.Headers : new Dictionary>(requestMessage.Headers, StringComparer.OrdinalIgnoreCase); + var headers = !IgnoreCase ? requestMessage.Headers : new Dictionary>(requestMessage.Headers, StringComparer.OrdinalIgnoreCase); if (Funcs != null) { @@ -124,7 +131,7 @@ public class RequestMessageHeaderMatcher : IRequestMatcher { if (!headers.ContainsKey(Name)) { - return MatchBehaviourHelper.Convert(_matchBehaviour, MatchScores.Mismatch); + return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.Mismatch); } var results = new List(); @@ -138,6 +145,6 @@ public class RequestMessageHeaderMatcher : IRequestMatcher return MatchResult.From(results, MatchOperator); } - return MatchBehaviourHelper.Convert(_matchBehaviour, MatchScores.Mismatch); + return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.Mismatch); } } \ No newline at end of file diff --git a/src/WireMock.Net/Matchers/Request/RequestMessageParamMatcher.cs b/src/WireMock.Net/Matchers/Request/RequestMessageParamMatcher.cs index e8b451f4..97070352 100644 --- a/src/WireMock.Net/Matchers/Request/RequestMessageParamMatcher.cs +++ b/src/WireMock.Net/Matchers/Request/RequestMessageParamMatcher.cs @@ -29,7 +29,7 @@ public class RequestMessageParamMatcher : IRequestMatcher /// /// Defines if the key should be matched using case-ignore. /// - public bool? IgnoreCase { get; } + public bool IgnoreCase { get; } /// /// The matchers. @@ -96,7 +96,7 @@ public class RequestMessageParamMatcher : IRequestMatcher return MatchScores.ToScore(requestMessage.Query != null && Funcs.Any(f => f(requestMessage.Query))); } - var valuesPresentInRequestMessage = ((RequestMessage)requestMessage).GetParameter(Key, IgnoreCase ?? false); + var valuesPresentInRequestMessage = ((RequestMessage)requestMessage).GetParameter(Key, IgnoreCase); if (valuesPresentInRequestMessage == null) { // Key is not present at all, just return Mismatch diff --git a/src/WireMock.Net/Serialization/MappingConverter.cs b/src/WireMock.Net/Serialization/MappingConverter.cs index 6b45b6a6..eccacf8a 100644 --- a/src/WireMock.Net/Serialization/MappingConverter.cs +++ b/src/WireMock.Net/Serialization/MappingConverter.cs @@ -259,19 +259,24 @@ internal class MappingConverter Headers = headerMatchers.Any() ? headerMatchers.Select(hm => new HeaderModel { Name = hm.Name, - Matchers = _mapper.Map(hm.Matchers) + IgnoreCase = hm.IgnoreCase ? true : null, + RejectOnMatch = hm.MatchBehaviour == MatchBehaviour.RejectOnMatch ? true : null, + Matchers = _mapper.Map(hm.Matchers), }).ToList() : null, Cookies = cookieMatchers.Any() ? cookieMatchers.Select(cm => new CookieModel { Name = cm.Name, + IgnoreCase = cm.IgnoreCase ? true : null, + RejectOnMatch = cm.MatchBehaviour == MatchBehaviour.RejectOnMatch ? true : null, Matchers = _mapper.Map(cm.Matchers) }).ToList() : null, Params = paramsMatchers.Any() ? paramsMatchers.Select(pm => new ParamModel { Name = pm.Key, - IgnoreCase = pm.IgnoreCase == true ? true : null, + IgnoreCase = pm.IgnoreCase ? true : null, + RejectOnMatch = pm.MatchBehaviour == MatchBehaviour.RejectOnMatch ? true : null, Matchers = _mapper.Map(pm.Matchers) }).ToList() : null }, diff --git a/test/WireMock.Net.Tests/Serialization/MappingConverterTests.ToMappingModel_WithHeader_And_Cookie_ReturnsCorrectModel.verified.txt b/test/WireMock.Net.Tests/Serialization/MappingConverterTests.ToMappingModel_WithHeader_And_Cookie_ReturnsCorrectModel.verified.txt new file mode 100644 index 00000000..36bdf49d --- /dev/null +++ b/test/WireMock.Net.Tests/Serialization/MappingConverterTests.ToMappingModel_WithHeader_And_Cookie_ReturnsCorrectModel.verified.txt @@ -0,0 +1,122 @@ +{ + Guid: Guid_1, + UpdatedAt: DateTime_1, + Request: { + Headers: [ + { + Name: MatchBehaviour.RejectOnMatch, + Matchers: [ + { + Name: WildcardMatcher, + Pattern: hv-1, + IgnoreCase: true, + RejectOnMatch: true + } + ], + IgnoreCase: true, + RejectOnMatch: true + }, + { + Name: MatchBehaviour.AcceptOnMatch, + Matchers: [ + { + Name: WildcardMatcher, + Pattern: hv-2, + IgnoreCase: true + } + ], + IgnoreCase: true + }, + { + Name: IgnoreCase_false, + Matchers: [ + { + Name: WildcardMatcher, + Pattern: hv-3, + IgnoreCase: false + } + ] + }, + { + Name: IgnoreCase_true, + Matchers: [ + { + Name: WildcardMatcher, + Pattern: hv-4, + IgnoreCase: true + } + ], + IgnoreCase: true + }, + { + Name: ExactMatcher, + Matchers: [ + { + Name: ExactMatcher, + Pattern: h-exact, + IgnoreCase: false + } + ] + } + ], + Cookies: [ + { + Name: MatchBehaviour.RejectOnMatch, + Matchers: [ + { + Name: WildcardMatcher, + Pattern: cv-1, + IgnoreCase: true, + RejectOnMatch: true + } + ], + IgnoreCase: true, + RejectOnMatch: true + }, + { + Name: MatchBehaviour.AcceptOnMatch, + Matchers: [ + { + Name: WildcardMatcher, + Pattern: cv-2, + IgnoreCase: true + } + ], + IgnoreCase: true + }, + { + Name: IgnoreCase_false, + Matchers: [ + { + Name: WildcardMatcher, + Pattern: cv-3, + IgnoreCase: false + } + ] + }, + { + Name: IgnoreCase_true, + Matchers: [ + { + Name: WildcardMatcher, + Pattern: cv-4, + IgnoreCase: true + } + ], + IgnoreCase: true + }, + { + Name: ExactMatcher, + Matchers: [ + { + Name: ExactMatcher, + Pattern: c-exact, + IgnoreCase: false + } + ] + } + ] + }, + Response: {}, + UseWebhooksFireAndForget: false +} \ No newline at end of file diff --git a/test/WireMock.Net.Tests/Serialization/MappingConverterTests.ToMappingModel_WithParam_ReturnsCorrectModel.verified.txt b/test/WireMock.Net.Tests/Serialization/MappingConverterTests.ToMappingModel_WithParam_ReturnsCorrectModel.verified.txt new file mode 100644 index 00000000..ede5275c --- /dev/null +++ b/test/WireMock.Net.Tests/Serialization/MappingConverterTests.ToMappingModel_WithParam_ReturnsCorrectModel.verified.txt @@ -0,0 +1,59 @@ +{ + Guid: Guid_1, + UpdatedAt: DateTime_1, + Request: { + Params: [ + { + Name: MatchBehaviour.RejectOnMatch, + RejectOnMatch: true + }, + { + Name: MatchBehaviour.RejectOnMatch|IgnoreCase_false, + RejectOnMatch: true + }, + { + Name: IgnoreCase_false, + Matchers: [ + { + Name: ExactMatcher, + Pattern: pv-3a, + IgnoreCase: false + }, + { + Name: ExactMatcher, + Pattern: pv-3b, + IgnoreCase: false + } + ] + }, + { + Name: IgnoreCase_true, + IgnoreCase: true, + Matchers: [ + { + Name: ExactMatcher, + Pattern: pv-3a, + IgnoreCase: true + }, + { + Name: ExactMatcher, + Pattern: pv-3b, + IgnoreCase: true + } + ] + }, + { + Name: ExactMatcher, + Matchers: [ + { + Name: ExactMatcher, + Pattern: exact, + IgnoreCase: false + } + ] + } + ] + }, + Response: {}, + UseWebhooksFireAndForget: false +} \ No newline at end of file diff --git a/test/WireMock.Net.Tests/Serialization/MappingConverterTests.cs b/test/WireMock.Net.Tests/Serialization/MappingConverterTests.cs index 3e648f82..de85ab34 100644 --- a/test/WireMock.Net.Tests/Serialization/MappingConverterTests.cs +++ b/test/WireMock.Net.Tests/Serialization/MappingConverterTests.cs @@ -5,6 +5,7 @@ using System.Threading; using System.Threading.Tasks; using FluentAssertions; using VerifyXunit; +using WireMock.Matchers; using WireMock.Models; using WireMock.RequestBuilders; using WireMock.ResponseBuilders; @@ -362,6 +363,60 @@ public partial class MappingConverterTests return Verifier.Verify(model); } + [Fact] + public Task ToMappingModel_WithHeader_And_Cookie_ReturnsCorrectModel() + { + // Assign + var request = Request.Create() + .WithHeader("MatchBehaviour.RejectOnMatch", "hv-1", MatchBehaviour.RejectOnMatch) + .WithHeader("MatchBehaviour.AcceptOnMatch", "hv-2", MatchBehaviour.AcceptOnMatch) + .WithHeader("IgnoreCase_false", "hv-3", false) + .WithHeader("IgnoreCase_true", "hv-4") + .WithHeader("ExactMatcher", new ExactMatcher("h-exact")) + + .WithCookie("MatchBehaviour.RejectOnMatch", "cv-1", MatchBehaviour.RejectOnMatch) + .WithCookie("MatchBehaviour.AcceptOnMatch", "cv-2", MatchBehaviour.AcceptOnMatch) + .WithCookie("IgnoreCase_false", "cv-3", false) + .WithCookie("IgnoreCase_true", "cv-4") + .WithCookie("ExactMatcher", new ExactMatcher("c-exact")) + ; + var response = Response.Create(); + var mapping = new Mapping(_guid, _updatedAt, null, null, null, _settings, request, response, 0, null, null, null, null, null, false, null, data: null, probability: null); + + // Act + var model = _sut.ToMappingModel(mapping); + + // Assert + model.Should().NotBeNull(); + + // Verify + return Verifier.Verify(model); + } + + [Fact] + public Task ToMappingModel_WithParam_ReturnsCorrectModel() + { + // Assign + var request = Request.Create() + .WithParam("MatchBehaviour.RejectOnMatch", MatchBehaviour.RejectOnMatch) + .WithParam("MatchBehaviour.RejectOnMatch|IgnoreCase_false", false, MatchBehaviour.RejectOnMatch) + .WithParam("IgnoreCase_false", false, "pv-3a", "pv-3b") + .WithParam("IgnoreCase_true", true, "pv-3a", "pv-3b") + .WithParam("ExactMatcher", new ExactMatcher("exact")) + ; + var response = Response.Create(); + var mapping = new Mapping(_guid, _updatedAt, null, null, null, _settings, request, response, 0, null, null, null, null, null, false, null, data: null, probability: null); + + // Act + var model = _sut.ToMappingModel(mapping); + + // Assert + model.Should().NotBeNull(); + + // Verify + return Verifier.Verify(model); + } + #if GRAPHQL [Fact] public Task ToMappingModel_Request_WithBodyAsGraphQLSchema_ReturnsCorrectModel()