Skip to content

Commit

Permalink
ExactMatcher : IgnoreCase (#817)
Browse files Browse the repository at this point in the history
* ...

* mm

* fix some null warnings

* fx
  • Loading branch information
StefH authored Oct 15, 2022
1 parent b523ab9 commit 55afc80
Show file tree
Hide file tree
Showing 20 changed files with 812 additions and 698 deletions.
6 changes: 3 additions & 3 deletions src/WireMock.Net.Abstractions/Models/IBodyData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ public interface IBodyData
/// <summary>
/// The body (as bytearray).
/// </summary>
byte[] BodyAsBytes { get; set; }
byte[]? BodyAsBytes { get; set; }

/// <summary>
/// Gets or sets the body as a file.
/// </summary>
string BodyAsFile { get; set; }
string? BodyAsFile { get; set; }

/// <summary>
/// Is the body as file cached?
Expand All @@ -38,7 +38,7 @@ public interface IBodyData
/// <summary>
/// The body as string, this is defined when BodyAsString or BodyAsJson are not null.
/// </summary>
string BodyAsString { get; set; }
string? BodyAsString { get; set; }

/// <summary>
/// The detected body type (detection based on body content).
Expand Down
29 changes: 24 additions & 5 deletions src/WireMock.Net/Matchers/ExactMatcher.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
using System;
using System.Linq;
using AnyOfTypes;
using Stef.Validation;
using WireMock.Extensions;
using WireMock.Models;

namespace WireMock.Matchers;

/// <summary>
/// ExactMatcher
/// </summary>
/// <seealso cref="IStringMatcher" />
public class ExactMatcher : IStringMatcher
/// <seealso cref="IStringMatcher" /> and <seealso cref="IIgnoreCaseMatcher" />
public class ExactMatcher : IStringMatcher, IIgnoreCaseMatcher
{
private readonly AnyOf<string, StringPattern>[] _values;

Expand All @@ -24,19 +24,30 @@ public class ExactMatcher : IStringMatcher
/// Initializes a new instance of the <see cref="ExactMatcher"/> class.
/// </summary>
/// <param name="values">The values.</param>
public ExactMatcher(params AnyOf<string, StringPattern>[] values) : this(MatchBehaviour.AcceptOnMatch, false, MatchOperator.Or, values)
public ExactMatcher(params AnyOf<string, StringPattern>[] values) : this(MatchBehaviour.AcceptOnMatch, false, false, MatchOperator.Or, values)
{
}

/// <summary>
/// Initializes a new instance of the <see cref="ExactMatcher"/> class.
/// </summary>
/// <param name="ignoreCase">Ignore the case from the pattern(s).</param>
/// <param name="values">The values.</param>
public ExactMatcher(bool ignoreCase, params AnyOf<string, StringPattern>[] values) : this(MatchBehaviour.AcceptOnMatch, ignoreCase, false, MatchOperator.Or, values)
{
}

/// <summary>
/// Initializes a new instance of the <see cref="ExactMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="ignoreCase">Ignore the case from the pattern(s).</param>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
/// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use. (default = "Or")</param>
/// <param name="values">The values.</param>
public ExactMatcher(
MatchBehaviour matchBehaviour,
bool ignoreCase = false,
bool throwException = false,
MatchOperator matchOperator = MatchOperator.Or,
params AnyOf<string, StringPattern>[] values)
Expand All @@ -45,13 +56,18 @@ public ExactMatcher(

MatchBehaviour = matchBehaviour;
ThrowException = throwException;
IgnoreCase = ignoreCase;
MatchOperator = matchOperator;
}

/// <inheritdoc cref="IStringMatcher.IsMatch"/>
public double IsMatch(string? input)
{
double score = MatchScores.ToScore(_values.Select(v => v.GetPattern() == input).ToArray(), MatchOperator);
Func<string?, bool> equals = IgnoreCase
? pattern => string.Equals(pattern, input, StringComparison.OrdinalIgnoreCase)
: pattern => pattern == input;

double score = MatchScores.ToScore(_values.Select(v => equals(v)).ToArray(), MatchOperator);
return MatchBehaviourHelper.Convert(MatchBehaviour, score);
}

Expand All @@ -66,4 +82,7 @@ public AnyOf<string, StringPattern>[] GetPatterns()

/// <inheritdoc cref="IMatcher.Name"/>
public string Name => "ExactMatcher";

/// <inheritdoc />
public bool IgnoreCase { get; }
}
2 changes: 1 addition & 1 deletion src/WireMock.Net/Matchers/JsonPartialMatcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public JsonPartialMatcher(MatchBehaviour matchBehaviour, object value, bool igno
/// <inheritdoc />
protected override bool IsMatch(string value, string input)
{
var exactStringMatcher = new ExactMatcher(MatchBehaviour.AcceptOnMatch, ThrowException, MatchOperator.Or, value);
var exactStringMatcher = new ExactMatcher(MatchBehaviour.AcceptOnMatch, IgnoreCase, ThrowException, MatchOperator.Or, value);
return MatchScores.IsPerfect(exactStringMatcher.IsMatch(input));
}
}
2 changes: 1 addition & 1 deletion src/WireMock.Net/Matchers/MatchOperator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,5 @@ public enum MatchOperator
/// <summary>
/// The average value from all patterns.
/// </summary>
Average,
Average
}
18 changes: 9 additions & 9 deletions src/WireMock.Net/Matchers/Request/RequestMessageBodyMatcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,22 @@ public class RequestMessageBodyMatcher : IRequestMatcher
/// <summary>
/// The body function
/// </summary>
public Func<string, bool>? Func { get; }
public Func<string?, bool>? Func { get; }

