Update MappingConverter to correctly write the Matcher as C# code (#1152)

* Update MappingConverter to correctly write the Matcher as C# code

* .

* CSharpCodeMatcher

* tests

* .
This commit is contained in:
Stef Heyenrath
2024-08-27 19:38:07 +02:00
committed by GitHub
parent 95573eeb96
commit da100298c1
41 changed files with 709 additions and 158 deletions

View File

@@ -33,6 +33,7 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=Guids/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Guids/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Heyenrath/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Heyenrath/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Jmes/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Jmes/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Levenstein/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=openapi/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=openapi/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Pacticipant/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Pacticipant/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=protobuf/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=protobuf/@EntryIndexedValue">True</s:Boolean>

View File

@@ -10,6 +10,7 @@ using Stef.Validation;
using WireMock.Exceptions; using WireMock.Exceptions;
using WireMock.Extensions; using WireMock.Extensions;
using WireMock.Models; using WireMock.Models;
using WireMock.Util;
namespace WireMock.Matchers; namespace WireMock.Matchers;
@@ -92,6 +93,17 @@ internal class CSharpCodeMatcher : ICSharpCodeMatcher
return new MatchResult(MatchBehaviourHelper.Convert(MatchBehaviour, score), exception); return new MatchResult(MatchBehaviourHelper.Convert(MatchBehaviour, score), exception);
} }
/// <inheritdoc />
public string GetCSharpCodeArguments()
{
return $"new {Name}" +
$"(" +
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}, " +
$"{MatchOperator.GetFullyQualifiedEnumValue()}, " +
$"{MappingConverterUtils.ToCSharpCodeArguments(_patterns)}" +
$")";
}
private bool IsMatch(dynamic input, string pattern) private bool IsMatch(dynamic input, string pattern)
{ {
var isMatchWithString = input is string; var isMatchWithString = input is string;

View File

@@ -42,7 +42,7 @@ internal class AzureADAuthenticationMatcher : IStringMatcher
return EmptyArray<AnyOf<string, StringPattern>>.Value; return EmptyArray<AnyOf<string, StringPattern>>.Value;
} }
public MatchOperator MatchOperator { get; } = MatchOperator.Or; public MatchOperator MatchOperator => MatchOperator.Or;
public MatchResult IsMatch(string? input) public MatchResult IsMatch(string? input)
{ {
@@ -76,5 +76,11 @@ internal class AzureADAuthenticationMatcher : IStringMatcher
return new MatchResult(MatchScores.Mismatch, ex); return new MatchResult(MatchScores.Mismatch, ex);
} }
} }
/// <inheritdoc />
public virtual string GetCSharpCodeArguments()
{
throw new NotImplementedException();
}
} }
#endif #endif

View File

@@ -130,7 +130,10 @@ public class MappingBuilder : IMappingBuilder
private IMapping[] GetNonAdminMappings() private IMapping[] GetNonAdminMappings()
{ {
return _options.Mappings.Values.Where(m => !m.IsAdminInterface).OrderBy(m => m.UpdatedAt).ToArray(); return _options.Mappings.Values
.Where(m => !m.IsAdminInterface)
.OrderBy(m => m.Guid)
.ToArray();
} }
private void RegisterMapping(IMapping mapping, bool saveToFile) private void RegisterMapping(IMapping mapping, bool saveToFile)

View File

@@ -2,7 +2,10 @@
using System.Net.Http.Headers; using System.Net.Http.Headers;
using AnyOfTypes; using AnyOfTypes;
using Stef.Validation;
using WireMock.Extensions;
using WireMock.Models; using WireMock.Models;
using WireMock.Util;
namespace WireMock.Matchers; namespace WireMock.Matchers;
@@ -19,7 +22,7 @@ public class ContentTypeMatcher : WildcardMatcher
/// </summary> /// </summary>
/// <param name="pattern">The pattern.</param> /// <param name="pattern">The pattern.</param>
/// <param name="ignoreCase">IgnoreCase (default false)</param> /// <param name="ignoreCase">IgnoreCase (default false)</param>
public ContentTypeMatcher(AnyOf<string, StringPattern> pattern, bool ignoreCase = false) : this(new[] { pattern }, ignoreCase) public ContentTypeMatcher(AnyOf<string, StringPattern> pattern, bool ignoreCase = false) : this([pattern], ignoreCase)
{ {
} }
@@ -29,7 +32,8 @@ public class ContentTypeMatcher : WildcardMatcher
/// <param name="matchBehaviour">The match behaviour.</param> /// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="pattern">The pattern.</param> /// <param name="pattern">The pattern.</param>
/// <param name="ignoreCase">IgnoreCase (default false)</param> /// <param name="ignoreCase">IgnoreCase (default false)</param>
public ContentTypeMatcher(MatchBehaviour matchBehaviour, AnyOf<string, StringPattern> pattern, bool ignoreCase = false) : this(matchBehaviour, new[] { pattern }, ignoreCase) public ContentTypeMatcher(MatchBehaviour matchBehaviour, AnyOf<string, StringPattern> pattern, bool ignoreCase = false) : this(matchBehaviour,
[pattern], ignoreCase)
{ {
} }
@@ -50,7 +54,7 @@ public class ContentTypeMatcher : WildcardMatcher
/// <param name="ignoreCase">IgnoreCase (default false)</param> /// <param name="ignoreCase">IgnoreCase (default false)</param>
public ContentTypeMatcher(MatchBehaviour matchBehaviour, AnyOf<string, StringPattern>[] patterns, bool ignoreCase = false) : base(matchBehaviour, patterns, ignoreCase) public ContentTypeMatcher(MatchBehaviour matchBehaviour, AnyOf<string, StringPattern>[] patterns, bool ignoreCase = false) : base(matchBehaviour, patterns, ignoreCase)
{ {
_patterns = patterns; _patterns = Guard.NotNull(patterns);
} }
/// <inheritdoc /> /// <inheritdoc />
@@ -72,4 +76,15 @@ public class ContentTypeMatcher : WildcardMatcher
/// <inheritdoc /> /// <inheritdoc />
public override string Name => nameof(ContentTypeMatcher); public override string Name => nameof(ContentTypeMatcher);
/// <inheritdoc />
public override string GetCSharpCodeArguments()
{
return $"new {Name}" +
$"(" +
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}, " +
$"{MappingConverterUtils.ToCSharpCodeArguments(_patterns)}, " +
$"{CSharpFormatter.ToCSharpBooleanLiteral(IgnoreCase)}" +
$")";
}
} }

View File

@@ -4,7 +4,9 @@ using System;
using System.Linq; using System.Linq;
using AnyOfTypes; using AnyOfTypes;
using Stef.Validation; using Stef.Validation;
using WireMock.Extensions;
using WireMock.Models; using WireMock.Models;
using WireMock.Util;
namespace WireMock.Matchers; namespace WireMock.Matchers;
@@ -86,8 +88,20 @@ public class ExactMatcher : IStringMatcher, IIgnoreCaseMatcher
public MatchOperator MatchOperator { get; } public MatchOperator MatchOperator { get; }
/// <inheritdoc /> /// <inheritdoc />
public string Name => "ExactMatcher"; public string Name => nameof(ExactMatcher);
/// <inheritdoc /> /// <inheritdoc />
public bool IgnoreCase { get; } public bool IgnoreCase { get; }
/// <inheritdoc />
public string GetCSharpCodeArguments()
{
return $"new {Name}" +
$"(" +
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}, " +
$"{CSharpFormatter.ToCSharpBooleanLiteral(IgnoreCase)}, " +
$"{MatchOperator.GetFullyQualifiedEnumValue()}, " +
$"{MappingConverterUtils.ToCSharpCodeArguments(_values)}" +
$")";
}
} }

View File

@@ -72,5 +72,11 @@ public class ExactObjectMatcher : IObjectMatcher
} }
/// <inheritdoc /> /// <inheritdoc />
public string Name => "ExactObjectMatcher"; public string Name => nameof(ExactObjectMatcher);
/// <inheritdoc />
public string GetCSharpCodeArguments()
{
return "NotImplemented";
}
} }

View File

@@ -4,6 +4,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using AnyOfTypes; using AnyOfTypes;
using Stef.Validation; using Stef.Validation;
using WireMock.Extensions;
using WireMock.Models; using WireMock.Models;
using WireMock.Util; using WireMock.Util;
@@ -163,4 +164,16 @@ public class FormUrlEncodedMatcher : IStringMatcher, IIgnoreCaseMatcher
/// <inheritdoc /> /// <inheritdoc />
public MatchOperator MatchOperator { get; } public MatchOperator MatchOperator { get; }
/// <inheritdoc />
public string GetCSharpCodeArguments()
{
return $"new {Name}" +
$"(" +
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}, " +
$"{MappingConverterUtils.ToCSharpCodeArguments(_patterns)}, " +
$"{CSharpFormatter.ToCSharpBooleanLiteral(IgnoreCase)}, " +
$"{MatchOperator.GetFullyQualifiedEnumValue()}" +
$")";
}
} }

