mirror of
https://github.com/wiremock/WireMock.Net.git
synced 2026-04-19 23:41:41 +02:00
Add 'Data' to response which can be used during transforming the response (#893)
* Add 'Data' to response which can be used during transforming the response * md * hb * fix * Linq * fix test * v4 * 14 * . * x * remove * s
This commit is contained in:
@@ -27,7 +27,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\src\WireMock.Net\WireMock.Net.csproj" />
|
<ProjectReference Include="..\..\src\WireMock.Net\WireMock.Net.csproj" />
|
||||||
<PackageReference Include="Handlebars.Net.Helpers" Version="2.*" />
|
<!--<PackageReference Include="Handlebars.Net.Helpers" Version="2.*" />-->
|
||||||
<PackageReference Include="log4net" Version="2.0.15" />
|
<PackageReference Include="log4net" Version="2.0.15" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="6.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Configuration" Version="6.0.0" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using WireMock.Models;
|
using WireMock.Models;
|
||||||
|
|
||||||
namespace WireMock.Admin.Mappings;
|
namespace WireMock.Admin.Mappings;
|
||||||
@@ -84,4 +85,13 @@ public class MappingModel
|
|||||||
/// Fire and forget for webhooks.
|
/// Fire and forget for webhooks.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool? UseWebhooksFireAndForget { get; set; }
|
public bool? UseWebhooksFireAndForget { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Data Object which can be used when WithTransformer is used.
|
||||||
|
/// e.g. lookup an path in this object using
|
||||||
|
/// <example>
|
||||||
|
/// lookup data "1"
|
||||||
|
/// </example>
|
||||||
|
/// </summary>
|
||||||
|
public object? Data { get; set; }
|
||||||
}
|
}
|
||||||
@@ -1,121 +1,120 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace WireMock.Admin.Mappings
|
namespace WireMock.Admin.Mappings;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ResponseModel
|
||||||
|
/// </summary>
|
||||||
|
[FluentBuilder.AutoGenerateBuilder]
|
||||||
|
public class ResponseModel
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ResponseModel
|
/// Gets or sets the HTTP status.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[FluentBuilder.AutoGenerateBuilder]
|
public object? StatusCode { get; set; }
|
||||||
public class ResponseModel
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the HTTP status.
|
|
||||||
/// </summary>
|
|
||||||
public object? StatusCode { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the body destination (SameAsSource, String or Bytes).
|
/// Gets or sets the body destination (SameAsSource, String or Bytes).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string? BodyDestination { get; set; }
|
public string? BodyDestination { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the body.
|
/// Gets or sets the body.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string? Body { get; set; }
|
public string? Body { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the body (as JSON object).
|
/// Gets or sets the body (as JSON object).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public object? BodyAsJson { get; set; }
|
public object? BodyAsJson { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a value indicating whether child objects to be indented according to the Newtonsoft.Json.JsonTextWriter.Indentation and Newtonsoft.Json.JsonTextWriter.IndentChar settings.
|
/// Gets or sets a value indicating whether child objects to be indented according to the Newtonsoft.Json.JsonTextWriter.Indentation and Newtonsoft.Json.JsonTextWriter.IndentChar settings.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool? BodyAsJsonIndented { get; set; }
|
public bool? BodyAsJsonIndented { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the body (as bytearray).
|
/// Gets or sets the body (as bytearray).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public byte[]? BodyAsBytes { get; set; }
|
public byte[]? BodyAsBytes { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the body as a file.
|
/// Gets or sets the body as a file.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string? BodyAsFile { get; set; }
|
public string? BodyAsFile { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Is the body as file cached?
|
/// Is the body as file cached?
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool? BodyAsFileIsCached { get; set; }
|
public bool? BodyAsFileIsCached { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the body encoding.
|
/// Gets or sets the body encoding.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public EncodingModel? BodyEncoding { get; set; }
|
public EncodingModel? BodyEncoding { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Use ResponseMessage Transformer.
|
/// Use ResponseMessage Transformer.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool? UseTransformer { get; set; }
|
public bool? UseTransformer { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the type of the transformer.
|
/// Gets the type of the transformer.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string? TransformerType { get; set; }
|
public string? TransformerType { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Use the Handlebars transformer for the content from the referenced BodyAsFile.
|
/// Use the Handlebars transformer for the content from the referenced BodyAsFile.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool? UseTransformerForBodyAsFile { get; set; }
|
public bool? UseTransformerForBodyAsFile { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The ReplaceNodeOptions to use when transforming a JSON node.
|
/// The ReplaceNodeOptions to use when transforming a JSON node.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string? TransformerReplaceNodeOptions { get; set; }
|
public string? TransformerReplaceNodeOptions { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the headers.
|
/// Gets or sets the headers.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IDictionary<string, object>? Headers { get; set; }
|
public IDictionary<string, object>? Headers { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the Headers (Raw).
|
/// Gets or sets the Headers (Raw).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string? HeadersRaw { get; set; }
|
public string? HeadersRaw { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the delay in milliseconds.
|
/// Gets or sets the delay in milliseconds.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int? Delay { get; set; }
|
public int? Delay { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the minimum random delay in milliseconds.
|
/// Gets or sets the minimum random delay in milliseconds.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int? MinimumRandomDelay { get; set; }
|
public int? MinimumRandomDelay { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the maximum random delay in milliseconds.
|
/// Gets or sets the maximum random delay in milliseconds.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int? MaximumRandomDelay { get; set; }
|
public int? MaximumRandomDelay { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the Proxy URL.
|
/// Gets or sets the Proxy URL.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string? ProxyUrl { get; set; }
|
public string? ProxyUrl { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The client X509Certificate2 Thumbprint or SubjectName to use.
|
/// The client X509Certificate2 Thumbprint or SubjectName to use.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string? X509Certificate2ThumbprintOrSubjectName { get; set; }
|
public string? X509Certificate2ThumbprintOrSubjectName { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the fault.
|
/// Gets or sets the fault.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public FaultModel? Fault { get; set; }
|
public FaultModel? Fault { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the WebProxy settings.
|
/// Gets or sets the WebProxy settings.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public WebProxyModel? WebProxy { get; set; }
|
public WebProxyModel? WebProxy { get; set; }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -44,7 +44,7 @@ public interface IResponseMessage
|
|||||||
/// Gets or sets the status code.
|
/// Gets or sets the status code.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
object? StatusCode { get; }
|
object? StatusCode { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds the header.
|
/// Adds the header.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using WireMock.Matchers.Request;
|
using WireMock.Matchers.Request;
|
||||||
using WireMock.Models;
|
using WireMock.Models;
|
||||||
@@ -120,7 +121,16 @@ public interface IMapping
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Use Fire and Forget for the defined webhook(s). [Optional]
|
/// Use Fire and Forget for the defined webhook(s). [Optional]
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool? UseWebhooksFireAndForget { get; set; }
|
bool? UseWebhooksFireAndForget { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Data Object which can be used when WithTransformer is used.
|
||||||
|
/// e.g. lookup an path in this object using
|
||||||
|
/// <example>
|
||||||
|
/// lookup data "1"
|
||||||
|
/// </example>
|
||||||
|
/// </summary>
|
||||||
|
object? Data { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ProvideResponseAsync
|
/// ProvideResponseAsync
|
||||||
|
|||||||
10
src/WireMock.Net/Json/DynamicJsonClassOptions.cs
Normal file
10
src/WireMock.Net/Json/DynamicJsonClassOptions.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
// Copied from https://github.com/Handlebars-Net/Handlebars.Net.Helpers/blob/master/src/Handlebars.Net.Helpers.DynamicLinq
|
||||||
|
|
||||||
|
namespace WireMock.Json;
|
||||||
|
|
||||||
|
internal class DynamicJsonClassOptions
|
||||||
|
{
|
||||||
|
public IntegerBehavior IntegerConvertBehavior { get; set; } = IntegerBehavior.UseLong;
|
||||||
|
|
||||||
|
public FloatBehavior FloatConvertBehavior { get; set; } = FloatBehavior.UseDouble;
|
||||||
|
}
|
||||||
15
src/WireMock.Net/Json/DynamicPropertyWithValue.cs
Normal file
15
src/WireMock.Net/Json/DynamicPropertyWithValue.cs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
// Copied from https://github.com/Handlebars-Net/Handlebars.Net.Helpers/blob/master/src/Handlebars.Net.Helpers.DynamicLinq
|
||||||
|
|
||||||
|
using System.Linq.Dynamic.Core;
|
||||||
|
|
||||||
|
namespace WireMock.Json;
|
||||||
|
|
||||||
|
public class DynamicPropertyWithValue : DynamicProperty
|
||||||
|
{
|
||||||
|
public object? Value { get; }
|
||||||
|
|
||||||
|
public DynamicPropertyWithValue(string name, object? value) : base(name, value?.GetType() ?? typeof(object))
|
||||||
|
{
|
||||||
|
Value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
24
src/WireMock.Net/Json/FloatBehavior.cs
Normal file
24
src/WireMock.Net/Json/FloatBehavior.cs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
// Copied from https://github.com/Handlebars-Net/Handlebars.Net.Helpers/blob/master/src/Handlebars.Net.Helpers.DynamicLinq
|
||||||
|
|
||||||
|
namespace WireMock.Json;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enum to define how to convert an Float in the Json Object.
|
||||||
|
/// </summary>
|
||||||
|
internal enum FloatBehavior
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Convert all Float types in the Json Object to a double. (default)
|
||||||
|
/// </summary>
|
||||||
|
UseDouble = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Convert all Float types in the Json Object to a float (unless overflow).
|
||||||
|
/// </summary>
|
||||||
|
UseFloat = 1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Convert all Float types in the Json Object to a decimal (unless overflow).
|
||||||
|
/// </summary>
|
||||||
|
UseDecimal = 2
|
||||||
|
}
|
||||||
20
src/WireMock.Net/Json/IntegerBehavior.cs
Normal file
20
src/WireMock.Net/Json/IntegerBehavior.cs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
// Copied from https://github.com/Handlebars-Net/Handlebars.Net.Helpers/blob/master/src/Handlebars.Net.Helpers.DynamicLinq
|
||||||
|
|
||||||
|
namespace WireMock.Json;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enum to define how to convert an Integer in the Json Object.
|
||||||
|
/// </summary>
|
||||||
|
internal enum IntegerBehavior
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Convert all Integer types in the Json Object to a int (unless overflow).
|
||||||
|
/// (default)
|
||||||
|
/// </summary>
|
||||||
|
UseInt = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Convert all Integer types in the Json Object to a long.
|
||||||
|
/// </summary>
|
||||||
|
UseLong = 1
|
||||||
|
}
|
||||||
202
src/WireMock.Net/Json/JObjectExtensions.cs
Normal file
202
src/WireMock.Net/Json/JObjectExtensions.cs
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
// Copied from https://github.com/Handlebars-Net/Handlebars.Net.Helpers/blob/master/src/Handlebars.Net.Helpers.DynamicLinq
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Linq.Dynamic.Core;
|
||||||
|
using System.Reflection;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
|
namespace WireMock.Json;
|
||||||
|
|
||||||
|
internal static class JObjectExtensions
|
||||||
|
{
|
||||||
|
private class JTokenResolvers : Dictionary<JTokenType, Func<JToken, DynamicJsonClassOptions?, object?>>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private static readonly JTokenResolvers Resolvers = new()
|
||||||
|
{
|
||||||
|
{ JTokenType.Array, ConvertJTokenArray },
|
||||||
|
{ JTokenType.Boolean, (jToken, _) => jToken.Value<bool>() },
|
||||||
|
{ JTokenType.Bytes, (jToken, _) => jToken.Value<byte[]>() },
|
||||||
|
{ JTokenType.Date, (jToken, _) => jToken.Value<DateTime>() },
|
||||||
|
{ JTokenType.Float, ConvertJTokenFloat },
|
||||||
|
{ JTokenType.Guid, (jToken, _) => jToken.Value<Guid>() },
|
||||||
|
{ JTokenType.Integer, ConvertJTokenInteger },
|
||||||
|
{ JTokenType.None, (_, _) => null },
|
||||||
|
{ JTokenType.Null, (_, _) => null },
|
||||||
|
{ JTokenType.Object, ConvertJObject },
|
||||||
|
{ JTokenType.Property, ConvertJTokenProperty },
|
||||||
|
{ JTokenType.String, (jToken, _) => jToken.Value<string>() },
|
||||||
|
{ JTokenType.TimeSpan, (jToken, _) => jToken.Value<TimeSpan>() },
|
||||||
|
{ JTokenType.Undefined, (_, _) => null },
|
||||||
|
{ JTokenType.Uri, (o, _) => o.Value<Uri>() },
|
||||||
|
};
|
||||||
|
|
||||||
|
internal static DynamicClass? ToDynamicJsonClass(this JObject? src, DynamicJsonClassOptions? options = null)
|
||||||
|
{
|
||||||
|
if (src == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var dynamicPropertyWithValues = new List<DynamicPropertyWithValue>();
|
||||||
|
|
||||||
|
foreach (var prop in src.Properties())
|
||||||
|
{
|
||||||
|
var value = Resolvers[prop.Type](prop.Value, options);
|
||||||
|
if (value != null)
|
||||||
|
{
|
||||||
|
dynamicPropertyWithValues.Add(new DynamicPropertyWithValue(prop.Name, value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return CreateInstance(dynamicPropertyWithValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static IEnumerable ToDynamicClassArray(this JArray? src, DynamicJsonClassOptions? options = null)
|
||||||
|
{
|
||||||
|
if (src == null)
|
||||||
|
{
|
||||||
|
return new object?[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return ConvertJTokenArray(src, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static object? ConvertJObject(JToken arg, DynamicJsonClassOptions? options = null)
|
||||||
|
{
|
||||||
|
if (arg is JObject asJObject)
|
||||||
|
{
|
||||||
|
return asJObject.ToDynamicJsonClass(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
return GetResolverFor(arg)(arg, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static object PassThrough(JToken arg, DynamicJsonClassOptions? options)
|
||||||
|
{
|
||||||
|
return arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Func<JToken, DynamicJsonClassOptions?, object?> GetResolverFor(JToken arg)
|
||||||
|
{
|
||||||
|
return Resolvers.TryGetValue(arg.Type, out var result) ? result : PassThrough;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static object ConvertJTokenFloat(JToken arg, DynamicJsonClassOptions? options = null)
|
||||||
|
{
|
||||||
|
if (arg.Type != JTokenType.Float)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"Unable to convert {nameof(JToken)} of type: {arg.Type} to double or float.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options?.FloatConvertBehavior == FloatBehavior.UseFloat)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return arg.Value<float>();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return arg.Value<double>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options?.FloatConvertBehavior == FloatBehavior.UseDecimal)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return arg.Value<decimal>();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return arg.Value<double>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return arg.Value<double>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static object ConvertJTokenInteger(JToken arg, DynamicJsonClassOptions? options = null)
|
||||||
|
{
|
||||||
|
if (arg.Type != JTokenType.Integer)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"Unable to convert {nameof(JToken)} of type: {arg.Type} to long or int.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var longValue = arg.Value<long>();
|
||||||
|
|
||||||
|
if (options is null || options.IntegerConvertBehavior == IntegerBehavior.UseInt)
|
||||||
|
{
|
||||||
|
if (longValue is >= int.MinValue and <= int.MaxValue)
|
||||||
|
{
|
||||||
|
return Convert.ToInt32(longValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return longValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static object? ConvertJTokenProperty(JToken arg, DynamicJsonClassOptions? options = null)
|
||||||
|
{
|
||||||
|
var resolver = GetResolverFor(arg);
|
||||||
|
if (resolver is null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"Unable to handle {nameof(JToken)} of type: {arg.Type}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolver(arg, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IEnumerable ConvertJTokenArray(JToken arg, DynamicJsonClassOptions? options = null)
|
||||||
|
{
|
||||||
|
if (arg is not JArray array)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"Unable to convert {nameof(JToken)} of type: {arg.Type} to {nameof(JArray)}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = new List<object?>();
|
||||||
|
foreach (var item in array)
|
||||||
|
{
|
||||||
|
result.Add(ConvertJObject(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
var distinctType = FindSameTypeOf(result);
|
||||||
|
return distinctType == null ? result.ToArray() : ConvertToTypedArray(result, distinctType);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Type? FindSameTypeOf(IEnumerable<object?> src)
|
||||||
|
{
|
||||||
|
var types = src.Select(o => o?.GetType()).Distinct().OfType<Type>().ToArray();
|
||||||
|
return types.Length == 1 ? types[0] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IEnumerable ConvertToTypedArray(IEnumerable<object?> src, Type newType)
|
||||||
|
{
|
||||||
|
var method = ConvertToTypedArrayGenericMethod.MakeGenericMethod(newType);
|
||||||
|
return (IEnumerable)method.Invoke(null, new object[] { src })!;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static readonly MethodInfo ConvertToTypedArrayGenericMethod = typeof(JObjectExtensions).GetMethod(nameof(ConvertToTypedArrayGeneric), BindingFlags.NonPublic | BindingFlags.Static)!;
|
||||||
|
|
||||||
|
private static T[] ConvertToTypedArrayGeneric<T>(IEnumerable<object> src)
|
||||||
|
{
|
||||||
|
return src.Cast<T>().ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DynamicClass CreateInstance(IList<DynamicPropertyWithValue> dynamicPropertiesWithValue, bool createParameterCtor = true)
|
||||||
|
{
|
||||||
|
var type = DynamicClassFactory.CreateType(dynamicPropertiesWithValue.Cast<DynamicProperty>().ToArray(), createParameterCtor);
|
||||||
|
var dynamicClass = (DynamicClass)Activator.CreateInstance(type);
|
||||||
|
foreach (var dynamicPropertyWithValue in dynamicPropertiesWithValue.Where(p => p.Value != null))
|
||||||
|
{
|
||||||
|
dynamicClass.SetDynamicPropertyValue(dynamicPropertyWithValue.Name, dynamicPropertyWithValue.Value!);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dynamicClass;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -72,6 +72,9 @@ public class Mapping : IMapping
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public ITimeSettings? TimeSettings { get; }
|
public ITimeSettings? TimeSettings { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public object? Data { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="Mapping"/> class.
|
/// Initializes a new instance of the <see cref="Mapping"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -91,6 +94,7 @@ public class Mapping : IMapping
|
|||||||
/// <param name="webhooks">The Webhooks. [Optional]</param>
|
/// <param name="webhooks">The Webhooks. [Optional]</param>
|
||||||
/// <param name="useWebhooksFireAndForget">Use Fire and Forget for the defined webhook(s). [Optional]</param>
|
/// <param name="useWebhooksFireAndForget">Use Fire and Forget for the defined webhook(s). [Optional]</param>
|
||||||
/// <param name="timeSettings">The TimeSettings. [Optional]</param>
|
/// <param name="timeSettings">The TimeSettings. [Optional]</param>
|
||||||
|
/// <param name="data">The data object. [Optional]</param>
|
||||||
public Mapping(
|
public Mapping(
|
||||||
Guid guid,
|
Guid guid,
|
||||||
DateTime updatedAt,
|
DateTime updatedAt,
|
||||||
@@ -107,7 +111,8 @@ public class Mapping : IMapping
|
|||||||
int? stateTimes,
|
int? stateTimes,
|
||||||
IWebhook[]? webhooks,
|
IWebhook[]? webhooks,
|
||||||
bool? useWebhooksFireAndForget,
|
bool? useWebhooksFireAndForget,
|
||||||
ITimeSettings? timeSettings)
|
ITimeSettings? timeSettings,
|
||||||
|
object? data)
|
||||||
{
|
{
|
||||||
Guid = guid;
|
Guid = guid;
|
||||||
UpdatedAt = updatedAt;
|
UpdatedAt = updatedAt;
|
||||||
@@ -125,6 +130,7 @@ public class Mapping : IMapping
|
|||||||
Webhooks = webhooks;
|
Webhooks = webhooks;
|
||||||
UseWebhooksFireAndForget = useWebhooksFireAndForget;
|
UseWebhooksFireAndForget = useWebhooksFireAndForget;
|
||||||
TimeSettings = timeSettings;
|
TimeSettings = timeSettings;
|
||||||
|
Data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="IMapping.ProvideResponseAsync" />
|
/// <inheritdoc cref="IMapping.ProvideResponseAsync" />
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ using AnyOfTypes;
|
|||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using Stef.Validation;
|
using Stef.Validation;
|
||||||
using WireMock.Extensions;
|
using WireMock.Extensions;
|
||||||
|
using WireMock.Json;
|
||||||
using WireMock.Models;
|
using WireMock.Models;
|
||||||
using WireMock.Util;
|
|
||||||
|
|
||||||
namespace WireMock.Matchers;
|
namespace WireMock.Matchers;
|
||||||
|
|
||||||
@@ -100,38 +100,55 @@ public class LinqMatcher : IObjectMatcher, IStringMatcher
|
|||||||
{
|
{
|
||||||
double match = MatchScores.Mismatch;
|
double match = MatchScores.Mismatch;
|
||||||
|
|
||||||
JObject value;
|
JArray jArray;
|
||||||
switch (input)
|
try
|
||||||
{
|
{
|
||||||
case JObject valueAsJObject:
|
jArray = new JArray { input };
|
||||||
value = valueAsJObject;
|
}
|
||||||
break;
|
catch
|
||||||
|
{
|
||||||
case { } valueAsObject:
|
jArray = new JArray { JToken.FromObject(input) };
|
||||||
value = JObject.FromObject(valueAsObject);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return MatchScores.Mismatch;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//enumerable = jArray.ToDynamicClassArray();
|
||||||
|
|
||||||
|
//JObject value;
|
||||||
|
//switch (input)
|
||||||
|
//{
|
||||||
|
// case JObject valueAsJObject:
|
||||||
|
// value = valueAsJObject;
|
||||||
|
// break;
|
||||||
|
|
||||||
|
// case { } valueAsObject:
|
||||||
|
// value = JObject.FromObject(valueAsObject);
|
||||||
|
// break;
|
||||||
|
|
||||||
|
// default:
|
||||||
|
// return MatchScores.Mismatch;
|
||||||
|
//}
|
||||||
|
|
||||||
// Convert a single object to a Queryable JObject-list with 1 entry.
|
// Convert a single object to a Queryable JObject-list with 1 entry.
|
||||||
var queryable1 = new[] { value }.AsQueryable();
|
//var queryable1 = new[] { value }.AsQueryable();
|
||||||
|
var queryable = jArray.ToDynamicClassArray().AsQueryable();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Generate the DynamicLinq select statement.
|
// Generate the DynamicLinq select statement.
|
||||||
string dynamicSelect = JsonUtils.GenerateDynamicLinqStatement(value);
|
//string dynamicSelect = JsonUtils.GenerateDynamicLinqStatement(value);
|
||||||
|
|
||||||
// Execute DynamicLinq Select statement.
|
// Execute DynamicLinq Select statement.
|
||||||
var queryable2 = queryable1.Select(dynamicSelect);
|
//var queryable2 = queryable1.Select(dynamicSelect);
|
||||||
|
|
||||||
// Use the Any(...) method to check if the result matches.
|
// Use the Any(...) method to check if the result matches.
|
||||||
match = MatchScores.ToScore(_patterns.Select(pattern => queryable2.Any(pattern)).ToArray(), MatchOperator);
|
|
||||||
|
var patternsAsStringArray = _patterns.Select(p => p.GetPattern()).ToArray();
|
||||||
|
var scores = patternsAsStringArray.Select(p => queryable.Any(p)).ToArray();
|
||||||
|
|
||||||
|
match = MatchScores.ToScore(_patterns.Select(pattern => queryable.Any(pattern.GetPattern())).ToArray(), MatchOperator);
|
||||||
|
|
||||||
return MatchBehaviourHelper.Convert(MatchBehaviour, match);
|
return MatchBehaviourHelper.Convert(MatchBehaviour, match);
|
||||||
}
|
}
|
||||||
catch
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
if (ThrowException)
|
if (ThrowException)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -107,14 +107,12 @@ public partial class Response : IResponseBuilder
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="Response"/> class.
|
/// Initializes a new instance of the <see cref="Response"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="responseMessage">
|
/// <param name="responseMessage">The response.</param>
|
||||||
/// The response.
|
|
||||||
/// </param>
|
|
||||||
private Response(ResponseMessage responseMessage)
|
private Response(ResponseMessage responseMessage)
|
||||||
{
|
{
|
||||||
ResponseMessage = responseMessage;
|
ResponseMessage = responseMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="IStatusCodeResponseBuilder.WithStatusCode(int)"/>
|
/// <inheritdoc cref="IStatusCodeResponseBuilder.WithStatusCode(int)"/>
|
||||||
[PublicAPI]
|
[PublicAPI]
|
||||||
public IResponseBuilder WithStatusCode(int code)
|
public IResponseBuilder WithStatusCode(int code)
|
||||||
|
|||||||
@@ -181,6 +181,7 @@ internal class MappingConverter
|
|||||||
Scenario = mapping.Scenario,
|
Scenario = mapping.Scenario,
|
||||||
WhenStateIs = mapping.ExecutionConditionState,
|
WhenStateIs = mapping.ExecutionConditionState,
|
||||||
SetStateTo = mapping.NextState,
|
SetStateTo = mapping.NextState,
|
||||||
|
Data = mapping.Data,
|
||||||
Request = new RequestModel
|
Request = new RequestModel
|
||||||
{
|
{
|
||||||
Headers = headerMatchers.Any() ? headerMatchers.Select(hm => new HeaderModel
|
Headers = headerMatchers.Any() ? headerMatchers.Select(hm => new HeaderModel
|
||||||
|
|||||||
@@ -177,7 +177,8 @@ internal class ProxyMappingConverter
|
|||||||
stateTimes: null,
|
stateTimes: null,
|
||||||
webhooks: null,
|
webhooks: null,
|
||||||
useWebhooksFireAndForget: null,
|
useWebhooksFireAndForget: null,
|
||||||
timeSettings: null
|
timeSettings: null,
|
||||||
|
data: mapping?.Data
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -166,4 +166,14 @@ public interface IRespondWithAProvider
|
|||||||
bool useTransformer = true,
|
bool useTransformer = true,
|
||||||
TransformerType transformerType = TransformerType.Handlebars
|
TransformerType transformerType = TransformerType.Handlebars
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Data Object which can be used when WithTransformer is used.
|
||||||
|
/// e.g. lookup an path in this object using
|
||||||
|
/// <param name="data">The data dictionary object.</param>
|
||||||
|
/// <example>
|
||||||
|
/// lookup data "1"
|
||||||
|
/// </example>
|
||||||
|
/// </summary>
|
||||||
|
IRespondWithAProvider WithData(object data);
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
// For more details see 'mock4net/LICENSE.txt' and 'mock4net/readme.md' in this project root.
|
// For more details see 'mock4net/LICENSE.txt' and 'mock4net/readme.md' in this project root.
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using JetBrains.Annotations;
|
||||||
using Stef.Validation;
|
using Stef.Validation;
|
||||||
using WireMock.Matchers.Request;
|
using WireMock.Matchers.Request;
|
||||||
using WireMock.Models;
|
using WireMock.Models;
|
||||||
@@ -39,6 +40,8 @@ internal class RespondWithAProvider : IRespondWithAProvider
|
|||||||
|
|
||||||
public ITimeSettings? TimeSettings { get; private set; }
|
public ITimeSettings? TimeSettings { get; private set; }
|
||||||
|
|
||||||
|
public object? Data { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="RespondWithAProvider"/> class.
|
/// Initializes a new instance of the <see cref="RespondWithAProvider"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -88,10 +91,20 @@ internal class RespondWithAProvider : IRespondWithAProvider
|
|||||||
_timesInSameState,
|
_timesInSameState,
|
||||||
Webhooks,
|
Webhooks,
|
||||||
_useWebhookFireAndForget,
|
_useWebhookFireAndForget,
|
||||||
TimeSettings);
|
TimeSettings,
|
||||||
|
Data);
|
||||||
|
|
||||||
_registrationCallback(mapping, _saveToFile);
|
_registrationCallback(mapping, _saveToFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
[PublicAPI]
|
||||||
|
public IRespondWithAProvider WithData(object data)
|
||||||
|
{
|
||||||
|
Data = data;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public IRespondWithAProvider WithGuid(string guid)
|
public IRespondWithAProvider WithGuid(string guid)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ public partial class WireMockServer
|
|||||||
}
|
}
|
||||||
|
|
||||||
var respondProvider = Given(requestBuilder, mappingModel.SaveToFile == true);
|
var respondProvider = Given(requestBuilder, mappingModel.SaveToFile == true);
|
||||||
|
|
||||||
if (guid != null)
|
if (guid != null)
|
||||||
{
|
{
|
||||||
respondProvider = respondProvider.WithGuid(guid.Value);
|
respondProvider = respondProvider.WithGuid(guid.Value);
|
||||||
@@ -56,6 +56,11 @@ public partial class WireMockServer
|
|||||||
respondProvider = respondProvider.WithGuid(mappingModel.Guid.Value);
|
respondProvider = respondProvider.WithGuid(mappingModel.Guid.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mappingModel.Data != null)
|
||||||
|
{
|
||||||
|
respondProvider = respondProvider.WithData(mappingModel.Data);
|
||||||
|
}
|
||||||
|
|
||||||
var timeSettings = TimeSettingsMapper.Map(mappingModel.TimeSettings);
|
var timeSettings = TimeSettingsMapper.Map(mappingModel.TimeSettings);
|
||||||
if (timeSettings != null)
|
if (timeSettings != null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -10,4 +10,6 @@ internal struct TransformModel
|
|||||||
public IRequestMessage request { get; set; }
|
public IRequestMessage request { get; set; }
|
||||||
|
|
||||||
public IResponseMessage? response { get; set; }
|
public IResponseMessage? response { get; set; }
|
||||||
|
|
||||||
|
public object data { get; set; }
|
||||||
}
|
}
|
||||||
@@ -5,6 +5,7 @@ using System.Linq;
|
|||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using Stef.Validation;
|
using Stef.Validation;
|
||||||
|
using WireMock.ResponseBuilders;
|
||||||
using WireMock.Settings;
|
using WireMock.Settings;
|
||||||
using WireMock.Types;
|
using WireMock.Types;
|
||||||
using WireMock.Util;
|
using WireMock.Util;
|
||||||
@@ -115,7 +116,8 @@ internal class Transformer : ITransformer
|
|||||||
{
|
{
|
||||||
mapping = mapping,
|
mapping = mapping,
|
||||||
request = request,
|
request = request,
|
||||||
response = response
|
response = response,
|
||||||
|
data = mapping.Data ?? new { }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
@@ -108,103 +106,4 @@ internal static class JsonUtils
|
|||||||
_ => throw new NotSupportedException($"Unable to convert value to {typeof(T)}.")
|
_ => throw new NotSupportedException($"Unable to convert value to {typeof(T)}.")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Based on / copied from Handlebars.Net Handlebars.Net.Helpers.Utils.JsonUtils
|
|
||||||
/// </summary>
|
|
||||||
public static string GenerateDynamicLinqStatement(JToken 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)
|
|
||||||
{
|
|
||||||
switch (node.Type)
|
|
||||||
{
|
|
||||||
case JTokenType.Object:
|
|
||||||
ProcessObject(node, propertyName, lines);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case JTokenType.Array:
|
|
||||||
ProcessArray(node, propertyName, lines);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
ProcessItem(node, path ?? "it", propertyName, lines);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 (var child in node.Children<JProperty>().ToArray())
|
|
||||||
{
|
|
||||||
WalkNode(child.Value, child.Path, child.Name, items);
|
|
||||||
}
|
|
||||||
|
|
||||||
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.
|
|
||||||
var idx = 0;
|
|
||||||
foreach (var 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)
|
|
||||||
{
|
|
||||||
var castText = node.Type switch
|
|
||||||
{
|
|
||||||
JTokenType.Boolean => $"bool({path})",
|
|
||||||
JTokenType.Date => $"DateTime({path})",
|
|
||||||
JTokenType.Float => $"double({path})",
|
|
||||||
JTokenType.Guid => $"Guid({path})",
|
|
||||||
JTokenType.Integer => $"long({path})",
|
|
||||||
JTokenType.Null => "null",
|
|
||||||
JTokenType.String => $"string({path})",
|
|
||||||
JTokenType.TimeSpan => $"TimeSpan({path})",
|
|
||||||
JTokenType.Uri => $"Uri({path})",
|
|
||||||
_ => 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -53,13 +53,13 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="JetBrains.Annotations" Version="2022.3.1" PrivateAssets="All" />
|
<PackageReference Include="JetBrains.Annotations" Version="2022.3.1" PrivateAssets="All" />
|
||||||
<PackageReference Include="JsonConverter.Abstractions" Version="0.3.0" />
|
<PackageReference Include="JsonConverter.Abstractions" Version="0.4.0" />
|
||||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All" />
|
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||||
<PackageReference Include="NJsonSchema.Extensions" Version="0.1.0" />
|
<PackageReference Include="NJsonSchema.Extensions" Version="0.1.0" />
|
||||||
<PackageReference Include="NSwag.Core" Version="13.16.1" />
|
<PackageReference Include="NSwag.Core" Version="13.16.1" />
|
||||||
<PackageReference Include="SimMetrics.Net" Version="1.0.5" />
|
<PackageReference Include="SimMetrics.Net" Version="1.0.5" />
|
||||||
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.2.23" />
|
<!--<PackageReference Include="System.Linq.Dynamic.Core" Version="1.2.23" />-->
|
||||||
<PackageReference Include="JmesPath.Net" Version="1.0.125" />
|
<PackageReference Include="JmesPath.Net" Version="1.0.125" />
|
||||||
<PackageReference Include="AnyOf" Version="0.3.0" />
|
<PackageReference Include="AnyOf" Version="0.3.0" />
|
||||||
<PackageReference Include="TinyMapper" Version="3.0.3" />
|
<PackageReference Include="TinyMapper" Version="3.0.3" />
|
||||||
@@ -177,13 +177,13 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Handlebars.Net.Helpers" Version="2.3.12" />
|
<PackageReference Include="Handlebars.Net.Helpers" Version="2.3.15-preview-01" />
|
||||||
<PackageReference Include="Handlebars.Net.Helpers.DynamicLinq" Version="2.3.12" />
|
<PackageReference Include="Handlebars.Net.Helpers.DynamicLinq" Version="2.3.15-preview-01" />
|
||||||
<PackageReference Include="Handlebars.Net.Helpers.Humanizer" Version="2.3.12" />
|
<PackageReference Include="Handlebars.Net.Helpers.Humanizer" Version="2.3.15-preview-01" />
|
||||||
<PackageReference Include="Handlebars.Net.Helpers.Json" Version="2.3.12" />
|
<PackageReference Include="Handlebars.Net.Helpers.Json" Version="2.3.15-preview-01" />
|
||||||
<PackageReference Include="Handlebars.Net.Helpers.Random" Version="2.3.12" />
|
<PackageReference Include="Handlebars.Net.Helpers.Random" Version="2.3.15-preview-01" />
|
||||||
<PackageReference Include="Handlebars.Net.Helpers.XPath" Version="2.3.12" />
|
<PackageReference Include="Handlebars.Net.Helpers.XPath" Version="2.3.15-preview-01" />
|
||||||
<PackageReference Include="Handlebars.Net.Helpers.Xeger" Version="2.3.12" />
|
<PackageReference Include="Handlebars.Net.Helpers.Xeger" Version="2.3.15-preview-01" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -177,7 +177,7 @@ public class WireMockMiddlewareTests
|
|||||||
_mappingMock.SetupGet(m => m.Provider).Returns(responseBuilder);
|
_mappingMock.SetupGet(m => m.Provider).Returns(responseBuilder);
|
||||||
_mappingMock.SetupGet(m => m.Settings).Returns(settings);
|
_mappingMock.SetupGet(m => m.Settings).Returns(settings);
|
||||||
|
|
||||||
var newMappingFromProxy = new Mapping(Guid.NewGuid(), _updatedAt, string.Empty, string.Empty, null, settings, Request.Create(), Response.Create(), 0, null, null, null, null, null, false, null);
|
var newMappingFromProxy = new Mapping(Guid.NewGuid(), _updatedAt, string.Empty, string.Empty, null, settings, Request.Create(), Response.Create(), 0, null, null, null, null, null, false, null, null);
|
||||||
_mappingMock.Setup(m => m.ProvideResponseAsync(It.IsAny<RequestMessage>())).ReturnsAsync((new ResponseMessage(), newMappingFromProxy));
|
_mappingMock.Setup(m => m.ProvideResponseAsync(It.IsAny<RequestMessage>())).ReturnsAsync((new ResponseMessage(), newMappingFromProxy));
|
||||||
|
|
||||||
var requestBuilder = Request.Create().UsingAnyMethod();
|
var requestBuilder = Request.Create().UsingAnyMethod();
|
||||||
@@ -231,7 +231,7 @@ public class WireMockMiddlewareTests
|
|||||||
_mappingMock.SetupGet(m => m.Provider).Returns(responseBuilder);
|
_mappingMock.SetupGet(m => m.Provider).Returns(responseBuilder);
|
||||||
_mappingMock.SetupGet(m => m.Settings).Returns(settings);
|
_mappingMock.SetupGet(m => m.Settings).Returns(settings);
|
||||||
|
|
||||||
var newMappingFromProxy = new Mapping(Guid.NewGuid(), _updatedAt, "my-title", "my-description", null, settings, Request.Create(), Response.Create(), 0, null, null, null, null, null, false, null);
|
var newMappingFromProxy = new Mapping(Guid.NewGuid(), _updatedAt, "my-title", "my-description", null, settings, Request.Create(), Response.Create(), 0, null, null, null, null, null, false, null, data: null);
|
||||||
_mappingMock.Setup(m => m.ProvideResponseAsync(It.IsAny<RequestMessage>())).ReturnsAsync((new ResponseMessage(), newMappingFromProxy));
|
_mappingMock.Setup(m => m.ProvideResponseAsync(It.IsAny<RequestMessage>())).ReturnsAsync((new ResponseMessage(), newMappingFromProxy));
|
||||||
|
|
||||||
var requestBuilder = Request.Create().UsingAnyMethod();
|
var requestBuilder = Request.Create().UsingAnyMethod();
|
||||||
|
|||||||
@@ -163,22 +163,6 @@ public class ResponseWithHandlebarsLinqTests
|
|||||||
Check.ThatAsyncCode(() => responseBuilder.ProvideResponseAsync(mappingMock.Object, request, _settings)).Throws<ArgumentException>();
|
Check.ThatAsyncCode(() => responseBuilder.ProvideResponseAsync(mappingMock.Object, request, _settings)).Throws<ArgumentException>();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Response_ProvideResponse_Handlebars_Linq1_Throws_ArgumentNullException()
|
|
||||||
{
|
|
||||||
// Assign
|
|
||||||
var body = new BodyData();
|
|
||||||
|
|
||||||
var request = new RequestMessage(new UrlDetails("http://localhost:1234"), "POST", "::1", body);
|
|
||||||
|
|
||||||
var responseBuilder = Response.Create()
|
|
||||||
.WithBodyAsJson(new { x = "{{Linq request.body 'Name'}}" })
|
|
||||||
.WithTransformer();
|
|
||||||
|
|
||||||
// Act
|
|
||||||
Check.ThatAsyncCode(() => responseBuilder.ProvideResponseAsync(mappingMock.Object, request, _settings)).Throws<ArgumentNullException>();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Response_ProvideResponse_Handlebars_Linq1_Throws_HandlebarsException()
|
public void Response_ProvideResponse_Handlebars_Linq1_Throws_HandlebarsException()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -782,4 +782,31 @@ public class ResponseWithTransformerTests
|
|||||||
response.Message.BodyData!.BodyAsString.Should().Be(text);
|
response.Message.BodyData!.BodyAsString.Should().Be(text);
|
||||||
response.Message.BodyData.Encoding.Should().Be(enc);
|
response.Message.BodyData.Encoding.Should().Be(enc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("/wiremock-data/1", "one")]
|
||||||
|
[InlineData("/wiremock-data/2", "two")]
|
||||||
|
[InlineData("/wiremock-data/3", "N/A")]
|
||||||
|
public async Task Response_ProvideResponse_Handlebars_DataObject(string path, string expected)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var request = new RequestMessage(new UrlDetails("https://localhost" + path), "POST", ClientIp);
|
||||||
|
var data = new Dictionary<string, object?>
|
||||||
|
{
|
||||||
|
{ "1", "one" },
|
||||||
|
{ "2", "two" }
|
||||||
|
};
|
||||||
|
|
||||||
|
var responseBuilder = Response.Create()
|
||||||
|
.WithBody("{{lookup data request.PathSegments.[1] 'N/A'}}")
|
||||||
|
.WithTransformer();
|
||||||
|
|
||||||
|
_mappingMock.SetupGet(m => m.Data).Returns(data);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await responseBuilder.ProvideResponseAsync(_mappingMock.Object, request, _settings).ConfigureAwait(false);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
response.Message.BodyData!.BodyAsString.Should().Be(expected);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -119,7 +119,25 @@ public partial class MappingConverterTests
|
|||||||
.WithDelay(12345)
|
.WithDelay(12345)
|
||||||
.WithTransformer();
|
.WithTransformer();
|
||||||
|
|
||||||
return new Mapping(guid, _updatedAt, string.Empty, string.Empty, null, _settings, request, response, 42, null, null, null, null, null, false, null);
|
return new Mapping(
|
||||||
|
guid,
|
||||||
|
_updatedAt,
|
||||||
|
string.Empty,
|
||||||
|
string.Empty,
|
||||||
|
null,
|
||||||
|
_settings,
|
||||||
|
request,
|
||||||
|
response,
|
||||||
|
42,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
false,
|
||||||
|
null,
|
||||||
|
data: null
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -57,7 +57,7 @@ public partial class MappingConverterTests
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
var mapping = new Mapping(_guid, _updatedAt, string.Empty, string.Empty, null, _settings, request, response, 0, null, null, null, null, webhooks, false, null);
|
var mapping = new Mapping(_guid, _updatedAt, string.Empty, string.Empty, null, _settings, request, response, 0, null, null, null, null, webhooks, false, null, data: null);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var model = _sut.ToMappingModel(mapping);
|
var model = _sut.ToMappingModel(mapping);
|
||||||
@@ -130,7 +130,7 @@ public partial class MappingConverterTests
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
var mapping = new Mapping(_guid, _updatedAt, string.Empty, string.Empty, null, _settings, request, response, 0, null, null, null, null, webhooks, true, null);
|
var mapping = new Mapping(_guid, _updatedAt, string.Empty, string.Empty, null, _settings, request, response, 0, null, null, null, null, webhooks, true, null, data: null);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var model = _sut.ToMappingModel(mapping);
|
var model = _sut.ToMappingModel(mapping);
|
||||||
@@ -168,7 +168,7 @@ public partial class MappingConverterTests
|
|||||||
var description = "my-description";
|
var description = "my-description";
|
||||||
var request = Request.Create();
|
var request = Request.Create();
|
||||||
var response = Response.Create();
|
var response = Response.Create();
|
||||||
var mapping = new Mapping(_guid, _updatedAt, title, description, null, _settings, request, response, 0, null, null, null, null, null, false, null);
|
var mapping = new Mapping(_guid, _updatedAt, title, description, null, _settings, request, response, 0, null, null, null, null, null, false, null, data: null);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var model = _sut.ToMappingModel(mapping);
|
var model = _sut.ToMappingModel(mapping);
|
||||||
@@ -188,7 +188,7 @@ public partial class MappingConverterTests
|
|||||||
// Assign
|
// Assign
|
||||||
var request = Request.Create();
|
var request = Request.Create();
|
||||||
var response = Response.Create().WithBodyAsJson(new { x = "x" }).WithTransformer();
|
var response = Response.Create().WithBodyAsJson(new { x = "x" }).WithTransformer();
|
||||||
var mapping = new Mapping(_guid, _updatedAt, string.Empty, string.Empty, null, _settings, request, response, 42, null, null, null, null, null, false, null);
|
var mapping = new Mapping(_guid, _updatedAt, string.Empty, string.Empty, null, _settings, request, response, 42, null, null, null, null, null, false, null, data: null);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var model = _sut.ToMappingModel(mapping);
|
var model = _sut.ToMappingModel(mapping);
|
||||||
@@ -217,7 +217,7 @@ public partial class MappingConverterTests
|
|||||||
End = end,
|
End = end,
|
||||||
TTL = ttl
|
TTL = ttl
|
||||||
};
|
};
|
||||||
var mapping = new Mapping(_guid, _updatedAt, string.Empty, string.Empty, null, _settings, request, response, 42, null, null, null, null, null, false, timeSettings);
|
var mapping = new Mapping(_guid, _updatedAt, string.Empty, string.Empty, null, _settings, request, response, 42, null, null, null, null, null, false, timeSettings, data: null);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var model = _sut.ToMappingModel(mapping);
|
var model = _sut.ToMappingModel(mapping);
|
||||||
@@ -248,7 +248,7 @@ public partial class MappingConverterTests
|
|||||||
{
|
{
|
||||||
var request = Request.Create();
|
var request = Request.Create();
|
||||||
var response = Response.Create().WithDelay(test.Delay);
|
var response = Response.Create().WithDelay(test.Delay);
|
||||||
var mapping = new Mapping(Guid.NewGuid(), _updatedAt, string.Empty, string.Empty, string.Empty, _settings, request, response, 42, null, null, null, null, null, false, null);
|
var mapping = new Mapping(Guid.NewGuid(), _updatedAt, string.Empty, string.Empty, string.Empty, _settings, request, response, 42, null, null, null, null, null, false, null, data: null);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var model = _sut.ToMappingModel(mapping);
|
var model = _sut.ToMappingModel(mapping);
|
||||||
@@ -266,7 +266,7 @@ public partial class MappingConverterTests
|
|||||||
var delay = 1000;
|
var delay = 1000;
|
||||||
var request = Request.Create();
|
var request = Request.Create();
|
||||||
var response = Response.Create().WithDelay(delay);
|
var response = Response.Create().WithDelay(delay);
|
||||||
var mapping = new Mapping(_guid, _updatedAt, string.Empty, string.Empty, null, _settings, request, response, 42, null, null, null, null, null, false, null);
|
var mapping = new Mapping(_guid, _updatedAt, string.Empty, string.Empty, null, _settings, request, response, 42, null, null, null, null, null, false, null, data: null);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var model = _sut.ToMappingModel(mapping);
|
var model = _sut.ToMappingModel(mapping);
|
||||||
@@ -286,7 +286,7 @@ public partial class MappingConverterTests
|
|||||||
int minimumDelay = 1000;
|
int minimumDelay = 1000;
|
||||||
var request = Request.Create();
|
var request = Request.Create();
|
||||||
var response = Response.Create().WithRandomDelay(minimumDelay);
|
var response = Response.Create().WithRandomDelay(minimumDelay);
|
||||||
var mapping = new Mapping(_guid, _updatedAt, string.Empty, string.Empty, null, _settings, request, response, 42, null, null, null, null, null, false, null);
|
var mapping = new Mapping(_guid, _updatedAt, string.Empty, string.Empty, null, _settings, request, response, 42, null, null, null, null, null, false, null, data: null);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var model = _sut.ToMappingModel(mapping);
|
var model = _sut.ToMappingModel(mapping);
|
||||||
@@ -309,7 +309,7 @@ public partial class MappingConverterTests
|
|||||||
int maximumDelay = 2000;
|
int maximumDelay = 2000;
|
||||||
var request = Request.Create();
|
var request = Request.Create();
|
||||||
var response = Response.Create().WithRandomDelay(minimumDelay, maximumDelay);
|
var response = Response.Create().WithRandomDelay(minimumDelay, maximumDelay);
|
||||||
var mapping = new Mapping(_guid, _updatedAt, string.Empty, string.Empty, null, _settings, request, response, 42, null, null, null, null, null, false, null);
|
var mapping = new Mapping(_guid, _updatedAt, string.Empty, string.Empty, null, _settings, request, response, 42, null, null, null, null, null, false, null, data: null);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var model = _sut.ToMappingModel(mapping);
|
var model = _sut.ToMappingModel(mapping);
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
<SignAssembly>true</SignAssembly>
|
<SignAssembly>true</SignAssembly>
|
||||||
<AssemblyOriginatorKeyFile>../../src/WireMock.Net/WireMock.Net.snk</AssemblyOriginatorKeyFile>
|
<AssemblyOriginatorKeyFile>../../src/WireMock.Net/WireMock.Net.snk</AssemblyOriginatorKeyFile>
|
||||||
<!--<DelaySign>true</DelaySign>-->
|
|
||||||
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
|
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
|
||||||
|
|
||||||
<!--https://developercommunity.visualstudio.com/content/problem/26347/unit-tests-fail-with-fileloadexception-newtonsoftj-1.html-->
|
<!--https://developercommunity.visualstudio.com/content/problem/26347/unit-tests-fail-with-fileloadexception-newtonsoftj-1.html-->
|
||||||
@@ -63,12 +63,13 @@
|
|||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
|
||||||
<PackageReference Include="Moq" Version="4.17.2" />
|
<PackageReference Include="Moq" Version="4.17.2" />
|
||||||
|
|
||||||
|
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.3.1-preview-02" />
|
||||||
<PackageReference Include="System.Threading" Version="4.3.0" />
|
<PackageReference Include="System.Threading" Version="4.3.0" />
|
||||||
<PackageReference Include="RestEase" Version="1.5.7" />
|
<PackageReference Include="RestEase" Version="1.5.7" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
|
||||||
<PackageReference Include="NFluent" Version="2.8.0" />
|
<PackageReference Include="NFluent" Version="2.8.0" />
|
||||||
<PackageReference Include="SimMetrics.Net" Version="1.0.5" />
|
<PackageReference Include="SimMetrics.Net" Version="1.0.5" />
|
||||||
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.2.23" />
|
|
||||||
<PackageReference Include="AnyOf" Version="0.3.0" />
|
<PackageReference Include="AnyOf" Version="0.3.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
@@ -97,7 +98,8 @@
|
|||||||
|
|
||||||
<ItemGroup Condition="'$(TargetFramework)' != 'net452'">
|
<ItemGroup Condition="'$(TargetFramework)' != 'net452'">
|
||||||
<PackageReference Include="System.Net.Http.Json" Version="3.2.1" />
|
<PackageReference Include="System.Net.Http.Json" Version="3.2.1" />
|
||||||
<PackageReference Include="JsonConverter.System.Text.Json" Version="0.3.0" />
|
<PackageReference Include="JsonConverter.System.Text.Json" Version="0.4.0" />
|
||||||
|
<!--<PackageReference Include="JsonConverter.NewtonSoft.Json" Version="0.4.0" />-->
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -117,8 +119,8 @@
|
|||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
<None Update="client_cert.pfx">
|
<None Update="client_cert.pfx">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
<DependentUpon>WireMockServerTests.ClientCertificate.cs</DependentUpon>
|
<DependentUpon>WireMockServerTests.ClientCertificate.cs</DependentUpon>
|
||||||
</None>
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
@@ -127,7 +129,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Folder Include="Pact\files\" />
|
<Folder Include="Pact\files\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
Reference in New Issue
Block a user