diff --git a/src/WireMock.Net.Abstractions/Admin/Mappings/MappingModel.cs b/src/WireMock.Net.Abstractions/Admin/Mappings/MappingModel.cs index 33d4f424..0c84f53e 100644 --- a/src/WireMock.Net.Abstractions/Admin/Mappings/MappingModel.cs +++ b/src/WireMock.Net.Abstractions/Admin/Mappings/MappingModel.cs @@ -89,7 +89,7 @@ public class MappingModel /// /// Data Object which can be used when WithTransformer is used. - /// e.g. lookup an path in this object using + /// e.g. lookup a path in this object using /// /// lookup data "1" /// @@ -105,4 +105,9 @@ public class MappingModel /// The Grpc ProtoDefinition which is used for this mapping (request and response). [Optional] /// public string? ProtoDefinition { get; set; } + + /// + /// The Grpc ProtoDefinitions which are used for this mapping (request and response). [Optional] + /// + public string[]? ProtoDefinitions { get; set; } } \ No newline at end of file diff --git a/src/WireMock.Net.Abstractions/Admin/Mappings/ResponseModel.cs b/src/WireMock.Net.Abstractions/Admin/Mappings/ResponseModel.cs index 5e15acba..3570439e 100644 --- a/src/WireMock.Net.Abstractions/Admin/Mappings/ResponseModel.cs +++ b/src/WireMock.Net.Abstractions/Admin/Mappings/ResponseModel.cs @@ -137,6 +137,11 @@ public class ResponseModel /// public string? ProtoDefinition { get; set; } + /// + /// Gets or sets the proto definitions. + /// + public string[]? ProtoDefinitions { get; set; } + /// /// Gets or sets the full type of the protobuf (request/response) message object. Format is "{package-name}.{type-name}". /// diff --git a/src/WireMock.Net.Abstractions/Admin/Settings/SettingsModel.cs b/src/WireMock.Net.Abstractions/Admin/Settings/SettingsModel.cs index 050f40e8..ad78701b 100644 --- a/src/WireMock.Net.Abstractions/Admin/Settings/SettingsModel.cs +++ b/src/WireMock.Net.Abstractions/Admin/Settings/SettingsModel.cs @@ -121,7 +121,7 @@ public class SettingsModel /// /// A list of Grpc ProtoDefinitions which can be used. /// - public Dictionary? ProtoDefinitions { get; set; } + public Dictionary? ProtoDefinitions { get; set; } #if NETSTANDARD1_3_OR_GREATER || NET461 /// diff --git a/src/WireMock.Net.Abstractions/Models/IBodyData.cs b/src/WireMock.Net.Abstractions/Models/IBodyData.cs index 5c9b446f..7c9f35e6 100644 --- a/src/WireMock.Net.Abstractions/Models/IBodyData.cs +++ b/src/WireMock.Net.Abstractions/Models/IBodyData.cs @@ -79,7 +79,7 @@ public interface IBodyData /// /// Gets or sets the proto definition. /// - public Func? ProtoDefinition { get; set; } + public Func? ProtoDefinition { get; set; } /// /// Gets or sets the full type of the protobuf (request/response) message object. Format is "{package-name}.{type-name}". diff --git a/src/WireMock.Net.Abstractions/Models/IdOrText.cs b/src/WireMock.Net.Abstractions/Models/IdOrText.cs deleted file mode 100644 index 720d8645..00000000 --- a/src/WireMock.Net.Abstractions/Models/IdOrText.cs +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright © WireMock.Net - -namespace WireMock.Models; - -/// -/// A structure defining an (optional) Id and a Text. -/// -public readonly struct IdOrText -{ - /// - /// The Id [optional]. - /// - public string? Id { get; } - - /// - /// The Text. - /// - public string Text { get; } - - /// - /// When Id is defined, return the Id, else the Text. - /// - public string Value => Id ?? Text; - - /// - /// Create a IdOrText - /// - /// The Id [optional] - /// The Text. - public IdOrText(string? id, string text) - { - Id = id; - Text = text; - } -} \ No newline at end of file diff --git a/src/WireMock.Net.Abstractions/Models/IdOrTexts.cs b/src/WireMock.Net.Abstractions/Models/IdOrTexts.cs new file mode 100644 index 00000000..7a7a03e0 --- /dev/null +++ b/src/WireMock.Net.Abstractions/Models/IdOrTexts.cs @@ -0,0 +1,59 @@ +// Copyright © WireMock.Net + +using System; +using System.Collections.Generic; + +namespace WireMock.Models; + +/// +/// A structure defining an (optional) Id and a Text. +/// +public readonly struct IdOrTexts +{ + /// + /// The Id [optional]. + /// + public string? Id { get; } + + /// + /// The Text. + /// + public IReadOnlyList Texts { get; } + + /// + /// Create a IdOrText + /// + /// The Id [optional] + /// The Text. + public IdOrTexts(string? id, string text) : this(id, [text]) + { + } + + /// + /// Create a IdOrText + /// + /// The Id [optional] + /// The Texts. + public IdOrTexts(string? id, IReadOnlyList texts) + { + Id = id; + Texts = texts; + } + + /// + /// When Id is defined, return process the Id, else process the Texts. + /// + /// Callback to process the id. + /// Callback to process the texts. + public void Value(Action id, Action> texts) + { + if (Id != null) + { + id(Id); + } + else + { + texts(Texts); + } + } +} \ No newline at end of file diff --git a/src/WireMock.Net/Extensions/AnyOfExtensions.cs b/src/WireMock.Net/Extensions/AnyOfExtensions.cs index a97adb38..72646f74 100644 --- a/src/WireMock.Net/Extensions/AnyOfExtensions.cs +++ b/src/WireMock.Net/Extensions/AnyOfExtensions.cs @@ -22,6 +22,16 @@ public static class AnyOfExtensions return value.IsFirst ? value.First : value.Second.Pattern; } + /// + /// Gets the patterns. + /// + /// AnyOf types + /// string values + public static string[] GetPatterns(this AnyOf[] values) + { + return values.Select(GetPattern).ToArray(); + } + /// /// Converts a string-patterns to AnyOf patterns. /// diff --git a/src/WireMock.Net/IMapping.cs b/src/WireMock.Net/IMapping.cs index 67102998..c0d70b72 100644 --- a/src/WireMock.Net/IMapping.cs +++ b/src/WireMock.Net/IMapping.cs @@ -141,7 +141,7 @@ public interface IMapping /// /// The Grpc ProtoDefinition which is used for this mapping (request and response). [Optional] /// - IdOrText? ProtoDefinition { get; } + IdOrTexts? ProtoDefinition { get; } /// /// ProvideResponseAsync @@ -175,26 +175,7 @@ public interface IMapping /// /// Define a Grpc ProtoDefinition which is used for this mapping (request and response). /// - /// The proto definition as text. + /// The proto definitions as id or text. /// The . - IMapping WithProtoDefinition(IdOrText protoDefinition); -} - -/* - executionConditionState">State in which the current mapping can occur. [Optional] - nextState">The next state which will occur after the current mapping execution. [Optional] - stateTimes">Only when the current state is executed this number, the next state which will occur. [Optional] - webhooks">The Webhooks. [Optional] - useWebhooksFireAndForget">Use Fire and Forget for the defined webhook(s). [Optional] - timeSettings">The TimeSettings. [Optional] - data">The data object. [Optional] - - - string? executionConditionState, - string? nextState, - int? stateTimes, - IWebhook[]? webhooks, - bool? useWebhooksFireAndForget, - ITimeSettings? timeSettings, - object? data, -*/ \ No newline at end of file + IMapping WithProtoDefinition(IdOrTexts protoDefinition); +} \ No newline at end of file diff --git a/src/WireMock.Net/Mapping.cs b/src/WireMock.Net/Mapping.cs index ff97f8b7..fc83ce6a 100644 --- a/src/WireMock.Net/Mapping.cs +++ b/src/WireMock.Net/Mapping.cs @@ -82,7 +82,7 @@ public class Mapping : IMapping public double? Probability { get; private set; } /// - public IdOrText? ProtoDefinition { get; private set; } + public IdOrTexts? ProtoDefinition { get; private set; } /// /// Initializes a new instance of the class. @@ -189,7 +189,7 @@ public class Mapping : IMapping } /// - public IMapping WithProtoDefinition(IdOrText protoDefinition) + public IMapping WithProtoDefinition(IdOrTexts protoDefinition) { ProtoDefinition = protoDefinition; return this; diff --git a/src/WireMock.Net/Matchers/ProtoBufMatcher.cs b/src/WireMock.Net/Matchers/ProtoBufMatcher.cs index ee109d6a..b29dcc8d 100644 --- a/src/WireMock.Net/Matchers/ProtoBufMatcher.cs +++ b/src/WireMock.Net/Matchers/ProtoBufMatcher.cs @@ -2,6 +2,7 @@ #if PROTOBUF using System; +using System.Linq; using System.Threading; using System.Threading.Tasks; using ProtoBufJsonConverter; @@ -25,9 +26,9 @@ public class ProtoBufMatcher : IProtoBufMatcher public MatchBehaviour MatchBehaviour { get; } /// - /// The Func to define The proto definition as text. + /// The Func to define the proto definition as id or texts. /// - public Func ProtoDefinition { get; } + public Func ProtoDefinition { get; } /// /// The full type of the protobuf (request/response) message object. Format is "{package-name}.{type-name}". @@ -44,12 +45,12 @@ public class ProtoBufMatcher : IProtoBufMatcher /// /// Initializes a new instance of the class. /// - /// The proto definition. + /// The proto definition as id or text. /// The full type of the protobuf (request/response) message object. Format is "{package-name}.{type-name}". /// The match behaviour. (default = "AcceptOnMatch") /// The optional jsonMatcher to use to match the ProtoBuf as (json) object. public ProtoBufMatcher( - Func protoDefinition, + Func protoDefinition, string messageType, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch, IObjectMatcher? matcher = null @@ -102,7 +103,11 @@ public class ProtoBufMatcher : IProtoBufMatcher return null; } - var request = new ConvertToObjectRequest(ProtoDefinition().Text, MessageType, input); + var protoDefinitions = ProtoDefinition().Texts; + + var resolver = new WireMockProtoFileResolver(protoDefinitions); + var request = new ConvertToObjectRequest(protoDefinitions[0], MessageType, input) + .WithProtoFileResolver(resolver); try { diff --git a/src/WireMock.Net/Matchers/Request/RequestMessageProtoBufMatcher.cs b/src/WireMock.Net/Matchers/Request/RequestMessageProtoBufMatcher.cs index f9b52fd9..0f5f62ff 100644 --- a/src/WireMock.Net/Matchers/Request/RequestMessageProtoBufMatcher.cs +++ b/src/WireMock.Net/Matchers/Request/RequestMessageProtoBufMatcher.cs @@ -19,10 +19,10 @@ public class RequestMessageProtoBufMatcher : IRequestMatcher /// Initializes a new instance of the class. /// /// The match behaviour. (default = "AcceptOnMatch") - /// The Func to define The proto definition as text. + /// The Func to define the proto definitions as id or text. /// The full type of the protobuf (request/response) message object. Format is "{package-name}.{type-name}". /// The optional matcher to use to match the ProtoBuf as (json) object. - public RequestMessageProtoBufMatcher(MatchBehaviour matchBehaviour, Func protoDefinition, string messageType, IObjectMatcher? matcher = null) + public RequestMessageProtoBufMatcher(MatchBehaviour matchBehaviour, Func protoDefinition, string messageType, IObjectMatcher? matcher = null) { #if PROTOBUF Matcher = new ProtoBufMatcher(protoDefinition, messageType, matchBehaviour, matcher); diff --git a/src/WireMock.Net/Models/BodyData.cs b/src/WireMock.Net/Models/BodyData.cs index 67af9df5..2b214aca 100644 --- a/src/WireMock.Net/Models/BodyData.cs +++ b/src/WireMock.Net/Models/BodyData.cs @@ -52,7 +52,7 @@ public class BodyData : IBodyData #region ProtoBuf /// - public Func? ProtoDefinition { get; set; } + public Func? ProtoDefinition { get; set; } /// public string? ProtoBufMessageType { get; set; } diff --git a/src/WireMock.Net/Owin/Mappers/OwinResponseMapper.cs b/src/WireMock.Net/Owin/Mappers/OwinResponseMapper.cs index 03ee5c25..85700942 100644 --- a/src/WireMock.Net/Owin/Mappers/OwinResponseMapper.cs +++ b/src/WireMock.Net/Owin/Mappers/OwinResponseMapper.cs @@ -151,8 +151,8 @@ namespace WireMock.Owin.Mappers #if PROTOBUF case BodyType.ProtoBuf: - var protoDefinition = bodyData.ProtoDefinition?.Invoke().Text; - return await ProtoBufUtils.GetProtoBufMessageWithHeaderAsync(protoDefinition, bodyData.ProtoBufMessageType, bodyData.BodyAsJson).ConfigureAwait(false); + var protoDefinitions = bodyData.ProtoDefinition?.Invoke().Texts; + return await ProtoBufUtils.GetProtoBufMessageWithHeaderAsync(protoDefinitions, responseMessage.BodyData.ProtoBufMessageType, responseMessage.BodyData.BodyAsJson).ConfigureAwait(false); #endif case BodyType.Bytes: diff --git a/src/WireMock.Net/RequestBuilders/IProtoBufRequestBuilder.cs b/src/WireMock.Net/RequestBuilders/IProtoBufRequestBuilder.cs index daaceada..f5362837 100644 --- a/src/WireMock.Net/RequestBuilders/IProtoBufRequestBuilder.cs +++ b/src/WireMock.Net/RequestBuilders/IProtoBufRequestBuilder.cs @@ -1,5 +1,6 @@ // Copyright © WireMock.Net +using System.Collections.Generic; using WireMock.Matchers; namespace WireMock.RequestBuilders; @@ -10,7 +11,7 @@ namespace WireMock.RequestBuilders; public interface IProtoBufRequestBuilder : IGraphQLRequestBuilder { /// - /// WithGrpcProto + /// WithBodyAsProtoBuf /// /// The proto definition as text. /// The full type of the protobuf (request/response) message object. Format is "{package-name}.{type-name}". @@ -19,7 +20,7 @@ public interface IProtoBufRequestBuilder : IGraphQLRequestBuilder IRequestBuilder WithBodyAsProtoBuf(string protoDefinition, string messageType, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch); /// - /// WithGrpcProto + /// WithBodyAsProtoBuf /// /// The proto definition as text. /// The full type of the protobuf (request/response) message object. Format is "{package-name}.{type-name}". @@ -29,7 +30,26 @@ public interface IProtoBufRequestBuilder : IGraphQLRequestBuilder IRequestBuilder WithBodyAsProtoBuf(string protoDefinition, string messageType, IObjectMatcher matcher, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch); /// - /// WithGrpcProto + /// WithBodyAsProtoBuf + /// + /// The proto definitions as text. + /// The full type of the protobuf (request/response) message object. Format is "{package-name}.{type-name}". + /// The match behaviour. (default = "AcceptOnMatch") + /// The . + IRequestBuilder WithBodyAsProtoBuf(IReadOnlyList protoDefinitions, string messageType, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch); + + /// + /// WithBodyAsProtoBuf + /// + /// The proto definitions as text. + /// The full type of the protobuf (request/response) message object. Format is "{package-name}.{type-name}". + /// The matcher to use to match the ProtoBuf as (json) object. + /// The match behaviour. (default = "AcceptOnMatch") + /// The . + IRequestBuilder WithBodyAsProtoBuf(IReadOnlyList protoDefinitions, string messageType, IObjectMatcher matcher, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch); + + /// + /// WithBodyAsProtoBuf /// /// The full type of the protobuf (request/response) message object. Format is "{package-name}.{type-name}". /// The match behaviour. (default = "AcceptOnMatch") @@ -37,7 +57,7 @@ public interface IProtoBufRequestBuilder : IGraphQLRequestBuilder IRequestBuilder WithBodyAsProtoBuf(string messageType, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch); /// - /// WithGrpcProto + /// WithBodyAsProtoBuf /// /// The full type of the protobuf (request/response) message object. Format is "{package-name}.{type-name}". /// The matcher to use to match the ProtoBuf as (json) object. diff --git a/src/WireMock.Net/RequestBuilders/Request.WithBodyAsProtoBuf.cs b/src/WireMock.Net/RequestBuilders/Request.WithBodyAsProtoBuf.cs index 2f493568..61259644 100644 --- a/src/WireMock.Net/RequestBuilders/Request.WithBodyAsProtoBuf.cs +++ b/src/WireMock.Net/RequestBuilders/Request.WithBodyAsProtoBuf.cs @@ -1,7 +1,10 @@ // Copyright © WireMock.Net +using System.Collections.Generic; +using System.Linq; using WireMock.Matchers; using WireMock.Matchers.Request; +using WireMock.Models; namespace WireMock.RequestBuilders; @@ -10,13 +13,25 @@ public partial class Request /// public IRequestBuilder WithBodyAsProtoBuf(string protoDefinition, string messageType, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch) { - return Add(new RequestMessageProtoBufMatcher(matchBehaviour, () => new (null, protoDefinition), messageType)); + return WithBodyAsProtoBuf([ protoDefinition ], messageType, matchBehaviour); } /// public IRequestBuilder WithBodyAsProtoBuf(string protoDefinition, string messageType, IObjectMatcher matcher, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch) { - return Add(new RequestMessageProtoBufMatcher(matchBehaviour, () => new(null, protoDefinition), messageType, matcher)); + return WithBodyAsProtoBuf([protoDefinition], messageType, matcher, matchBehaviour); + } + + /// + public IRequestBuilder WithBodyAsProtoBuf(IReadOnlyList protoDefinitions, string messageType, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch) + { + return Add(new RequestMessageProtoBufMatcher(matchBehaviour, () => new IdOrTexts(null, protoDefinitions), messageType)); + } + + /// + public IRequestBuilder WithBodyAsProtoBuf(IReadOnlyList protoDefinitions, string messageType, IObjectMatcher matcher, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch) + { + return Add(new RequestMessageProtoBufMatcher(matchBehaviour, () => new IdOrTexts(null, protoDefinitions), messageType, matcher)); } /// diff --git a/src/WireMock.Net/ResponseBuilders/IBodyResponseBuilder.cs b/src/WireMock.Net/ResponseBuilders/IBodyResponseBuilder.cs index e1ff7e50..df9259c4 100644 --- a/src/WireMock.Net/ResponseBuilders/IBodyResponseBuilder.cs +++ b/src/WireMock.Net/ResponseBuilders/IBodyResponseBuilder.cs @@ -1,6 +1,7 @@ // Copyright © WireMock.Net using System; +using System.Collections.Generic; using System.Text; using System.Threading.Tasks; using JsonConverter.Abstractions; @@ -109,7 +110,7 @@ public interface IBodyResponseBuilder : IFaultResponseBuilder IResponseBuilder WithBody(object body, Encoding? encoding, IJsonConverter jsonConverter, JsonConverterOptions? options = null); /// - /// WithBody : Create a ProtoBuf byte[] response based on a proto definition, message type and the value. + /// WithBodyAsProtoBuf : Create a ProtoBuf byte[] response based on a proto definition, message type and the value. /// /// The proto definition as text. /// The full type of the protobuf (request/response) message object. Format is "{package-name}.{type-name}". @@ -126,7 +127,24 @@ public interface IBodyResponseBuilder : IFaultResponseBuilder ); /// - /// WithBody : Create a ProtoBuf byte[] response based on a proto definition, message type and the value. + /// WithBodyAsProtoBuf : Create a ProtoBuf byte[] response based on proto definitions, message type and the value. + /// + /// The proto definition as text. + /// The full type of the protobuf (request/response) message object. Format is "{package-name}.{type-name}". + /// The object to convert to protobuf byte[]. + /// The [optional]. Default value is NewtonsoftJsonConverter. + /// The [optional]. + /// A . + IResponseBuilder WithBodyAsProtoBuf( + IReadOnlyList protoDefinitions, + string messageType, + object value, + IJsonConverter? jsonConverter = null, + JsonConverterOptions? options = null + ); + + /// + /// WithBodyAsProtoBuf : Create a ProtoBuf byte[] response based on a proto definition, message type and the value. /// /// The full type of the protobuf (request/response) message object. Format is "{package-name}.{type-name}". /// The object to convert to protobuf byte[]. diff --git a/src/WireMock.Net/ResponseBuilders/Response.WithBody.cs b/src/WireMock.Net/ResponseBuilders/Response.WithBody.cs index 14956902..7faedb1e 100644 --- a/src/WireMock.Net/ResponseBuilders/Response.WithBody.cs +++ b/src/WireMock.Net/ResponseBuilders/Response.WithBody.cs @@ -1,11 +1,13 @@ // Copyright © WireMock.Net using System; +using System.Collections.Generic; using System.Text; using System.Threading.Tasks; using JsonConverter.Abstractions; using Stef.Validation; using WireMock.Exceptions; +using WireMock.Models; using WireMock.Types; using WireMock.Util; @@ -223,7 +225,19 @@ public partial class Response JsonConverterOptions? options = null ) { - Guard.NotNullOrWhiteSpace(protoDefinition); + return WithBodyAsProtoBuf([protoDefinition], messageType, value, jsonConverter, options); + } + + /// + public IResponseBuilder WithBodyAsProtoBuf( + IReadOnlyList protoDefinitions, + string messageType, + object value, + IJsonConverter? jsonConverter = null, + JsonConverterOptions? options = null + ) + { + Guard.NotNullOrEmpty(protoDefinitions); Guard.NotNullOrWhiteSpace(messageType); Guard.NotNull(value); @@ -235,7 +249,7 @@ public partial class Response { DetectedBodyType = BodyType.ProtoBuf, BodyAsJson = value, - ProtoDefinition = () => new (null, protoDefinition), + ProtoDefinition = () => new IdOrTexts(null, protoDefinitions), ProtoBufMessageType = messageType }; #endif diff --git a/src/WireMock.Net/Serialization/MappingConverter.cs b/src/WireMock.Net/Serialization/MappingConverter.cs index 5f1eed82..260fba53 100644 --- a/src/WireMock.Net/Serialization/MappingConverter.cs +++ b/src/WireMock.Net/Serialization/MappingConverter.cs @@ -273,7 +273,6 @@ internal class MappingConverter(MatcherMapper mapper) WhenStateIs = mapping.ExecutionConditionState, SetStateTo = mapping.NextState, Data = mapping.Data, - ProtoDefinition = mapping.ProtoDefinition?.Value, Probability = mapping.Probability, Request = new RequestModel { @@ -304,6 +303,20 @@ internal class MappingConverter(MatcherMapper mapper) Response = new ResponseModel() }; + mapping.ProtoDefinition?.Value( + id => mappingModel.ProtoDefinition = id, + texts => + { + if (texts.Count == 1) + { + mappingModel.ProtoDefinition = texts[0]; + } + else + { + mappingModel.ProtoDefinitions = texts.ToArray(); + } + }); + if (methodMatcher != null) { mappingModel.Request.Methods = methodMatcher.Methods; @@ -491,10 +504,22 @@ internal class MappingConverter(MatcherMapper mapper) break; case BodyType.ProtoBuf: - // If the ProtoDefinition is not defined at the MappingModel, get the ProtoDefinition from the ResponseMessage. - if (mappingModel.ProtoDefinition == null) + // If the ProtoDefinition(s) is/are not defined at the MappingModel, get the ProtoDefinition(s) from the ResponseMessage. + if (mappingModel.ProtoDefinition == null && mappingModel.ProtoDefinitions == null) { - mappingModel.Response.ProtoDefinition = response.ResponseMessage.BodyData.ProtoDefinition?.Invoke().Value; + response.ResponseMessage.BodyData.ProtoDefinition?.Invoke().Value( + id => mappingModel.Response.ProtoDefinition = id, + texts => + { + if (texts.Count == 1) + { + mappingModel.Response.ProtoDefinition = texts[0]; + } + else + { + mappingModel.Response.ProtoDefinitions = texts.ToArray(); + } + }); } mappingModel.Response.ProtoBufMessageType = response.ResponseMessage.BodyData.ProtoBufMessageType; diff --git a/src/WireMock.Net/Serialization/MatcherMapper.cs b/src/WireMock.Net/Serialization/MatcherMapper.cs index b4e66194..8cadbb62 100644 --- a/src/WireMock.Net/Serialization/MatcherMapper.cs +++ b/src/WireMock.Net/Serialization/MatcherMapper.cs @@ -79,7 +79,7 @@ internal class MatcherMapper #if PROTOBUF case nameof(ProtoBufMatcher): - return CreateProtoBufMatcher(matchBehaviour, stringPatterns[0].GetPattern(), matcherModel); + return CreateProtoBufMatcher(matchBehaviour, stringPatterns.GetPatterns(), matcherModel); #endif case nameof(RegexMatcher): return new RegexMatcher(matchBehaviour, stringPatterns, ignoreCase, useRegexExtended, matchOperator); @@ -211,7 +211,18 @@ internal class MatcherMapper #if PROTOBUF case ProtoBufMatcher protoBufMatcher: - model.Pattern = protoBufMatcher.ProtoDefinition().Value; + protoBufMatcher.ProtoDefinition().Value(id => model.Pattern = id, texts => + { + if (texts.Count == 1) + { + model.Pattern = texts[0]; + } + else + { + model.Patterns = texts.Cast().ToArray(); + } + }); + model.ProtoBufMessageType = protoBufMatcher.MessageType; model.ContentMatcher = Map(protoBufMatcher.Matcher); break; @@ -278,22 +289,30 @@ internal class MatcherMapper #endif #if PROTOBUF - private ProtoBufMatcher CreateProtoBufMatcher(MatchBehaviour? matchBehaviour, string protoDefinitionOrId, MatcherModel matcher) + private ProtoBufMatcher CreateProtoBufMatcher(MatchBehaviour? matchBehaviour, IReadOnlyList protoDefinitions, MatcherModel matcher) { var objectMatcher = Map(matcher.ContentMatcher) as IObjectMatcher; - IdOrText protoDefinition; - if (_settings.ProtoDefinitions?.TryGetValue(protoDefinitionOrId, out var protoDefinitionFromSettings) == true) + IdOrTexts protoDefinitionAsIdOrTexts; + if (protoDefinitions.Count == 1) { - protoDefinition = new(protoDefinitionOrId, protoDefinitionFromSettings); + var idOrText = protoDefinitions[0]; + if (_settings.ProtoDefinitions?.TryGetValue(idOrText, out var protoDefinitionFromSettings) == true) + { + protoDefinitionAsIdOrTexts = new(idOrText, protoDefinitionFromSettings); + } + else + { + protoDefinitionAsIdOrTexts = new(null, protoDefinitions); + } } else { - protoDefinition = new(null, protoDefinitionOrId); + protoDefinitionAsIdOrTexts = new(null, protoDefinitions); } return new ProtoBufMatcher( - () => protoDefinition, + () => protoDefinitionAsIdOrTexts, matcher!.ProtoBufMessageType!, matchBehaviour ?? MatchBehaviour.AcceptOnMatch, objectMatcher diff --git a/src/WireMock.Net/Server/IRespondWithAProvider.cs b/src/WireMock.Net/Server/IRespondWithAProvider.cs index c0067a3d..963e3e10 100644 --- a/src/WireMock.Net/Server/IRespondWithAProvider.cs +++ b/src/WireMock.Net/Server/IRespondWithAProvider.cs @@ -242,7 +242,7 @@ public interface IRespondWithAProvider /// /// The proto definition as text or as id. /// The . - IRespondWithAProvider WithProtoDefinition(string protoDefinitionOrId); + IRespondWithAProvider WithProtoDefinition(params string[] protoDefinitionOrId); /// /// Define a GraphQL Schema which is used for the request and the response. diff --git a/src/WireMock.Net/Server/RespondWithAProvider.cs b/src/WireMock.Net/Server/RespondWithAProvider.cs index 8d82057d..0ea2332d 100644 --- a/src/WireMock.Net/Server/RespondWithAProvider.cs +++ b/src/WireMock.Net/Server/RespondWithAProvider.cs @@ -37,7 +37,7 @@ internal class RespondWithAProvider : IRespondWithAProvider private int _timesInSameState = 1; private bool? _useWebhookFireAndForget; private double? _probability; - private IdOrText? _protoDefinition; + private IdOrTexts? _protoDefinition; private GraphQLSchemaDetails? _graphQLSchemaDetails; public Guid Guid { get; private set; } @@ -351,18 +351,27 @@ internal class RespondWithAProvider : IRespondWithAProvider } /// - public IRespondWithAProvider WithProtoDefinition(string protoDefinitionOrId) + public IRespondWithAProvider WithProtoDefinition(params string[] protoDefinitionOrId) { - Guard.NotNullOrWhiteSpace(protoDefinitionOrId); + Guard.NotNull(protoDefinitionOrId); - if (_settings.ProtoDefinitions?.TryGetValue(protoDefinitionOrId, out var protoDefinition) == true) + if (protoDefinitionOrId.Length == 1) { - _protoDefinition = new (protoDefinitionOrId, protoDefinition); + var idOrText = protoDefinitionOrId[0]; + if (_settings.ProtoDefinitions?.TryGetValue(idOrText, out var protoDefinitions) == true) + { + _protoDefinition = new(idOrText, protoDefinitions); + } + else + { + _protoDefinition = new(null, protoDefinitionOrId); + } } else { _protoDefinition = new(null, protoDefinitionOrId); } + return this; } diff --git a/src/WireMock.Net/Server/WireMockServer.cs b/src/WireMock.Net/Server/WireMockServer.cs index 3079c52b..4eedf455 100644 --- a/src/WireMock.Net/Server/WireMockServer.cs +++ b/src/WireMock.Net/Server/WireMockServer.cs @@ -595,12 +595,12 @@ public partial class WireMockServer : IWireMockServer /// The ProtoDefinition as text. /// [PublicAPI] - public WireMockServer AddProtoDefinition(string id, string protoDefinition) + public WireMockServer AddProtoDefinition(string id, params string[] protoDefinition) { Guard.NotNullOrWhiteSpace(id); - Guard.NotNullOrWhiteSpace(protoDefinition); + Guard.NotNullOrEmpty(protoDefinition); - _settings.ProtoDefinitions ??= new Dictionary(); + _settings.ProtoDefinitions ??= new Dictionary(); _settings.ProtoDefinitions[id] = protoDefinition; diff --git a/src/WireMock.Net/Settings/WireMockServerSettings.cs b/src/WireMock.Net/Settings/WireMockServerSettings.cs index 1a788422..bf8479b6 100644 --- a/src/WireMock.Net/Settings/WireMockServerSettings.cs +++ b/src/WireMock.Net/Settings/WireMockServerSettings.cs @@ -298,7 +298,7 @@ public class WireMockServerSettings public IDictionary>? CustomMatcherMappings { get; set; } /// - /// The used when the a JSON response is generated. + /// The used when the JSON response is generated. /// [PublicAPI, JsonIgnore] public JsonSerializerSettings? JsonSerializerSettings { get; set; } @@ -315,7 +315,7 @@ public class WireMockServerSettings /// A list of Grpc ProtoDefinitions which can be used. /// [PublicAPI] - public Dictionary? ProtoDefinitions { get; set; } + public Dictionary? ProtoDefinitions { get; set; } /// /// A list of GraphQL Schemas which can be used. diff --git a/src/WireMock.Net/Settings/WireMockServerSettingsParser.cs b/src/WireMock.Net/Settings/WireMockServerSettingsParser.cs index f5887947..03d44262 100644 --- a/src/WireMock.Net/Settings/WireMockServerSettingsParser.cs +++ b/src/WireMock.Net/Settings/WireMockServerSettingsParser.cs @@ -61,7 +61,7 @@ public static class WireMockServerSettingsParser HandleRequestsSynchronously = parser.GetBoolValue(nameof(WireMockServerSettings.HandleRequestsSynchronously)), HostingScheme = parser.GetEnumValue(nameof(WireMockServerSettings.HostingScheme)), MaxRequestLogCount = parser.GetIntValue(nameof(WireMockServerSettings.MaxRequestLogCount)), - ProtoDefinitions = parser.GetObjectValueFromJson>(nameof(settings.ProtoDefinitions)), + ProtoDefinitions = parser.GetObjectValueFromJson>(nameof(settings.ProtoDefinitions)), QueryParameterMultipleValueSupport = parser.GetEnumValue(nameof(WireMockServerSettings.QueryParameterMultipleValueSupport)), ReadStaticMappings = parser.GetBoolValue(nameof(WireMockServerSettings.ReadStaticMappings)), RequestLogExpirationDuration = parser.GetIntValue(nameof(WireMockServerSettings.RequestLogExpirationDuration)), diff --git a/src/WireMock.Net/Util/ProtoBufUtils.cs b/src/WireMock.Net/Util/ProtoBufUtils.cs index fe6bdded..4fc8393b 100644 --- a/src/WireMock.Net/Util/ProtoBufUtils.cs +++ b/src/WireMock.Net/Util/ProtoBufUtils.cs @@ -1,7 +1,7 @@ // Copyright © WireMock.Net #if PROTOBUF -using System; +using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using JsonConverter.Abstractions; @@ -13,31 +13,25 @@ namespace WireMock.Util; internal static class ProtoBufUtils { internal static async Task GetProtoBufMessageWithHeaderAsync( - string? protoDefinition, + IReadOnlyList? protoDefinitions, string? messageType, object? value, IJsonConverter? jsonConverter = null, - JsonConverterOptions? options = null, CancellationToken cancellationToken = default ) { - if (string.IsNullOrWhiteSpace(protoDefinition) || string.IsNullOrWhiteSpace(messageType) || value is null) + if (protoDefinitions == null || string.IsNullOrWhiteSpace(messageType) || value is null) { - return Array.Empty(); + return []; } - var request = new ConvertToProtoBufRequest(protoDefinition, messageType, value, true); + var resolver = new WireMockProtoFileResolver(protoDefinitions); + var request = new ConvertToProtoBufRequest(protoDefinitions[0], messageType, value, true) + .WithProtoFileResolver(resolver); - if (jsonConverter != null) - { - request = request.WithJsonConverter(jsonConverter); - if (options != null) - { - request = request.WithJsonConverterOptions(options); - } - } - - return await SingletonFactory.GetInstance().ConvertAsync(request, cancellationToken).ConfigureAwait(false); + return await SingletonFactory + .GetInstance() + .ConvertAsync(request, cancellationToken).ConfigureAwait(false); } } #endif \ No newline at end of file diff --git a/src/WireMock.Net/Util/WireMockProtoFileResolver.cs b/src/WireMock.Net/Util/WireMockProtoFileResolver.cs new file mode 100644 index 00000000..86250a1d --- /dev/null +++ b/src/WireMock.Net/Util/WireMockProtoFileResolver.cs @@ -0,0 +1,46 @@ +// Copyright © WireMock.Net + +#if PROTOBUF +using System.Collections.Generic; +using System.IO; +using System.Linq; +using ProtoBufJsonConverter; +using Stef.Validation; + +namespace WireMock.Util; + +internal class WireMockProtoFileResolver : IProtoFileResolver +{ + private readonly Dictionary _files = new(); + + public WireMockProtoFileResolver(IReadOnlyCollection protoDefinitions) + { + if (Guard.NotNullOrEmpty(protoDefinitions).Count() > 1) + { + foreach (var extraProtoDefinition in protoDefinitions.Skip(1)) + { + var firstNonEmptyLine = extraProtoDefinition.Split(['\r', '\n']).FirstOrDefault(l => !string.IsNullOrEmpty(l)); + if (firstNonEmptyLine != null) + { + _files.Add(firstNonEmptyLine.TrimStart(['\r', '\n', '/', ' ']), extraProtoDefinition); + } + } + } + } + + public bool Exists(string path) + { + return _files.ContainsKey(path); + } + + public TextReader OpenText(string path) + { + if (_files.TryGetValue(path, out var extraProtoDefinition)) + { + return new StringReader(extraProtoDefinition); + } + + throw new FileNotFoundException($"The ProtoDefinition '{path}' was not found."); + } +} +#endif \ No newline at end of file diff --git a/src/WireMock.Net/WireMock.Net.csproj b/src/WireMock.Net/WireMock.Net.csproj index 89753148..9f305c01 100644 --- a/src/WireMock.Net/WireMock.Net.csproj +++ b/src/WireMock.Net/WireMock.Net.csproj @@ -150,7 +150,7 @@ - + diff --git a/test/WireMock.Net.Tests/Grpc/WireMockServerTests.Grpc.cs b/test/WireMock.Net.Tests/Grpc/WireMockServerTests.Grpc.cs index b76200ee..6072a3f7 100644 --- a/test/WireMock.Net.Tests/Grpc/WireMockServerTests.Grpc.cs +++ b/test/WireMock.Net.Tests/Grpc/WireMockServerTests.Grpc.cs @@ -35,6 +35,69 @@ message HelloRequest { message HelloReply { string message = 1; } +"; + + private const string ProtoDefinitionWithWellKnownTypes = @" +syntax = ""proto3""; + +package communication.api.v1; + +import ""google/protobuf/empty.proto""; +import ""google/protobuf/timestamp.proto""; +import ""google/protobuf/duration.proto""; + +service Greeter { + rpc SayNothing (google.protobuf.Empty) returns (google.protobuf.Empty); +} + +message MyMessageTimestamp { + google.protobuf.Timestamp ts = 1; +} + +message MyMessageDuration { + google.protobuf.Duration du = 1; +} +"; + + private const string ProtoDefinitionMain = @" +syntax = ""proto3""; + +package greet; + +import ""other.proto""; +import ""google/protobuf/empty.proto""; + +service Greeter { + rpc Nothing (google.protobuf.Empty) returns (google.protobuf.Empty); + + rpc SayHello (HelloRequest) returns (HelloReply); + + rpc SayOther (Other) returns (HelloReply); +} + +message HelloRequest { + string name = 1; +} + +message HelloReply { + string message = 1; +} + +message Person { + string name = 1; + int32 id = 2; + string email = 3; +} +"; + + private const string ProtoDefinitionOther = @"// other.proto +syntax = ""proto3""; + +package greet; + +message Other { + string name = 1; +} "; [Theory] @@ -80,6 +143,129 @@ message HelloReply { server.Stop(); } + [Fact] + public async Task WireMockServer_WithBodyAsProtoBuf_WithWellKnownTypes() + { + // Arrange + var bytes = Convert.FromBase64String("CgRzdGVm"); + + using var server = WireMockServer.Start(); + + server + .Given(Request.Create() + .UsingPost() + .WithPath("/grpc/Greeter/SayNothing") + .WithBody(new NotNullOrEmptyMatcher()) + ) + .RespondWith(Response.Create() + .WithBodyAsProtoBuf(ProtoDefinitionWithWellKnownTypes, "google.protobuf.Empty", + new { } + ) + .WithTrailingHeader("grpc-status", "0") + .WithTransformer() + ); + + // Act + var protoBuf = new ByteArrayContent(bytes); + protoBuf.Headers.ContentType = new MediaTypeHeaderValue("application/grpc-web"); + + var client = server.CreateClient(); + var response = await client.PostAsync("/grpc/Greeter/SayNothing", protoBuf); + + // Assert + response.StatusCode.Should().Be(HttpStatusCode.OK); + var responseBytes = await response.Content.ReadAsByteArrayAsync(); + + Convert.ToBase64String(responseBytes).Should().Be(""); + + server.Stop(); + } + + [Fact] + public async Task WireMockServer_WithBodyAsProtoBuf_ServerProtoDefinition_WithWellKnownTypes() + { + // Arrange + var bytes = Convert.FromBase64String("CgRzdGVm"); + + using var server = WireMockServer.Start(); + + var id = $"proto-{Guid.NewGuid()}"; + + server + .AddProtoDefinition(id, ProtoDefinitionWithWellKnownTypes) + .Given(Request.Create() + .UsingPost() + .WithPath("/grpc/Greeter/SayNothing") + .WithBody(new NotNullOrEmptyMatcher()) + ) + .WithProtoDefinition(id) + .RespondWith(Response.Create() + .WithBodyAsProtoBuf("google.protobuf.Empty", + new { } + ) + .WithTrailingHeader("grpc-status", "0") + .WithTransformer() + ); + + // Act + var protoBuf = new ByteArrayContent(bytes); + protoBuf.Headers.ContentType = new MediaTypeHeaderValue("application/grpc-web"); + + var client = server.CreateClient(); + var response = await client.PostAsync("/grpc/Greeter/SayNothing", protoBuf); + + // Assert + response.StatusCode.Should().Be(HttpStatusCode.OK); + var responseBytes = await response.Content.ReadAsByteArrayAsync(); + + Convert.ToBase64String(responseBytes).Should().Be(""); + + server.Stop(); + } + + [Fact] + public async Task WireMockServer_WithBodyAsProtoBuf_MultipleFiles() + { + // Arrange + var bytes = Convert.FromBase64String("CgRzdGVm"); + var jsonMatcher = new JsonMatcher(new { name = "stef" }); + + using var server = WireMockServer.Start(); + + var protoFiles = new [] { ProtoDefinitionMain, ProtoDefinitionOther }; + + server + .Given(Request.Create() + .UsingPost() + .WithPath("/grpc/greet.Greeter/SayOther") + .WithBodyAsProtoBuf(protoFiles, "greet.Other", jsonMatcher) + ) + .RespondWith(Response.Create() + .WithBodyAsProtoBuf(protoFiles, "greet.HelloReply", + new + { + message = "hello" + } + ) + .WithTrailingHeader("grpc-status", "0") + ); + + // Act + var protoBuf = new ByteArrayContent(bytes); + protoBuf.Headers.ContentType = new MediaTypeHeaderValue("application/grpc-web"); + + var client = server.CreateClient(); + var response = await client.PostAsync("/grpc/greet.Greeter/SayOther", protoBuf); + + // Assert + response.StatusCode.Should().Be(HttpStatusCode.OK); + var responseBytes = await response.Content.ReadAsByteArrayAsync(); + + Convert.ToBase64String(responseBytes).Should().Be("AAAAAAcKBWhlbGxv"); + + server.Stop(); + } + [Fact] public async Task WireMockServer_WithBodyAsProtoBuf_InlineProtoDefinition_UsingGrpcGeneratedClient() { diff --git a/test/WireMock.Net.Tests/Matchers/ProtoBufMatcherTests.cs b/test/WireMock.Net.Tests/Matchers/ProtoBufMatcherTests.cs index 975a9d4b..7a8930fb 100644 --- a/test/WireMock.Net.Tests/Matchers/ProtoBufMatcherTests.cs +++ b/test/WireMock.Net.Tests/Matchers/ProtoBufMatcherTests.cs @@ -14,7 +14,8 @@ namespace WireMock.Net.Tests.Matchers; public class ProtoBufMatcherTests { private const string MessageType = "greet.HelloRequest"; - private readonly IdOrText _protoDefinition = new(null, @" + + private static IdOrTexts ProtoDefinition => new(null, @" syntax = ""proto3""; package greet; @@ -30,7 +31,7 @@ message HelloRequest { message HelloReply { string message = 1; } -"); +" + "\r\n// Dummy " + Guid.NewGuid()); [Fact] public async Task ProtoBufMatcher_For_ValidProtoBuf_And_ValidMethod_DecodeAsync() @@ -39,7 +40,7 @@ message HelloReply { var bytes = Convert.FromBase64String("CgRzdGVm"); // Act - var matcher = new ProtoBufMatcher(() => _protoDefinition, MessageType); + var matcher = new ProtoBufMatcher(() => ProtoDefinition, MessageType); var result = await matcher.DecodeAsync(bytes).ConfigureAwait(false); // Assert @@ -53,7 +54,7 @@ message HelloReply { var bytes = Convert.FromBase64String("CgRzdGVm"); // Act - var matcher = new ProtoBufMatcher(() => _protoDefinition, MessageType); + var matcher = new ProtoBufMatcher(() => ProtoDefinition, MessageType); var result = await matcher.IsMatchAsync(bytes).ConfigureAwait(false); // Assert @@ -69,7 +70,7 @@ message HelloReply { var bytes = Convert.FromBase64String("CgRzdGVm"); // Act - var matcher = new ProtoBufMatcher(() => _protoDefinition, MessageType, matcher: jsonMatcher); + var matcher = new ProtoBufMatcher(() => ProtoDefinition, MessageType, matcher: jsonMatcher); var result = await matcher.IsMatchAsync(bytes); // Assert @@ -84,7 +85,7 @@ message HelloReply { var bytes = new byte[] { 1, 2, 3 }; // Act - var matcher = new ProtoBufMatcher(() => _protoDefinition, MessageType); + var matcher = new ProtoBufMatcher(() => ProtoDefinition, MessageType); var result = await matcher.IsMatchAsync(bytes); // Assert @@ -99,7 +100,7 @@ message HelloReply { var bytes = Convert.FromBase64String("CgRzdGVm"); // Act - var matcher = new ProtoBufMatcher(() => _protoDefinition, "greet.Greeter.X"); + var matcher = new ProtoBufMatcher(() => ProtoDefinition, "greet.Greeter.X"); var result = await matcher.IsMatchAsync(bytes); // Assert diff --git a/test/WireMock.Net.Tests/RequestBuilders/RequestBuilderWithProtoBufTests.cs b/test/WireMock.Net.Tests/RequestBuilders/RequestBuilderWithProtoBufTests.cs index b547ae2a..789807b4 100644 --- a/test/WireMock.Net.Tests/RequestBuilders/RequestBuilderWithProtoBufTests.cs +++ b/test/WireMock.Net.Tests/RequestBuilders/RequestBuilderWithProtoBufTests.cs @@ -42,7 +42,7 @@ message HelloReply { matchers.Should().HaveCount(1); var protoBufMatcher = (ProtoBufMatcher)((RequestMessageProtoBufMatcher)matchers[0]).Matcher!; - protoBufMatcher.ProtoDefinition().Text.Should().Be(TestProtoDefinition); + protoBufMatcher.ProtoDefinition().Texts.Should().Contain(TestProtoDefinition); protoBufMatcher.MessageType.Should().Be(MessageType); protoBufMatcher.Matcher.Should().BeNull(); } @@ -59,7 +59,7 @@ message HelloReply { matchers.Should().HaveCount(1); var protoBufMatcher = (ProtoBufMatcher)((RequestMessageProtoBufMatcher)matchers[0]).Matcher!; - protoBufMatcher.ProtoDefinition().Text.Should().Be(TestProtoDefinition); + protoBufMatcher.ProtoDefinition().Texts.Should().Contain(TestProtoDefinition); protoBufMatcher.MessageType.Should().Be(MessageType); protoBufMatcher.Matcher.Should().BeOfType(); } diff --git a/test/WireMock.Net.Tests/Serialization/MappingConverterTests.ToMappingModel_WithTimeSettings_ReturnsCorrectTimeSettings.verified.txt b/test/WireMock.Net.Tests/Serialization/MappingConverterTests.ToMappingModel_WithTimeSettings_ReturnsCorrectTimeSettings.verified.txt index 98e43889..21b33e3e 100644 --- a/test/WireMock.Net.Tests/Serialization/MappingConverterTests.ToMappingModel_WithTimeSettings_ReturnsCorrectTimeSettings.verified.txt +++ b/test/WireMock.Net.Tests/Serialization/MappingConverterTests.ToMappingModel_WithTimeSettings_ReturnsCorrectTimeSettings.verified.txt @@ -2,8 +2,8 @@ Guid: Guid_1, UpdatedAt: 2022-12-04 11:12:13, TimeSettings: { - Start: 2023-01-14 15:16:17, - End: 2023-01-14 15:17:57, + Start: 2023-01-14 15:16:17 Utc, + End: 2023-01-14 15:17:57 Utc, TTL: 100 }, Title: , diff --git a/test/WireMock.Net.Tests/Serialization/MappingConverterTests.cs b/test/WireMock.Net.Tests/Serialization/MappingConverterTests.cs index d8cffa3a..7b0f5855 100644 --- a/test/WireMock.Net.Tests/Serialization/MappingConverterTests.cs +++ b/test/WireMock.Net.Tests/Serialization/MappingConverterTests.cs @@ -226,7 +226,7 @@ message HelloReply { public Task ToMappingModel_WithTimeSettings_ReturnsCorrectTimeSettings() { // Assign - var start = new DateTime(2023, 1, 14, 15, 16, 17); + var start = new DateTime(2023, 1, 14, 15, 16, 17, DateTimeKind.Utc); var ttl = 100; var end = start.AddSeconds(ttl); var request = Request.Create(); diff --git a/test/WireMock.Net.Tests/Serialization/MatcherMapperTests.cs b/test/WireMock.Net.Tests/Serialization/MatcherMapperTests.cs index 0d361523..da31548a 100644 --- a/test/WireMock.Net.Tests/Serialization/MatcherMapperTests.cs +++ b/test/WireMock.Net.Tests/Serialization/MatcherMapperTests.cs @@ -102,7 +102,7 @@ public class MatcherMapperTests // Assign var matcherMock = new Mock(); matcherMock.Setup(m => m.Name).Returns("test"); - matcherMock.Setup(m => m.GetPatterns()).Returns(new AnyOf[] { "p1", "p2" }); + matcherMock.Setup(m => m.GetPatterns()).Returns(["p1", "p2"]); // Act var model = _sut.Map(matcherMock.Object)!; @@ -206,7 +206,7 @@ public class MatcherMapperTests public void MatcherMapper_Map_Matcher_ProtoBufMatcher() { // Arrange - IdOrText protoDefinition = new(null, @" + IdOrTexts protoDefinition = new(null, @" syntax = ""proto3""; package greet; @@ -235,7 +235,7 @@ message HelloReply { // Assert model.Name.Should().Be(nameof(ProtoBufMatcher)); - model.Pattern.Should().Be(protoDefinition.Text); + model.Pattern.Should().Be(protoDefinition.Texts[0]); model.ProtoBufMessageType.Should().Be(messageType); model.ContentMatcher?.Name.Should().Be("JsonMatcher"); model.ContentMatcher?.Pattern.Should().Be(jsonPattern); @@ -246,7 +246,7 @@ message HelloReply { { // Arrange string id = "abc123"; - IdOrText protoDefinition = new(id, @" + IdOrTexts protoDefinition = new(id, @" syntax = ""proto3""; package greet; @@ -327,7 +327,7 @@ message HelloReply { var model = new MatcherModel { Name = "LinqMatcher", - Patterns = new[] { "p1", "p2" } + Patterns = ["p1", "p2"] }; // Act @@ -362,7 +362,7 @@ message HelloReply { { // Assign var pattern = "{ \"post1\": \"value1\", \"post2\": \"value2\" }"; - var patterns = new[] { pattern }; + object[] patterns = [pattern]; var model = new MatcherModel { Name = "JsonMatcher", @@ -383,7 +383,7 @@ message HelloReply { // Assign var pattern1 = "{ \"AccountIds\": [ 1, 2, 3 ] }"; var pattern2 = "{ \"post1\": \"value1\", \"post2\": \"value2\" }"; - var patterns = new[] { pattern1, pattern2 }; + object[] patterns = [pattern1, pattern2]; var model = new MatcherModel { Name = "JsonMatcher", @@ -690,7 +690,7 @@ message HelloReply { var model = new MatcherModel { Name = "CSharpCodeMatcher", - Patterns = new[] { "return it == \"x\";" } + Patterns = ["return it == \"x\";"] }; var sut = new MatcherMapper(new WireMockServerSettings { AllowCSharpCodeMatcher = true }); @@ -716,7 +716,7 @@ message HelloReply { var model = new MatcherModel { Name = "CSharpCodeMatcher", - Patterns = new[] { "x" } + Patterns = ["x"] }; var sut = new MatcherMapper(new WireMockServerSettings { AllowCSharpCodeMatcher = false }); @@ -734,7 +734,7 @@ message HelloReply { var model = new MatcherModel { Name = "ExactMatcher", - Patterns = new[] { "x" } + Patterns = ["x"] }; // Act @@ -751,7 +751,7 @@ message HelloReply { var model = new MatcherModel { Name = "ExactMatcher", - Patterns = new[] { "x", "y" } + Patterns = ["x", "y"] }; // Act @@ -819,7 +819,7 @@ message HelloReply { var matcher = (ExactObjectMatcher)_sut.Map(model)!; // Assert - Check.That((byte[])matcher.Value).ContainsExactly(new byte[] { 115, 116, 101, 102 }); + Check.That((byte[])matcher.Value).ContainsExactly(115, 116, 101, 102); } [Fact] @@ -846,7 +846,7 @@ message HelloReply { var model = new MatcherModel { Name = "RegexMatcher", - Patterns = new[] { "x", "y" }, + Patterns = ["x", "y"], IgnoreCase = true, MatchOperator = matchOperator.ToString() }; @@ -871,7 +871,7 @@ message HelloReply { var model = new MatcherModel { Name = "WildcardMatcher", - Patterns = new[] { "x", "y" }, + Patterns = ["x", "y"], IgnoreCase = true, MatchOperator = matchOperator.ToString() }; @@ -1127,7 +1127,7 @@ message HelloReply { var matcher = (ProtoBufMatcher)_sut.Map(model)!; // Assert - matcher.ProtoDefinition().Text.Should().Be(protoDefinition); + matcher.ProtoDefinition().Texts.Should().ContainSingle(protoDefinition); matcher.Name.Should().Be(nameof(ProtoBufMatcher)); matcher.MessageType.Should().Be(messageType); matcher.Matcher?.Value.Should().Be(jsonMatcherPattern); diff --git a/test/WireMock.Net.Tests/WireMockServer.Proxy.cs b/test/WireMock.Net.Tests/WireMockServer.Proxy.cs index d8efd106..842bb8ed 100644 --- a/test/WireMock.Net.Tests/WireMockServer.Proxy.cs +++ b/test/WireMock.Net.Tests/WireMockServer.Proxy.cs @@ -759,8 +759,8 @@ public class WireMockServerProxyTests var brokenJpegHeader = new byte[] {0xEF, 0xBF, 0xBD, 0xEF, 0xBF, 0xBD, 0xEF, 0xBF, 0xBD, 0xEF, 0xBF, 0xBD, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00}; - bool HasCorrectHeader(byte[] bytes) => bytes.SequenceEqual(jpegHeader); - bool HasBrokenHeader(byte[] bytes) => bytes.SequenceEqual(brokenJpegHeader); + bool HasCorrectHeader(byte[]? bytes) => bytes?.SequenceEqual(jpegHeader) == true; + bool HasBrokenHeader(byte[]? bytes) => bytes?.SequenceEqual(brokenJpegHeader) == true; var serverForProxyForwarding = WireMockServer.Start(); serverForProxyForwarding