View File

@@ -156,6 +156,12 @@ public class GraphQLMatcher : IStringMatcher
/// <inheritdoc /> /// <inheritdoc />
public string Name => nameof(GraphQLMatcher); public string Name => nameof(GraphQLMatcher);
/// <inheritdoc />
public string GetCSharpCodeArguments()
{
return "NotImplemented";
}
private static bool TryGetGraphQLRequest(string input, [NotNullWhen(true)] out GraphQLRequest? graphQLRequest) private static bool TryGetGraphQLRequest(string input, [NotNullWhen(true)] out GraphQLRequest? graphQLRequest)
{ {
try try

View File

@@ -16,4 +16,10 @@ public interface IMatcher
/// Gets the match behaviour. /// Gets the match behaviour.
/// </summary> /// </summary>
MatchBehaviour MatchBehaviour { get; } MatchBehaviour MatchBehaviour { get; }
/// <summary>
/// Get the C# code arguments.
/// </summary>
/// <returns></returns>
string GetCSharpCodeArguments();
} }

View File

@@ -7,6 +7,7 @@ using Newtonsoft.Json.Linq;
using Stef.Validation; using Stef.Validation;
using WireMock.Extensions; using WireMock.Extensions;
using WireMock.Models; using WireMock.Models;
using WireMock.Util;
namespace WireMock.Matchers; namespace WireMock.Matchers;
@@ -89,7 +90,7 @@ public class JsonPathMatcher : IStringMatcher, IObjectMatcher
Exception? exception = null; Exception? exception = null;
// When input is null or byte[], return Mismatch. // When input is null or byte[], return Mismatch.
if (input != null && !(input is byte[])) if (input != null && input is not byte[])
{ {
try try
{ {
@@ -116,7 +117,18 @@ public class JsonPathMatcher : IStringMatcher, IObjectMatcher
public MatchOperator MatchOperator { get; } public MatchOperator MatchOperator { get; }
/// <inheritdoc /> /// <inheritdoc />
public string Name => "JsonPathMatcher"; public string Name => nameof(JsonPathMatcher);
/// <inheritdoc />
public string GetCSharpCodeArguments()
{
return $"new {Name}" +
$"(" +
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}, " +
$"{MatchOperator.GetFullyQualifiedEnumValue()}, " +
$"{MappingConverterUtils.ToCSharpCodeArguments(_patterns)}" +
$")";
}
private double IsMatch(JToken jToken) private double IsMatch(JToken jToken)
{ {

View File

@@ -8,6 +8,7 @@ using Newtonsoft.Json;
using Stef.Validation; using Stef.Validation;
using WireMock.Extensions; using WireMock.Extensions;
using WireMock.Models; using WireMock.Models;
using WireMock.Util;
namespace WireMock.Matchers; namespace WireMock.Matchers;
@@ -115,4 +116,15 @@ public class JmesPathMatcher : IStringMatcher, IObjectMatcher
/// <inheritdoc /> /// <inheritdoc />
public string Name => nameof(JmesPathMatcher); public string Name => nameof(JmesPathMatcher);
/// <inheritdoc />
public string GetCSharpCodeArguments()
{
return $"new {Name}" +
$"(" +
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}, " +
$"{MatchOperator.GetFullyQualifiedEnumValue()}, " +
$"{MappingConverterUtils.ToCSharpCodeArguments(_patterns)}" +
$")";
}
} }

View File

@@ -5,6 +5,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using Stef.Validation; using Stef.Validation;
using WireMock.Extensions;
using WireMock.Util; using WireMock.Util;
using JsonUtils = WireMock.Util.JsonUtils; using JsonUtils = WireMock.Util.JsonUtils;
@@ -98,6 +99,18 @@ public class JsonMatcher : IJsonMatcher
return new MatchResult(MatchBehaviourHelper.Convert(MatchBehaviour, score), error); return new MatchResult(MatchBehaviourHelper.Convert(MatchBehaviour, score), error);
} }
/// <inheritdoc />
public virtual string GetCSharpCodeArguments()
{
return $"new {Name}" +
$"(" +
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}, " +
$"{CSharpFormatter.ConvertToAnonymousObjectDefinition(Value, 3)}, " +
$"{CSharpFormatter.ToCSharpBooleanLiteral(IgnoreCase)}, " +
$"{CSharpFormatter.ToCSharpBooleanLiteral(Regex)}" +
$")";
}
/// <summary> /// <summary>
/// Compares the input against the matcher value /// Compares the input against the matcher value
/// </summary> /// </summary>

View File

@@ -1,5 +1,8 @@
// Copyright © WireMock.Net // Copyright © WireMock.Net
using WireMock.Extensions;
using WireMock.Util;
namespace WireMock.Matchers; namespace WireMock.Matchers;
/// <summary> /// <summary>
@@ -34,4 +37,16 @@ public class JsonPartialMatcher : AbstractJsonPartialMatcher
var exactStringMatcher = new ExactMatcher(MatchBehaviour.AcceptOnMatch, IgnoreCase, MatchOperator.Or, value); var exactStringMatcher = new ExactMatcher(MatchBehaviour.AcceptOnMatch, IgnoreCase, MatchOperator.Or, value);
return exactStringMatcher.IsMatch(input).IsPerfect(); return exactStringMatcher.IsMatch(input).IsPerfect();
} }
/// <inheritdoc />
public override string GetCSharpCodeArguments()
{
return $"new {Name}" +
$"(" +
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}, " +
$"{CSharpFormatter.ConvertToAnonymousObjectDefinition(Value, 3)}, " +
$"{CSharpFormatter.ToCSharpBooleanLiteral(IgnoreCase)}, " +
$"{CSharpFormatter.ToCSharpBooleanLiteral(Regex)}" +
$")";
}
} }

View File

@@ -1,5 +1,8 @@
// Copyright © WireMock.Net // Copyright © WireMock.Net
using WireMock.Extensions;
using WireMock.Util;
namespace WireMock.Matchers; namespace WireMock.Matchers;
/// <summary> /// <summary>
@@ -34,4 +37,16 @@ public class JsonPartialWildcardMatcher : AbstractJsonPartialMatcher
var wildcardStringMatcher = new WildcardMatcher(MatchBehaviour.AcceptOnMatch, value, IgnoreCase); var wildcardStringMatcher = new WildcardMatcher(MatchBehaviour.AcceptOnMatch, value, IgnoreCase);
return wildcardStringMatcher.IsMatch(input).IsPerfect(); return wildcardStringMatcher.IsMatch(input).IsPerfect();
} }
/// <inheritdoc />
public override string GetCSharpCodeArguments()
{
return $"new {Name}" +
$"(" +
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}, " +
$"{CSharpFormatter.ConvertToAnonymousObjectDefinition(Value, 3)}, " +
$"{CSharpFormatter.ToCSharpBooleanLiteral(IgnoreCase)}, " +
$"{CSharpFormatter.ToCSharpBooleanLiteral(Regex)}" +
$")";
}
} }

View File

@@ -9,6 +9,7 @@ using Stef.Validation;
using WireMock.Extensions; using WireMock.Extensions;
using WireMock.Json; using WireMock.Json;
using WireMock.Models; using WireMock.Models;
using WireMock.Util;
namespace WireMock.Matchers; namespace WireMock.Matchers;
@@ -136,4 +137,15 @@ public class LinqMatcher : IObjectMatcher, IStringMatcher
/// <inheritdoc /> /// <inheritdoc />
public string Name => nameof(LinqMatcher); public string Name => nameof(LinqMatcher);
/// <inheritdoc />
public string GetCSharpCodeArguments()
{
return $"new {Name}" +
$"(" +
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}, " +
$"{MatchOperator.GetFullyQualifiedEnumValue()}, " +
$"{MappingConverterUtils.ToCSharpCodeArguments(_patterns)}" +
$")";
}
} }

View File

