Skip to content

Commit

Permalink
Stef negate matcher (#134)
Browse files Browse the repository at this point in the history
* RejectOnMatch (wip)

* RejectOnMatch (wip)

* RejectOnMatch (wip)

* RejectOnMatch (wip)

* docs: improve sample app matcher to show use of reject on match

* Reworked code review comments
  • Loading branch information
alastairtree authored and StefH committed May 12, 2018
1 parent 7cf283e commit a8ddd31
Show file tree
Hide file tree
Showing 53 changed files with 1,074 additions and 392 deletions.
2 changes: 1 addition & 1 deletion GitReleaseNotes.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
https://github.com/GitTools/GitReleaseNotes

GitReleaseNotes.exe . /OutputFile CHANGELOG.md /Version 1.0.3.16
GitReleaseNotes.exe . /OutputFile CHANGELOG.md /Version 1.0.3.17

GitReleaseNotes.exe . /OutputFile CHANGELOG.md /allTags
23 changes: 23 additions & 0 deletions examples/WireMock.Net.ConsoleApplication/MainApp.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Net;
using Newtonsoft.Json;
using WireMock.Matchers;
using WireMock.RequestBuilders;
Expand Down Expand Up @@ -150,6 +151,28 @@ public static void Run()
.WithHeader("Content-Type", "application/json")
.WithBody(@"{ ""result"": ""data deleted with 200""}"));

server
.Given(Request.Create()
.WithPath("/needs-a-key")
.UsingGet()
.WithHeader("api-key", "*", MatchBehaviour.AcceptOnMatch)
.UsingAnyMethod())
.RespondWith(Response.Create()
.WithStatusCode(HttpStatusCode.OK)
.WithBody(@"{ ""result"": ""api-key found""}"));

server
.Given(Request.Create()
.WithPath("/needs-a-key")
.UsingGet()
.WithHeader("api-key", "*", MatchBehaviour.RejectOnMatch)
.UsingAnyMethod())
.RespondWith(Response.Create()
.WithStatusCode(HttpStatusCode.Unauthorized)
.WithBody(@"{ ""result"": ""api-key missing""}"));



server
.Given(Request.Create().WithPath("/nobody").UsingGet())
.RespondWith(Response.Create().WithDelay(TimeSpan.FromSeconds(1))
Expand Down
2 changes: 1 addition & 1 deletion src/WireMock.Net.StandAlone/WireMock.Net.StandAlone.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<PropertyGroup>
<Description>Lightweight StandAlone Http Mocking Server for .Net.</Description>
<AssemblyTitle>WireMock.Net.StandAlone</AssemblyTitle>
<Version>1.0.3.16</Version>
<Version>1.0.3.17</Version>
<Authors>Stef Heyenrath</Authors>
<TargetFrameworks>net452;net46;netstandard1.3;netstandard2.0</TargetFrameworks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
Expand Down
5 changes: 5 additions & 0 deletions src/WireMock.Net/Admin/Mappings/MatcherModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,10 @@ public class MatcherModel
/// Gets or sets the ignore case.
/// </summary>
public bool? IgnoreCase { get; set; }

/// <summary>
/// Reject on match.
/// </summary>
public bool? RejectOnMatch { get; set; }
}
}
24 changes: 17 additions & 7 deletions src/WireMock.Net/Matchers/ExactMatcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,34 @@ public class ExactMatcher : IStringMatcher
{
private readonly string[] _values;

/// <inheritdoc cref="IMatcher.MatchBehaviour"/>
public MatchBehaviour MatchBehaviour { get; }

/// <summary>
/// Initializes a new instance of the <see cref="ExactMatcher"/> class.
/// </summary>
/// <param name="values">The values.</param>
public ExactMatcher([NotNull] params string[] values) : this(MatchBehaviour.AcceptOnMatch, values)
{
}

/// <summary>
/// Initializes a new instance of the <see cref="ExactMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="values">The values.</param>
public ExactMatcher([NotNull] params string[] values)
public ExactMatcher(MatchBehaviour matchBehaviour, [NotNull] params string[] values)
{
Check.HasNoNulls(values, nameof(values));

_values = values;
MatchBehaviour = matchBehaviour;
}

/// <inheritdoc cref="IStringMatcher.IsMatch"/>
public double IsMatch(string input)
{
return MatchScores.ToScore(_values.Select(value => value.Equals(input)));
return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.ToScore(_values.Select(value => value.Equals(input))));
}

