mirror of
https://github.com/wiremock/WireMock.Net.git
synced 2026-03-29 22:02:16 +02:00
Merge branch 'LinqMatcher_JObject'
This commit is contained in:
@@ -1,6 +1,8 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Linq.Dynamic.Core;
|
using System.Linq.Dynamic.Core;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
using WireMock.Util;
|
||||||
|
|
||||||
namespace WireMock.Matchers
|
namespace WireMock.Matchers
|
||||||
{
|
{
|
||||||
@@ -63,29 +65,33 @@ namespace WireMock.Matchers
|
|||||||
return MatchBehaviourHelper.Convert(MatchBehaviour, match);
|
return MatchBehaviourHelper.Convert(MatchBehaviour, match);
|
||||||
}
|
}
|
||||||
|
|
||||||
///// <inheritdoc cref="IObjectMatcher.IsMatch"/>
|
/// <inheritdoc cref="IObjectMatcher.IsMatch"/>
|
||||||
//public double IsMatch(object input)
|
public double IsMatch(object input)
|
||||||
//{
|
{
|
||||||
// object value;
|
JObject value;
|
||||||
// switch (input)
|
switch (input)
|
||||||
// {
|
{
|
||||||
// case JObject valueAsJObject:
|
case JObject valueAsJObject:
|
||||||
// value = valueAsJObject.ToObject<object>();
|
value = valueAsJObject;
|
||||||
// break;
|
break;
|
||||||
|
|
||||||
// default:
|
default:
|
||||||
// value = input;
|
value = JObject.FromObject(input);
|
||||||
// break;
|
break;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// // Convert a single object to a Queryable object-list with 1 entry.
|
// Convert a single object to a Queryable JObject-list with 1 entry.
|
||||||
// IQueryable queryable = new[] { value }.AsQueryable().Select("new (it as x)");
|
var queryable1 = new[] { value }.AsQueryable();
|
||||||
|
|
||||||
// // Use the Any(...) method to check if the result matches
|
// Generate the dynamic linq select statement and generate a dynamic Queryable.
|
||||||
// double match = MatchScores.ToScore(_patterns.Select(pattern => queryable.Any(pattern)));
|
string dynamicSelect = JsonUtils.GenerateDynamicLinqStatement(value);
|
||||||
|
var queryable2 = queryable1.Select(dynamicSelect);
|
||||||
|
|
||||||
// return MatchBehaviourHelper.Convert(MatchBehaviour, match);
|
// Use the Any(...) method to check if the result matches
|
||||||
//}
|
double match = MatchScores.ToScore(_patterns.Select(pattern => queryable2.Any(pattern)));
|
||||||
|
|
||||||
|
return MatchBehaviourHelper.Convert(MatchBehaviour, match);
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="IStringMatcher.GetPatterns"/>
|
/// <inheritdoc cref="IStringMatcher.GetPatterns"/>
|
||||||
public string[] GetPatterns()
|
public string[] GetPatterns()
|
||||||
|
|||||||
@@ -7,9 +7,9 @@ using System.Threading.Tasks;
|
|||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using WireMock.Http;
|
|
||||||
using WireMock.HttpsCertificate;
|
using WireMock.HttpsCertificate;
|
||||||
using WireMock.Logging;
|
using WireMock.Logging;
|
||||||
|
using WireMock.Util;
|
||||||
using WireMock.Validation;
|
using WireMock.Validation;
|
||||||
|
|
||||||
namespace WireMock.Owin
|
namespace WireMock.Owin
|
||||||
@@ -43,7 +43,7 @@ namespace WireMock.Owin
|
|||||||
{
|
{
|
||||||
Urls.Add(uriPrefix);
|
Urls.Add(uriPrefix);
|
||||||
|
|
||||||
PortUtil.TryExtractProtocolAndPort(uriPrefix, out string host, out int port);
|
PortUtils.TryExtractProtocolAndPort(uriPrefix, out string host, out int port);
|
||||||
Ports.Add(port);
|
Ports.Add(port);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,13 +75,13 @@ namespace WireMock.Owin
|
|||||||
// https://docs.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel?tabs=aspnetcore2x
|
// https://docs.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel?tabs=aspnetcore2x
|
||||||
foreach (string url in _urls.Where(u => u.StartsWith("http://", StringComparison.OrdinalIgnoreCase)))
|
foreach (string url in _urls.Where(u => u.StartsWith("http://", StringComparison.OrdinalIgnoreCase)))
|
||||||
{
|
{
|
||||||
PortUtil.TryExtractProtocolAndPort(url, out string host, out int port);
|
PortUtils.TryExtractProtocolAndPort(url, out string host, out int port);
|
||||||
options.Listen(System.Net.IPAddress.Any, port);
|
options.Listen(System.Net.IPAddress.Any, port);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (string url in _urls.Where(u => u.StartsWith("https://", StringComparison.OrdinalIgnoreCase)))
|
foreach (string url in _urls.Where(u => u.StartsWith("https://", StringComparison.OrdinalIgnoreCase)))
|
||||||
{
|
{
|
||||||
PortUtil.TryExtractProtocolAndPort(url, out string host, out int port);
|
PortUtils.TryExtractProtocolAndPort(url, out string host, out int port);
|
||||||
options.Listen(System.Net.IPAddress.Any, port, listenOptions =>
|
options.Listen(System.Net.IPAddress.Any, port, listenOptions =>
|
||||||
{
|
{
|
||||||
listenOptions.UseHttps(PublicCertificateHelper.GetX509Certificate2());
|
listenOptions.UseHttps(PublicCertificateHelper.GetX509Certificate2());
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ using System.Threading;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using WireMock.Http;
|
using WireMock.Http;
|
||||||
using WireMock.Logging;
|
using WireMock.Logging;
|
||||||
|
using WireMock.Util;
|
||||||
using WireMock.Validation;
|
using WireMock.Validation;
|
||||||
|
|
||||||
namespace WireMock.Owin
|
namespace WireMock.Owin
|
||||||
@@ -30,7 +31,7 @@ namespace WireMock.Owin
|
|||||||
{
|
{
|
||||||
Urls.Add(uriPrefix);
|
Urls.Add(uriPrefix);
|
||||||
|
|
||||||
PortUtil.TryExtractProtocolAndPort(uriPrefix, out string host, out int port);
|
PortUtils.TryExtractProtocolAndPort(uriPrefix, out string host, out int port);
|
||||||
Ports.Add(port);
|
Ports.Add(port);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ using WireMock.Owin;
|
|||||||
using WireMock.RequestBuilders;
|
using WireMock.RequestBuilders;
|
||||||
using WireMock.ResponseProviders;
|
using WireMock.ResponseProviders;
|
||||||
using WireMock.Settings;
|
using WireMock.Settings;
|
||||||
|
using WireMock.Util;
|
||||||
using WireMock.Validation;
|
using WireMock.Validation;
|
||||||
|
|
||||||
namespace WireMock.Server
|
namespace WireMock.Server
|
||||||
@@ -199,7 +200,7 @@ namespace WireMock.Server
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int port = settings.Port > 0 ? settings.Port.Value : PortUtil.FindFreeTcpPort();
|
int port = settings.Port > 0 ? settings.Port.Value : PortUtils.FindFreeTcpPort();
|
||||||
Urls = new[] { $"{(settings.UseSSL == true ? "https" : "http")}://localhost:{port}" };
|
Urls = new[] { $"{(settings.UseSSL == true ? "https" : "http")}://localhost:{port}" };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
namespace WireMock.Util
|
namespace WireMock.Util
|
||||||
{
|
{
|
||||||
@@ -6,12 +10,138 @@ namespace WireMock.Util
|
|||||||
{
|
{
|
||||||
public static T ParseJTokenToObject<T>(object value)
|
public static T ParseJTokenToObject<T>(object value)
|
||||||
{
|
{
|
||||||
if (value == null)
|
switch (value)
|
||||||
{
|
{
|
||||||
return default(T);
|
case JToken tokenValue:
|
||||||
|
return tokenValue.ToObject<T>();
|
||||||
|
|
||||||
|
default:
|
||||||
|
return default(T);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GenerateDynamicLinqStatement(JObject jsonObject)
|
||||||
|
{
|
||||||
|
var lines = new List<string>();
|
||||||
|
WalkNode(jsonObject, null, null, lines);
|
||||||
|
|
||||||
|
return lines.First();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void WalkNode(JToken node, string path, string propertyName, List<string> lines)
|
||||||
|
{
|
||||||
|
if (node.Type == JTokenType.Object)
|
||||||
|
{
|
||||||
|
ProcessObject(node, propertyName, lines);
|
||||||
|
}
|
||||||
|
else if (node.Type == JTokenType.Array)
|
||||||
|
{
|
||||||
|
ProcessArray(node, propertyName, lines);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ProcessItem(node, path, propertyName, lines);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ProcessObject(JToken node, string propertyName, List<string> lines)
|
||||||
|
{
|
||||||
|
var items = new List<string>();
|
||||||
|
var text = new StringBuilder("new (");
|
||||||
|
|
||||||
|
// In case of Object, loop all children. Do a ToArray() to avoid `Collection was modified` exceptions.
|
||||||
|
foreach (JProperty child in node.Children<JProperty>().ToArray())
|
||||||
|
{
|
||||||
|
WalkNode(child.Value, child.Path, child.Name, items);
|
||||||
}
|
}
|
||||||
|
|
||||||
return !(value is JToken token) ? default(T) : token.ToObject<T>();
|
text.Append(string.Join(", ", items));
|
||||||
|
text.Append(")");
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(propertyName))
|
||||||
|
{
|
||||||
|
text.AppendFormat(" as {0}", propertyName);
|
||||||
|
}
|
||||||
|
|
||||||
|
lines.Add(text.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ProcessArray(JToken node, string propertyName, List<string> lines)
|
||||||
|
{
|
||||||
|
var items = new List<string>();
|
||||||
|
var text = new StringBuilder("(new [] { ");
|
||||||
|
|
||||||
|
// In case of Array, loop all items. Do a ToArray() to avoid `Collection was modified` exceptions.
|
||||||
|
int idx = 0;
|
||||||
|
foreach (JToken child in node.Children().ToArray())
|
||||||
|
{
|
||||||
|
WalkNode(child, $"{node.Path}[{idx}]", null, items);
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
text.Append(string.Join(", ", items));
|
||||||
|
text.Append("})");
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(propertyName))
|
||||||
|
{
|
||||||
|
text.AppendFormat(" as {0}", propertyName);
|
||||||
|
}
|
||||||
|
|
||||||
|
lines.Add(text.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ProcessItem(JToken node, string path, string propertyName, List<string> lines)
|
||||||
|
{
|
||||||
|
string castText = string.Empty;
|
||||||
|
switch (node.Type)
|
||||||
|
{
|
||||||
|
case JTokenType.Boolean:
|
||||||
|
castText = $"bool({path})";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case JTokenType.Date:
|
||||||
|
castText = $"DateTime({path})";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case JTokenType.Float:
|
||||||
|
castText = $"double({path})";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case JTokenType.Guid:
|
||||||
|
castText = $"Guid({path})";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case JTokenType.Integer:
|
||||||
|
castText = $"int({path})";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case JTokenType.Null:
|
||||||
|
castText = "null";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case JTokenType.String:
|
||||||
|
castText = $"string({path})";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case JTokenType.TimeSpan:
|
||||||
|
castText = $"TimeSpan({path})";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case JTokenType.Uri:
|
||||||
|
castText = $"Uri({path})";
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new NotSupportedException(
|
||||||
|
$"JTokenType '{node.Type}' cannot be converted to a Dynamic Linq cast operator.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(propertyName))
|
||||||
|
{
|
||||||
|
castText += $" as {propertyName}";
|
||||||
|
}
|
||||||
|
|
||||||
|
lines.Add(castText);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,12 +2,12 @@
|
|||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
namespace WireMock.Http
|
namespace WireMock.Util
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Port Utility class
|
/// Port Utility class
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class PortUtil
|
public static class PortUtils
|
||||||
{
|
{
|
||||||
private static readonly Regex UrlDetailsRegex = new Regex(@"^(?<proto>\w+)://[^/]+?(?<port>\d+)/?", RegexOptions.Compiled);
|
private static readonly Regex UrlDetailsRegex = new Regex(@"^(?<proto>\w+)://[^/]+?(?<port>\d+)/?", RegexOptions.Compiled);
|
||||||
|
|
||||||
@@ -49,7 +49,7 @@
|
|||||||
<PackageReference Include="System.Net.Http" Version="4.3.3" />
|
<PackageReference Include="System.Net.Http" Version="4.3.3" />
|
||||||
<PackageReference Include="RestEase" Version="1.4.4" />
|
<PackageReference Include="RestEase" Version="1.4.4" />
|
||||||
<PackageReference Include="MimeKitLite" Version="2.0.1" />
|
<PackageReference Include="MimeKitLite" Version="2.0.1" />
|
||||||
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.0.8.17" />
|
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.0.8.18" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup Condition=" '$(TargetFramework)' == 'net451' ">
|
<ItemGroup Condition=" '$(TargetFramework)' == 'net451' ">
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using NFluent;
|
using Newtonsoft.Json.Linq;
|
||||||
|
using NFluent;
|
||||||
using WireMock.Matchers;
|
using WireMock.Matchers;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
@@ -45,43 +46,41 @@ namespace WireMock.Net.Tests.Matchers
|
|||||||
Check.That(matcher.IsMatch(input)).IsEqualTo(0.0d);
|
Check.That(matcher.IsMatch(input)).IsEqualTo(0.0d);
|
||||||
}
|
}
|
||||||
|
|
||||||
//[Fact]
|
[Fact]
|
||||||
//public void LinqMatcher_For_Object_IsMatch()
|
public void LinqMatcher_For_Object_IsMatch()
|
||||||
//{
|
{
|
||||||
// // Assign
|
// Assign
|
||||||
// var input = new
|
var input = new
|
||||||
// {
|
{
|
||||||
// Id = 9,
|
Id = 9,
|
||||||
// Name = "Test"
|
Name = "Test"
|
||||||
// };
|
};
|
||||||
|
|
||||||
// // Act
|
// Act
|
||||||
// var matcher = new LinqMatcher("Id > 1 AND Name == \"Test\"");
|
var matcher = new LinqMatcher("Id > 1 AND Name == \"Test\"");
|
||||||
|
double match = matcher.IsMatch(input);
|
||||||
|
|
||||||
// double match = matcher.IsMatch(input);
|
// Assert
|
||||||
|
Assert.Equal(1.0, match);
|
||||||
|
}
|
||||||
|
|
||||||
// // Assert
|
[Fact]
|
||||||
// Assert.Equal(1.0, match);
|
public void LinqMatcher_For_JObject_IsMatch()
|
||||||
//}
|
{
|
||||||
|
// Assign
|
||||||
|
var input = new JObject
|
||||||
|
{
|
||||||
|
{ "Id", new JValue(9) },
|
||||||
|
{ "Name", new JValue("Test") }
|
||||||
|
};
|
||||||
|
|
||||||
//[Fact]
|
// Act
|
||||||
//public void LinqMatcher_For_JObject_IsMatch()
|
var matcher = new LinqMatcher("Id > 1 AND Name == \"Test\"");
|
||||||
//{
|
double match = matcher.IsMatch(input);
|
||||||
// // Assign
|
|
||||||
// var input = new JObject
|
|
||||||
// {
|
|
||||||
// { "Id", new JValue(9) },
|
|
||||||
// { "Name", new JValue("Test") }
|
|
||||||
// };
|
|
||||||
|
|
||||||
// // Act
|
// Assert
|
||||||
// var matcher = new LinqMatcher("it.Id > 1 AND it.Name == \"Test\"");
|
Assert.Equal(1.0, match);
|
||||||
|
}
|
||||||
// double match = matcher.IsMatch(input);
|
|
||||||
|
|
||||||
// // Assert
|
|
||||||
// Assert.Equal(1.0, match);
|
|
||||||
//}
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void LinqMatcher_GetName()
|
public void LinqMatcher_GetName()
|
||||||
|
|||||||
62
test/WireMock.Net.Tests/Util/JsonUtilsTests.cs
Normal file
62
test/WireMock.Net.Tests/Util/JsonUtilsTests.cs
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
using NFluent;
|
||||||
|
using System.Linq.Dynamic.Core;
|
||||||
|
using WireMock.Util;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace WireMock.Net.Tests.Util
|
||||||
|
{
|
||||||
|
public class JsonUtilsTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void JsonUtils_GenerateDynamicLinqStatement()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var j = new JObject
|
||||||
|
{
|
||||||
|
{"U", new JValue(new Uri("http://localhost:80/abc?a=5"))},
|
||||||
|
{"N", new JValue((object) null)},
|
||||||
|
{"G", new JValue(Guid.NewGuid())},
|
||||||
|
{"Flt", new JValue(10.0f)},
|
||||||
|
{"Dbl", new JValue(Math.PI)},
|
||||||
|
{"Check", new JValue(true)},
|
||||||
|
{"Items", new JArray(new[] {new JValue(4), new JValue(8)})},
|
||||||
|
{
|
||||||
|
"Child", new JObject
|
||||||
|
{
|
||||||
|
{"ChildId", new JValue(4)},
|
||||||
|
{"ChildDateTime", new JValue(new DateTime(2018, 2, 17))},
|
||||||
|
{"TS", new JValue(TimeSpan.FromMilliseconds(999))}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{"Id", new JValue(9)},
|
||||||
|
{"Name", new JValue("Test")}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
string line = JsonUtils.GenerateDynamicLinqStatement(j);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var queryable = new[] {j}.AsQueryable().Select(line);
|
||||||
|
bool result = queryable.Any("Id > 4");
|
||||||
|
Check.That(result).IsTrue();
|
||||||
|
|
||||||
|
Check.That(line).IsEqualTo("new (Uri(U) as U, null as N, Guid(G) as G, double(Flt) as Flt, double(Dbl) as Dbl, bool(Check) as Check, (new [] { int(Items[0]), int(Items[1])}) as Items, new (int(Child.ChildId) as ChildId, DateTime(Child.ChildDateTime) as ChildDateTime, TimeSpan(Child.TS) as TS) as Child, int(Id) as Id, string(Name) as Name)");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void JsonUtils_GenerateDynamicLinqStatement_Throws()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var j = new JObject
|
||||||
|
{
|
||||||
|
{"B", new JValue(new byte[] {48, 49})}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act and Assert
|
||||||
|
Check.ThatCode(() => JsonUtils.GenerateDynamicLinqStatement(j)).Throws<NotSupportedException>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,6 +25,7 @@
|
|||||||
<PackageReference Include="System.Threading" Version="4.3.0" />
|
<PackageReference Include="System.Threading" Version="4.3.0" />
|
||||||
<PackageReference Include="xunit" Version="2.4.0" />
|
<PackageReference Include="xunit" Version="2.4.0" />
|
||||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
|
||||||
|
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.0.8.18" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup Condition="'$(TargetFramework)' == 'net452'">
|
<ItemGroup Condition="'$(TargetFramework)' == 'net452'">
|
||||||
|
|||||||
Reference in New Issue
Block a user