@@ -3,6 +3,7 @@
#if MIMEKIT #if MIMEKIT
using System; using System;
using MimeKit; using MimeKit;
using WireMock.Extensions;
using WireMock.Matchers; using WireMock.Matchers;
using WireMock.Matchers.Helpers; using WireMock.Matchers.Helpers;
using WireMock.Models; using WireMock.Models;
@@ -60,13 +61,13 @@ public class MimePartMatcher : IMatcher
ContentTransferEncodingMatcher = contentTransferEncodingMatcher; ContentTransferEncodingMatcher = contentTransferEncodingMatcher;
ContentMatcher = contentMatcher; ContentMatcher = contentMatcher;
_funcs = new[] _funcs =
{ [
mp => ContentTypeMatcher?.IsMatch(GetContentTypeAsString(mp.ContentType)) ?? MatchScores.Perfect, mp => ContentTypeMatcher?.IsMatch(GetContentTypeAsString(mp.ContentType)) ?? MatchScores.Perfect,
mp => ContentDispositionMatcher?.IsMatch(mp.ContentDisposition.ToString().Replace("Content-Disposition: ", string.Empty)) ?? MatchScores.Perfect, mp => ContentDispositionMatcher?.IsMatch(mp.ContentDisposition.ToString().Replace("Content-Disposition: ", string.Empty)) ?? MatchScores.Perfect,
mp => ContentTransferEncodingMatcher?.IsMatch(mp.ContentTransferEncoding.ToString().ToLowerInvariant()) ?? MatchScores.Perfect, mp => ContentTransferEncodingMatcher?.IsMatch(mp.ContentTransferEncoding.ToString().ToLowerInvariant()) ?? MatchScores.Perfect,
MatchOnContent MatchOnContent
}; ];
} }
/// <summary> /// <summary>
@@ -94,6 +95,12 @@ public class MimePartMatcher : IMatcher
return new MatchResult(MatchBehaviourHelper.Convert(MatchBehaviour, score), exception); return new MatchResult(MatchBehaviourHelper.Convert(MatchBehaviour, score), exception);
} }
/// <inheritdoc />
public string GetCSharpCodeArguments()
{
return "NotImplemented";
}
private MatchResult MatchOnContent(MimePart mimePart) private MatchResult MatchOnContent(MimePart mimePart)
{ {
if (ContentMatcher == null) if (ContentMatcher == null)

View File

@@ -3,7 +3,9 @@
using System; using System;
using System.Linq; using System.Linq;
using AnyOfTypes; using AnyOfTypes;
using WireMock.Extensions;
using WireMock.Models; using WireMock.Models;
using WireMock.Util;
namespace WireMock.Matchers; namespace WireMock.Matchers;
@@ -70,5 +72,14 @@ public class NotNullOrEmptyMatcher : IObjectMatcher, IStringMatcher
} }
/// <inheritdoc /> /// <inheritdoc />
public MatchOperator MatchOperator { get; } = MatchOperator.Or; public MatchOperator MatchOperator => MatchOperator.Or;
/// <inheritdoc />
public string GetCSharpCodeArguments()
{
return $"new {Name}" +
$"(" +
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}" +
$")";
}
} }

View File

