mirror of
https://github.com/wiremock/WireMock.Net.git
synced 2026-04-19 15:31:39 +02:00
GraphQL - custom scalar support (#1012)
* x * CustomScalars * more tests * . * add or set * ... * x
This commit is contained in:
@@ -43,6 +43,9 @@ namespace WireMock.Net.ConsoleApplication
|
|||||||
public static class MainApp
|
public static class MainApp
|
||||||
{
|
{
|
||||||
private const string TestSchema = @"
|
private const string TestSchema = @"
|
||||||
|
scalar DateTime
|
||||||
|
scalar MyCustomScalar
|
||||||
|
|
||||||
input MessageInput {
|
input MessageInput {
|
||||||
content: String
|
content: String
|
||||||
author: String
|
author: String
|
||||||
@@ -56,6 +59,7 @@ namespace WireMock.Net.ConsoleApplication
|
|||||||
|
|
||||||
type Mutation {
|
type Mutation {
|
||||||
createMessage(input: MessageInput): Message
|
createMessage(input: MessageInput): Message
|
||||||
|
createAnotherMessage(x: MyCustomScalar, dt: DateTime): Message
|
||||||
updateMessage(id: ID!, input: MessageInput): Message
|
updateMessage(id: ID!, input: MessageInput): Message
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,11 +172,12 @@ namespace WireMock.Net.ConsoleApplication
|
|||||||
|
|
||||||
// server.AllowPartialMapping();
|
// server.AllowPartialMapping();
|
||||||
#if GRAPHQL
|
#if GRAPHQL
|
||||||
|
var customScalars = new Dictionary<string, Type> { { "MyCustomScalar", typeof(int) } };
|
||||||
server
|
server
|
||||||
.Given(Request.Create()
|
.Given(Request.Create()
|
||||||
.WithPath("/graphql")
|
.WithPath("/graphql")
|
||||||
.UsingPost()
|
.UsingPost()
|
||||||
.WithGraphQLSchema(TestSchema)
|
.WithGraphQLSchema(TestSchema, customScalars)
|
||||||
)
|
)
|
||||||
.RespondWith(Response.Create()
|
.RespondWith(Response.Create()
|
||||||
.WithBody("GraphQL is ok")
|
.WithBody("GraphQL is ok")
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace WireMock.Admin.Mappings;
|
namespace WireMock.Admin.Mappings;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -75,6 +78,16 @@ public class MatcherModel
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region XPathMatcher
|
#region XPathMatcher
|
||||||
|
/// <summary>
|
||||||
|
/// Array of namespace prefix and uri. (optional)
|
||||||
|
/// </summary>
|
||||||
public XmlNamespace[]? XmlNamespaceMap { get; set; }
|
public XmlNamespace[]? XmlNamespaceMap { get; set; }
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region GraphQLMatcher
|
||||||
|
/// <summary>
|
||||||
|
/// Mapping of custom GraphQL Scalar name to ClrType. (optional)
|
||||||
|
/// </summary>
|
||||||
|
public IDictionary<string, Type>? CustomScalars { get; set; }
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
@@ -6,10 +6,15 @@ using System.Linq;
|
|||||||
using AnyOfTypes;
|
using AnyOfTypes;
|
||||||
using GraphQL;
|
using GraphQL;
|
||||||
using GraphQL.Types;
|
using GraphQL.Types;
|
||||||
|
using GraphQLParser;
|
||||||
|
using GraphQLParser.AST;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Stef.Validation;
|
using Stef.Validation;
|
||||||
|
using WireMock.Exceptions;
|
||||||
using WireMock.Extensions;
|
using WireMock.Extensions;
|
||||||
|
using WireMock.Matchers.Models;
|
||||||
using WireMock.Models;
|
using WireMock.Models;
|
||||||
|
using WireMock.Util;
|
||||||
|
|
||||||
namespace WireMock.Matchers;
|
namespace WireMock.Matchers;
|
||||||
|
|
||||||
@@ -36,14 +41,40 @@ public class GraphQLMatcher : IStringMatcher
|
|||||||
public MatchBehaviour MatchBehaviour { get; }
|
public MatchBehaviour MatchBehaviour { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="LinqMatcher"/> class.
|
/// An optional dictionary defining the custom Scalar and the type.
|
||||||
|
/// </summary>
|
||||||
|
public IDictionary<string, Type>? CustomScalars { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="GraphQLMatcher"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="schema">The schema.</param>
|
/// <param name="schema">The schema.</param>
|
||||||
/// <param name="matchBehaviour">The match behaviour.</param>
|
/// <param name="matchBehaviour">The match behaviour. (default = "AcceptOnMatch")</param>
|
||||||
/// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use. (default = "Or")</param>
|
/// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use. (default = "Or")</param>
|
||||||
public GraphQLMatcher(AnyOf<string, StringPattern, ISchema> schema, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch, MatchOperator matchOperator = MatchOperator.Or)
|
public GraphQLMatcher(
|
||||||
|
AnyOf<string, StringPattern, ISchema> schema,
|
||||||
|
MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch,
|
||||||
|
MatchOperator matchOperator = MatchOperator.Or
|
||||||
|
) : this(schema, null, matchBehaviour, matchOperator)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="GraphQLMatcher"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="schema">The schema.</param>
|
||||||
|
/// <param name="customScalars">A dictionary defining the custom scalars used in this schema. (optional)</param>
|
||||||
|
/// <param name="matchBehaviour">The match behaviour. (default = "AcceptOnMatch")</param>
|
||||||
|
/// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use. (default = "Or")</param>
|
||||||
|
public GraphQLMatcher(
|
||||||
|
AnyOf<string, StringPattern, ISchema> schema,
|
||||||
|
IDictionary<string, Type>? customScalars,
|
||||||
|
MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch,
|
||||||
|
MatchOperator matchOperator = MatchOperator.Or
|
||||||
|
)
|
||||||
{
|
{
|
||||||
Guard.NotNull(schema);
|
Guard.NotNull(schema);
|
||||||
|
CustomScalars = customScalars;
|
||||||
MatchBehaviour = matchBehaviour;
|
MatchBehaviour = matchBehaviour;
|
||||||
MatchOperator = matchOperator;
|
MatchOperator = matchOperator;
|
||||||
|
|
||||||
@@ -137,12 +168,36 @@ public class GraphQLMatcher : IStringMatcher
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ISchema BuildSchema(string typeDefinitions)
|
/// <param name="typeDefinitions">A textual description of the schema in SDL (Schema Definition Language) format.</param>
|
||||||
|
private ISchema BuildSchema(string typeDefinitions)
|
||||||
{
|
{
|
||||||
var schema = Schema.For(typeDefinitions);
|
var schema = Schema.For(typeDefinitions);
|
||||||
|
|
||||||
// #984
|
// #984
|
||||||
schema.RegisterTypes(schema.BuiltInTypeMappings.Select(x => x.graphType).ToArray());
|
var graphTypes = schema.BuiltInTypeMappings.Select(tm => tm.graphType).ToArray();
|
||||||
|
schema.RegisterTypes(graphTypes);
|
||||||
|
|
||||||
|
var doc = Parser.Parse(typeDefinitions);
|
||||||
|
var scalarTypeDefinitions = doc.Definitions
|
||||||
|
.Where(d => d.Kind == ASTNodeKind.ScalarTypeDefinition)
|
||||||
|
.OfType<GraphQLTypeDefinition>();
|
||||||
|
|
||||||
|
foreach (var scalarTypeDefinitionName in scalarTypeDefinitions.Select(s => s.Name.StringValue))
|
||||||
|
{
|
||||||
|
var customScalarGraphTypeName = $"{scalarTypeDefinitionName}GraphType";
|
||||||
|
if (graphTypes.All(t => t.Name != customScalarGraphTypeName)) // Only process when not built-in.
|
||||||
|
{
|
||||||
|
// Check if this custom Scalar is defined in the dictionary
|
||||||
|
if (CustomScalars == null || !CustomScalars.TryGetValue(scalarTypeDefinitionName, out var clrType))
|
||||||
|
{
|
||||||
|
throw new WireMockException($"The GraphQL Scalar type '{scalarTypeDefinitionName}' is not defined in the CustomScalars dictionary.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a this custom Scalar GraphType (extending the WireMockCustomScalarGraphType<{clrType}> class)
|
||||||
|
var customScalarGraphType = ReflectionUtils.CreateGenericType(customScalarGraphTypeName, typeof(WireMockCustomScalarGraphType<>), clrType);
|
||||||
|
schema.RegisterType(customScalarGraphType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return schema;
|
return schema;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
#if GRAPHQL
|
||||||
|
using System;
|
||||||
|
using GraphQL.Types;
|
||||||
|
|
||||||
|
namespace WireMock.Matchers.Models;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public abstract class WireMockCustomScalarGraphType<T> : ScalarGraphType
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override object? ParseValue(object? value)
|
||||||
|
{
|
||||||
|
switch (value)
|
||||||
|
{
|
||||||
|
case null:
|
||||||
|
return null;
|
||||||
|
|
||||||
|
case T:
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value is string && typeof(T) != typeof(string))
|
||||||
|
{
|
||||||
|
throw new InvalidCastException($"Unable to convert value '{value}' of type '{typeof(string)}' to type '{typeof(T)}'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return (T)Convert.ChangeType(value, typeof(T));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Stef.Validation;
|
using Stef.Validation;
|
||||||
@@ -25,8 +26,9 @@ public class RequestMessageGraphQLMatcher : IRequestMatcher
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="matchBehaviour">The match behaviour.</param>
|
/// <param name="matchBehaviour">The match behaviour.</param>
|
||||||
/// <param name="schema">The schema.</param>
|
/// <param name="schema">The schema.</param>
|
||||||
public RequestMessageGraphQLMatcher(MatchBehaviour matchBehaviour, string schema) :
|
/// <param name="customScalars">A dictionary defining the custom scalars used in this schema. (optional)</param>
|
||||||
this(CreateMatcherArray(matchBehaviour, schema))
|
public RequestMessageGraphQLMatcher(MatchBehaviour matchBehaviour, string schema, IDictionary<string, Type>? customScalars = null) :
|
||||||
|
this(CreateMatcherArray(matchBehaviour, schema, customScalars))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,8 +38,9 @@ public class RequestMessageGraphQLMatcher : IRequestMatcher
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="matchBehaviour">The match behaviour.</param>
|
/// <param name="matchBehaviour">The match behaviour.</param>
|
||||||
/// <param name="schema">The schema.</param>
|
/// <param name="schema">The schema.</param>
|
||||||
public RequestMessageGraphQLMatcher(MatchBehaviour matchBehaviour, GraphQL.Types.ISchema schema) :
|
/// <param name="customScalars">A dictionary defining the custom scalars used in this schema. (optional)</param>
|
||||||
this(CreateMatcherArray(matchBehaviour, new AnyOfTypes.AnyOf<string, Models.StringPattern, GraphQL.Types.ISchema>(schema)))
|
public RequestMessageGraphQLMatcher(MatchBehaviour matchBehaviour, GraphQL.Types.ISchema schema, IDictionary<string, Type>? customScalars = null) :
|
||||||
|
this(CreateMatcherArray(matchBehaviour, new AnyOfTypes.AnyOf<string, WireMock.Models.StringPattern, GraphQL.Types.ISchema>(schema), customScalars))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -89,12 +92,17 @@ public class RequestMessageGraphQLMatcher : IRequestMatcher
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if GRAPHQL
|
#if GRAPHQL
|
||||||
private static IMatcher[] CreateMatcherArray(MatchBehaviour matchBehaviour, AnyOfTypes.AnyOf<string, Models.StringPattern, GraphQL.Types.ISchema> schema)
|
private static IMatcher[] CreateMatcherArray(
|
||||||
|
MatchBehaviour matchBehaviour,
|
||||||
|
AnyOfTypes.AnyOf<string, WireMock.Models.StringPattern,
|
||||||
|
GraphQL.Types.ISchema> schema,
|
||||||
|
IDictionary<string, Type>? customScalars
|
||||||
|
)
|
||||||
{
|
{
|
||||||
return new[] { new GraphQLMatcher(schema, matchBehaviour) }.Cast<IMatcher>().ToArray();
|
return new[] { new GraphQLMatcher(schema, customScalars, matchBehaviour) }.Cast<IMatcher>().ToArray();
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
private static IMatcher[] CreateMatcherArray(MatchBehaviour matchBehaviour, object schema)
|
private static IMatcher[] CreateMatcherArray(MatchBehaviour matchBehaviour, object schema, IDictionary<string, Type>? customScalars)
|
||||||
{
|
{
|
||||||
throw new System.NotSupportedException("The GrapQLMatcher can not be used for .NETStandard1.3 or .NET Framework 4.6.1 or lower.");
|
throw new System.NotSupportedException("The GrapQLMatcher can not be used for .NETStandard1.3 or .NET Framework 4.6.1 or lower.");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using WireMock.Matchers;
|
using WireMock.Matchers;
|
||||||
|
|
||||||
namespace WireMock.RequestBuilders;
|
namespace WireMock.RequestBuilders;
|
||||||
@@ -15,6 +17,15 @@ public interface IGraphQLRequestBuilder : IMultiPartRequestBuilder
|
|||||||
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
|
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
|
||||||
IRequestBuilder WithGraphQLSchema(string schema, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch);
|
IRequestBuilder WithGraphQLSchema(string schema, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// WithGraphQLSchema: The GraphQL schema as a string.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="schema">The GraphQL schema.</param>
|
||||||
|
/// <param name="customScalars">A dictionary defining the custom scalars used in this schema. (optional)</param>
|
||||||
|
/// <param name="matchBehaviour">The match behaviour. (Default is <c>MatchBehaviour.AcceptOnMatch</c>).</param>
|
||||||
|
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
|
||||||
|
IRequestBuilder WithGraphQLSchema(string schema, IDictionary<string, Type>? customScalars, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch);
|
||||||
|
|
||||||
#if GRAPHQL
|
#if GRAPHQL
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// WithGraphQLSchema: The GraphQL schema as a ISchema.
|
/// WithGraphQLSchema: The GraphQL schema as a ISchema.
|
||||||
@@ -23,5 +34,14 @@ public interface IGraphQLRequestBuilder : IMultiPartRequestBuilder
|
|||||||
/// <param name="matchBehaviour">The match behaviour. (Default is <c>MatchBehaviour.AcceptOnMatch</c>).</param>
|
/// <param name="matchBehaviour">The match behaviour. (Default is <c>MatchBehaviour.AcceptOnMatch</c>).</param>
|
||||||
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
|
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
|
||||||
IRequestBuilder WithGraphQLSchema(GraphQL.Types.ISchema schema, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch);
|
IRequestBuilder WithGraphQLSchema(GraphQL.Types.ISchema schema, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// WithGraphQLSchema: The GraphQL schema as a ISchema.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="schema">The GraphQL schema.</param>
|
||||||
|
/// <param name="customScalars">A dictionary defining the custom scalars used in this schema. (optional)</param>
|
||||||
|
/// <param name="matchBehaviour">The match behaviour. (Default is <c>MatchBehaviour.AcceptOnMatch</c>).</param>
|
||||||
|
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
|
||||||
|
IRequestBuilder WithGraphQLSchema(GraphQL.Types.ISchema schema, IDictionary<string, Type>? customScalars, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System;
|
||||||
using WireMock.Matchers;
|
using WireMock.Matchers;
|
||||||
using WireMock.Matchers.Request;
|
using WireMock.Matchers.Request;
|
||||||
|
|
||||||
@@ -12,6 +14,13 @@ public partial class Request
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public IRequestBuilder WithGraphQLSchema(string schema, IDictionary<string, Type>? customScalars, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch)
|
||||||
|
{
|
||||||
|
_requestMatchers.Add(new RequestMessageGraphQLMatcher(matchBehaviour, schema, customScalars));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
#if GRAPHQL
|
#if GRAPHQL
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public IRequestBuilder WithGraphQLSchema(GraphQL.Types.ISchema schema, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch)
|
public IRequestBuilder WithGraphQLSchema(GraphQL.Types.ISchema schema, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch)
|
||||||
@@ -19,5 +28,12 @@ public partial class Request
|
|||||||
_requestMatchers.Add(new RequestMessageGraphQLMatcher(matchBehaviour, schema));
|
_requestMatchers.Add(new RequestMessageGraphQLMatcher(matchBehaviour, schema));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public IRequestBuilder WithGraphQLSchema(GraphQL.Types.ISchema schema, IDictionary<string, Type>? customScalars, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch)
|
||||||
|
{
|
||||||
|
_requestMatchers.Add(new RequestMessageGraphQLMatcher(matchBehaviour, schema, customScalars));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -72,7 +72,7 @@ internal class MatcherMapper
|
|||||||
return CreateExactObjectMatcher(matchBehaviour, stringPatterns[0]);
|
return CreateExactObjectMatcher(matchBehaviour, stringPatterns[0]);
|
||||||
#if GRAPHQL
|
#if GRAPHQL
|
||||||
case nameof(GraphQLMatcher):
|
case nameof(GraphQLMatcher):
|
||||||
return new GraphQLMatcher(stringPatterns[0].GetPattern(), matchBehaviour, matchOperator);
|
return new GraphQLMatcher(stringPatterns[0].GetPattern(), matcher.CustomScalars, matchBehaviour, matchOperator);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if MIMEKIT
|
#if MIMEKIT
|
||||||
@@ -101,8 +101,7 @@ internal class MatcherMapper
|
|||||||
return new JmesPathMatcher(matchBehaviour, matchOperator, stringPatterns);
|
return new JmesPathMatcher(matchBehaviour, matchOperator, stringPatterns);
|
||||||
|
|
||||||
case nameof(XPathMatcher):
|
case nameof(XPathMatcher):
|
||||||
var xmlNamespaces = matcher.XmlNamespaceMap;
|
return new XPathMatcher(matchBehaviour, matchOperator, matcher.XmlNamespaceMap, stringPatterns);
|
||||||
return new XPathMatcher(matchBehaviour, matchOperator, xmlNamespaces, stringPatterns);
|
|
||||||
|
|
||||||
case nameof(WildcardMatcher):
|
case nameof(WildcardMatcher):
|
||||||
return new WildcardMatcher(matchBehaviour, stringPatterns, ignoreCase, matchOperator);
|
return new WildcardMatcher(matchBehaviour, stringPatterns, ignoreCase, matchOperator);
|
||||||
@@ -164,6 +163,11 @@ internal class MatcherMapper
|
|||||||
case XPathMatcher xpathMatcher:
|
case XPathMatcher xpathMatcher:
|
||||||
model.XmlNamespaceMap = xpathMatcher.XmlNamespaceMap;
|
model.XmlNamespaceMap = xpathMatcher.XmlNamespaceMap;
|
||||||
break;
|
break;
|
||||||
|
#if GRAPHQL
|
||||||
|
case GraphQLMatcher graphQLMatcher:
|
||||||
|
model.CustomScalars = graphQLMatcher.CustomScalars;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (matcher)
|
switch (matcher)
|
||||||
|
|||||||
48
src/WireMock.Net/Util/ReflectionUtils.cs
Normal file
48
src/WireMock.Net/Util/ReflectionUtils.cs
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Reflection.Emit;
|
||||||
|
|
||||||
|
namespace WireMock.Util;
|
||||||
|
|
||||||
|
internal static class ReflectionUtils
|
||||||
|
{
|
||||||
|
private const string DynamicModuleName = "WireMockDynamicModule";
|
||||||
|
private static readonly AssemblyName AssemblyName = new("WireMockDynamicAssembly");
|
||||||
|
private const TypeAttributes ClassAttributes =
|
||||||
|
TypeAttributes.Public |
|
||||||
|
TypeAttributes.Class |
|
||||||
|
TypeAttributes.AutoClass |
|
||||||
|
TypeAttributes.AnsiClass |
|
||||||
|
TypeAttributes.BeforeFieldInit |
|
||||||
|
TypeAttributes.AutoLayout;
|
||||||
|
private static readonly ConcurrentDictionary<string, Type> TypeCache = new();
|
||||||
|
|
||||||
|
public static Type CreateType(string typeName, Type? parentType = null)
|
||||||
|
{
|
||||||
|
return TypeCache.GetOrAdd(typeName, key =>
|
||||||
|
{
|
||||||
|
var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(AssemblyName, AssemblyBuilderAccess.Run);
|
||||||
|
var moduleBuilder = assemblyBuilder.DefineDynamicModule(DynamicModuleName);
|
||||||
|
|
||||||
|
var typeBuilder = moduleBuilder.DefineType(key, ClassAttributes, parentType);
|
||||||
|
|
||||||
|
// Create the type and cache it
|
||||||
|
return typeBuilder.CreateTypeInfo()!.AsType();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Type CreateGenericType(string typeName, Type genericTypeDefinition, params Type[] typeArguments)
|
||||||
|
{
|
||||||
|
var genericKey = $"{typeName}_{genericTypeDefinition.Name}_{string.Join(", ", typeArguments.Select(t => t.Name))}";
|
||||||
|
|
||||||
|
return TypeCache.GetOrAdd(genericKey, _ =>
|
||||||
|
{
|
||||||
|
var genericType = genericTypeDefinition.MakeGenericType(typeArguments);
|
||||||
|
|
||||||
|
// Create the type based on the genericType and cache it
|
||||||
|
return CreateType(typeName, genericType);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,10 @@
|
|||||||
#if GRAPHQL
|
#if GRAPHQL
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using CSScripting;
|
||||||
using FluentAssertions;
|
using FluentAssertions;
|
||||||
using GraphQLParser.Exceptions;
|
using GraphQLParser.Exceptions;
|
||||||
|
using WireMock.Exceptions;
|
||||||
using WireMock.Matchers;
|
using WireMock.Matchers;
|
||||||
using WireMock.Models;
|
using WireMock.Models;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
@@ -99,6 +102,62 @@ public class GraphQLMatcherTests
|
|||||||
matcher.GetPatterns().Should().Contain(TestSchema);
|
matcher.GetPatterns().Should().Contain(TestSchema);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GraphQLMatcher_For_ValidSchema_And_CorrectGraphQL_UsingCustomType_Mutation_IsMatch()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
const string testSchema = @"
|
||||||
|
scalar DateTime
|
||||||
|
scalar MyCustomScalar
|
||||||
|
|
||||||
|
type Message {
|
||||||
|
id: ID!
|
||||||
|
}
|
||||||
|
|
||||||
|
type Mutation {
|
||||||
|
createMessage(x: MyCustomScalar, dt: DateTime): Message
|
||||||
|
}";
|
||||||
|
|
||||||
|
var input = @"{
|
||||||
|
""query"": ""mutation CreateMessage($x: MyCustomScalar!, $dt: DateTime!) { createMessage(x: $x, dt: $dt) { id } }"",
|
||||||
|
""variables"": { ""x"": 100, ""dt"": ""2007-12-03T10:15:30Z"" }
|
||||||
|
}";
|
||||||
|
|
||||||
|
var customScalars = new Dictionary<string, Type> { { "MyCustomScalar", typeof(int) } };
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var matcher = new GraphQLMatcher(testSchema, customScalars);
|
||||||
|
var result = matcher.IsMatch(input);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Score.Should().Be(MatchScores.Perfect);
|
||||||
|
|
||||||
|
matcher.GetPatterns().Should().Contain(testSchema);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GraphQLMatcher_For_ValidSchema_And_CorrectGraphQL_UsingCustomType_But_NoDefinedCustomScalars_Mutation_IsNoMatch()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
const string testSchema = @"
|
||||||
|
scalar DateTime
|
||||||
|
scalar MyCustomScalar
|
||||||
|
|
||||||
|
type Message {
|
||||||
|
id: ID!
|
||||||
|
}
|
||||||
|
|
||||||
|
type Mutation {
|
||||||
|
createMessage(x: MyCustomScalar, dt: DateTime): Message
|
||||||
|
}";
|
||||||
|
|
||||||
|
// Act
|
||||||
|
Action action = () => _ = new GraphQLMatcher(testSchema);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
action.Should().Throw<WireMockException>().WithMessage("The GraphQL Scalar type 'MyCustomScalar' is not defined in the CustomScalars dictionary.");
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void GraphQLMatcher_For_ValidSchema_And_IncorrectQuery_IsMismatch()
|
public void GraphQLMatcher_For_ValidSchema_And_IncorrectQuery_IsMismatch()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,96 @@
|
|||||||
|
#if GRAPHQL
|
||||||
|
using System;
|
||||||
|
using FluentAssertions;
|
||||||
|
using WireMock.Matchers.Models;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace WireMock.Net.Tests.Matchers.Models;
|
||||||
|
|
||||||
|
public class WireMockCustomScalarGraphTypeTests
|
||||||
|
{
|
||||||
|
private class MyIntScalarGraphType : WireMockCustomScalarGraphType<int> { }
|
||||||
|
|
||||||
|
private class MyStringScalarGraphType : WireMockCustomScalarGraphType<string> { }
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ParseValue_ShouldReturnNull_When_ValueIsNull()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var intGraphType = new MyIntScalarGraphType();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = intGraphType.ParseValue(null);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Should().BeNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ParseValue_ShouldReturnValue_When_ValueIsOfCorrectType()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var intGraphType = new MyIntScalarGraphType();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = intGraphType.ParseValue(5);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Should().Be(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("someString")]
|
||||||
|
[InlineData("100")]
|
||||||
|
public void ParseValue_ShouldThrowInvalidCastException_When_ValueIsStringAndTargetIsNotString(string stringValue)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var intGraphType = new MyIntScalarGraphType();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
Action act = () => intGraphType.ParseValue(stringValue);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
act.Should().Throw<InvalidCastException>()
|
||||||
|
.WithMessage("Unable to convert value '*' of type 'System.String' to type 'System.Int32'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ParseValue_ShouldConvertValue_WhenTypeIsConvertible()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var intGraphType = new MyIntScalarGraphType();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = intGraphType.ParseValue(5L);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Should().Be(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ParseValue_ShouldThrowException_When_ValueIsMaxLongAndTargetIsInt()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var intGraphType = new MyIntScalarGraphType();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
Action act = () => intGraphType.ParseValue(long.MaxValue);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
act.Should().Throw<OverflowException>();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ParseValue_ShouldReturnStringValue_When_TypeIsString()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var stringGraphType = new MyStringScalarGraphType();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = stringGraphType.ParseValue("someString");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Should().Be("someString");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -16,7 +16,7 @@ public class RequestMessageGraphQLMatcherTests
|
|||||||
[Fact]
|
[Fact]
|
||||||
public void RequestMessageGraphQLMatcher_GetMatchingScore_BodyAsString_IStringMatcher()
|
public void RequestMessageGraphQLMatcher_GetMatchingScore_BodyAsString_IStringMatcher()
|
||||||
{
|
{
|
||||||
// Assign
|
// Arrange
|
||||||
var body = new BodyData
|
var body = new BodyData
|
||||||
{
|
{
|
||||||
BodyAsString = "b",
|
BodyAsString = "b",
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using AnyOfTypes;
|
using AnyOfTypes;
|
||||||
using FluentAssertions;
|
using FluentAssertions;
|
||||||
|
using FluentAssertions.Execution;
|
||||||
using Moq;
|
using Moq;
|
||||||
|
using Newtonsoft.Json;
|
||||||
using NFluent;
|
using NFluent;
|
||||||
using WireMock.Admin.Mappings;
|
using WireMock.Admin.Mappings;
|
||||||
|
using WireMock.Handlers;
|
||||||
using WireMock.Matchers;
|
using WireMock.Matchers;
|
||||||
using WireMock.Models;
|
using WireMock.Models;
|
||||||
using WireMock.Serialization;
|
using WireMock.Serialization;
|
||||||
@@ -165,6 +169,36 @@ public class MatcherMapperTests
|
|||||||
model.XmlNamespaceMap.Should().BeEquivalentTo(xmlNamespaceMap);
|
model.XmlNamespaceMap.Should().BeEquivalentTo(xmlNamespaceMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if GRAPHQL
|
||||||
|
[Fact]
|
||||||
|
public void MatcherMapper_Map_GraphQLMatcher()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
const string testSchema = @"
|
||||||
|
scalar DateTime
|
||||||
|
scalar MyCustomScalar
|
||||||
|
|
||||||
|
type Message {
|
||||||
|
id: ID!
|
||||||
|
}
|
||||||
|
|
||||||
|
type Mutation {
|
||||||
|
createMessage(x: MyCustomScalar, dt: DateTime): Message
|
||||||
|
}";
|
||||||
|
|
||||||
|
var customScalars = new Dictionary<string, Type> { { "MyCustomScalar", typeof(string) } };
|
||||||
|
var matcher = new GraphQLMatcher(testSchema, customScalars);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var model = _sut.Map(matcher)!;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
model.Name.Should().Be(nameof(GraphQLMatcher));
|
||||||
|
model.Pattern.Should().Be(testSchema);
|
||||||
|
model.CustomScalars.Should().BeEquivalentTo(customScalars);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void MatcherMapper_Map_MatcherModel_Null()
|
public void MatcherMapper_Map_MatcherModel_Null()
|
||||||
{
|
{
|
||||||
@@ -463,26 +497,6 @@ public class MatcherMapperTests
|
|||||||
matcher.Regex.Should().BeFalse();
|
matcher.Regex.Should().BeFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void MatcherMapper_Map_MatcherModel_ExactMatcher_Pattern()
|
|
||||||
{
|
|
||||||
// Assign
|
|
||||||
var model = new MatcherModel
|
|
||||||
{
|
|
||||||
Name = "ExactMatcher",
|
|
||||||
Pattern = "p",
|
|
||||||
IgnoreCase = true
|
|
||||||
};
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var matcher = (ExactMatcher)_sut.Map(model)!;
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
matcher.MatchBehaviour.Should().Be(MatchBehaviour.AcceptOnMatch);
|
|
||||||
matcher.GetPatterns().Should().Contain("p");
|
|
||||||
matcher.IgnoreCase.Should().BeTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void MatcherMapper_Map_MatcherModel_NotNullOrEmptyMatcher()
|
public void MatcherMapper_Map_MatcherModel_NotNullOrEmptyMatcher()
|
||||||
{
|
{
|
||||||
@@ -585,4 +599,406 @@ public class MatcherMapperTests
|
|||||||
matcher.MatchBehaviour.Should().Be(MatchBehaviour.AcceptOnMatch);
|
matcher.MatchBehaviour.Should().Be(MatchBehaviour.AcceptOnMatch);
|
||||||
matcher.XmlNamespaceMap.Should().BeNull();
|
matcher.XmlNamespaceMap.Should().BeNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void MatcherMapper_Map_MatcherModel_CSharpCodeMatcher()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var model = new MatcherModel
|
||||||
|
{
|
||||||
|
Name = "CSharpCodeMatcher",
|
||||||
|
Patterns = new[] { "return it == \"x\";" }
|
||||||
|
};
|
||||||
|
var sut = new MatcherMapper(new WireMockServerSettings { AllowCSharpCodeMatcher = true });
|
||||||
|
|
||||||
|
// Act 1
|
||||||
|
var matcher1 = (ICSharpCodeMatcher)sut.Map(model)!;
|
||||||
|
|
||||||
|
// Assert 1
|
||||||
|
matcher1.Should().NotBeNull();
|
||||||
|
matcher1.IsMatch("x").Score.Should().Be(1.0d);
|
||||||
|
|
||||||
|
// Act 2
|
||||||
|
var matcher2 = (ICSharpCodeMatcher)sut.Map(model)!;
|
||||||
|
|
||||||
|
// Assert 2
|
||||||
|
matcher2.Should().NotBeNull();
|
||||||
|
matcher2.IsMatch("x").Score.Should().Be(1.0d);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void MatcherMapper_Map_MatcherModel_CSharpCodeMatcher_NotAllowed_ThrowsException()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var model = new MatcherModel
|
||||||
|
{
|
||||||
|
Name = "CSharpCodeMatcher",
|
||||||
|
Patterns = new[] { "x" }
|
||||||
|
};
|
||||||
|
var sut = new MatcherMapper(new WireMockServerSettings { AllowCSharpCodeMatcher = false });
|
||||||
|
|
||||||
|
// Act
|
||||||
|
Action action = () => sut.Map(model);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
action.Should().Throw<NotSupportedException>();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void MatcherMapper_Map_MatcherModel_ExactMatcher_Pattern()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var model = new MatcherModel
|
||||||
|
{
|
||||||
|
Name = "ExactMatcher",
|
||||||
|
Patterns = new[] { "x" }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var matcher = (ExactMatcher)_sut.Map(model)!;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
matcher.GetPatterns().Should().ContainSingle("x");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void MatcherMapper_Map_MatcherModel_ExactMatcher_Patterns()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var model = new MatcherModel
|
||||||
|
{
|
||||||
|
Name = "ExactMatcher",
|
||||||
|
Patterns = new[] { "x", "y" }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var matcher = (ExactMatcher)_sut.Map(model)!;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Check.That(matcher.GetPatterns()).ContainsExactly("x", "y");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void MatcherMapper_Map_MatcherModel_JsonPartialMatcher_RegexFalse()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var pattern = "{ \"x\": 1 }";
|
||||||
|
var model = new MatcherModel
|
||||||
|
{
|
||||||
|
Name = "JsonPartialMatcher",
|
||||||
|
Regex = false,
|
||||||
|
Pattern = pattern
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var matcher = (JsonPartialMatcher)_sut.Map(model)!;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
matcher.MatchBehaviour.Should().Be(MatchBehaviour.AcceptOnMatch);
|
||||||
|
matcher.IgnoreCase.Should().BeFalse();
|
||||||
|
matcher.Value.Should().Be(pattern);
|
||||||
|
matcher.Regex.Should().BeFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void MatcherMapper_Map_MatcherModel_JsonPartialMatcher_RegexTrue()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var pattern = "{ \"x\": 1 }";
|
||||||
|
var model = new MatcherModel
|
||||||
|
{
|
||||||
|
Name = "JsonPartialMatcher",
|
||||||
|
Regex = true,
|
||||||
|
Pattern = pattern
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var matcher = (JsonPartialMatcher)_sut.Map(model)!;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
matcher.MatchBehaviour.Should().Be(MatchBehaviour.AcceptOnMatch);
|
||||||
|
matcher.IgnoreCase.Should().BeFalse();
|
||||||
|
matcher.Value.Should().Be(pattern);
|
||||||
|
matcher.Regex.Should().BeTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void MatcherMapper_Map_MatcherModel_ExactObjectMatcher_ValidBase64StringPattern()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var model = new MatcherModel
|
||||||
|
{
|
||||||
|
Name = "ExactObjectMatcher",
|
||||||
|
Patterns = new object[] { "c3RlZg==" }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var matcher = (ExactObjectMatcher)_sut.Map(model)!;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Check.That(matcher.ValueAsBytes).ContainsExactly(new byte[] { 115, 116, 101, 102 });
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void MatcherMapper_Map_MatcherModel_ExactObjectMatcher_InvalidBase64StringPattern()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var model = new MatcherModel
|
||||||
|
{
|
||||||
|
Name = "ExactObjectMatcher",
|
||||||
|
Patterns = new object[] { "_" }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
Check.ThatCode(() => _sut.Map(model)).Throws<ArgumentException>();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(MatchOperator.Or, 1.0d)]
|
||||||
|
[InlineData(MatchOperator.And, 0.0d)]
|
||||||
|
[InlineData(MatchOperator.Average, 0.5d)]
|
||||||
|
public void MatcherMapper_Map_MatcherModel_RegexMatcher(MatchOperator matchOperator, double expected)
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var model = new MatcherModel
|
||||||
|
{
|
||||||
|
Name = "RegexMatcher",
|
||||||
|
Patterns = new[] { "x", "y" },
|
||||||
|
IgnoreCase = true,
|
||||||
|
MatchOperator = matchOperator.ToString()
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var matcher = (RegexMatcher)_sut.Map(model)!;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Check.That(matcher.GetPatterns()).ContainsExactly("x", "y");
|
||||||
|
|
||||||
|
var result = matcher.IsMatch("X");
|
||||||
|
result.Score.Should().Be(expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(MatchOperator.Or, 1.0d)]
|
||||||
|
[InlineData(MatchOperator.And, 0.0d)]
|
||||||
|
[InlineData(MatchOperator.Average, 0.5d)]
|
||||||
|
public void MatcherMapper_Map_MatcherModel_WildcardMatcher_IgnoreCase(MatchOperator matchOperator, double expected)
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var model = new MatcherModel
|
||||||
|
{
|
||||||
|
Name = "WildcardMatcher",
|
||||||
|
Patterns = new[] { "x", "y" },
|
||||||
|
IgnoreCase = true,
|
||||||
|
MatchOperator = matchOperator.ToString()
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var matcher = (WildcardMatcher)_sut.Map(model)!;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Check.That(matcher.GetPatterns()).ContainsExactly("x", "y");
|
||||||
|
|
||||||
|
var result = matcher.IsMatch("X");
|
||||||
|
result.Score.Should().Be(expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void MatcherMapper_Map_MatcherModel_WildcardMatcher_With_PatternAsFile()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var file = "c:\\test.txt";
|
||||||
|
var fileContent = "c";
|
||||||
|
var stringPattern = new StringPattern
|
||||||
|
{
|
||||||
|
Pattern = fileContent,
|
||||||
|
PatternAsFile = file
|
||||||
|
};
|
||||||
|
var fileSystemHandleMock = new Mock<IFileSystemHandler>();
|
||||||
|
fileSystemHandleMock.Setup(f => f.ReadFileAsString(file)).Returns(fileContent);
|
||||||
|
|
||||||
|
var model = new MatcherModel
|
||||||
|
{
|
||||||
|
Name = "WildcardMatcher",
|
||||||
|
PatternAsFile = file
|
||||||
|
};
|
||||||
|
|
||||||
|
var settings = new WireMockServerSettings
|
||||||
|
{
|
||||||
|
FileSystemHandler = fileSystemHandleMock.Object
|
||||||
|
};
|
||||||
|
var sut = new MatcherMapper(settings);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var matcher = (WildcardMatcher)sut.Map(model)!;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
matcher.GetPatterns().Should().HaveCount(1).And.Contain(new AnyOf<string, StringPattern>(stringPattern));
|
||||||
|
|
||||||
|
var result = matcher.IsMatch("c");
|
||||||
|
result.Score.Should().Be(MatchScores.Perfect);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void MatcherMapper_Map_MatcherModel_SimMetricsMatcher()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var model = new MatcherModel
|
||||||
|
{
|
||||||
|
Name = "SimMetricsMatcher",
|
||||||
|
Pattern = "x"
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var matcher = (SimMetricsMatcher)_sut.Map(model)!;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Check.That(matcher.GetPatterns()).ContainsExactly("x");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void MatcherMapper_Map_MatcherModel_SimMetricsMatcher_BlockDistance()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var model = new MatcherModel
|
||||||
|
{
|
||||||
|
Name = "SimMetricsMatcher.BlockDistance",
|
||||||
|
Pattern = "x"
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var matcher = (SimMetricsMatcher)_sut.Map(model)!;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Check.That(matcher.GetPatterns()).ContainsExactly("x");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void MatcherMapper_Map_MatcherModel_SimMetricsMatcher_Throws1()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var model = new MatcherModel
|
||||||
|
{
|
||||||
|
Name = "error",
|
||||||
|
Pattern = "x"
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
Check.ThatCode(() => _sut.Map(model)).Throws<NotSupportedException>();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void MatcherMapper_Map_MatcherModel_SimMetricsMatcher_Throws2()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var model = new MatcherModel
|
||||||
|
{
|
||||||
|
Name = "SimMetricsMatcher.error",
|
||||||
|
Pattern = "x"
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
Check.ThatCode(() => _sut.Map(model)).Throws<NotSupportedException>();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void MatcherMapper_Map_MatcherModel_MatcherModelToCustomMatcher()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var patternModel = new CustomPathParamMatcherModel("/customer/{customerId}/document/{documentId}",
|
||||||
|
new Dictionary<string, string>(2)
|
||||||
|
{
|
||||||
|
{ "customerId", @"^[0-9]+$" },
|
||||||
|
{ "documentId", @"^[0-9a-zA-Z\-\_]+\.[a-zA-Z]+$" }
|
||||||
|
});
|
||||||
|
var model = new MatcherModel
|
||||||
|
{
|
||||||
|
Name = nameof(CustomPathParamMatcher),
|
||||||
|
Pattern = JsonConvert.SerializeObject(patternModel)
|
||||||
|
};
|
||||||
|
|
||||||
|
var settings = new WireMockServerSettings();
|
||||||
|
settings.CustomMatcherMappings = settings.CustomMatcherMappings ?? new Dictionary<string, Func<MatcherModel, IMatcher>>();
|
||||||
|
settings.CustomMatcherMappings[nameof(CustomPathParamMatcher)] = matcherModel =>
|
||||||
|
{
|
||||||
|
var matcherParams = JsonConvert.DeserializeObject<CustomPathParamMatcherModel>((string)matcherModel.Pattern!)!;
|
||||||
|
return new CustomPathParamMatcher(
|
||||||
|
matcherModel.RejectOnMatch == true ? MatchBehaviour.RejectOnMatch : MatchBehaviour.AcceptOnMatch,
|
||||||
|
matcherParams.Path,
|
||||||
|
matcherParams.PathParams
|
||||||
|
);
|
||||||
|
};
|
||||||
|
var sut = new MatcherMapper(settings);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var matcher = sut.Map(model) as CustomPathParamMatcher;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
matcher.Should().NotBeNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void MatcherMapper_Map_MatcherModel_CustomMatcherToMatcherModel()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var matcher = new CustomPathParamMatcher("/customer/{customerId}/document/{documentId}",
|
||||||
|
new Dictionary<string, string>(2)
|
||||||
|
{
|
||||||
|
{ "customerId", @"^[0-9]+$" },
|
||||||
|
{ "documentId", @"^[0-9a-zA-Z\-\_]+\.[a-zA-Z]+$" }
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var model = _sut.Map(matcher)!;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
using (new AssertionScope())
|
||||||
|
{
|
||||||
|
model.Should().NotBeNull();
|
||||||
|
model.Name.Should().Be(nameof(CustomPathParamMatcher));
|
||||||
|
|
||||||
|
var matcherParams = JsonConvert.DeserializeObject<CustomPathParamMatcherModel>((string)model.Pattern!)!;
|
||||||
|
matcherParams.Path.Should().Be("/customer/{customerId}/document/{documentId}");
|
||||||
|
matcherParams.PathParams.Should().BeEquivalentTo(new Dictionary<string, string>(2)
|
||||||
|
{
|
||||||
|
{ "customerId", @"^[0-9]+$" },
|
||||||
|
{ "documentId", @"^[0-9a-zA-Z\-\_]+\.[a-zA-Z]+$" }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if GRAPHQL
|
||||||
|
[Fact]
|
||||||
|
public void MatcherMapper_Map_MatcherModel_GraphQLMatcher()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
const string testSchema = @"
|
||||||
|
scalar DateTime
|
||||||
|
scalar MyCustomScalar
|
||||||
|
|
||||||
|
type Message {
|
||||||
|
id: ID!
|
||||||
|
}
|
||||||
|
|
||||||
|
type Mutation {
|
||||||
|
createMessage(x: MyCustomScalar, dt: DateTime): Message
|
||||||
|
}";
|
||||||
|
|
||||||
|
var customScalars = new Dictionary<string, Type> { { "MyCustomScalar", typeof(string) } };
|
||||||
|
var model = new MatcherModel
|
||||||
|
{
|
||||||
|
Name = nameof(GraphQLMatcher),
|
||||||
|
Pattern = testSchema,
|
||||||
|
CustomScalars = customScalars
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var matcher = (GraphQLMatcher)_sut.Map(model)!;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
matcher.GetPatterns().Should().HaveElementAt(0, testSchema);
|
||||||
|
matcher.Name.Should().Be(nameof(GraphQLMatcher));
|
||||||
|
matcher.CustomScalars.Should().BeEquivalentTo(customScalars);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
@@ -1,406 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using AnyOfTypes;
|
|
||||||
using FluentAssertions;
|
|
||||||
using FluentAssertions.Execution;
|
|
||||||
using Moq;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using NFluent;
|
|
||||||
using WireMock.Admin.Mappings;
|
|
||||||
using WireMock.Handlers;
|
|
||||||
using WireMock.Matchers;
|
|
||||||
using WireMock.Models;
|
|
||||||
using WireMock.Serialization;
|
|
||||||
using WireMock.Settings;
|
|
||||||
using Xunit;
|
|
||||||
|
|
||||||
namespace WireMock.Net.Tests.Serialization;
|
|
||||||
|
|
||||||
public class MatcherModelMapperTests
|
|
||||||
{
|
|
||||||
private readonly WireMockServerSettings _settings = new();
|
|
||||||
|
|
||||||
private readonly MatcherMapper _sut;
|
|
||||||
|
|
||||||
public MatcherModelMapperTests()
|
|
||||||
{
|
|
||||||
_sut = new MatcherMapper(_settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void MatcherModelMapper_Map_CSharpCodeMatcher()
|
|
||||||
{
|
|
||||||
// Assign
|
|
||||||
var model = new MatcherModel
|
|
||||||
{
|
|
||||||
Name = "CSharpCodeMatcher",
|
|
||||||
Patterns = new[] { "return it == \"x\";" }
|
|
||||||
};
|
|
||||||
var sut = new MatcherMapper(new WireMockServerSettings { AllowCSharpCodeMatcher = true });
|
|
||||||
|
|
||||||
// Act 1
|
|
||||||
var matcher1 = (ICSharpCodeMatcher)sut.Map(model)!;
|
|
||||||
|
|
||||||
// Assert 1
|
|
||||||
matcher1.Should().NotBeNull();
|
|
||||||
matcher1.IsMatch("x").Score.Should().Be(1.0d);
|
|
||||||
|
|
||||||
// Act 2
|
|
||||||
var matcher2 = (ICSharpCodeMatcher)sut.Map(model)!;
|
|
||||||
|
|
||||||
// Assert 2
|
|
||||||
matcher2.Should().NotBeNull();
|
|
||||||
matcher2.IsMatch("x").Score.Should().Be(1.0d);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void MatcherModelMapper_Map_CSharpCodeMatcher_NotAllowed_ThrowsException()
|
|
||||||
{
|
|
||||||
// Assign
|
|
||||||
var model = new MatcherModel
|
|
||||||
{
|
|
||||||
Name = "CSharpCodeMatcher",
|
|
||||||
Patterns = new[] { "x" }
|
|
||||||
};
|
|
||||||
var sut = new MatcherMapper(new WireMockServerSettings { AllowCSharpCodeMatcher = false });
|
|
||||||
|
|
||||||
// Act
|
|
||||||
Action action = () => sut.Map(model);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
action.Should().Throw<NotSupportedException>();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void MatcherModelMapper_Map_Null()
|
|
||||||
{
|
|
||||||
// Act
|
|
||||||
IMatcher matcher = _sut.Map((MatcherModel?)null)!;
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
Check.That(matcher).IsNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void MatcherModelMapper_Map_ExactMatcher_Pattern()
|
|
||||||
{
|
|
||||||
// Assign
|
|
||||||
var model = new MatcherModel
|
|
||||||
{
|
|
||||||
Name = "ExactMatcher",
|
|
||||||
Patterns = new[] { "x" }
|
|
||||||
};
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var matcher = (ExactMatcher)_sut.Map(model)!;
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
matcher.GetPatterns().Should().ContainSingle("x");
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void MatcherModelMapper_Map_ExactMatcher_Patterns()
|
|
||||||
{
|
|
||||||
// Assign
|
|
||||||
var model = new MatcherModel
|
|
||||||
{
|
|
||||||
Name = "ExactMatcher",
|
|
||||||
Patterns = new[] { "x", "y" }
|
|
||||||
};
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var matcher = (ExactMatcher)_sut.Map(model)!;
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
Check.That(matcher.GetPatterns()).ContainsExactly("x", "y");
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void MatcherModelMapper_Map_JsonPartialMatcher_RegexFalse()
|
|
||||||
{
|
|
||||||
// Assign
|
|
||||||
var pattern = "{ \"x\": 1 }";
|
|
||||||
var model = new MatcherModel
|
|
||||||
{
|
|
||||||
Name = "JsonPartialMatcher",
|
|
||||||
Regex = false,
|
|
||||||
Pattern = pattern
|
|
||||||
};
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var matcher = (JsonPartialMatcher)_sut.Map(model)!;
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
matcher.MatchBehaviour.Should().Be(MatchBehaviour.AcceptOnMatch);
|
|
||||||
matcher.IgnoreCase.Should().BeFalse();
|
|
||||||
matcher.Value.Should().Be(pattern);
|
|
||||||
matcher.Regex.Should().BeFalse();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void MatcherModelMapper_Map_JsonPartialMatcher_RegexTrue()
|
|
||||||
{
|
|
||||||
// Assign
|
|
||||||
var pattern = "{ \"x\": 1 }";
|
|
||||||
var model = new MatcherModel
|
|
||||||
{
|
|
||||||
Name = "JsonPartialMatcher",
|
|
||||||
Regex = true,
|
|
||||||
Pattern = pattern
|
|
||||||
};
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var matcher = (JsonPartialMatcher)_sut.Map(model)!;
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
matcher.MatchBehaviour.Should().Be(MatchBehaviour.AcceptOnMatch);
|
|
||||||
matcher.IgnoreCase.Should().BeFalse();
|
|
||||||
matcher.Value.Should().Be(pattern);
|
|
||||||
matcher.Regex.Should().BeTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void MatcherModelMapper_Map_ExactObjectMatcher_ValidBase64StringPattern()
|
|
||||||
{
|
|
||||||
// Assign
|
|
||||||
var model = new MatcherModel
|
|
||||||
{
|
|
||||||
Name = "ExactObjectMatcher",
|
|
||||||
Patterns = new object[] { "c3RlZg==" }
|
|
||||||
};
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var matcher = (ExactObjectMatcher)_sut.Map(model)!;
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
Check.That(matcher.ValueAsBytes).ContainsExactly(new byte[] { 115, 116, 101, 102 });
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void MatcherModelMapper_Map_ExactObjectMatcher_InvalidBase64StringPattern()
|
|
||||||
{
|
|
||||||
// Assign
|
|
||||||
var model = new MatcherModel
|
|
||||||
{
|
|
||||||
Name = "ExactObjectMatcher",
|
|
||||||
Patterns = new object[] { "_" }
|
|
||||||
};
|
|
||||||
|
|
||||||
// Act & Assert
|
|
||||||
Check.ThatCode(() => _sut.Map(model)).Throws<ArgumentException>();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory]
|
|
||||||
[InlineData(MatchOperator.Or, 1.0d)]
|
|
||||||
[InlineData(MatchOperator.And, 0.0d)]
|
|
||||||
[InlineData(MatchOperator.Average, 0.5d)]
|
|
||||||
public void MatcherModelMapper_Map_RegexMatcher(MatchOperator matchOperator, double expected)
|
|
||||||
{
|
|
||||||
// Assign
|
|
||||||
var model = new MatcherModel
|
|
||||||
{
|
|
||||||
Name = "RegexMatcher",
|
|
||||||
Patterns = new[] { "x", "y" },
|
|
||||||
IgnoreCase = true,
|
|
||||||
MatchOperator = matchOperator.ToString()
|
|
||||||
};
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var matcher = (RegexMatcher)_sut.Map(model)!;
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
Check.That(matcher.GetPatterns()).ContainsExactly("x", "y");
|
|
||||||
|
|
||||||
var result = matcher.IsMatch("X");
|
|
||||||
result.Score.Should().Be(expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory]
|
|
||||||
[InlineData(MatchOperator.Or, 1.0d)]
|
|
||||||
[InlineData(MatchOperator.And, 0.0d)]
|
|
||||||
[InlineData(MatchOperator.Average, 0.5d)]
|
|
||||||
public void MatcherModelMapper_Map_WildcardMatcher_IgnoreCase(MatchOperator matchOperator, double expected)
|
|
||||||
{
|
|
||||||
// Assign
|
|
||||||
var model = new MatcherModel
|
|
||||||
{
|
|
||||||
Name = "WildcardMatcher",
|
|
||||||
Patterns = new[] { "x", "y" },
|
|
||||||
IgnoreCase = true,
|
|
||||||
MatchOperator = matchOperator.ToString()
|
|
||||||
};
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var matcher = (WildcardMatcher)_sut.Map(model)!;
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
Check.That(matcher.GetPatterns()).ContainsExactly("x", "y");
|
|
||||||
|
|
||||||
var result = matcher.IsMatch("X");
|
|
||||||
result.Score.Should().Be(expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void MatcherModelMapper_Map_WildcardMatcher_With_PatternAsFile()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var file = "c:\\test.txt";
|
|
||||||
var fileContent = "c";
|
|
||||||
var stringPattern = new StringPattern
|
|
||||||
{
|
|
||||||
Pattern = fileContent,
|
|
||||||
PatternAsFile = file
|
|
||||||
};
|
|
||||||
var fileSystemHandleMock = new Mock<IFileSystemHandler>();
|
|
||||||
fileSystemHandleMock.Setup(f => f.ReadFileAsString(file)).Returns(fileContent);
|
|
||||||
|
|
||||||
var model = new MatcherModel
|
|
||||||
{
|
|
||||||
Name = "WildcardMatcher",
|
|
||||||
PatternAsFile = file
|
|
||||||
};
|
|
||||||
|
|
||||||
var settings = new WireMockServerSettings
|
|
||||||
{
|
|
||||||
FileSystemHandler = fileSystemHandleMock.Object
|
|
||||||
};
|
|
||||||
var sut = new MatcherMapper(settings);
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var matcher = (WildcardMatcher)sut.Map(model)!;
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
matcher.GetPatterns().Should().HaveCount(1).And.Contain(new AnyOf<string, StringPattern>(stringPattern));
|
|
||||||
|
|
||||||
var result = matcher.IsMatch("c");
|
|
||||||
result.Score.Should().Be(MatchScores.Perfect);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void MatcherModelMapper_Map_SimMetricsMatcher()
|
|
||||||
{
|
|
||||||
// Assign
|
|
||||||
var model = new MatcherModel
|
|
||||||
{
|
|
||||||
Name = "SimMetricsMatcher",
|
|
||||||
Pattern = "x"
|
|
||||||
};
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var matcher = (SimMetricsMatcher)_sut.Map(model)!;
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
Check.That(matcher.GetPatterns()).ContainsExactly("x");
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void MatcherModelMapper_Map_SimMetricsMatcher_BlockDistance()
|
|
||||||
{
|
|
||||||
// Assign
|
|
||||||
var model = new MatcherModel
|
|
||||||
{
|
|
||||||
Name = "SimMetricsMatcher.BlockDistance",
|
|
||||||
Pattern = "x"
|
|
||||||
};
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var matcher = (SimMetricsMatcher)_sut.Map(model)!;
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
Check.That(matcher.GetPatterns()).ContainsExactly("x");
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void MatcherModelMapper_Map_SimMetricsMatcher_Throws1()
|
|
||||||
{
|
|
||||||
// Assign
|
|
||||||
var model = new MatcherModel
|
|
||||||
{
|
|
||||||
Name = "error",
|
|
||||||
Pattern = "x"
|
|
||||||
};
|
|
||||||
|
|
||||||
// Act
|
|
||||||
Check.ThatCode(() => _sut.Map(model)).Throws<NotSupportedException>();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void MatcherModelMapper_Map_SimMetricsMatcher_Throws2()
|
|
||||||
{
|
|
||||||
// Assign
|
|
||||||
var model = new MatcherModel
|
|
||||||
{
|
|
||||||
Name = "SimMetricsMatcher.error",
|
|
||||||
Pattern = "x"
|
|
||||||
};
|
|
||||||
|
|
||||||
// Act
|
|
||||||
Check.ThatCode(() => _sut.Map(model)).Throws<NotSupportedException>();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void MatcherModelMapper_Map_MatcherModelToCustomMatcher()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var patternModel = new CustomPathParamMatcherModel("/customer/{customerId}/document/{documentId}",
|
|
||||||
new Dictionary<string, string>(2)
|
|
||||||
{
|
|
||||||
{ "customerId", @"^[0-9]+$" },
|
|
||||||
{ "documentId", @"^[0-9a-zA-Z\-\_]+\.[a-zA-Z]+$" }
|
|
||||||
});
|
|
||||||
var model = new MatcherModel
|
|
||||||
{
|
|
||||||
Name = nameof(CustomPathParamMatcher),
|
|
||||||
Pattern = JsonConvert.SerializeObject(patternModel)
|
|
||||||
};
|
|
||||||
|
|
||||||
var settings = new WireMockServerSettings();
|
|
||||||
settings.CustomMatcherMappings = settings.CustomMatcherMappings ?? new Dictionary<string, Func<MatcherModel, IMatcher>>();
|
|
||||||
settings.CustomMatcherMappings[nameof(CustomPathParamMatcher)] = matcherModel =>
|
|
||||||
{
|
|
||||||
var matcherParams = JsonConvert.DeserializeObject<CustomPathParamMatcherModel>((string)matcherModel.Pattern!)!;
|
|
||||||
return new CustomPathParamMatcher(
|
|
||||||
matcherModel.RejectOnMatch == true ? MatchBehaviour.RejectOnMatch : MatchBehaviour.AcceptOnMatch,
|
|
||||||
matcherParams.Path,
|
|
||||||
matcherParams.PathParams
|
|
||||||
);
|
|
||||||
};
|
|
||||||
var sut = new MatcherMapper(settings);
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var matcher = sut.Map(model) as CustomPathParamMatcher;
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
matcher.Should().NotBeNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void MatcherModelMapper_Map_CustomMatcherToMatcherModel()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var matcher = new CustomPathParamMatcher("/customer/{customerId}/document/{documentId}",
|
|
||||||
new Dictionary<string, string>(2)
|
|
||||||
{
|
|
||||||
{ "customerId", @"^[0-9]+$" },
|
|
||||||
{ "documentId", @"^[0-9a-zA-Z\-\_]+\.[a-zA-Z]+$" }
|
|
||||||
});
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var model = _sut.Map(matcher)!;
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
using (new AssertionScope())
|
|
||||||
{
|
|
||||||
model.Should().NotBeNull();
|
|
||||||
model.Name.Should().Be(nameof(CustomPathParamMatcher));
|
|
||||||
|
|
||||||
var matcherParams = JsonConvert.DeserializeObject<CustomPathParamMatcherModel>((string)model.Pattern!)!;
|
|
||||||
matcherParams.Path.Should().Be("/customer/{customerId}/document/{documentId}");
|
|
||||||
matcherParams.PathParams.Should().BeEquivalentTo(new Dictionary<string, string>(2)
|
|
||||||
{
|
|
||||||
{ "customerId", @"^[0-9]+$" },
|
|
||||||
{ "documentId", @"^[0-9a-zA-Z\-\_]+\.[a-zA-Z]+$" }
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,17 +1,15 @@
|
|||||||
namespace MultipartUploader
|
namespace MultipartUploader;
|
||||||
|
|
||||||
|
internal static class Program
|
||||||
{
|
{
|
||||||
internal static class Program
|
/// <summary>
|
||||||
|
/// The main entry point for the application.
|
||||||
|
/// </summary>
|
||||||
|
[STAThread]
|
||||||
|
static void Main()
|
||||||
{
|
{
|
||||||
/// <summary>
|
// To customize application configuration such as set high DPI settings or default font, see https://aka.ms/applicationconfiguration.
|
||||||
/// The main entry point for the application.
|
ApplicationConfiguration.Initialize();
|
||||||
/// </summary>
|
Application.Run(new Form1());
|
||||||
[STAThread]
|
|
||||||
static void Main()
|
|
||||||
{
|
|
||||||
// To customize application configuration such as set high DPI settings or default font,
|
|
||||||
// see https://aka.ms/applicationconfiguration.
|
|
||||||
ApplicationConfiguration.Initialize();
|
|
||||||
Application.Run(new Form1());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user