Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add LinqMatcher #195

Merged
merged 3 commits into from
Aug 31, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions examples/WireMock.Net.Console.Net452.Classic/MainApp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,14 @@ public static void Run()
.WithTransformer()
);

// https://stackoverflow.com/questions/51985089/wiremock-request-matching-with-comparison-between-two-query-parameters
server
.Given(Request.Create().WithPath("/linq")
.WithParam("from", new LinqMatcher("DateTime.Parse(it) > \"2018-03-01 00:00:00\"")))
.RespondWith(Response.Create()
.WithBody("linq match !!!")
);

System.Console.WriteLine("Press any key to stop the server");
System.Console.ReadKey();
server.Stop();
Expand Down
99 changes: 99 additions & 0 deletions src/WireMock.Net/Matchers/LinqMatcher.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
using System.Linq;
using System.Linq.Dynamic.Core;
using JetBrains.Annotations;

namespace WireMock.Matchers
{
/// <summary>
/// System.Linq.Dynamic.Core Expression Matcher
/// </summary>
/// <inheritdoc cref="IStringMatcher"/>
public class LinqMatcher : IStringMatcher
{
private readonly string[] _patterns;

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

/// <summary>
/// Initializes a new instance of the <see cref="LinqMatcher"/> class.
/// </summary>
/// <param name="pattern">The pattern.</param>
public LinqMatcher([NotNull] string pattern) : this(new[] { pattern })
{
}

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

/// <summary>
/// Initializes a new instance of the <see cref="LinqMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="pattern">The pattern.</param>
public LinqMatcher(MatchBehaviour matchBehaviour, [NotNull] string pattern) : this(matchBehaviour, new[] { pattern })
{
}

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

/// <inheritdoc cref="IStringMatcher.IsMatch"/>
public double IsMatch(string input)
{
// Convert a single input string to a Queryable string-list with 1 entry.
IQueryable queryable = new[] { input }.AsQueryable();

// Use the Any(...) method to check if the result matches
double match = MatchScores.ToScore(_patterns.Select(pattern => queryable.Any(pattern)));

return MatchBehaviourHelper.Convert(MatchBehaviour, match);
}

///// <inheritdoc cref="IObjectMatcher.IsMatch"/>
//public double IsMatch(object input)
//{
// object value;
// switch (input)
// {
// case JObject valueAsJObject:
// value = valueAsJObject.ToObject<object>();
// break;

// default:
// value = input;
// break;
// }

// // Convert a single object to a Queryable object-list with 1 entry.
// IQueryable queryable = new[] { value }.AsQueryable().Select("new (it as x)");

// // Use the Any(...) method to check if the result matches
// double match = MatchScores.ToScore(_patterns.Select(pattern => queryable.Any(pattern)));

// return MatchBehaviourHelper.Convert(MatchBehaviour, match);
//}

/// <inheritdoc cref="IStringMatcher.GetPatterns"/>
public string[] GetPatterns()
{
return _patterns;
}

/// <inheritdoc cref="IMatcher.Name"/>
public string Name => "LinqMatcher";
}
}
3 changes: 3 additions & 0 deletions src/WireMock.Net/Serialization/MatcherMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ public static IMatcher Map([CanBeNull] MatcherModel matcher)