@@ -89,6 +89,12 @@ public class ProtoBufMatcher : IProtoBufMatcher
return DecodeAsync(input, false, cancellationToken); return DecodeAsync(input, false, cancellationToken);
} }
/// <inheritdoc />
public string GetCSharpCodeArguments()
{
return "NotImplemented";
}
private async Task<object?> DecodeAsync(byte[]? input, bool throwException, CancellationToken cancellationToken) private async Task<object?> DecodeAsync(byte[]? input, bool throwException, CancellationToken cancellationToken)
{ {
if (input == null) if (input == null)

View File

@@ -10,6 +10,7 @@ using WireMock.Constants;
using WireMock.Extensions; using WireMock.Extensions;
using WireMock.Models; using WireMock.Models;
using WireMock.RegularExpressions; using WireMock.RegularExpressions;
using WireMock.Util;
namespace WireMock.Matchers; namespace WireMock.Matchers;
@@ -22,6 +23,7 @@ public class RegexMatcher : IStringMatcher, IIgnoreCaseMatcher
{ {
private readonly AnyOf<string, StringPattern>[] _patterns; private readonly AnyOf<string, StringPattern>[] _patterns;
private readonly Regex[] _expressions; private readonly Regex[] _expressions;
private readonly bool _useRegexExtended;
/// <inheritdoc /> /// <inheritdoc />
public MatchBehaviour MatchBehaviour { get; } public MatchBehaviour MatchBehaviour { get; }
@@ -77,10 +79,11 @@ public class RegexMatcher : IStringMatcher, IIgnoreCaseMatcher
{ {
_patterns = Guard.NotNull(patterns); _patterns = Guard.NotNull(patterns);
IgnoreCase = ignoreCase; IgnoreCase = ignoreCase;
_useRegexExtended = useRegexExtended;
MatchBehaviour = matchBehaviour; MatchBehaviour = matchBehaviour;
MatchOperator = matchOperator; MatchOperator = matchOperator;
RegexOptions options = RegexOptions.Compiled | RegexOptions.Multiline; var options = RegexOptions.Compiled | RegexOptions.Multiline;
if (ignoreCase) if (ignoreCase)
{ {
@@ -126,4 +129,16 @@ public class RegexMatcher : IStringMatcher, IIgnoreCaseMatcher
/// <inheritdoc /> /// <inheritdoc />
public MatchOperator MatchOperator { get; } public MatchOperator MatchOperator { get; }
/// <inheritdoc />
public virtual string GetCSharpCodeArguments()
{
return $"new {Name}" +
$"(" +
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}, " +
$"{MappingConverterUtils.ToCSharpCodeArguments(_patterns)}, " +
$"{CSharpFormatter.ToCSharpBooleanLiteral(IgnoreCase)}, " +
$"{CSharpFormatter.ToCSharpBooleanLiteral(_useRegexExtended)}, " +
$"{MatchOperator.GetFullyQualifiedEnumValue()}" +
$")";
}
} }

View File

@@ -8,6 +8,7 @@ using SimMetrics.Net.Metric;
using Stef.Validation; using Stef.Validation;
using WireMock.Extensions; using WireMock.Extensions;
using WireMock.Models; using WireMock.Models;
using WireMock.Util;
namespace WireMock.Matchers; namespace WireMock.Matchers;
@@ -88,6 +89,18 @@ public class SimMetricsMatcher : IStringMatcher
return MatchBehaviourHelper.Convert(MatchBehaviour, score); return MatchBehaviourHelper.Convert(MatchBehaviour, score);
} }
/// <inheritdoc />
public virtual string GetCSharpCodeArguments()
{
return $"new {Name}" +
$"(" +
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}, " +
$"{MappingConverterUtils.ToCSharpCodeArguments(_patterns)}, " +
$"{_simMetricType.GetFullyQualifiedEnumValue()}, " +
$"{MatchOperator.GetFullyQualifiedEnumValue()}" +
$")";
}
private IStringMetric GetStringMetricType() private IStringMetric GetStringMetricType()
{ {
return _simMetricType switch return _simMetricType switch

View File

@@ -6,6 +6,7 @@ using AnyOfTypes;
using Stef.Validation; using Stef.Validation;
using WireMock.Extensions; using WireMock.Extensions;
using WireMock.Models; using WireMock.Models;
using WireMock.Util;
namespace WireMock.Matchers; namespace WireMock.Matchers;
@@ -70,6 +71,18 @@ public class WildcardMatcher : RegexMatcher
/// <inheritdoc /> /// <inheritdoc />
public override string Name => nameof(WildcardMatcher); public override string Name => nameof(WildcardMatcher);
/// <inheritdoc />
public override string GetCSharpCodeArguments()
{
return $"new {Name}" +
$"(" +
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}, " +
$"{MappingConverterUtils.ToCSharpCodeArguments(_patterns)}, " +
$"{CSharpFormatter.ToCSharpBooleanLiteral(IgnoreCase)}, " +
$"{MatchOperator.GetFullyQualifiedEnumValue()}" +
$")";
}
private static AnyOf<string, StringPattern>[] CreateArray(AnyOf<string, StringPattern>[] patterns) private static AnyOf<string, StringPattern>[] CreateArray(AnyOf<string, StringPattern>[] patterns)
{ {
return patterns return patterns

View File

@@ -10,6 +10,7 @@ using WireMock.Extensions;
using WireMock.Models; using WireMock.Models;
using Stef.Validation; using Stef.Validation;
using WireMock.Admin.Mappings; using WireMock.Admin.Mappings;
using WireMock.Util;
#if !NETSTANDARD1_3 #if !NETSTANDARD1_3
using Wmhelp.XPath2; using Wmhelp.XPath2;
#endif #endif
@@ -89,11 +90,6 @@ public class XPathMatcher : IStringMatcher
return CreateMatchResult(score); return CreateMatchResult(score);
} }
private MatchResult CreateMatchResult(double score, Exception? exception = null)
{
return new MatchResult(MatchBehaviourHelper.Convert(MatchBehaviour, score), exception);
}
/// <inheritdoc /> /// <inheritdoc />
public AnyOf<string, StringPattern>[] GetPatterns() public AnyOf<string, StringPattern>[] GetPatterns()
{ {
@@ -106,6 +102,23 @@ public class XPathMatcher : IStringMatcher
/// <inheritdoc /> /// <inheritdoc />
public string Name => nameof(XPathMatcher); public string Name => nameof(XPathMatcher);
/// <inheritdoc />
public string GetCSharpCodeArguments()
{
return $"new {Name}" +
$"(" +
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}, " +
$"{MatchOperator.GetFullyQualifiedEnumValue()}, " +
$"null, " +
$"{MappingConverterUtils.ToCSharpCodeArguments(_patterns)}" +
$")";
}
private MatchResult CreateMatchResult(double score, Exception? exception = null)
{
return new MatchResult(MatchBehaviourHelper.Convert(MatchBehaviour, score), exception);
}
private sealed class XPathEvaluator private sealed class XPathEvaluator
{ {
private XmlDocument? _xmlDocument; private XmlDocument? _xmlDocument;
@@ -130,6 +143,7 @@ public class XPathMatcher : IStringMatcher
{ {
return _xpathNavigator == null ? [] : patterns.Select(pattern => true.Equals(Evaluate(_xpathNavigator, pattern, xmlNamespaceMap))).ToArray(); return _xpathNavigator == null ? [] : patterns.Select(pattern => true.Equals(Evaluate(_xpathNavigator, pattern, xmlNamespaceMap))).ToArray();
} }
private object Evaluate(XPathNavigator navigator, AnyOf<string, StringPattern> pattern, IEnumerable<XmlNamespace>? xmlNamespaceMap) private object Evaluate(XPathNavigator navigator, AnyOf<string, StringPattern> pattern, IEnumerable<XmlNamespace>? xmlNamespaceMap)
{ {
var xpath = $"boolean({pattern.GetPattern()})"; var xpath = $"boolean({pattern.GetPattern()})";

View File

@@ -23,16 +23,11 @@ using static WireMock.Util.CSharpFormatter;
namespace WireMock.Serialization; namespace WireMock.Serialization;
internal class MappingConverter internal class MappingConverter(MatcherMapper mapper)
{ {
private static readonly string AcceptOnMatch = MatchBehaviour.AcceptOnMatch.GetFullyQualifiedEnumValue(); private static readonly string AcceptOnMatch = MatchBehaviour.AcceptOnMatch.GetFullyQualifiedEnumValue();
private readonly MatcherMapper _mapper; private readonly MatcherMapper _mapper = Guard.NotNull(mapper);
public MappingConverter(MatcherMapper mapper)
{
_mapper = Guard.NotNull(mapper);
}
public string ToCSharpCode(IMapping mapping, MappingConverterSettings? settings = null) public string ToCSharpCode(IMapping mapping, MappingConverterSettings? settings = null)
{ {
@@ -77,26 +72,26 @@ internal class MappingConverter
sb.AppendLine(" .Given(Request.Create()"); sb.AppendLine(" .Given(Request.Create()");
sb.AppendLine($" .UsingMethod({To1Or2Or3Arguments(methodMatcher?.MatchBehaviour, methodMatcher?.MatchOperator, methodMatcher?.Methods, HttpRequestMethod.GET)})"); sb.AppendLine($" .UsingMethod({To1Or2Or3Arguments(methodMatcher?.MatchBehaviour, methodMatcher?.MatchOperator, methodMatcher?.Methods, HttpRequestMethod.GET)})");
if (pathMatcher is { Matchers: { } }) if (pathMatcher?.Matchers != null)
{ {
sb.AppendLine($" .WithPath({To1Or2Arguments(pathMatcher.MatchOperator, pathMatcher.Matchers)})"); sb.AppendLine($" .WithPath({To1Or2Arguments(pathMatcher.MatchOperator, pathMatcher.Matchers)})");
} }
else if (urlMatcher is { Matchers: { } }) else if (urlMatcher?.Matchers != null)
{ {
sb.AppendLine($" .WithUrl({To1Or2Arguments(urlMatcher.MatchOperator, urlMatcher.Matchers)})"); sb.AppendLine($" .WithUrl({To1Or2Arguments(urlMatcher.MatchOperator, urlMatcher.Matchers)})");
} }
foreach (var paramsMatcher in paramsMatchers) foreach (var paramsMatcher in paramsMatchers.Where(pm => pm.Matchers != null))
{ {
sb.AppendLine($" .WithParam({To1Or2Or3Arguments(paramsMatcher.Key, paramsMatcher.MatchBehaviour, paramsMatcher.Matchers!)})"); sb.AppendLine($" .WithParam({To2Or3Arguments(paramsMatcher.Key, paramsMatcher.MatchBehaviour, paramsMatcher.Matchers!)})");
} }
if (clientIPMatcher is { Matchers: { } }) if (clientIPMatcher?.Matchers != null)
{ {
sb.AppendLine($" .WithClientIP({ToValueArguments(GetStringArray(clientIPMatcher.Matchers))})"); sb.AppendLine($" .WithClientIP({ToValueArguments(GetStringArray(clientIPMatcher.Matchers))})");
} }
foreach (var headerMatcher in headerMatchers.Where(h => h.Matchers is { })) foreach (var headerMatcher in headerMatchers.Where(h => h.Matchers != null))
{ {
var headerBuilder = new StringBuilder($"\"{headerMatcher.Name}\", {ToValueArguments(GetStringArray(headerMatcher.Matchers!))}, true"); var headerBuilder = new StringBuilder($"\"{headerMatcher.Name}\", {ToValueArguments(GetStringArray(headerMatcher.Matchers!))}, true");
if (headerMatcher.MatchOperator != MatchOperator.Or) if (headerMatcher.MatchOperator != MatchOperator.Or)
@@ -106,7 +101,7 @@ internal class MappingConverter
sb.AppendLine($" .WithHeader({headerBuilder})"); sb.AppendLine($" .WithHeader({headerBuilder})");
} }
foreach (var cookieMatcher in cookieMatchers.Where(h => h.Matchers is { })) foreach (var cookieMatcher in cookieMatchers.Where(c => c.Matchers != null))
{ {
sb.AppendLine($" .WithCookie(\"{cookieMatcher.Name}\", {ToValueArguments(GetStringArray(cookieMatcher.Matchers!))}, true)"); sb.AppendLine($" .WithCookie(\"{cookieMatcher.Name}\", {ToValueArguments(GetStringArray(cookieMatcher.Matchers!))}, true)");
} }
@@ -117,7 +112,7 @@ internal class MappingConverter
} }
#if GRAPHQL #if GRAPHQL
if (requestMessageGraphQLMatcher is { Matchers: { } }) if (requestMessageGraphQLMatcher?.Matchers != null)
{ {
if (requestMessageGraphQLMatcher.Matchers.OfType<GraphQLMatcher>().FirstOrDefault() is { } graphQLMatcher && graphQLMatcher.GetPatterns().Any()) if (requestMessageGraphQLMatcher.Matchers.OfType<GraphQLMatcher>().FirstOrDefault() is { } graphQLMatcher && graphQLMatcher.GetPatterns().Any())
{ {
@@ -127,7 +122,7 @@ internal class MappingConverter
#endif #endif
#if MIMEKIT #if MIMEKIT
if (requestMessageMultiPartMatcher is { Matchers: { } }) if (requestMessageMultiPartMatcher?.Matchers != null)
{ {
if (requestMessageMultiPartMatcher.Matchers.OfType<MimePartMatcher>().Any()) if (requestMessageMultiPartMatcher.Matchers.OfType<MimePartMatcher>().Any())
{ {
@@ -137,13 +132,13 @@ internal class MappingConverter
#endif #endif
#if PROTOBUF #if PROTOBUF
if (requestMessageProtoBufMatcher is { Matcher: { } }) if (requestMessageProtoBufMatcher?.Matcher != null)
{ {
sb.AppendLine(" // .WithBodyAsProtoBuf() is not yet supported"); sb.AppendLine(" // .WithBodyAsProtoBuf() is not yet supported");
} }
#endif #endif
if (requestMessageBodyMatcher is { Matchers: { } }) if (requestMessageBodyMatcher?.Matchers != null)
{ {
var firstMatcher = requestMessageBodyMatcher.Matchers.FirstOrDefault(); var firstMatcher = requestMessageBodyMatcher.Matchers.FirstOrDefault();
@@ -154,15 +149,15 @@ internal class MappingConverter
break; break;
case JsonMatcher jsonMatcher: case JsonMatcher jsonMatcher:
{ {
var matcherType = jsonMatcher.GetType().Name; var matcherType = jsonMatcher.GetType().Name;
sb.AppendLine($" .WithBody(new {matcherType}("); sb.AppendLine($" .WithBody(new {matcherType}(");
sb.AppendLine($" value: {ConvertToAnonymousObjectDefinition(jsonMatcher.Value, 3)},"); sb.AppendLine($" value: {ConvertToAnonymousObjectDefinition(jsonMatcher.Value, 3)},");
sb.AppendLine($" ignoreCase: {ToCSharpBooleanLiteral(jsonMatcher.IgnoreCase)},"); sb.AppendLine($" ignoreCase: {ToCSharpBooleanLiteral(jsonMatcher.IgnoreCase)},");
sb.AppendLine($" regex: {ToCSharpBooleanLiteral(jsonMatcher.Regex)}"); sb.AppendLine($" regex: {ToCSharpBooleanLiteral(jsonMatcher.Regex)}");
sb.AppendLine(@" ))"); sb.AppendLine(@" ))");
break; break;
} }
} }
} }
@@ -309,7 +304,7 @@ internal class MappingConverter
Response = new ResponseModel() Response = new ResponseModel()
}; };
if (methodMatcher is { Methods: { } }) if (methodMatcher != null)
{ {
mappingModel.Request.Methods = methodMatcher.Methods; mappingModel.Request.Methods = methodMatcher.Methods;
mappingModel.Request.MethodsRejectOnMatch = methodMatcher.MatchBehaviour == MatchBehaviour.RejectOnMatch ? true : null; mappingModel.Request.MethodsRejectOnMatch = methodMatcher.MatchBehaviour == MatchBehaviour.RejectOnMatch ? true : null;
@@ -321,7 +316,7 @@ internal class MappingConverter
mappingModel.Request.HttpVersion = httpVersionMatcher.HttpVersion; mappingModel.Request.HttpVersion = httpVersionMatcher.HttpVersion;
} }
if (clientIPMatcher is { Matchers: { } }) if (clientIPMatcher?.Matchers != null)
{ {
var clientIPMatchers = _mapper.Map(clientIPMatcher.Matchers); var clientIPMatchers = _mapper.Map(clientIPMatcher.Matchers);
mappingModel.Request.Path = new ClientIPModel mappingModel.Request.Path = new ClientIPModel
@@ -331,7 +326,7 @@ internal class MappingConverter
}; };
} }
if (pathMatcher is { Matchers: { } }) if (pathMatcher?.Matchers != null)
{ {
var pathMatchers = _mapper.Map(pathMatcher.Matchers); var pathMatchers = _mapper.Map(pathMatcher.Matchers);
mappingModel.Request.Path = new PathModel mappingModel.Request.Path = new PathModel
@@ -340,7 +335,7 @@ internal class MappingConverter
MatchOperator = pathMatchers?.Length > 1 ? pathMatcher.MatchOperator.ToString() : null MatchOperator = pathMatchers?.Length > 1 ? pathMatcher.MatchOperator.ToString() : null
}; };
} }
else if (urlMatcher is { Matchers: { } }) else if (urlMatcher?.Matchers != null)
{ {
var urlMatchers = _mapper.Map(urlMatcher.Matchers); var urlMatchers = _mapper.Map(urlMatcher.Matchers);
mappingModel.Request.Url = new UrlModel mappingModel.Request.Url = new UrlModel
@@ -538,7 +533,7 @@ internal class MappingConverter
return stringMatchers.SelectMany(m => m.GetPatterns()).Select(p => p.GetPattern()).ToArray(); return stringMatchers.SelectMany(m => m.GetPatterns()).Select(p => p.GetPattern()).ToArray();
} }
private static string To1Or2Or3Arguments(string key, MatchBehaviour? matchBehaviour, IReadOnlyList<IStringMatcher> matchers) private static string To2Or3Arguments(string key, MatchBehaviour? matchBehaviour, IReadOnlyList<IStringMatcher> matchers)
{ {
var sb = new StringBuilder($"\"{key}\", "); var sb = new StringBuilder($"\"{key}\", ");
@@ -547,7 +542,7 @@ internal class MappingConverter
sb.AppendFormat("{0}, ", matchBehaviour.Value.GetFullyQualifiedEnumValue()); sb.AppendFormat("{0}, ", matchBehaviour.Value.GetFullyQualifiedEnumValue());
} }
sb.AppendFormat("{0}", ToValueArguments(GetStringArray(matchers), string.Empty)); sb.AppendFormat("{0}", MappingConverterUtils.ToCSharpCodeArguments(matchers));
return sb.ToString(); return sb.ToString();
} }
@@ -566,7 +561,16 @@ internal class MappingConverter
private static string To1Or2Arguments(MatchOperator? matchOperator, IReadOnlyList<IStringMatcher> matchers) private static string To1Or2Arguments(MatchOperator? matchOperator, IReadOnlyList<IStringMatcher> matchers)
{ {
return To1Or2Arguments(matchOperator, GetStringArray(matchers), string.Empty); var sb = new StringBuilder();
if (matchOperator.HasValue && matchOperator != MatchOperator.Or)
{
sb.AppendFormat("{0}, ", matchOperator.Value.GetFullyQualifiedEnumValue());
}
sb.AppendFormat("{0}", MappingConverterUtils.ToCSharpCodeArguments(matchers));
return sb.ToString();
} }
private static string To1Or2Arguments(MatchOperator? matchOperator, string[]? values, string defaultValue) private static string To1Or2Arguments(MatchOperator? matchOperator, string[]? values, string defaultValue)

View File

@@ -0,0 +1,23 @@
// Copyright © WireMock.Net
using System.Collections.Generic;
using System.Linq;
using AnyOfTypes;
using WireMock.Extensions;
using WireMock.Matchers;
using WireMock.Models;
namespace WireMock.Util;
internal static class MappingConverterUtils
{
internal static string ToCSharpCodeArguments(IReadOnlyList<IMatcher> matchers)
{
return string.Join(", ", matchers.Select(m => m.GetCSharpCodeArguments()));
}
internal static string ToCSharpCodeArguments(AnyOf<string, StringPattern>[] patterns)
{
return string.Join(", ", patterns.Select(p => CSharpFormatter.ToCSharpStringLiteral(p.GetPattern())));
}
}

View File

@@ -47,6 +47,7 @@ message HelloReply {
.WithPath("/grpc/greet.Greeter/SayHello") .WithPath("/grpc/greet.Greeter/SayHello")
.WithBodyAsProtoBuf(ProtoDefinition, "greet.HelloRequest", protoBufJsonMatcher) .WithBodyAsProtoBuf(ProtoDefinition, "greet.HelloRequest", protoBufJsonMatcher)
) )
.WithGuid(_guidUtilsMock.Object.NewGuid())
.RespondWith(Response.Create() .RespondWith(Response.Create()
.WithHeader("Content-Type", "application/grpc") .WithHeader("Content-Type", "application/grpc")
.WithBodyAsProtoBuf(ProtoDefinition, "greet.HelloReply", .WithBodyAsProtoBuf(ProtoDefinition, "greet.HelloReply",
@@ -66,6 +67,7 @@ message HelloReply {
.WithBodyAsProtoBuf("greet.HelloRequest", protoBufJsonMatcher) .WithBodyAsProtoBuf("greet.HelloRequest", protoBufJsonMatcher)
) )
.WithProtoDefinition(ProtoDefinition) .WithProtoDefinition(ProtoDefinition)
.WithGuid(_guidUtilsMock.Object.NewGuid())
.RespondWith(Response.Create() .RespondWith(Response.Create()
.WithHeader("Content-Type", "application/grpc") .WithHeader("Content-Type", "application/grpc")
.WithBodyAsProtoBuf("greet.HelloReply", .WithBodyAsProtoBuf("greet.HelloReply",
@@ -86,6 +88,7 @@ message HelloReply {
.WithBodyAsProtoBuf("greet.HelloRequest", protoBufJsonMatcher) .WithBodyAsProtoBuf("greet.HelloRequest", protoBufJsonMatcher)
) )
.WithProtoDefinition("my-greeter") .WithProtoDefinition("my-greeter")
.WithGuid(_guidUtilsMock.Object.NewGuid())
.RespondWith(Response.Create() .RespondWith(Response.Create()
.WithHeader("Content-Type", "application/grpc") .WithHeader("Content-Type", "application/grpc")
.WithBodyAsProtoBuf("greet.HelloReply", .WithBodyAsProtoBuf("greet.HelloReply",
@@ -106,6 +109,7 @@ message HelloReply {
.WithBodyAsProtoBuf("greet.HelloRequest") .WithBodyAsProtoBuf("greet.HelloRequest")
) )
.WithProtoDefinition("my-greeter") .WithProtoDefinition("my-greeter")
.WithGuid(_guidUtilsMock.Object.NewGuid())
.RespondWith(Response.Create() .RespondWith(Response.Create()
.WithHeader("Content-Type", "application/grpc") .WithHeader("Content-Type", "application/grpc")
.WithBodyAsProtoBuf("greet.HelloReply", .WithBodyAsProtoBuf("greet.HelloReply",

View File

@@ -2,8 +2,8 @@
server server
.Given(Request.Create() .Given(Request.Create()
.UsingMethod("GET") .UsingMethod("GET")
.WithPath("/foo1") .WithPath(new WildcardMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, "/foo1", false, WireMock.Matchers.MatchOperator.Or))
.WithParam("p1", "xyz") .WithParam("p1", new ExactMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, false, WireMock.Matchers.MatchOperator.And, "xyz"))
) )
.WithGuid("90356dba-b36c-469a-a17e-669cd84f1f05") .WithGuid("90356dba-b36c-469a-a17e-669cd84f1f05")
.RespondWith(Response.Create() .RespondWith(Response.Create()

View File

@@ -2,25 +2,7 @@
server server
.Given(Request.Create() .Given(Request.Create()
.UsingMethod("POST") .UsingMethod("POST")
.WithPath("/users/post1") .WithPath(new WildcardMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, "/users/post2", false, WireMock.Matchers.MatchOperator.Or))
.WithBody(new JsonMatcher(
value: new
{
city = "Amsterdam",
country = "The Netherlands"
},
ignoreCase: false,
regex: false
))
)
.WithGuid("90356dba-b36c-469a-a17e-669cd84f1f05")
.RespondWith(Response.Create()
);
server
.Given(Request.Create()
.UsingMethod("POST")
.WithPath("/users/post2")
.WithBody(new JsonPartialMatcher( .WithBody(new JsonPartialMatcher(
value: new value: new
{ {
@@ -37,23 +19,11 @@ server
Some ""value"" in Line2") Some ""value"" in Line2")
); );
server
.Given(Request.Create()
.UsingMethod("GET")
.WithPath("/foo1")
.WithParam("p1", "xyz")
)
.WithGuid("f74fd144-df53-404f-8e35-da22a640bd5f")
.RespondWith(Response.Create()
.WithStatusCode(200)
.WithBody("1")
);
server server
.Given(Request.Create() .Given(Request.Create()
.UsingMethod("POST") .UsingMethod("POST")
.WithPath("/foo2") .WithPath(new WildcardMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, "/foo2", false, WireMock.Matchers.MatchOperator.Or))
.WithParam("p2", "abc") .WithParam("p2", new ExactMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, false, WireMock.Matchers.MatchOperator.And, "abc"))
.WithHeader("h1", "W/\"234f2q3r\"", true) .WithHeader("h1", "W/\"234f2q3r\"", true)
) )
.WithGuid("4126dec8-470b-4eff-93bb-c24f83b8b1fd") .WithGuid("4126dec8-470b-4eff-93bb-c24f83b8b1fd")
@@ -64,10 +34,28 @@ server
.WithBody("2") .WithBody("2")
); );
server
.Given(Request.Create()
.UsingMethod("POST")
.WithPath(new WildcardMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, "/users/post1", false, WireMock.Matchers.MatchOperator.Or))
.WithBody(new JsonMatcher(
value: new
{
city = "Amsterdam",
country = "The Netherlands"
},
ignoreCase: false,
regex: false
))
)
.WithGuid("90356dba-b36c-469a-a17e-669cd84f1f05")
.RespondWith(Response.Create()
);
server server
.Given(Request.Create() .Given(Request.Create()
.UsingMethod("DELETE") .UsingMethod("DELETE")
.WithUrl("https://localhost/test") .WithUrl(new WildcardMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, "https://localhost/test", false, WireMock.Matchers.MatchOperator.Or))
) )
.WithGuid("c9929240-7ae8-4a5d-8ed8-0913479f6eeb") .WithGuid("c9929240-7ae8-4a5d-8ed8-0913479f6eeb")
.RespondWith(Response.Create() .RespondWith(Response.Create()
@@ -108,3 +96,15 @@ text
}) })
); );
server
.Given(Request.Create()
.UsingMethod("GET")
.WithPath(new WildcardMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, "/foo1", false, WireMock.Matchers.MatchOperator.Or))
.WithParam("p1", new ExactMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, false, WireMock.Matchers.MatchOperator.And, "xyz"))
)
.WithGuid("f74fd144-df53-404f-8e35-da22a640bd5f")
.RespondWith(Response.Create()
.WithStatusCode(200)
.WithBody("1")
);

View File

@@ -30,6 +30,7 @@ using WireMock.ResponseBuilders;
using WireMock.Server; using WireMock.Server;
using WireMock.Settings; using WireMock.Settings;
using WireMock.Types; using WireMock.Types;
using WireMock.Util;
using Xunit; using Xunit;
namespace WireMock.Net.Tests.AdminApi; namespace WireMock.Net.Tests.AdminApi;
@@ -39,6 +40,14 @@ public partial class WireMockAdminApiTests
{ {
private static readonly VerifySettings VerifySettings = new(); private static readonly VerifySettings VerifySettings = new();
private readonly Mock<IGuidUtils> _guidUtilsMock = new();
public WireMockAdminApiTests()
{
var startGuid = 1000;
_guidUtilsMock.Setup(g => g.NewGuid()).Returns(() => new Guid($"98fae52e-76df-47d9-876f-2ee32e93{startGuid++}"));
}
static WireMockAdminApiTests() static WireMockAdminApiTests()
{ {
VerifyNewtonsoftJson.Enable(VerifySettings); VerifyNewtonsoftJson.Enable(VerifySettings);

View File

@@ -32,6 +32,35 @@
Body: { msg: "Hello world!"} Body: { msg: "Hello world!"}
} }
}, },
{
Guid: 98fae52e-76df-47d9-876f-2ee32e931001,
UpdatedAt: 2023-01-14 15:16:17,
Request: {
Path: {
Matchers: [
{
Name: WildcardMatcher,
Pattern: /users/post1,
IgnoreCase: false
}
]
},
Methods: [
POST
],
Body: {
Matcher: {
Name: JsonMatcher,
Pattern: {
Request: Hello?
},
IgnoreCase: false,
Regex: false
}
}
},
Response: {}
},
{ {
Guid: 98fae52e-76df-47d9-876f-2ee32e931002, Guid: 98fae52e-76df-47d9-876f-2ee32e931002,
UpdatedAt: 2023-01-14 15:16:17, UpdatedAt: 2023-01-14 15:16:17,
@@ -106,31 +135,33 @@
Response: {} Response: {}
}, },
{ {
Guid: 98fae52e-76df-47d9-876f-2ee32e931001, Guid: 98fae52e-76df-47d9-876f-2ee32e931004,
UpdatedAt: 2023-01-14 15:16:17, UpdatedAt: 2023-01-14 15:16:17,
Request: { Request: {
Path: { Path: {
Matchers: [ Matchers: [
{ {
Name: WildcardMatcher, Name: WildcardMatcher,
Pattern: /users/post1, Pattern: /regex,
IgnoreCase: false IgnoreCase: false
} }
] ]
}, },
Methods: [ Methods: [
POST GET
], ],
Body: { Params: [
Matcher: { {
Name: JsonMatcher, Name: foo,
Pattern: { Matchers: [
Request: Hello? {
}, Name: RegexMatcher,
IgnoreCase: false, Pattern: .*,
Regex: false IgnoreCase: false
}
]
} }
} ]
}, },
Response: {} Response: {}
} }

View File

@@ -2,8 +2,8 @@
builder builder
.Given(Request.Create() .Given(Request.Create()
.UsingMethod("GET") .UsingMethod("GET")
.WithPath("/foo") .WithPath(new WildcardMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, "/foo", false, WireMock.Matchers.MatchOperator.Or))
.WithParam("test", "it.Length < 10") .WithParam("test", new LinqMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, WireMock.Matchers.MatchOperator.Or, "it.Length < 10"))
) )
.WithGuid("41372914-1838-4c67-916b-b9aacdd096ce") .WithGuid("41372914-1838-4c67-916b-b9aacdd096ce")
.RespondWith(Response.Create() .RespondWith(Response.Create()
@@ -13,7 +13,24 @@ builder
builder builder
.Given(Request.Create() .Given(Request.Create()
.UsingMethod("POST") .UsingMethod("POST")
.WithPath("/users/post2") .WithPath(new WildcardMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, "/users/post1", false, WireMock.Matchers.MatchOperator.Or))
.WithBody(new JsonMatcher(
value: new
{
Request = "Hello?"
},
ignoreCase: false,
regex: false
))
)
.WithGuid("98fae52e-76df-47d9-876f-2ee32e931001")
.RespondWith(Response.Create()
);
builder
.Given(Request.Create()
.UsingMethod("POST")
.WithPath(new WildcardMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, "/users/post2", false, WireMock.Matchers.MatchOperator.Or))
.WithBody(new JsonMatcher( .WithBody(new JsonMatcher(
value: new value: new
{ {
@@ -31,7 +48,7 @@ builder
builder builder
.Given(Request.Create() .Given(Request.Create()
.UsingMethod("POST") .UsingMethod("POST")
.WithPath("/form-urlencoded") .WithPath(new WildcardMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, "/form-urlencoded", false, WireMock.Matchers.MatchOperator.Or))
.WithHeader("Content-Type", "application/x-www-form-urlencoded", true) .WithHeader("Content-Type", "application/x-www-form-urlencoded", true)
.WithBody("name=John Doe") .WithBody("name=John Doe")
) )
@@ -41,18 +58,11 @@ builder
builder builder
.Given(Request.Create() .Given(Request.Create()
.UsingMethod("POST") .UsingMethod("GET")
.WithPath("/users/post1") .WithPath(new WildcardMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, "/regex", false, WireMock.Matchers.MatchOperator.Or))
.WithBody(new JsonMatcher( .WithParam("foo", new RegexMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, ".*", false, true, WireMock.Matchers.MatchOperator.Or))
value: new
{
Request = "Hello?"
},
ignoreCase: false,
regex: false
))
) )
.WithGuid("98fae52e-76df-47d9-876f-2ee32e931001") .WithGuid("98fae52e-76df-47d9-876f-2ee32e931004")
.RespondWith(Response.Create() .RespondWith(Response.Create()
); );

View File

@@ -2,8 +2,8 @@
server server
.Given(Request.Create() .Given(Request.Create()
.UsingMethod("GET") .UsingMethod("GET")
.WithPath("/foo") .WithPath(new WildcardMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, "/foo", false, WireMock.Matchers.MatchOperator.Or))
.WithParam("test", "it.Length < 10") .WithParam("test", new LinqMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, WireMock.Matchers.MatchOperator.Or, "it.Length < 10"))
) )
.WithGuid("41372914-1838-4c67-916b-b9aacdd096ce") .WithGuid("41372914-1838-4c67-916b-b9aacdd096ce")
.RespondWith(Response.Create() .RespondWith(Response.Create()
@@ -13,7 +13,24 @@ server
server server
.Given(Request.Create() .Given(Request.Create()
.UsingMethod("POST") .UsingMethod("POST")
.WithPath("/users/post2") .WithPath(new WildcardMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, "/users/post1", false, WireMock.Matchers.MatchOperator.Or))
.WithBody(new JsonMatcher(
value: new
{
Request = "Hello?"
},
ignoreCase: false,
regex: false
))
)
.WithGuid("98fae52e-76df-47d9-876f-2ee32e931001")
.RespondWith(Response.Create()
);
server
.Given(Request.Create()
.UsingMethod("POST")
.WithPath(new WildcardMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, "/users/post2", false, WireMock.Matchers.MatchOperator.Or))
.WithBody(new JsonMatcher( .WithBody(new JsonMatcher(
value: new value: new
{ {
@@ -31,7 +48,7 @@ server
server server
.Given(Request.Create() .Given(Request.Create()
.UsingMethod("POST") .UsingMethod("POST")
.WithPath("/form-urlencoded") .WithPath(new WildcardMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, "/form-urlencoded", false, WireMock.Matchers.MatchOperator.Or))
.WithHeader("Content-Type", "application/x-www-form-urlencoded", true) .WithHeader("Content-Type", "application/x-www-form-urlencoded", true)
.WithBody("name=John Doe") .WithBody("name=John Doe")
) )
@@ -41,18 +58,11 @@ server
server server
.Given(Request.Create() .Given(Request.Create()
.UsingMethod("POST") .UsingMethod("GET")
.WithPath("/users/post1") .WithPath(new WildcardMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, "/regex", false, WireMock.Matchers.MatchOperator.Or))
.WithBody(new JsonMatcher( .WithParam("foo", new RegexMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, ".*", false, true, WireMock.Matchers.MatchOperator.Or))
value: new
{
Request = "Hello?"
},
ignoreCase: false,
regex: false
))
) )
.WithGuid("98fae52e-76df-47d9-876f-2ee32e931001") .WithGuid("98fae52e-76df-47d9-876f-2ee32e931004")
.RespondWith(Response.Create() .RespondWith(Response.Create()
); );

View File

@@ -32,6 +32,34 @@
Body: { msg: "Hello world!"} Body: { msg: "Hello world!"}
} }
}, },
{
Guid: 98fae52e-76df-47d9-876f-2ee32e931001,
UpdatedAt: 2023-01-14T15:16:17,
Request: {
Path: {
Matchers: [
{
Name: WildcardMatcher,
Pattern: /users/post1,
IgnoreCase: false
}
]
},
Methods: [
POST
],
Body: {
Matcher: {
Name: JsonMatcher,
Pattern: {
Request: Hello?
},
IgnoreCase: false,
Regex: false
}
}
}
},
{ {
Guid: 98fae52e-76df-47d9-876f-2ee32e931002, Guid: 98fae52e-76df-47d9-876f-2ee32e931002,
UpdatedAt: 2023-01-14T15:16:17, UpdatedAt: 2023-01-14T15:16:17,
@@ -104,31 +132,33 @@
} }
}, },
{ {
Guid: 98fae52e-76df-47d9-876f-2ee32e931001, Guid: 98fae52e-76df-47d9-876f-2ee32e931004,
UpdatedAt: 2023-01-14T15:16:17, UpdatedAt: 2023-01-14T15:16:17,
Request: { Request: {
Path: { Path: {
Matchers: [ Matchers: [
{ {
Name: WildcardMatcher, Name: WildcardMatcher,
Pattern: /users/post1, Pattern: /regex,
IgnoreCase: false IgnoreCase: false
} }
] ]
}, },
Methods: [ Methods: [
POST GET
], ],
Body: { Params: [
Matcher: { {
Name: JsonMatcher, Name: foo,
Pattern: { Matchers: [
Request: Hello? {
}, Name: RegexMatcher,
IgnoreCase: false, Pattern: .*,
Regex: false IgnoreCase: false
}
]
} }
} ]
} }
} }
] ]

View File

@@ -102,6 +102,13 @@ public class MappingBuilderTests
.WithHeader("Content-Type", "application/x-www-form-urlencoded") .WithHeader("Content-Type", "application/x-www-form-urlencoded")
.WithBody(new FormUrlEncodedMatcher(["name=John Doe", "email=johndoe@example.com"])) .WithBody(new FormUrlEncodedMatcher(["name=John Doe", "email=johndoe@example.com"]))
).RespondWith(Response.Create()); ).RespondWith(Response.Create());
_sut.Given(Request.Create()
.WithPath("/regex")
.WithParam("foo", new RegexMatcher(".*"))
.UsingGet()
)
.RespondWith(Response.Create());
} }
[Fact] [Fact]
@@ -190,9 +197,9 @@ public class MappingBuilderTests
_sut.SaveMappingsToFolder(null); _sut.SaveMappingsToFolder(null);
// Verify // Verify
_fileSystemHandlerMock.Verify(fs => fs.GetMappingFolder(), Times.Exactly(4)); _fileSystemHandlerMock.Verify(fs => fs.GetMappingFolder(), Times.Exactly(5));
_fileSystemHandlerMock.Verify(fs => fs.FolderExists(mappingFolder), Times.Exactly(4)); _fileSystemHandlerMock.Verify(fs => fs.FolderExists(mappingFolder), Times.Exactly(5));
_fileSystemHandlerMock.Verify(fs => fs.WriteMappingFile(It.IsAny<string>(), It.IsAny<string>()), Times.Exactly(4)); _fileSystemHandlerMock.Verify(fs => fs.WriteMappingFile(It.IsAny<string>(), It.IsAny<string>()), Times.Exactly(5));
_fileSystemHandlerMock.VerifyNoOtherCalls(); _fileSystemHandlerMock.VerifyNoOtherCalls();
} }
@@ -208,8 +215,8 @@ public class MappingBuilderTests
// Verify // Verify
_fileSystemHandlerMock.Verify(fs => fs.GetMappingFolder(), Times.Never); _fileSystemHandlerMock.Verify(fs => fs.GetMappingFolder(), Times.Never);
_fileSystemHandlerMock.Verify(fs => fs.FolderExists(path), Times.Exactly(4)); _fileSystemHandlerMock.Verify(fs => fs.FolderExists(path), Times.Exactly(5));
_fileSystemHandlerMock.Verify(fs => fs.WriteMappingFile(It.IsAny<string>(), It.IsAny<string>()), Times.Exactly(4)); _fileSystemHandlerMock.Verify(fs => fs.WriteMappingFile(It.IsAny<string>(), It.IsAny<string>()), Times.Exactly(5));
_fileSystemHandlerMock.VerifyNoOtherCalls(); _fileSystemHandlerMock.VerifyNoOtherCalls();
} }
} }