/// <inheritdoc cref="IStringMatcher.GetPatterns"/>
Expand All @@ -35,10 +48,7 @@ public string[] GetPatterns()
return _values;
}

/// <inheritdoc cref="IMatcher.GetName"/>
public string GetName()
{
return "ExactMatcher";
}
/// <inheritdoc cref="IMatcher.Name"/>
public string Name => "ExactMatcher";
}
}
41 changes: 33 additions & 8 deletions src/WireMock.Net/Matchers/ExactObjectMatcher.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Linq;
using JetBrains.Annotations;
using WireMock.Validation;

namespace WireMock.Matchers
{
Expand All @@ -12,35 +13,59 @@ public class ExactObjectMatcher : IObjectMatcher
private readonly object _object;
private readonly byte[] _bytes;

/// <inheritdoc cref="IMatcher.MatchBehaviour"/>
public MatchBehaviour MatchBehaviour { get; }

/// <summary>
/// Initializes a new instance of the <see cref="ExactMatcher"/> class.
/// </summary>
/// <param name="value">The value.</param>
public ExactObjectMatcher([NotNull] object value) : this(MatchBehaviour.AcceptOnMatch, value)
{
}

/// <summary>
/// Initializes a new instance of the <see cref="ExactMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="value">The value.</param>
public ExactObjectMatcher([NotNull] object value)
public ExactObjectMatcher(MatchBehaviour matchBehaviour, [NotNull] object value)
{
Check.NotNull(value, nameof(value));

_object = value;
MatchBehaviour = matchBehaviour;
}

/// <summary>
/// Initializes a new instance of the <see cref="ExactMatcher"/> class.
/// </summary>
/// <param name="value">The value.</param>
public ExactObjectMatcher([NotNull] byte[] value)
public ExactObjectMatcher([NotNull] byte[] value) : this(MatchBehaviour.AcceptOnMatch, value)
{
}

/// <summary>
/// Initializes a new instance of the <see cref="ExactMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="value">The value.</param>
public ExactObjectMatcher(MatchBehaviour matchBehaviour, [NotNull] byte[] value)
{
Check.NotNull(value, nameof(value));

_bytes = value;
MatchBehaviour = matchBehaviour;
}

/// <inheritdoc cref="IObjectMatcher.IsMatch"/>
public double IsMatch(object input)
{
bool equals = _object != null ? Equals(_object, input) : _bytes.SequenceEqual((byte[])input);
return MatchScores.ToScore(equals);
return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.ToScore(equals));
}

/// <inheritdoc cref="IMatcher.GetName"/>
public string GetName()
{
return "ExactObjectMatcher";
}
/// <inheritdoc cref="IMatcher.Name"/>
public string Name => "ExactObjectMatcher";
}
}
3 changes: 2 additions & 1 deletion src/WireMock.Net/Matchers/IIgnoreCaseMatcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
/// <summary>
/// IIgnoreCaseMatcher
/// </summary>
/// <inheritdoc cref="IMatcher"/>
public interface IIgnoreCaseMatcher : IMatcher
{
/// <summary>
/// Ignore the case.
/// Ignore the case from the pattern.
/// </summary>
bool IgnoreCase { get; }
}
Expand Down
9 changes: 7 additions & 2 deletions src/WireMock.Net/Matchers/IMatcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@ public interface IMatcher
/// <summary>
/// Gets the name.
/// </summary>
/// <returns>Name</returns>
string GetName();
string Name { get; }