switch (matcherName)
{
case "LinqMatcher":
return new LinqMatcher(matchBehaviour, stringPatterns);

case "ExactMatcher":
return new ExactMatcher(matchBehaviour, stringPatterns);

Expand Down
1 change: 1 addition & 0 deletions src/WireMock.Net/WireMock.Net.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
<PackageReference Include="System.Net.Http" Version="4.3.3" />
<PackageReference Include="RestEase" Version="1.4.4" />
<PackageReference Include="MimeKitLite" Version="2.0.1" />
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.0.8.17" />
</ItemGroup>

<ItemGroup Condition=" '$(TargetFramework)' == 'net451' ">
Expand Down
97 changes: 97 additions & 0 deletions test/WireMock.Net.Tests/MatcherMapperTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
using System;
using NFluent;
using WireMock.Admin.Mappings;
using WireMock.Matchers;
using WireMock.Serialization;
using Xunit;

namespace WireMock.Net.Tests
{
public class MatcherMapperTests
{
[Fact]
public void MatcherMapper_Map_MatcherModel_Null()
{
// Act
var result = MatcherMapper.Map((MatcherModel)null);

// Assert
Check.That(result).IsNull();
}

[Fact]
public void MatcherMapper_Map_MatcherModel_Exception()
{
// Assign
var model = new MatcherModel { Name = "test" };

// Act and Assert
Check.ThatCode(() => MatcherMapper.Map(model)).Throws<NotSupportedException>();
}

[Fact]
public void MatcherMapper_Map_MatcherModel_LinqMatcher_Pattern()
{
// Assign
var model = new MatcherModel
{
Name = "LinqMatcher",
Pattern = "p"
};

// Act
var matcher = MatcherMapper.Map(model) as LinqMatcher;

// Assert
Check.That(matcher).IsNotNull();
Check.That(matcher.MatchBehaviour).IsEqualTo(MatchBehaviour.AcceptOnMatch);
Check.That(matcher.GetPatterns()).ContainsExactly("p");
}

[Fact]
public void MatcherMapper_Map_MatcherModel_LinqMatcher_Patterns()
{
// Assign
var model = new MatcherModel
{
Name = "LinqMatcher",
Patterns = new[] { "p1", "p2" }
};

// Act
var matcher = MatcherMapper.Map(model) as LinqMatcher;

// Assert
Check.That(matcher).IsNotNull();
Check.That(matcher.MatchBehaviour).IsEqualTo(MatchBehaviour.AcceptOnMatch);
Check.That(matcher.GetPatterns()).Contains(new[] { "p1", "p2" });
}

[Fact]
public void MatcherMapper_Map_IMatcher_Null()
{
// Act
var result = MatcherMapper.Map((IMatcher)null);

// Assert
Check.That(result).IsNull();
}

[Fact]
public void MatcherMapper_Map_IMatcher_LinqMatcher_Pattern()
{
// Assign
var matcher = new LinqMatcher(MatchBehaviour.AcceptOnMatch, "p");

// Act
var result = MatcherMapper.Map(matcher);

// Assert
Check.That(result).IsNotNull();
Check.That(result.Name).IsEqualTo("LinqMatcher");
Check.That(result.IgnoreCase).IsNull();
Check.That(result.Pattern).IsEqualTo("p");
Check.That(result.Patterns).IsNull();
}
}
}
112 changes: 112 additions & 0 deletions test/WireMock.Net.Tests/Matchers/LinqMatcherTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
using NFluent;
using WireMock.Matchers;
using Xunit;

namespace WireMock.Net.Tests.Matchers
{
public class LinqMatcherTests
{
[Fact]
public void LinqMatcher_For_String_SinglePattern_IsMatch_Positive()
{
// Assign
string input = "2018-08-31 13:59:59";

// Act
var matcher = new LinqMatcher("DateTime.Parse(it) > \"2018-08-01 13:50:00\"");

// Assert
Check.That(matcher.IsMatch(input)).IsEqualTo(1.0d);
}

[Fact]
public void LinqMatcher_For_String_IsMatch_Negative()
{
// Assign
string input = "2018-08-31 13:59:59";

// Act
var matcher = new LinqMatcher("DateTime.Parse(it) > \"2019-01-01 00:00:00\"");

// Assert
Check.That(matcher.IsMatch(input)).IsEqualTo(0.0d);
}

[Fact]
public void LinqMatcher_For_String_IsMatch_RejectOnMatch()
{
// Assign
string input = "2018-08-31 13:59:59";

// Act
var matcher = new LinqMatcher(MatchBehaviour.RejectOnMatch, "DateTime.Parse(it) > \"2018-08-01 13:50:00\"");

// Assert
Check.That(matcher.IsMatch(input)).IsEqualTo(0.0d);
}

//[Fact]
//public void LinqMatcher_For_Object_IsMatch()
//{
// // Assign
// var input = new
// {
// Id = 9,
// Name = "Test"
// };

// // Act
// var matcher = new LinqMatcher("Id > 1 AND Name == \"Test\"");

// double match = matcher.IsMatch(input);

// // Assert
// Assert.Equal(1.0, match);
//}

//[Fact]
//public void LinqMatcher_For_JObject_IsMatch()
//{
// // Assign
// var input = new JObject
// {
// { "Id", new JValue(9) },
// { "Name", new JValue("Test") }
// };

// // Act
// var matcher = new LinqMatcher("it.Id > 1 AND it.Name == \"Test\"");

// double match = matcher.IsMatch(input);

// // Assert
// Assert.Equal(1.0, match);
//}

[Fact]
public void LinqMatcher_GetName()
{
// Assign
var matcher = new LinqMatcher("x");

// Act
string name = matcher.Name;

// Assert
Check.That(name).Equals("LinqMatcher");
}

[Fact]
public void LinqMatcher_GetPatterns()
{
// Assign
var matcher = new LinqMatcher("x");

// Act
string[] patterns = matcher.GetPatterns();

// Assert
Check.That(patterns).ContainsExactly("x");
}
}
}