View File

@@ -29,7 +29,7 @@ public class ExactObjectMatcherTests
object checkValue = new byte[] { 1, 2 }; object checkValue = new byte[] { 1, 2 };
// Act // Act
var matcher = new ExactObjectMatcher(new byte[] { 1, 2 }); var matcher = new ExactObjectMatcher([1, 2]);
var score = matcher.IsMatch(checkValue).Score; var score = matcher.IsMatch(checkValue).Score;
// Assert // Assert

View File

@@ -0,0 +1,177 @@
using FluentAssertions;
using WireMock.Matchers;
using Xunit;
namespace WireMock.Net.Tests.Matchers;
public class MatcherTests
{
[Fact]
public void ContentTypeMatcher_GetCSharpCodeArguments_ShouldReturnCorrectArguments()
{
// Arrange
var matcher = new ContentTypeMatcher("application/json");
// Act
var result = matcher.GetCSharpCodeArguments();
// Assert
result.Should().Be("new ContentTypeMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, \"application/json\", false)");
}
[Fact]
public void ExactMatcher_GetCSharpCodeArguments_ShouldReturnCorrectArguments()
{
// Arrange
var matcher = new ExactMatcher("test");
// Act
var result = matcher.GetCSharpCodeArguments();
// Assert
result.Should().Be("new ExactMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, false, WireMock.Matchers.MatchOperator.Or, \"test\")");
}
[Fact]
public void ExactObjectMatcher_GetCSharpCodeArguments_ShouldReturnNotImplemented()
{
// Arrange
var matcher = new ExactObjectMatcher(new { Name = "test" });
// Act
var result = matcher.GetCSharpCodeArguments();
// Assert
result.Should().Be("NotImplemented");
}
[Fact]
public void FormUrlEncodedMatcher_GetCSharpCodeArguments_ShouldReturnCorrectArguments()
{
// Arrange
var matcher = new FormUrlEncodedMatcher("key=value");
// Act
var result = matcher.GetCSharpCodeArguments();
// Assert
result.Should().Be("new FormUrlEncodedMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, \"key=value\", false, WireMock.Matchers.MatchOperator.Or)");
}
[Fact]
public void JmesPathMatcher_GetCSharpCodeArguments_ShouldReturnCorrectArguments()
{
// Arrange
var matcher = new JmesPathMatcher("expression");
// Act
var result = matcher.GetCSharpCodeArguments();
// Assert
result.Should().Be("new JmesPathMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, WireMock.Matchers.MatchOperator.Or, \"expression\")");
}
[Fact]
public void JsonMatcher_GetCSharpCodeArguments_ShouldReturnCorrectArguments()
{
// Arrange
var matcher = new JsonMatcher(new { key = "value" });
// Act
var result = matcher.GetCSharpCodeArguments();
// Assert
result.Should().StartWith("new JsonMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch,");
}
[Fact]
public void JsonPartialMatcher_GetCSharpCodeArguments_ShouldReturnCorrectArguments()
{
// Arrange
var matcher = new JsonPartialMatcher(new { key = "value" });
// Act
var result = matcher.GetCSharpCodeArguments();
// Assert
result.Should().StartWith("new JsonPartialMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch,");
}
[Fact]
public void JsonPartialWildcardMatcher_GetCSharpCodeArguments_ShouldReturnCorrectArguments()
{
// Arrange
var matcher = new JsonPartialWildcardMatcher(new { key = "value" });
// Act
var result = matcher.GetCSharpCodeArguments();
// Assert
result.Should().StartWith("new JsonPartialWildcardMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch,");
}
[Fact]
public void LinqMatcher_GetCSharpCodeArguments_ShouldReturnCorrectArguments()
{
// Arrange
var matcher = new LinqMatcher("it.Contains(\"test\"");
// Act
var result = matcher.GetCSharpCodeArguments();
// Assert
result.Should().Be("new LinqMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, WireMock.Matchers.MatchOperator.Or, \"it.Contains(\\\"test\\\"\")");
}
[Fact]
public void RegexMatcher_GetCSharpCodeArguments_ShouldReturnCorrectArguments()
{
// Arrange
var matcher = new RegexMatcher("pattern");
// Act
var result = matcher.GetCSharpCodeArguments();
// Assert
result.Should().Be("new RegexMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, \"pattern\", false, true, WireMock.Matchers.MatchOperator.Or)");
}
[Fact]
public void SimMetricsMatcher_GetCSharpCodeArguments_ShouldReturnCorrectArguments()
{
// Arrange
var matcher = new SimMetricsMatcher("test");
// Act
var result = matcher.GetCSharpCodeArguments();
// Assert
result.Should().Be("new SimMetricsMatcher.Levenstein(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, \"test\", SimMetrics.Net.SimMetricType.Levenstein, WireMock.Matchers.MatchOperator.Average)");
}
[Fact]
public void WildcardMatcher_GetCSharpCodeArguments_ShouldReturnCorrectArguments()
{
// Arrange
var matcher = new WildcardMatcher("pattern");
// Act
var result = matcher.GetCSharpCodeArguments();
// Assert
result.Should().Be("new WildcardMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, \"pattern\", false, WireMock.Matchers.MatchOperator.Or)");
}
[Fact]
public void XPathMatcher_GetCSharpCodeArguments_ShouldReturnCorrectArguments()
{
// Arrange
var matcher = new XPathMatcher("pattern1");
// Act
var result = matcher.GetCSharpCodeArguments();
// Assert
result.Should().Be("new XPathMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, WireMock.Matchers.MatchOperator.Or, null, \"pattern1\")");
}
}