/// <summary>
/// Gets the match behaviour.
/// </summary>
MatchBehaviour MatchBehaviour { get; }
}
}
1 change: 1 addition & 0 deletions src/WireMock.Net/Matchers/IStringMatcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
/// <summary>
/// IStringMatcher
/// </summary>
/// <inheritdoc cref="IMatcher"/>
public interface IStringMatcher : IMatcher
{
/// <summary>
Expand Down
74 changes: 43 additions & 31 deletions src/WireMock.Net/Matchers/JSONPathMatcher.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System;
using System.Linq;
using System.Linq;
using JetBrains.Annotations;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using WireMock.Validation;

Expand All @@ -14,54 +14,69 @@ public class JsonPathMatcher : IStringMatcher, IObjectMatcher
{
private readonly string[] _patterns;

/// <inheritdoc cref="IMatcher.MatchBehaviour"/>
public MatchBehaviour MatchBehaviour { get; }

/// <summary>
/// Initializes a new instance of the <see cref="JsonPathMatcher"/> class.
/// </summary>
/// <param name="patterns">The patterns.</param>
public JsonPathMatcher([NotNull] params string[] patterns)
public JsonPathMatcher([NotNull] params string[] patterns) : this(MatchBehaviour.AcceptOnMatch, patterns)
{
}

/// <summary>
/// Initializes a new instance of the <see cref="JsonPathMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="patterns">The patterns.</param>
public JsonPathMatcher(MatchBehaviour matchBehaviour, [NotNull] params string[] patterns)
{
Check.NotNull(patterns, nameof(patterns));

MatchBehaviour = matchBehaviour;
_patterns = patterns;
}

/// <inheritdoc cref="IStringMatcher.IsMatch"/>
public double IsMatch(string input)
{
if (input == null)
double match = MatchScores.Mismatch;
if (input != null)
{
return MatchScores.Mismatch;
try
{
var jtoken = JToken.Parse(input);
match = IsMatch(jtoken);
}
catch (JsonException)
{
// just ignore JsonException
}
}

try
{
var jtoken = JToken.Parse(input);
return IsMatch(jtoken);
}
catch (Exception)
{
return MatchScores.Mismatch;
}
return MatchBehaviourHelper.Convert(MatchBehaviour, match);
}

/// <inheritdoc cref="IObjectMatcher.IsMatch"/>
public double IsMatch(object input)
{
if (input == null)
double match = MatchScores.Mismatch;
if (input != null)
{
return MatchScores.Mismatch;
try
{
// Check if JToken or object
JToken jtoken = input is JToken token ? token : JObject.FromObject(input);
match = IsMatch(jtoken);
}
catch (JsonException)
{
// just ignore JsonException
}
}

try
{
// Check if JToken or object
JToken jtoken = input is JToken token ? token : JObject.FromObject(input);
return IsMatch(jtoken);
}
catch (Exception)
{
return MatchScores.Mismatch;
}
return MatchBehaviourHelper.Convert(MatchBehaviour, match);
}

/// <inheritdoc cref="IStringMatcher.GetPatterns"/>
Expand All @@ -70,11 +85,8 @@ public string[] GetPatterns()
return _patterns;
}

/// <inheritdoc cref="IMatcher.GetName"/>
public string GetName()
{
return "JsonPathMatcher";
}
/// <inheritdoc cref="IMatcher.Name"/>
public string Name => "JsonPathMatcher";

private double IsMatch(JToken jtoken)
{
Expand Down
18 changes: 18 additions & 0 deletions src/WireMock.Net/Matchers/MatchBehaviour.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
namespace WireMock.Matchers
{
/// <summary>
/// MatchBehaviour
/// </summary>
public enum MatchBehaviour
{
/// <summary>
/// Accept on match (default)
/// </summary>
AcceptOnMatch,

/// <summary>
/// Reject on match
/// </summary>
RejectOnMatch
}
}
28 changes: 28 additions & 0 deletions src/WireMock.Net/Matchers/MatchBehaviourHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@

namespace WireMock.Matchers
{
internal static class MatchBehaviourHelper
{
/// <summary>
/// Converts the specified match behaviour and match value to a new match value.
///
/// if AcceptOnMatch --> return match (default)
/// if RejectOnMatch and match = 0.0 --> return 1.0
/// if RejectOnMatch and match = 0.? --> return 0.0
/// if RejectOnMatch and match = 1.0 --> return 0.0
/// </summary>
///
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="match">The match.</param>
/// <returns>match value</returns>
internal static double Convert(MatchBehaviour matchBehaviour, double match)
{
if (matchBehaviour == MatchBehaviour.AcceptOnMatch)
{
return match;
}

return match <= MatchScores.Tolerance ? MatchScores.Perfect : MatchScores.Mismatch;
}
}
}
Loading

0 comments on commit a8ddd31

Please sign in to comment.