/// <summary>
/// The body data function for byte[]
/// </summary>
public Func<byte[], bool>? DataFunc { get; }
public Func<byte[]?, bool>? DataFunc { get; }

/// <summary>
/// The body data function for json
/// </summary>
public Func<object, bool>? JsonFunc { get; }
public Func<object?, bool>? JsonFunc { get; }

/// <summary>
/// The body data function for BodyData
/// </summary>
public Func<IBodyData, bool>? BodyDataFunc { get; }
public Func<IBodyData?, bool>? BodyDataFunc { get; }

/// <summary>
/// The matchers.
Expand Down Expand Up @@ -77,7 +77,7 @@ public RequestMessageBodyMatcher(MatchBehaviour matchBehaviour, object body) :
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
/// </summary>
/// <param name="func">The function.</param>
public RequestMessageBodyMatcher(Func<string, bool> func)
public RequestMessageBodyMatcher(Func<string?, bool> func)
{
Func = Guard.NotNull(func);
}
Expand All @@ -86,7 +86,7 @@ public RequestMessageBodyMatcher(Func<string, bool> func)
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
/// </summary>
/// <param name="func">The function.</param>
public RequestMessageBodyMatcher(Func<byte[], bool> func)
public RequestMessageBodyMatcher(Func<byte[]?, bool> func)
{
DataFunc = Guard.NotNull(func);
}
Expand All @@ -95,7 +95,7 @@ public RequestMessageBodyMatcher(Func<byte[], bool> func)
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
/// </summary>
/// <param name="func">The function.</param>
public RequestMessageBodyMatcher(Func<object, bool> func)
public RequestMessageBodyMatcher(Func<object?, bool> func)
{
JsonFunc = Guard.NotNull(func);
}
Expand Down Expand Up @@ -158,9 +158,9 @@ private static double CalculateMatchScore(IRequestMessage requestMessage, IMatch
{
// If the body is a byte array, try to match.
var detectedBodyType = requestMessage.BodyData?.DetectedBodyType;
if (detectedBodyType == BodyType.Bytes || detectedBodyType == BodyType.String)
if (detectedBodyType is BodyType.Bytes or BodyType.String)
{
return exactObjectMatcher.IsMatch(requestMessage.BodyData.BodyAsBytes);
return exactObjectMatcher.IsMatch(requestMessage.BodyData?.BodyAsBytes);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public RequestMessageParamMatcher(MatchBehaviour matchBehaviour, string key, boo
/// <param name="key">The key.</param>
/// <param name="ignoreCase">Defines if the key should be matched using case-ignore.</param>
/// <param name="values">The values.</param>
public RequestMessageParamMatcher(MatchBehaviour matchBehaviour, string key, bool ignoreCase, string[]? values) : this(matchBehaviour, key, ignoreCase, values?.Select(value => new ExactMatcher(matchBehaviour, false, MatchOperator.And, value)).Cast<IStringMatcher>().ToArray())
public RequestMessageParamMatcher(MatchBehaviour matchBehaviour, string key, bool ignoreCase, string[]? values) : this(matchBehaviour, key, ignoreCase, values?.Select(value => new ExactMatcher(matchBehaviour, ignoreCase, false, MatchOperator.And, value)).Cast<IStringMatcher>().ToArray())
{
}

Expand Down
2 changes: 1 addition & 1 deletion src/WireMock.Net/Models/BodyData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public class BodyData : IBodyData
/// <inheritdoc cref="IBodyData.Encoding" />
public Encoding? Encoding { get; set; }

/// <inheritdoc cref="IBodyData.BodyAsBytes" />
/// <inheritdoc />
public string? BodyAsString { get; set; }

/// <inheritdoc cref="IBodyData.BodyAsJson" />
Expand Down
2 changes: 1 addition & 1 deletion src/WireMock.Net/Owin/AspNetCoreSelfHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ private Task RunHost(CancellationToken token)
{
try
{
var appLifetime = (IApplicationLifetime)_host.Services.GetService(typeof(IApplicationLifetime));
var appLifetime = _host.Services.GetRequiredService<IApplicationLifetime>();
appLifetime.ApplicationStarted.Register(() =>
{
var addresses = _host.ServerFeatures
Expand Down
72 changes: 72 additions & 0 deletions src/WireMock.Net/Proxy/ProxyHelper.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
using Stef.Validation;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using WireMock.Constants;
using WireMock.Http;
using WireMock.Matchers;
using WireMock.RequestBuilders;
using WireMock.ResponseBuilders;
using WireMock.Serialization;
using WireMock.Settings;
using WireMock.Types;
using WireMock.Util;

namespace WireMock.Proxy;
Expand Down Expand Up @@ -55,4 +62,69 @@ public ProxyHelper(WireMockServerSettings settings)

return (responseMessage, newMapping);
}

private IMapping ToMapping(ProxyAndRecordSettings proxyAndRecordSettings, IRequestMessage requestMessage, ResponseMessage responseMessage)
{
var excludedHeaders = proxyAndRecordSettings.ExcludedHeaders ?? new string[] { };
var excludedCookies = proxyAndRecordSettings.ExcludedCookies ?? new string[] { };

var request = Request.Create();
request.WithPath(requestMessage.Path);
request.UsingMethod(requestMessage.Method);

requestMessage.Query?.Loop((key, value) => request.WithParam(key, false, value.ToArray()));
requestMessage.Cookies?.Loop((key, value) =>
{
if (!excludedCookies.Contains(key, StringComparer.OrdinalIgnoreCase))
{
request.WithCookie(key, value);
}
});

var allExcludedHeaders = new List<string>(excludedHeaders) { "Cookie" };
requestMessage.Headers?.Loop((key, value) =>
{
if (!allExcludedHeaders.Contains(key, StringComparer.OrdinalIgnoreCase))
{
request.WithHeader(key, value.ToArray());
}
});

bool throwExceptionWhenMatcherFails = _settings.ThrowExceptionWhenMatcherFails == true;
switch (requestMessage.BodyData?.DetectedBodyType)
{
case BodyType.Json:
request.WithBody(new JsonMatcher(MatchBehaviour.AcceptOnMatch, requestMessage.BodyData.BodyAsJson!, true, throwExceptionWhenMatcherFails));
break;

case BodyType.String:
request.WithBody(new ExactMatcher(MatchBehaviour.AcceptOnMatch, false, throwExceptionWhenMatcherFails, MatchOperator.Or, requestMessage.BodyData.BodyAsString));
break;

case BodyType.Bytes:
request.WithBody(new ExactObjectMatcher(MatchBehaviour.AcceptOnMatch, requestMessage.BodyData.BodyAsBytes, throwExceptionWhenMatcherFails));
break;
}

var response = Response.Create(responseMessage);

return new Mapping
(
guid: Guid.NewGuid(),
title: $"Proxy Mapping for {requestMessage.Method} {requestMessage.Path}",
description: string.Empty,
path: null,
settings: _settings,
request,
response,
priority: WireMockConstants.ProxyPriority, // This was 0
scenario: null,
executionConditionState: null,
nextState: null,
stateTimes: null,
webhooks: null,
useWebhooksFireAndForget: null,
timeSettings: null
);
}
}
2 changes: 1 addition & 1 deletion src/WireMock.Net/Serialization/MatcherMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public MatcherMapper(WireMockServerSettings settings)
return new LinqMatcher(matchBehaviour, throwExceptionWhenMatcherFails, matchOperator, stringPatterns);

case nameof(ExactMatcher):
return new ExactMatcher(matchBehaviour, throwExceptionWhenMatcherFails, matchOperator, stringPatterns);
return new ExactMatcher(matchBehaviour, ignoreCase, throwExceptionWhenMatcherFails, matchOperator, stringPatterns);

case nameof(ExactObjectMatcher):
return CreateExactObjectMatcher(matchBehaviour, stringPatterns[0], throwExceptionWhenMatcherFails);
Expand Down
4 changes: 2 additions & 2 deletions src/WireMock.Net/Serialization/ProxyMappingConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -140,11 +140,11 @@ public IMapping ToMapping(IMapping? mapping, ProxyAndRecordSettings proxyAndReco
break;

case BodyType.String:
newRequest.WithBody(new ExactMatcher(MatchBehaviour.AcceptOnMatch, throwExceptionWhenMatcherFails, MatchOperator.Or, requestMessage.BodyData.BodyAsString));
newRequest.WithBody(new ExactMatcher(MatchBehaviour.AcceptOnMatch, true, throwExceptionWhenMatcherFails, MatchOperator.Or, requestMessage.BodyData.BodyAsString!));
break;

case BodyType.Bytes:
newRequest.WithBody(new ExactObjectMatcher(MatchBehaviour.AcceptOnMatch, requestMessage.BodyData.BodyAsBytes, throwExceptionWhenMatcherFails));
newRequest.WithBody(new ExactObjectMatcher(MatchBehaviour.AcceptOnMatch, requestMessage.BodyData.BodyAsBytes!, throwExceptionWhenMatcherFails));
break;
}
}
Expand Down
Loading

0 comments on commit 55afc80

Please sign in to comment.