View File

@@ -92,11 +92,17 @@ public class CustomPathParamMatcher : IStringMatcher
public MatchOperator MatchOperator { get; } public MatchOperator MatchOperator { get; }
/// <inheritdoc />
public string GetCSharpCodeArguments()
{
return "// TODO: CustomPathParamMatcher";
}
private static string[] GetPathParts(string? path) private static string[] GetPathParts(string? path)
{ {
if (path is null) if (path is null)
{ {
return new string[0]; return [];
} }
var hashMarkIndex = path.IndexOf('#'); var hashMarkIndex = path.IndexOf('#');

View File

@@ -1,8 +1,8 @@
builder builder
.Given(Request.Create() .Given(Request.Create()
.UsingMethod("GET") .UsingMethod("GET")
.WithPath("test_path") .WithPath(new WildcardMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, "test_path", false, WireMock.Matchers.MatchOperator.Or))
.WithParam("q", "42") .WithParam("q", new ExactMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, false, WireMock.Matchers.MatchOperator.And, "42"))
.WithClientIP("112.123.100.99") .WithClientIP("112.123.100.99")
.WithHeader("h-key", "h-value", true) .WithHeader("h-key", "h-value", true)
.WithCookie("c-key", "c-value", true) .WithCookie("c-key", "c-value", true)

View File

@@ -2,8 +2,8 @@
builder builder
.Given(Request.Create() .Given(Request.Create()
.UsingMethod("GET") .UsingMethod("GET")
.WithPath("test_path") .WithPath(new WildcardMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, "test_path", false, WireMock.Matchers.MatchOperator.Or))
.WithParam("q", "42") .WithParam("q", new ExactMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, false, WireMock.Matchers.MatchOperator.And, "42"))
.WithClientIP("112.123.100.99") .WithClientIP("112.123.100.99")
.WithHeader("h-key", "h-value", true) .WithHeader("h-key", "h-value", true)
.WithCookie("c-key", "c-value", true) .WithCookie("c-key", "c-value", true)

View File

@@ -1,8 +1,8 @@
server server
.Given(Request.Create() .Given(Request.Create()
.UsingMethod("GET") .UsingMethod("GET")
.WithPath("test_path") .WithPath(new WildcardMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, "test_path", false, WireMock.Matchers.MatchOperator.Or))
.WithParam("q", "42") .WithParam("q", new ExactMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, false, WireMock.Matchers.MatchOperator.And, "42"))
.WithClientIP("112.123.100.99") .WithClientIP("112.123.100.99")
.WithHeader("h-key", "h-value", true) .WithHeader("h-key", "h-value", true)
.WithCookie("c-key", "c-value", true) .WithCookie("c-key", "c-value", true)

View File

@@ -2,8 +2,8 @@
server server
.Given(Request.Create() .Given(Request.Create()
.UsingMethod("GET") .UsingMethod("GET")
.WithPath("test_path") .WithPath(new WildcardMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, "test_path", false, WireMock.Matchers.MatchOperator.Or))
.WithParam("q", "42") .WithParam("q", new ExactMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, false, WireMock.Matchers.MatchOperator.And, "42"))
.WithClientIP("112.123.100.99") .WithClientIP("112.123.100.99")
.WithHeader("h-key", "h-value", true) .WithHeader("h-key", "h-value", true)
.WithCookie("c-key", "c-value", true) .WithCookie("c-key", "c-value", true)