diff --git a/WireMock.Net Solution.sln.DotSettings b/WireMock.Net Solution.sln.DotSettings index 2e1d593a..dadfb7f5 100644 --- a/WireMock.Net Solution.sln.DotSettings +++ b/WireMock.Net Solution.sln.DotSettings @@ -15,6 +15,7 @@ True True True + True True True True diff --git a/examples/WireMock.Net.Console.Net452.Classic/CustomFileSystemFileHandler.cs b/examples/WireMock.Net.Console.Net452.Classic/CustomFileSystemFileHandler.cs index aeeefc81..a04adae1 100644 --- a/examples/WireMock.Net.Console.Net452.Classic/CustomFileSystemFileHandler.cs +++ b/examples/WireMock.Net.Console.Net452.Classic/CustomFileSystemFileHandler.cs @@ -69,6 +69,12 @@ namespace WireMock.Net.ConsoleApplication File.WriteAllBytes(AdjustPath(path), bytes); } + public void WriteFile(string folder, string filename, byte[] bytes) + { + File.WriteAllBytes(Path.Combine(folder, filename), bytes); + + } + /// public void DeleteFile(string path) { diff --git a/examples/WireMock.Net.Console.Net452.Classic/MainApp.cs b/examples/WireMock.Net.Console.Net452.Classic/MainApp.cs index bc36cbac..0ad7dfa6 100644 --- a/examples/WireMock.Net.Console.Net452.Classic/MainApp.cs +++ b/examples/WireMock.Net.Console.Net452.Classic/MainApp.cs @@ -89,6 +89,8 @@ namespace WireMock.Net.ConsoleApplication server .Given(Request.Create().WithPath(p => p.Contains("x")).UsingGet()) .AtPriority(4) + .WithTitle("t") + .WithDescription("d") .RespondWith(Response.Create() .WithStatusCode(200) .WithHeader("Content-Type", "application/json") diff --git a/src/WireMock.Net.Abstractions/Admin/Mappings/CookieModel.cs b/src/WireMock.Net.Abstractions/Admin/Mappings/CookieModel.cs index 450f77c1..420d95be 100644 --- a/src/WireMock.Net.Abstractions/Admin/Mappings/CookieModel.cs +++ b/src/WireMock.Net.Abstractions/Admin/Mappings/CookieModel.cs @@ -1,31 +1,30 @@ -using System.Collections.Generic; +using System.Collections.Generic; -namespace WireMock.Admin.Mappings +namespace WireMock.Admin.Mappings; + +/// +/// Cookie Model +/// +[FluentBuilder.AutoGenerateBuilder] +public class CookieModel { /// - /// Cookie Model + /// Gets or sets the name. /// - [FluentBuilder.AutoGenerateBuilder] - public class CookieModel - { - /// - /// Gets or sets the name. - /// - public string Name { get; set; } + public string Name { get; set; } = null!; - /// - /// Gets or sets the matchers. - /// - public IList Matchers { get; set; } + /// + /// Gets or sets the matchers. + /// + public IList? Matchers { get; set; } - /// - /// Gets or sets the ignore case. - /// - public bool? IgnoreCase { get; set; } + /// + /// Gets or sets the ignore case. + /// + public bool? IgnoreCase { get; set; } - /// - /// Reject on match. - /// - public bool? RejectOnMatch { get; set; } - } + /// + /// Reject on match. + /// + public bool? RejectOnMatch { get; set; } } \ No newline at end of file diff --git a/src/WireMock.Net.Abstractions/Admin/Mappings/HeaderModel.cs b/src/WireMock.Net.Abstractions/Admin/Mappings/HeaderModel.cs index 27d967fc..724c11b9 100644 --- a/src/WireMock.Net.Abstractions/Admin/Mappings/HeaderModel.cs +++ b/src/WireMock.Net.Abstractions/Admin/Mappings/HeaderModel.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; namespace WireMock.Admin.Mappings { @@ -11,12 +11,12 @@ namespace WireMock.Admin.Mappings /// /// Gets or sets the name. /// - public string Name { get; set; } + public string Name { get; set; } = null!; /// /// Gets or sets the matchers. /// - public IList Matchers { get; set; } + public IList? Matchers { get; set; } /// /// Gets or sets the ignore case. diff --git a/src/WireMock.Net.Abstractions/Admin/Mappings/MappingModel.cs b/src/WireMock.Net.Abstractions/Admin/Mappings/MappingModel.cs index e889fbc5..e9544e8e 100644 --- a/src/WireMock.Net.Abstractions/Admin/Mappings/MappingModel.cs +++ b/src/WireMock.Net.Abstractions/Admin/Mappings/MappingModel.cs @@ -24,6 +24,11 @@ namespace WireMock.Admin.Mappings /// public string Title { get; set; } + /// + /// The description. + /// + public string Description { get; set; } + /// /// The priority. (A low value means higher priority.) /// diff --git a/src/WireMock.Net.Abstractions/Admin/Mappings/ParamModel.cs b/src/WireMock.Net.Abstractions/Admin/Mappings/ParamModel.cs index 5f56a9db..7be363f1 100644 --- a/src/WireMock.Net.Abstractions/Admin/Mappings/ParamModel.cs +++ b/src/WireMock.Net.Abstractions/Admin/Mappings/ParamModel.cs @@ -1,24 +1,23 @@ -namespace WireMock.Admin.Mappings +namespace WireMock.Admin.Mappings; + +/// +/// Param Model +/// +[FluentBuilder.AutoGenerateBuilder] +public class ParamModel { /// - /// Param Model + /// Gets or sets the name. /// - [FluentBuilder.AutoGenerateBuilder] - public class ParamModel - { - /// - /// Gets or sets the name. - /// - public string Name { get; set; } + public string Name { get; set; } = null!; - /// - /// Defines if the key should be matched using case-ignore. - /// - public bool? IgnoreCase { get; set; } + /// + /// Defines if the key should be matched using case-ignore. + /// + public bool? IgnoreCase { get; set; } - /// - /// Gets or sets the matchers. - /// - public MatcherModel[] Matchers { get; set; } - } + /// + /// Gets or sets the matchers. + /// + public MatcherModel[]? Matchers { get; set; } } \ No newline at end of file diff --git a/src/WireMock.Net.Abstractions/Admin/Mappings/RequestModel.cs b/src/WireMock.Net.Abstractions/Admin/Mappings/RequestModel.cs index 1acde2c3..3f396685 100644 --- a/src/WireMock.Net.Abstractions/Admin/Mappings/RequestModel.cs +++ b/src/WireMock.Net.Abstractions/Admin/Mappings/RequestModel.cs @@ -1,51 +1,50 @@ -using System.Collections.Generic; +using System.Collections.Generic; -namespace WireMock.Admin.Mappings +namespace WireMock.Admin.Mappings; + +/// +/// RequestModel +/// +[FluentBuilder.AutoGenerateBuilder] +public class RequestModel { /// - /// RequestModel + /// Gets or sets the ClientIP. (Can be a string or a ClientIPModel) /// - [FluentBuilder.AutoGenerateBuilder] - public class RequestModel - { - /// - /// Gets or sets the ClientIP. (Can be a string or a ClientIPModel) - /// - public object ClientIP { get; set; } + public object? ClientIP { get; set; } - /// - /// Gets or sets the Path. (Can be a string or a PathModel) - /// - public object Path { get; set; } + /// + /// Gets or sets the Path. (Can be a string or a PathModel) + /// + public object? Path { get; set; } - /// - /// Gets or sets the Url. (Can be a string or a UrlModel) - /// - public object Url { get; set; } + /// + /// Gets or sets the Url. (Can be a string or a UrlModel) + /// + public object? Url { get; set; } - /// - /// The methods - /// - public string[] Methods { get; set; } + /// + /// The methods + /// + public string[]? Methods { get; set; } - /// - /// Gets or sets the Headers. - /// - public IList Headers { get; set; } + /// + /// Gets or sets the Headers. + /// + public IList? Headers { get; set; } - /// - /// Gets or sets the Cookies. - /// - public IList Cookies { get; set; } + /// + /// Gets or sets the Cookies. + /// + public IList? Cookies { get; set; } - /// - /// Gets or sets the Params. - /// - public IList Params { get; set; } + /// + /// Gets or sets the Params. + /// + public IList? Params { get; set; } - /// - /// Gets or sets the body. - /// - public BodyModel Body { get; set; } - } + /// + /// Gets or sets the body. + /// + public BodyModel? Body { 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 f9cbc218..40609b7f 100644 --- a/src/WireMock.Net.Abstractions/Admin/Mappings/ResponseModel.cs +++ b/src/WireMock.Net.Abstractions/Admin/Mappings/ResponseModel.cs @@ -11,22 +11,22 @@ namespace WireMock.Admin.Mappings /// /// Gets or sets the HTTP status. /// - public object StatusCode { get; set; } + public object? StatusCode { get; set; } /// /// Gets or sets the body destination (SameAsSource, String or Bytes). /// - public string BodyDestination { get; set; } + public string? BodyDestination { get; set; } /// /// Gets or sets the body. /// - public string Body { get; set; } + public string? Body { get; set; } /// /// Gets or sets the body (as JSON object). /// - public object BodyAsJson { get; set; } + public object? BodyAsJson { get; set; } /// /// Gets or sets a value indicating whether child objects to be indented according to the Newtonsoft.Json.JsonTextWriter.Indentation and Newtonsoft.Json.JsonTextWriter.IndentChar settings. @@ -36,12 +36,12 @@ namespace WireMock.Admin.Mappings /// /// Gets or sets the body (as bytearray). /// - public byte[] BodyAsBytes { get; set; } + public byte[]? BodyAsBytes { get; set; } /// /// Gets or sets the body as a file. /// - public string BodyAsFile { get; set; } + public string? BodyAsFile { get; set; } /// /// Is the body as file cached? @@ -51,7 +51,7 @@ namespace WireMock.Admin.Mappings /// /// Gets or sets the body encoding. /// - public EncodingModel BodyEncoding { get; set; } + public EncodingModel? BodyEncoding { get; set; } /// /// Use ResponseMessage Transformer. @@ -61,7 +61,7 @@ namespace WireMock.Admin.Mappings /// /// Gets the type of the transformer. /// - public string TransformerType { get; set; } + public string? TransformerType { get; set; } /// /// Use the Handlebars transformer for the content from the referenced BodyAsFile. @@ -71,17 +71,17 @@ namespace WireMock.Admin.Mappings /// /// The ReplaceNodeOptions to use when transforming a JSON node. /// - public string TransformerReplaceNodeOptions { get; set; } + public string? TransformerReplaceNodeOptions { get; set; } /// /// Gets or sets the headers. /// - public IDictionary Headers { get; set; } + public IDictionary? Headers { get; set; } /// /// Gets or sets the Headers (Raw). /// - public string HeadersRaw { get; set; } + public string? HeadersRaw { get; set; } /// /// Gets or sets the delay in milliseconds. @@ -101,21 +101,21 @@ namespace WireMock.Admin.Mappings /// /// Gets or sets the Proxy URL. /// - public string ProxyUrl { get; set; } + public string? ProxyUrl { get; set; } /// /// The client X509Certificate2 Thumbprint or SubjectName to use. /// - public string X509Certificate2ThumbprintOrSubjectName { get; set; } + public string? X509Certificate2ThumbprintOrSubjectName { get; set; } /// /// Gets or sets the fault. /// - public FaultModel Fault { get; set; } + public FaultModel? Fault { get; set; } /// /// Gets or sets the WebProxy settings. /// - public WebProxyModel WebProxy { get; set; } + public WebProxyModel? WebProxy { get; set; } } } \ No newline at end of file diff --git a/src/WireMock.Net.Abstractions/Admin/Requests/LogEntryModel.cs b/src/WireMock.Net.Abstractions/Admin/Requests/LogEntryModel.cs index 2a3480e6..ac327fa6 100644 --- a/src/WireMock.Net.Abstractions/Admin/Requests/LogEntryModel.cs +++ b/src/WireMock.Net.Abstractions/Admin/Requests/LogEntryModel.cs @@ -1,56 +1,54 @@ -using System; +using System; -namespace WireMock.Admin.Requests +namespace WireMock.Admin.Requests; + +/// +/// Request Log Model +/// +public class LogEntryModel { /// - /// Request Log Model + /// The unique identifier. /// - [FluentBuilder.AutoGenerateBuilder] - public class LogEntryModel - { - /// - /// The unique identifier. - /// - public Guid Guid { get; set; } + public Guid Guid { get; set; } - /// - /// The request. - /// - public LogRequestModel Request { get; set; } + /// + /// The request. + /// + public LogRequestModel Request { get; set; } - /// - /// The response. - /// - public LogResponseModel Response { get; set; } + /// + /// The response. + /// + public LogResponseModel Response { get; set; } - /// - /// The mapping unique identifier. - /// - public Guid? MappingGuid { get; set; } + /// + /// The mapping unique identifier. + /// + public Guid? MappingGuid { get; set; } - /// - /// The mapping unique title. - /// - public string MappingTitle { get; set; } + /// + /// The mapping unique title. + /// + public string MappingTitle { get; set; } - /// - /// The request match result. - /// - public LogRequestMatchModel RequestMatchResult { get; set; } + /// + /// The request match result. + /// + public LogRequestMatchModel RequestMatchResult { get; set; } - /// - /// The partial mapping unique identifier. - /// - public Guid? PartialMappingGuid { get; set; } + /// + /// The partial mapping unique identifier. + /// + public Guid? PartialMappingGuid { get; set; } - /// - /// The partial mapping unique title. - /// - public string PartialMappingTitle { get; set; } + /// + /// The partial mapping unique title. + /// + public string PartialMappingTitle { get; set; } - /// - /// The partial request match result. - /// - public LogRequestMatchModel PartialRequestMatchResult { get; set; } - } + /// + /// The partial request match result. + /// + public LogRequestMatchModel PartialRequestMatchResult { get; set; } } \ No newline at end of file diff --git a/src/WireMock.Net.Abstractions/Admin/Requests/LogRequestMatchModel.cs b/src/WireMock.Net.Abstractions/Admin/Requests/LogRequestMatchModel.cs index 8b409c1b..f187867f 100644 --- a/src/WireMock.Net.Abstractions/Admin/Requests/LogRequestMatchModel.cs +++ b/src/WireMock.Net.Abstractions/Admin/Requests/LogRequestMatchModel.cs @@ -1,51 +1,49 @@ -using System.Collections.Generic; +using System.Collections.Generic; -namespace WireMock.Admin.Requests +namespace WireMock.Admin.Requests; + +/// +/// LogRequestMatchModel +/// +public class LogRequestMatchModel { /// - /// LogRequestMatchModel + /// Gets or sets the match-score. /// - [FluentBuilder.AutoGenerateBuilder] - public class LogRequestMatchModel - { - /// - /// Gets or sets the match-score. - /// - /// - /// The match-score. - /// - public double TotalScore { get; set; } + /// + /// The match-score. + /// + public double TotalScore { get; set; } - /// - /// Gets or sets the total number of matches. - /// - /// - /// The total number of matches. - /// - public int TotalNumber { get; set; } + /// + /// Gets or sets the total number of matches. + /// + /// + /// The total number of matches. + /// + public int TotalNumber { get; set; } - /// - /// Gets or sets a value indicating whether this instance is perfect match. - /// - /// - /// true if this instance is perfect match; otherwise, false. - /// - public bool IsPerfectMatch { get; set; } + /// + /// Gets or sets a value indicating whether this instance is perfect match. + /// + /// + /// true if this instance is perfect match; otherwise, false. + /// + public bool IsPerfectMatch { get; set; } - /// - /// Gets the match percentage. - /// - /// - /// The match percentage. - /// - public double AverageTotalScore { get; set; } + /// + /// Gets the match percentage. + /// + /// + /// The match percentage. + /// + public double AverageTotalScore { get; set; } - /// - /// Gets the match details. - /// - /// - /// The match details. - /// - public IList MatchDetails { get; set; } - } + /// + /// Gets the match details. + /// + /// + /// The match details. + /// + public IList MatchDetails { get; set; } } \ No newline at end of file diff --git a/src/WireMock.Net.Abstractions/Admin/Requests/LogRequestModel.cs b/src/WireMock.Net.Abstractions/Admin/Requests/LogRequestModel.cs index ab5b10aa..16d0c415 100644 --- a/src/WireMock.Net.Abstractions/Admin/Requests/LogRequestModel.cs +++ b/src/WireMock.Net.Abstractions/Admin/Requests/LogRequestModel.cs @@ -1,109 +1,107 @@ -using System; +using System; using System.Collections.Generic; using WireMock.Admin.Mappings; using WireMock.Types; -namespace WireMock.Admin.Requests +namespace WireMock.Admin.Requests; + +/// +/// RequestMessage Model +/// +public class LogRequestModel { /// - /// RequestMessage Model + /// The Client IP Address. /// - [FluentBuilder.AutoGenerateBuilder] - public class LogRequestModel - { - /// - /// The Client IP Address. - /// - public string ClientIP { get; set; } + public string ClientIP { get; set; } - /// - /// The DateTime. - /// - public DateTime DateTime { get; set; } + /// + /// The DateTime. + /// + public DateTime DateTime { get; set; } - /// - /// The Path. - /// - public string Path { get; set; } + /// + /// The Path. + /// + public string Path { get; set; } - /// - /// The Absolute Path. - /// - public string AbsolutePath { get; set; } + /// + /// The Absolute Path. + /// + public string AbsolutePath { get; set; } - /// - /// Gets the url (relative). - /// - public string Url { get; set; } + /// + /// Gets the url (relative). + /// + public string Url { get; set; } - /// - /// The absolute URL. - /// - public string AbsoluteUrl { get; set; } + /// + /// The absolute URL. + /// + public string AbsoluteUrl { get; set; } - /// - /// The ProxyUrl (if a proxy is used). - /// - public string ProxyUrl { get; set; } + /// + /// The ProxyUrl (if a proxy is used). + /// + public string? ProxyUrl { get; set; } - /// - /// The query. - /// - public IDictionary> Query { get; set; } + /// + /// The query. + /// + public IDictionary>? Query { get; set; } - /// - /// The method. - /// - public string Method { get; set; } + /// + /// The method. + /// + public string Method { get; set; } - /// - /// The Headers. - /// - public IDictionary> Headers { get; set; } + /// + /// The Headers. + /// + public IDictionary>? Headers { get; set; } - /// - /// The Cookies. - /// - public IDictionary Cookies { get; set; } + /// + /// The Cookies. + /// + public IDictionary? Cookies { get; set; } - /// - /// The body (as string). - /// - public string Body { get; set; } + /// + /// The body (as string). + /// + public string? Body { get; set; } - /// - /// The body (as JSON object). - /// - public object BodyAsJson { get; set; } + /// + /// The body (as JSON object). + /// + public object? BodyAsJson { get; set; } - /// - /// The body (as bytearray). - /// - public byte[] BodyAsBytes { get; set; } + /// + /// The body (as bytearray). + /// + public byte[]? BodyAsBytes { get; set; } - /// - /// The body encoding. - /// - public EncodingModel BodyEncoding { get; set; } + /// + /// The body encoding. + /// + public EncodingModel? BodyEncoding { get; set; } - /// - /// The DetectedBodyType, valid values are: - /// - /// - None - /// - String - /// - Json - /// - Bytes - /// - public string DetectedBodyType { get; set; } + /// + /// The DetectedBodyType, valid values are: + /// + /// - None + /// - String + /// - Json + /// - Bytes + /// + public string? DetectedBodyType { get; set; } - /// - /// The DetectedBodyTypeFromContentType, valid values are: - /// - /// - None - /// - String - /// - Json - /// - Bytes - /// - public string DetectedBodyTypeFromContentType { get; set; } - } + /// + /// The DetectedBodyTypeFromContentType, valid values are: + /// + /// - None + /// - String + /// - Json + /// - Bytes + /// + public string? DetectedBodyTypeFromContentType { get; set; } } \ No newline at end of file diff --git a/src/WireMock.Net.Abstractions/Admin/Requests/LogResponseModel.cs b/src/WireMock.Net.Abstractions/Admin/Requests/LogResponseModel.cs index 487c388b..5e4b2429 100644 --- a/src/WireMock.Net.Abstractions/Admin/Requests/LogResponseModel.cs +++ b/src/WireMock.Net.Abstractions/Admin/Requests/LogResponseModel.cs @@ -1,83 +1,81 @@ -using System.Collections.Generic; +using System.Collections.Generic; using WireMock.Admin.Mappings; using WireMock.Types; -namespace WireMock.Admin.Requests +namespace WireMock.Admin.Requests; + +/// +/// Response MessageModel +/// +public class LogResponseModel { /// - /// Response MessageModel + /// Gets or sets the status code. /// - [FluentBuilder.AutoGenerateBuilder] - public class LogResponseModel - { - /// - /// Gets or sets the status code. - /// - public object StatusCode { get; set; } = 200; + public object? StatusCode { get; set; } - /// - /// Gets the headers. - /// - public IDictionary> Headers { get; set; } + /// + /// Gets the headers. + /// + public IDictionary>? Headers { get; set; } - /// - /// Gets or sets the body destination (SameAsSource, String or Bytes). - /// - public string BodyDestination { get; set; } + /// + /// Gets or sets the body destination (SameAsSource, String or Bytes). + /// + public string? BodyDestination { get; set; } - /// - /// The body (as string). - /// - public string Body { get; set; } + /// + /// The body (as string). + /// + public string? Body { get; set; } - /// - /// The body (as JSON object). - /// - public object BodyAsJson { get; set; } + /// + /// The body (as JSON object). + /// + public object? BodyAsJson { get; set; } - /// - /// The body (as bytearray). - /// - public byte[] BodyAsBytes { get; set; } + /// + /// The body (as bytearray). + /// + public byte[]? BodyAsBytes { get; set; } - /// - /// Gets or sets the body as file. - /// - public string BodyAsFile { get; set; } + /// + /// Gets or sets the body as file. + /// + public string? BodyAsFile { get; set; } - /// - /// Is the body as file cached? - /// - public bool? BodyAsFileIsCached { get; set; } + /// + /// Is the body as file cached? + /// + public bool? BodyAsFileIsCached { get; set; } - /// - /// Gets or sets the original body. - /// - public string BodyOriginal { get; set; } + /// + /// Gets or sets the original body. + /// + public string? BodyOriginal { get; set; } - /// - /// Gets or sets the body. - /// - public EncodingModel BodyEncoding { get; set; } + /// + /// Gets or sets the body. + /// + public EncodingModel? BodyEncoding { get; set; } - /// - /// The detected body type (detection based on body content). - /// - public BodyType DetectedBodyType { get; set; } + /// + /// The detected body type (detection based on body content). + /// + public BodyType? DetectedBodyType { get; set; } - /// - /// The detected body type (detection based on Content-Type). - /// - public BodyType DetectedBodyTypeFromContentType { get; set; } + /// + /// The detected body type (detection based on Content-Type). + /// + public BodyType? DetectedBodyTypeFromContentType { get; set; } - /// - /// The FaultType. - /// - public string FaultType { get; set; } + /// + /// The FaultType. + /// + public string? FaultType { get; set; } - /// - /// Gets or sets the Fault percentage. - /// - public double? FaultPercentage { get; set; } - } + /// + /// Gets or sets the Fault percentage. + /// + public double? FaultPercentage { get; set; } } \ No newline at end of file diff --git a/src/WireMock.Net.Abstractions/Admin/Scenarios/ScenarioStateModel.cs b/src/WireMock.Net.Abstractions/Admin/Scenarios/ScenarioStateModel.cs index 517891cd..bd204a88 100644 --- a/src/WireMock.Net.Abstractions/Admin/Scenarios/ScenarioStateModel.cs +++ b/src/WireMock.Net.Abstractions/Admin/Scenarios/ScenarioStateModel.cs @@ -1,4 +1,4 @@ -namespace WireMock.Admin.Scenarios +namespace WireMock.Admin.Scenarios { /// /// ScenarioStateModel @@ -14,7 +14,7 @@ /// /// Gets or sets the NextState. /// - public string NextState { get; set; } + public string? NextState { get; set; } /// /// Gets or sets a value indicating whether this is started. diff --git a/src/WireMock.Net.Abstractions/Admin/Settings/ProxyAndRecordSettingsModel.cs b/src/WireMock.Net.Abstractions/Admin/Settings/ProxyAndRecordSettingsModel.cs index d8f9281e..96ca4181 100644 --- a/src/WireMock.Net.Abstractions/Admin/Settings/ProxyAndRecordSettingsModel.cs +++ b/src/WireMock.Net.Abstractions/Admin/Settings/ProxyAndRecordSettingsModel.cs @@ -1,59 +1,58 @@ -using JetBrains.Annotations; - -namespace WireMock.Admin.Settings; - -[FluentBuilder.AutoGenerateBuilder] -public class ProxyAndRecordSettingsModel +namespace WireMock.Admin.Settings { - /// - /// The clientCertificate thumbprint or subject name fragment to use. - /// Example thumbprint : "D2DBF135A8D06ACCD0E1FAD9BFB28678DF7A9818". Example subject name: "www.google.com"" - /// - public string ClientX509Certificate2ThumbprintOrSubjectName { get; set; } + [FluentBuilder.AutoGenerateBuilder] + public class ProxyAndRecordSettingsModel + { + /// + /// The clientCertificate thumbprint or subject name fragment to use. + /// Example thumbprint : "D2DBF135A8D06ACCD0E1FAD9BFB28678DF7A9818". Example subject name: "www.google.com"" + /// + public string ClientX509Certificate2ThumbprintOrSubjectName { get; set; } - /// - /// Defines the WebProxySettings. - /// - public WebProxySettingsModel WebProxySettings { get; set; } + /// + /// Defines the WebProxySettings. + /// + public WebProxySettingsModel WebProxySettings { get; set; } - /// - /// Proxy requests should follow redirection (30x). - /// - public bool? AllowAutoRedirect { get; set; } + /// + /// Proxy requests should follow redirection (30x). + /// + public bool? AllowAutoRedirect { get; set; } - /// - /// The URL to proxy. - /// - public string Url { get; set; } + /// + /// The URL to proxy. + /// + public string Url { get; set; } - /// - /// Save the mapping for each request/response to the internal Mappings. - /// - public bool SaveMapping { get; set; } + /// + /// Save the mapping for each request/response to the internal Mappings. + /// + public bool SaveMapping { get; set; } - /// - /// Save the mapping for each request/response also to a file. (Note that SaveMapping must also be set to true.) - /// - public bool SaveMappingToFile { get; set; } + /// + /// Save the mapping for each request/response also to a file. (Note that SaveMapping must also be set to true.) + /// + public bool SaveMappingToFile { get; set; } - /// - /// Only save request/response to the internal Mappings if the status code is included in this pattern. (Note that SaveMapping must also be set to true.) - /// The pattern can contain a single value like "200", but also ranges like "2xx", "100,300,600" or "100-299,6xx" are supported. - /// - public string SaveMappingForStatusCodePattern { get; set; } = "*"; + /// + /// Only save request/response to the internal Mappings if the status code is included in this pattern. (Note that SaveMapping must also be set to true.) + /// The pattern can contain a single value like "200", but also ranges like "2xx", "100,300,600" or "100-299,6xx" are supported. + /// + public string SaveMappingForStatusCodePattern { get; set; } = "*"; - /// - /// Defines a list from headers which will be excluded from the saved mappings. - /// - public string[] ExcludedHeaders { get; set; } + /// + /// Defines a list from headers which will be excluded from the saved mappings. + /// + public string[] ExcludedHeaders { get; set; } - /// - /// Defines a list of cookies which will be excluded from the saved mappings. - /// - public string[] ExcludedCookies { get; set; } + /// + /// Defines a list of cookies which will be excluded from the saved mappings. + /// + public string[] ExcludedCookies { get; set; } - /// - /// Prefer the Proxy Mapping over the saved Mapping (in case SaveMapping is set to true). - /// - // public bool PreferProxyMapping { get; set; } + /// + /// Prefer the Proxy Mapping over the saved Mapping (in case SaveMapping is set to true). + /// + // public bool PreferProxyMapping { get; set; } + } } \ No newline at end of file diff --git a/src/WireMock.Net.Abstractions/Admin/Settings/SettingsModel.cs b/src/WireMock.Net.Abstractions/Admin/Settings/SettingsModel.cs index 84e6cd81..e9f4eccd 100644 --- a/src/WireMock.Net.Abstractions/Admin/Settings/SettingsModel.cs +++ b/src/WireMock.Net.Abstractions/Admin/Settings/SettingsModel.cs @@ -1,5 +1,4 @@ using System.Text.RegularExpressions; -using JetBrains.Annotations; using WireMock.Handlers; namespace WireMock.Admin.Settings @@ -73,11 +72,11 @@ namespace WireMock.Admin.Settings /// /// Policies to use when using CORS. By default CORS is disabled. [Optional] /// - public string CorsPolicyOptions { get; set; } + public string? CorsPolicyOptions { get; set; } /// /// The proxy and record settings. /// - public ProxyAndRecordSettingsModel ProxyAndRecordSettings { get; set; } + public ProxyAndRecordSettingsModel? ProxyAndRecordSettings { get; set; } } } \ No newline at end of file diff --git a/src/WireMock.Net.Abstractions/Admin/Settings/WebProxySettings.cs b/src/WireMock.Net.Abstractions/Admin/Settings/WebProxySettings.cs index 3f7ce1c8..8c6c081d 100644 --- a/src/WireMock.Net.Abstractions/Admin/Settings/WebProxySettings.cs +++ b/src/WireMock.Net.Abstractions/Admin/Settings/WebProxySettings.cs @@ -14,11 +14,11 @@ namespace WireMock.Admin.Settings /// /// The user name associated with the credentials. /// - public string UserName { get; set; } + public string? UserName { get; set; } /// /// The password for the user name associated with the credentials. /// - public string Password { get; set; } + public string? Password { get; set; } } } \ No newline at end of file diff --git a/src/WireMock.Net.Abstractions/Handlers/IFileSystemHandler.cs b/src/WireMock.Net.Abstractions/Handlers/IFileSystemHandler.cs index 9d841a01..dd0516cb 100644 --- a/src/WireMock.Net.Abstractions/Handlers/IFileSystemHandler.cs +++ b/src/WireMock.Net.Abstractions/Handlers/IFileSystemHandler.cs @@ -4,7 +4,7 @@ using System.Collections.Generic; namespace WireMock.Handlers { /// - /// Handler to interact with the file system to handle folders and read and write static mapping files. + /// Handler to interact with the file system to handle folders and read and write (static mapping) files. /// public interface IFileSystemHandler { @@ -83,6 +83,14 @@ namespace WireMock.Handlers /// The bytes. void WriteFile([NotNull] string filename, [NotNull] byte[] bytes); + /// + /// Write a file. + /// + /// The folder. + /// The filename. + /// The bytes. + void WriteFile([NotNull] string folder, [NotNull] string filename, [NotNull] byte[] bytes); + /// /// Read a file as bytes. /// diff --git a/src/WireMock.Net.Abstractions/IRequestMessage.cs b/src/WireMock.Net.Abstractions/IRequestMessage.cs index 1936fb97..39cd3f86 100644 --- a/src/WireMock.Net.Abstractions/IRequestMessage.cs +++ b/src/WireMock.Net.Abstractions/IRequestMessage.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using WireMock.Types; using WireMock.Util; @@ -28,7 +28,7 @@ namespace WireMock /// /// The ProxyUrl (if a proxy is used). /// - string ProxyUrl { get; } + string ProxyUrl { get; set; } /// /// Gets the DateTime. @@ -83,7 +83,7 @@ namespace WireMock /// /// The body. /// - IBodyData BodyData { get; } + IBodyData? BodyData { get; } /// /// The original body as string. Convenience getter for Handlebars. diff --git a/src/WireMock.Net.Abstractions/Logging/IWireMockLogger.cs b/src/WireMock.Net.Abstractions/Logging/IWireMockLogger.cs index c2ff3833..0336295d 100644 --- a/src/WireMock.Net.Abstractions/Logging/IWireMockLogger.cs +++ b/src/WireMock.Net.Abstractions/Logging/IWireMockLogger.cs @@ -1,4 +1,4 @@ -using System; +using System; using JetBrains.Annotations; using WireMock.Admin.Requests; @@ -17,7 +17,7 @@ namespace WireMock.Logging /// The arguments. [PublicAPI] [StringFormatMethod("formatString")] - void Debug([NotNull] string formatString, [NotNull] params object[] args); + void Debug(string formatString, params object[] args); /// /// Writes the message at the Info level using the specified parameters. @@ -26,7 +26,7 @@ namespace WireMock.Logging /// The arguments. [PublicAPI] [StringFormatMethod("formatString")] - void Info([NotNull] string formatString, [NotNull] params object[] args); + void Info(string formatString, params object[] args); /// /// Writes the message at the Warning level using the specified parameters. @@ -35,7 +35,7 @@ namespace WireMock.Logging /// The arguments. [PublicAPI] [StringFormatMethod("formatString")] - void Warn([NotNull] string formatString, [NotNull] params object[] args); + void Warn(string formatString, params object[] args); /// /// Writes the message at the Error level using the specified parameters. @@ -44,7 +44,7 @@ namespace WireMock.Logging /// The arguments. [PublicAPI] [StringFormatMethod("formatString")] - void Error([NotNull] string formatString, [NotNull] params object[] args); + void Error(string formatString, params object[] args); /// /// Writes the message at the Error level using the specified exception. @@ -53,7 +53,7 @@ namespace WireMock.Logging /// The exception. [PublicAPI] [StringFormatMethod("formatString")] - void Error([NotNull] string formatString, [NotNull] Exception exception); + void Error(string formatString, Exception exception); /// /// Writes the LogEntryModel (LogRequestModel, LogResponseModel and more). @@ -61,6 +61,6 @@ namespace WireMock.Logging /// The Request Log Model. /// Defines if this request is an admin request. [PublicAPI] - void DebugRequestResponse([NotNull] LogEntryModel logEntryModel, bool isAdminRequest); + void DebugRequestResponse(LogEntryModel logEntryModel, bool isAdminRequest); } } \ No newline at end of file diff --git a/src/WireMock.Net.Abstractions/Matchers/Request/IRequestMatchResult.cs b/src/WireMock.Net.Abstractions/Matchers/Request/IRequestMatchResult.cs index f38e733f..d32b9d4f 100644 --- a/src/WireMock.Net.Abstractions/Matchers/Request/IRequestMatchResult.cs +++ b/src/WireMock.Net.Abstractions/Matchers/Request/IRequestMatchResult.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; namespace WireMock.Matchers.Request @@ -44,5 +44,13 @@ namespace WireMock.Matchers.Request /// The match-score. /// double TotalScore { get; } + + /// + /// Adds the score. + /// + /// The matcher Type. + /// The score. + /// The score. + double AddScore(Type matcherType, double score); } } \ No newline at end of file diff --git a/src/WireMock.Net/Matchers/Request/IRequestMatcher.cs b/src/WireMock.Net.Abstractions/Matchers/Request/IRequestMatcher.cs similarity index 86% rename from src/WireMock.Net/Matchers/Request/IRequestMatcher.cs rename to src/WireMock.Net.Abstractions/Matchers/Request/IRequestMatcher.cs index 5c2cbad1..c3375d8f 100644 --- a/src/WireMock.Net/Matchers/Request/IRequestMatcher.cs +++ b/src/WireMock.Net.Abstractions/Matchers/Request/IRequestMatcher.cs @@ -1,4 +1,4 @@ -using JetBrains.Annotations; +using JetBrains.Annotations; namespace WireMock.Matchers.Request { @@ -15,6 +15,6 @@ namespace WireMock.Matchers.Request /// /// A value between 0.0 - 1.0 of the similarity. /// - double GetMatchingScore([NotNull] IRequestMessage requestMessage, [NotNull] RequestMatchResult requestMatchResult); + double GetMatchingScore([NotNull] IRequestMessage requestMessage, [NotNull] IRequestMatchResult requestMatchResult); } } \ No newline at end of file diff --git a/src/WireMock.Net.Abstractions/Models/IBodyData.cs b/src/WireMock.Net.Abstractions/Models/IBodyData.cs index e9223df4..3415edb0 100644 --- a/src/WireMock.Net.Abstractions/Models/IBodyData.cs +++ b/src/WireMock.Net.Abstractions/Models/IBodyData.cs @@ -1,61 +1,62 @@ -using System.Text; +using System.Diagnostics.CodeAnalysis; +using System.Text; +using JetBrains.Annotations; using WireMock.Types; -namespace WireMock.Util +namespace WireMock.Util; + +/// +/// IBodyData +/// +public interface IBodyData { /// - /// IBodyData + /// The body (as bytearray). /// - public interface IBodyData - { - /// - /// The body (as bytearray). - /// - byte[] BodyAsBytes { get; set; } + byte[] BodyAsBytes { get; set; } - /// - /// Gets or sets the body as a file. - /// - string BodyAsFile { get; set; } + /// + /// Gets or sets the body as a file. + /// + string BodyAsFile { get; set; } - /// - /// Is the body as file cached? - /// - bool? BodyAsFileIsCached { get; set; } + /// + /// Is the body as file cached? + /// + bool? BodyAsFileIsCached { get; set; } - /// - /// The body (as JSON object). - /// - object BodyAsJson { get; set; } + /// + /// The body (as JSON object). + /// + object? BodyAsJson { get; set; } - /// - /// Gets or sets a value indicating whether child objects to be indented according to the Newtonsoft.Json.JsonTextWriter.Indentation and Newtonsoft.Json.JsonTextWriter.IndentChar settings. - /// - bool? BodyAsJsonIndented { get; set; } + /// + /// Gets or sets a value indicating whether child objects to be indented according to the Newtonsoft.Json.JsonTextWriter.Indentation and Newtonsoft.Json.JsonTextWriter.IndentChar settings. + /// + bool? BodyAsJsonIndented { get; set; } - /// - /// The body as string, this is defined when BodyAsString or BodyAsJson are not null. - /// - string BodyAsString { get; set; } + /// + /// The body as string, this is defined when BodyAsString or BodyAsJson are not null. + /// + string BodyAsString { get; set; } - /// - /// The detected body type (detection based on body content). - /// - BodyType DetectedBodyType { get; set; } + /// + /// The detected body type (detection based on body content). + /// + BodyType? DetectedBodyType { get; set; } - /// - /// The detected body type (detection based on Content-Type). - /// - BodyType DetectedBodyTypeFromContentType { get; set; } + /// + /// The detected body type (detection based on Content-Type). + /// + BodyType? DetectedBodyTypeFromContentType { get; set; } - /// - /// The detected compression. - /// - string DetectedCompression { get; set; } + /// + /// The detected compression. + /// + string? DetectedCompression { get; set; } - /// - /// The body encoding. - /// - Encoding Encoding { get; set; } - } + /// + /// The body encoding. + /// + Encoding? Encoding { get; set; } } \ No newline at end of file diff --git a/src/WireMock.Net.Abstractions/Server/IWireMockServer.cs b/src/WireMock.Net.Abstractions/Server/IWireMockServer.cs index f24f8a4e..3393bdda 100644 --- a/src/WireMock.Net.Abstractions/Server/IWireMockServer.cs +++ b/src/WireMock.Net.Abstractions/Server/IWireMockServer.cs @@ -4,6 +4,7 @@ using System.Collections.Specialized; using JetBrains.Annotations; using WireMock.Admin.Mappings; using WireMock.Logging; +using WireMock.Matchers.Request; namespace WireMock.Server { @@ -51,7 +52,17 @@ namespace WireMock.Server /// /// Gets the first url. /// - string Url { get; } + string? Url { get; } + + /// + /// Gets the consumer. + /// + string? Consumer { get; } + + /// + /// Gets the provider. + /// + string? Provider { get; } //ConcurrentDictionary Scenarios { get; } @@ -94,7 +105,7 @@ namespace WireMock.Server //IEnumerable FindLogEntries([NotNull] params IRequestMatcher[] matchers); - //IRespondWithAProvider Given(IRequestMatcher requestMatcher, bool saveToFile = false); + // IRespondWithAProvider Given(IRequestMatcher requestMatcher, bool saveToFile = false); /// /// Reads a static mapping file and adds or updates a single mapping. @@ -102,7 +113,7 @@ namespace WireMock.Server /// Calling this method manually forces WireMock.Net to read and apply the specified static mapping file. /// /// The path to the static mapping file. - bool ReadStaticMappingAndAddOrUpdate([NotNull] string path); + bool ReadStaticMappingAndAddOrUpdate(string path); /// /// Reads the static mappings from a folder. @@ -111,7 +122,7 @@ namespace WireMock.Server /// Calling this method manually forces WireMock.Net to read and apply all static mapping files in the specified folder. /// /// The optional folder. If not defined, use {CurrentFolder}/__admin/mappings - void ReadStaticMappings([CanBeNull] string folder = null); + void ReadStaticMappings(string? folder = null); /// /// Removes the authentication. @@ -142,33 +153,33 @@ namespace WireMock.Server /// Saves the static mappings. /// /// The optional folder. If not defined, use {CurrentFolder}/__admin/mappings - void SaveStaticMappings([CanBeNull] string folder = null); + void SaveStaticMappings(string? folder = null); /// /// Sets the basic authentication. /// /// The Tenant. /// The Audience or Resource. - void SetAzureADAuthentication([NotNull] string tenant, [NotNull] string audience); + void SetAzureADAuthentication(string tenant, string audience); /// /// Sets the basic authentication. /// /// The username. /// The password. - void SetBasicAuthentication([NotNull] string username, [NotNull] string password); + void SetBasicAuthentication(string username, string password); /// /// Sets the maximum RequestLog count. /// /// The maximum RequestLog count. - void SetMaxRequestLogCount([CanBeNull] int? maxRequestLogCount); + void SetMaxRequestLogCount(int? maxRequestLogCount); /// /// Sets RequestLog expiration in hours. /// /// The RequestLog expiration in hours. - void SetRequestLogExpirationDuration([CanBeNull] int? requestLogExpirationDuration); + void SetRequestLogExpirationDuration(int? requestLogExpirationDuration); /// /// Stop this server. @@ -179,7 +190,7 @@ namespace WireMock.Server /// Watches the static mappings for changes. /// /// The optional folder. If not defined, use {CurrentFolder}/__admin/mappings - void WatchStaticMappings([CanBeNull] string folder = null); + void WatchStaticMappings(string? folder = null); /// /// Register the mappings (via ). diff --git a/src/WireMock.Net.OpenApiParser/WireMock.Net.OpenApiParser.csproj b/src/WireMock.Net.OpenApiParser/WireMock.Net.OpenApiParser.csproj index 4bdc44ff..28a64d67 100644 --- a/src/WireMock.Net.OpenApiParser/WireMock.Net.OpenApiParser.csproj +++ b/src/WireMock.Net.OpenApiParser/WireMock.Net.OpenApiParser.csproj @@ -1,36 +1,36 @@ - - An OpenApi (swagger) parser to generate MappingModel or mapping.json file. - net46;netstandard2.0;netstandard2.1 - true - wiremock;openapi;OAS;converter;parser;openapiparser - {D3804228-91F4-4502-9595-39584E5AADAD} - true - ../WireMock.Net/WireMock.Net.ruleset - true - ../WireMock.Net/WireMock.Net.snk - true - MIT - 8.0 - + + An OpenApi (swagger) parser to generate MappingModel or mapping.json file. + net46;netstandard2.0;netstandard2.1 + true + wiremock;openapi;OAS;converter;parser;openapiparser + {D3804228-91F4-4502-9595-39584E5AADAD} + true + ../WireMock.Net/WireMock.Net.ruleset + true + ../WireMock.Net/WireMock.Net.snk + true + MIT + 8.0 + - - true - + + true + - - - - - - - - - + + + + + + + + + - - - + + + \ No newline at end of file diff --git a/src/WireMock.Net/Handlers/LocalFileSystemHandler.cs b/src/WireMock.Net/Handlers/LocalFileSystemHandler.cs index e96b4779..806ce569 100644 --- a/src/WireMock.Net/Handlers/LocalFileSystemHandler.cs +++ b/src/WireMock.Net/Handlers/LocalFileSystemHandler.cs @@ -106,7 +106,7 @@ namespace WireMock.Handlers return File.Exists(AdjustPathForMappingFolder(filename)); } - /// + /// public virtual void WriteFile(string filename, byte[] bytes) { Guard.NotNullOrEmpty(filename, nameof(filename)); @@ -115,6 +115,16 @@ namespace WireMock.Handlers File.WriteAllBytes(AdjustPathForMappingFolder(filename), bytes); } + /// + public virtual void WriteFile(string folder, string filename, byte[] bytes) + { + Guard.NotNullOrEmpty(folder); + Guard.NotNullOrEmpty(filename); + Guard.NotNull(bytes); + + File.WriteAllBytes(PathUtils.Combine(folder, filename), bytes); + } + /// public virtual void DeleteFile(string filename) { diff --git a/src/WireMock.Net/Http/HttpRequestMessageHelper.cs b/src/WireMock.Net/Http/HttpRequestMessageHelper.cs index 6404002b..596ef3b1 100644 --- a/src/WireMock.Net/Http/HttpRequestMessageHelper.cs +++ b/src/WireMock.Net/Http/HttpRequestMessageHelper.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Net.Http; @@ -12,7 +12,7 @@ namespace WireMock.Http { internal static class HttpRequestMessageHelper { - internal static HttpRequestMessage Create([NotNull] RequestMessage requestMessage, [NotNull] string url) + internal static HttpRequestMessage Create([NotNull] IRequestMessage requestMessage, [NotNull] string url) { Guard.NotNull(requestMessage, nameof(requestMessage)); Guard.NotNullOrEmpty(url, nameof(url)); diff --git a/src/WireMock.Net/Http/WebhookSender.cs b/src/WireMock.Net/Http/WebhookSender.cs index aa18eb6d..628807a1 100644 --- a/src/WireMock.Net/Http/WebhookSender.cs +++ b/src/WireMock.Net/Http/WebhookSender.cs @@ -26,7 +26,7 @@ namespace WireMock.Http _settings = settings ?? throw new ArgumentNullException(nameof(settings)); } - public Task SendAsync([NotNull] HttpClient client, [NotNull] IWebhookRequest request, [NotNull] RequestMessage originalRequestMessage, [NotNull] ResponseMessage originalResponseMessage) + public Task SendAsync([NotNull] HttpClient client, [NotNull] IWebhookRequest request, [NotNull] IRequestMessage originalRequestMessage, [NotNull] IResponseMessage originalResponseMessage) { Guard.NotNull(client, nameof(client)); Guard.NotNull(request, nameof(request)); diff --git a/src/WireMock.Net/IMapping.cs b/src/WireMock.Net/IMapping.cs index b4bbaff9..e088cf91 100644 --- a/src/WireMock.Net/IMapping.cs +++ b/src/WireMock.Net/IMapping.cs @@ -28,6 +28,11 @@ namespace WireMock /// string Title { get; } + /// + /// Gets the description. + /// + string Description { get; } + /// /// The full filename path for this mapping (only defined for static mappings). /// @@ -117,7 +122,7 @@ namespace WireMock /// /// The request message. /// The including a new (optional) . - Task<(ResponseMessage Message, IMapping Mapping)> ProvideResponseAsync(RequestMessage requestMessage); + Task<(IResponseMessage Message, IMapping Mapping)> ProvideResponseAsync(IRequestMessage requestMessage); /// /// Gets the RequestMatchResult based on the RequestMessage. @@ -125,6 +130,6 @@ namespace WireMock /// The request message. /// The Next State. /// The . - RequestMatchResult GetRequestMatchResult(RequestMessage requestMessage, [CanBeNull] string nextState); + IRequestMatchResult GetRequestMatchResult(IRequestMessage requestMessage, [CanBeNull] string nextState); } } \ No newline at end of file diff --git a/src/WireMock.Net/Mapping.cs b/src/WireMock.Net/Mapping.cs index a43b2389..e3fd18c6 100644 --- a/src/WireMock.Net/Mapping.cs +++ b/src/WireMock.Net/Mapping.cs @@ -19,6 +19,9 @@ namespace WireMock /// public string Title { get; } + /// + public string Description { get; } + /// public string Path { get; set; } @@ -69,6 +72,7 @@ namespace WireMock /// /// The unique identifier. /// The unique title (can be null). + /// The description (can be null). /// The full file path from this mapping title (can be null). /// The WireMockServerSettings. /// The request matcher. @@ -82,21 +86,23 @@ namespace WireMock /// The TimeSettings. [Optional] public Mapping( Guid guid, - [CanBeNull] string title, - [CanBeNull] string path, - [NotNull] WireMockServerSettings settings, - [NotNull] IRequestMatcher requestMatcher, - [NotNull] IResponseProvider provider, + string? title, + string? description, + string? path, + WireMockServerSettings settings, + IRequestMatcher requestMatcher, + IResponseProvider provider, int priority, - [CanBeNull] string scenario, - [CanBeNull] string executionConditionState, - [CanBeNull] string nextState, - [CanBeNull] int? stateTimes, - [CanBeNull] IWebhook[] webhooks, - [CanBeNull] ITimeSettings timeSettings) + string? scenario, + string? executionConditionState, + string? nextState, + int? stateTimes, + IWebhook[]? webhooks, + ITimeSettings? timeSettings) { Guid = guid; Title = title; + Description = description; Path = path; Settings = settings; RequestMatcher = requestMatcher; @@ -111,13 +117,13 @@ namespace WireMock } /// - public Task<(ResponseMessage Message, IMapping Mapping)> ProvideResponseAsync(RequestMessage requestMessage) + public Task<(IResponseMessage Message, IMapping Mapping)> ProvideResponseAsync(IRequestMessage requestMessage) { return Provider.ProvideResponseAsync(requestMessage, Settings); } /// - public RequestMatchResult GetRequestMatchResult(RequestMessage requestMessage, string nextState) + public IRequestMatchResult GetRequestMatchResult(IRequestMessage requestMessage, string nextState) { var result = new RequestMatchResult(); diff --git a/src/WireMock.Net/Matchers/Request/RequestMessageBodyMatcher.cs b/src/WireMock.Net/Matchers/Request/RequestMessageBodyMatcher.cs index 36d3a3da..a6fd558d 100644 --- a/src/WireMock.Net/Matchers/Request/RequestMessageBodyMatcher.cs +++ b/src/WireMock.Net/Matchers/Request/RequestMessageBodyMatcher.cs @@ -114,8 +114,8 @@ namespace WireMock.Matchers.Request Matchers = matchers; } - /// - public double GetMatchingScore(IRequestMessage requestMessage, RequestMatchResult requestMatchResult) + /// + public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult) { double score = CalculateMatchScore(requestMessage); return requestMatchResult.AddScore(GetType(), score); diff --git a/src/WireMock.Net/Matchers/Request/RequestMessageClientIPMatcher.cs b/src/WireMock.Net/Matchers/Request/RequestMessageClientIPMatcher.cs index 52096ac9..a6eacaa6 100644 --- a/src/WireMock.Net/Matchers/Request/RequestMessageClientIPMatcher.cs +++ b/src/WireMock.Net/Matchers/Request/RequestMessageClientIPMatcher.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using JetBrains.Annotations; @@ -50,8 +50,8 @@ namespace WireMock.Matchers.Request Funcs = funcs; } - /// - public double GetMatchingScore(IRequestMessage requestMessage, RequestMatchResult requestMatchResult) + /// + public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult) { double score = IsMatch(requestMessage); return requestMatchResult.AddScore(GetType(), score); diff --git a/src/WireMock.Net/Matchers/Request/RequestMessageCompositeMatcher.cs b/src/WireMock.Net/Matchers/Request/RequestMessageCompositeMatcher.cs index c831c88f..1dcca5d8 100644 --- a/src/WireMock.Net/Matchers/Request/RequestMessageCompositeMatcher.cs +++ b/src/WireMock.Net/Matchers/Request/RequestMessageCompositeMatcher.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using JetBrains.Annotations; using Stef.Validation; @@ -33,8 +33,8 @@ namespace WireMock.Matchers.Request RequestMatchers = requestMatchers; } - /// - public double GetMatchingScore(IRequestMessage requestMessage, RequestMatchResult requestMatchResult) + /// + public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult) { if (!RequestMatchers.Any()) { diff --git a/src/WireMock.Net/Matchers/Request/RequestMessageCookieMatcher.cs b/src/WireMock.Net/Matchers/Request/RequestMessageCookieMatcher.cs index d9cb5c52..e3d56755 100644 --- a/src/WireMock.Net/Matchers/Request/RequestMessageCookieMatcher.cs +++ b/src/WireMock.Net/Matchers/Request/RequestMessageCookieMatcher.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using JetBrains.Annotations; @@ -90,8 +90,8 @@ namespace WireMock.Matchers.Request Funcs = funcs; } - /// - public double GetMatchingScore(IRequestMessage requestMessage, RequestMatchResult requestMatchResult) + /// + public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult) { double score = IsMatch(requestMessage); return requestMatchResult.AddScore(GetType(), score); diff --git a/src/WireMock.Net/Matchers/Request/RequestMessageHeaderMatcher.cs b/src/WireMock.Net/Matchers/Request/RequestMessageHeaderMatcher.cs index a66fd1a1..b0c7484a 100644 --- a/src/WireMock.Net/Matchers/Request/RequestMessageHeaderMatcher.cs +++ b/src/WireMock.Net/Matchers/Request/RequestMessageHeaderMatcher.cs @@ -1,4 +1,4 @@ -using JetBrains.Annotations; +using JetBrains.Annotations; using System; using System.Collections.Generic; using System.Linq; @@ -91,8 +91,8 @@ namespace WireMock.Matchers.Request Funcs = funcs; } - /// - public double GetMatchingScore(IRequestMessage requestMessage, RequestMatchResult requestMatchResult) + /// + public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult) { double score = IsMatch(requestMessage); return requestMatchResult.AddScore(GetType(), score); diff --git a/src/WireMock.Net/Matchers/Request/RequestMessageMethodMatcher.cs b/src/WireMock.Net/Matchers/Request/RequestMessageMethodMatcher.cs index 73c49cd8..8ce1fc2b 100644 --- a/src/WireMock.Net/Matchers/Request/RequestMessageMethodMatcher.cs +++ b/src/WireMock.Net/Matchers/Request/RequestMessageMethodMatcher.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Linq; using JetBrains.Annotations; using Stef.Validation; @@ -30,8 +30,8 @@ namespace WireMock.Matchers.Request Methods = methods; } - /// - public double GetMatchingScore(IRequestMessage requestMessage, RequestMatchResult requestMatchResult) + /// + public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult) { double score = MatchBehaviourHelper.Convert(_matchBehaviour, IsMatch(requestMessage)); return requestMatchResult.AddScore(GetType(), score); diff --git a/src/WireMock.Net/Matchers/Request/RequestMessageParamMatcher.cs b/src/WireMock.Net/Matchers/Request/RequestMessageParamMatcher.cs index 65055d2e..ac6bf23e 100644 --- a/src/WireMock.Net/Matchers/Request/RequestMessageParamMatcher.cs +++ b/src/WireMock.Net/Matchers/Request/RequestMessageParamMatcher.cs @@ -1,4 +1,4 @@ -using JetBrains.Annotations; +using JetBrains.Annotations; using System; using System.Collections.Generic; using System.Linq; @@ -83,8 +83,8 @@ namespace WireMock.Matchers.Request Funcs = funcs; } - /// - public double GetMatchingScore(IRequestMessage requestMessage, RequestMatchResult requestMatchResult) + /// + public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult) { double score = MatchBehaviourHelper.Convert(_matchBehaviour, IsMatch(requestMessage)); return requestMatchResult.AddScore(GetType(), score); diff --git a/src/WireMock.Net/Matchers/Request/RequestMessagePathMatcher.cs b/src/WireMock.Net/Matchers/Request/RequestMessagePathMatcher.cs index 63edf8b5..fbd0a38c 100644 --- a/src/WireMock.Net/Matchers/Request/RequestMessagePathMatcher.cs +++ b/src/WireMock.Net/Matchers/Request/RequestMessagePathMatcher.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using JetBrains.Annotations; @@ -53,7 +53,7 @@ namespace WireMock.Matchers.Request } /// - public double GetMatchingScore(IRequestMessage requestMessage, RequestMatchResult requestMatchResult) + public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult) { double score = IsMatch(requestMessage); return requestMatchResult.AddScore(GetType(), score); diff --git a/src/WireMock.Net/Matchers/Request/RequestMessageScenarioAndStateMatcher.cs b/src/WireMock.Net/Matchers/Request/RequestMessageScenarioAndStateMatcher.cs index 2741dcc0..cb374019 100644 --- a/src/WireMock.Net/Matchers/Request/RequestMessageScenarioAndStateMatcher.cs +++ b/src/WireMock.Net/Matchers/Request/RequestMessageScenarioAndStateMatcher.cs @@ -1,4 +1,4 @@ -using JetBrains.Annotations; +using JetBrains.Annotations; namespace WireMock.Matchers.Request { @@ -32,7 +32,7 @@ namespace WireMock.Matchers.Request } /// - public double GetMatchingScore(IRequestMessage requestMessage, RequestMatchResult requestMatchResult) + public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult) { double score = IsMatch(); return requestMatchResult.AddScore(GetType(), score); diff --git a/src/WireMock.Net/Matchers/Request/RequestMessageUrlMatcher.cs b/src/WireMock.Net/Matchers/Request/RequestMessageUrlMatcher.cs index 092016a8..9935eb5f 100644 --- a/src/WireMock.Net/Matchers/Request/RequestMessageUrlMatcher.cs +++ b/src/WireMock.Net/Matchers/Request/RequestMessageUrlMatcher.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using JetBrains.Annotations; @@ -50,8 +50,8 @@ namespace WireMock.Matchers.Request Funcs = funcs; } - /// - public double GetMatchingScore(IRequestMessage requestMessage, RequestMatchResult requestMatchResult) + /// + public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult) { double score = IsMatch(requestMessage); return requestMatchResult.AddScore(GetType(), score); diff --git a/src/WireMock.Net/Models/BodyData.cs b/src/WireMock.Net/Models/BodyData.cs index 1e7d54e0..10319cdb 100644 --- a/src/WireMock.Net/Models/BodyData.cs +++ b/src/WireMock.Net/Models/BodyData.cs @@ -1,4 +1,4 @@ -using System.Text; +using System.Text; using WireMock.Types; namespace WireMock.Util @@ -9,33 +9,33 @@ namespace WireMock.Util public class BodyData : IBodyData { /// - public Encoding Encoding { get; set; } + public Encoding? Encoding { get; set; } /// - public string BodyAsString { get; set; } + public string? BodyAsString { get; set; } /// - public object BodyAsJson { get; set; } + public object? BodyAsJson { get; set; } /// - public byte[] BodyAsBytes { get; set; } + public byte[]? BodyAsBytes { get; set; } /// public bool? BodyAsJsonIndented { get; set; } /// - public string BodyAsFile { get; set; } + public string? BodyAsFile { get; set; } /// public bool? BodyAsFileIsCached { get; set; } /// - public BodyType DetectedBodyType { get; set; } + public BodyType? DetectedBodyType { get; set; } /// - public BodyType DetectedBodyTypeFromContentType { get; set; } + public BodyType? DetectedBodyTypeFromContentType { get; set; } /// - public string DetectedCompression { get; set; } + public string? DetectedCompression { get; set; } } } \ No newline at end of file diff --git a/src/WireMock.Net/Owin/IWireMockMiddlewareOptions.cs b/src/WireMock.Net/Owin/IWireMockMiddlewareOptions.cs index 5691514c..92e7c847 100644 --- a/src/WireMock.Net/Owin/IWireMockMiddlewareOptions.cs +++ b/src/WireMock.Net/Owin/IWireMockMiddlewareOptions.cs @@ -4,7 +4,6 @@ using WireMock.Handlers; using WireMock.Logging; using WireMock.Matchers; using WireMock.Util; -using JetBrains.Annotations; using WireMock.Types; #if !USE_ASPNETCORE using Owin; @@ -21,7 +20,7 @@ namespace WireMock.Owin TimeSpan? RequestProcessingDelay { get; set; } - IStringMatcher AuthenticationMatcher { get; set; } + IStringMatcher? AuthenticationMatcher { get; set; } bool? AllowPartialMapping { get; set; } @@ -35,17 +34,17 @@ namespace WireMock.Owin int? MaxRequestLogCount { get; set; } - Action PreWireMockMiddlewareInit { get; set; } + Action? PreWireMockMiddlewareInit { get; set; } - Action PostWireMockMiddlewareInit { get; set; } + Action? PostWireMockMiddlewareInit { get; set; } #if USE_ASPNETCORE - Action AdditionalServiceRegistration { get; set; } + Action? AdditionalServiceRegistration { get; set; } CorsPolicyOptions? CorsPolicyOptions { get; set; } #endif - IFileSystemHandler FileSystemHandler { get; set; } + IFileSystemHandler? FileSystemHandler { get; set; } bool? AllowBodyForAllHttpMethods { get; set; } @@ -57,15 +56,15 @@ namespace WireMock.Owin bool? HandleRequestsSynchronously { get; set; } - string X509StoreName { get; set; } + string? X509StoreName { get; set; } - string X509StoreLocation { get; set; } + string? X509StoreLocation { get; set; } - string X509ThumbprintOrSubjectName { get; set; } + string? X509ThumbprintOrSubjectName { get; set; } - string X509CertificateFilePath { get; set; } + string? X509CertificateFilePath { get; set; } - string X509CertificatePassword { get; set; } + string? X509CertificatePassword { get; set; } bool CustomCertificateDefined { get; } diff --git a/src/WireMock.Net/Owin/Mappers/IOwinResponseMapper.cs b/src/WireMock.Net/Owin/Mappers/IOwinResponseMapper.cs index 14420938..461e5c39 100644 --- a/src/WireMock.Net/Owin/Mappers/IOwinResponseMapper.cs +++ b/src/WireMock.Net/Owin/Mappers/IOwinResponseMapper.cs @@ -1,4 +1,4 @@ -using System.Threading.Tasks; +using System.Threading.Tasks; #if !USE_ASPNETCORE using IResponse = Microsoft.Owin.IOwinResponse; #else @@ -17,6 +17,6 @@ namespace WireMock.Owin.Mappers /// /// The ResponseMessage /// The OwinResponse/HttpResponse - Task MapAsync(ResponseMessage responseMessage, IResponse response); + Task MapAsync(IResponseMessage responseMessage, IResponse response); } } \ No newline at end of file diff --git a/src/WireMock.Net/Owin/Mappers/OwinResponseMapper.cs b/src/WireMock.Net/Owin/Mappers/OwinResponseMapper.cs index efcfee1a..ff2649a9 100644 --- a/src/WireMock.Net/Owin/Mappers/OwinResponseMapper.cs +++ b/src/WireMock.Net/Owin/Mappers/OwinResponseMapper.cs @@ -53,7 +53,7 @@ namespace WireMock.Owin.Mappers } /// - public async Task MapAsync(ResponseMessage responseMessage, IResponse response) + public async Task MapAsync(IResponseMessage responseMessage, IResponse response) { if (responseMessage == null) { @@ -117,12 +117,12 @@ namespace WireMock.Owin.Mappers return code; } - private bool IsFault(ResponseMessage responseMessage) + private bool IsFault(IResponseMessage responseMessage) { return responseMessage.FaultPercentage == null || _randomizerDouble.Generate() <= responseMessage.FaultPercentage; } - private byte[] GetNormalBody(ResponseMessage responseMessage) + private byte[] GetNormalBody(IResponseMessage responseMessage) { byte[] bytes = null; switch (responseMessage.BodyData?.DetectedBodyType) @@ -151,7 +151,7 @@ namespace WireMock.Owin.Mappers return bytes; } - private static void SetResponseHeaders(ResponseMessage responseMessage, IResponse response) + private static void SetResponseHeaders(IResponseMessage responseMessage, IResponse response) { // Force setting the Date header (#577) AppendResponseHeader( diff --git a/src/WireMock.Net/Owin/MappingMatcherResult.cs b/src/WireMock.Net/Owin/MappingMatcherResult.cs index c479bd46..509327d6 100644 --- a/src/WireMock.Net/Owin/MappingMatcherResult.cs +++ b/src/WireMock.Net/Owin/MappingMatcherResult.cs @@ -1,4 +1,4 @@ -using WireMock.Matchers.Request; +using WireMock.Matchers.Request; namespace WireMock.Owin { @@ -6,6 +6,6 @@ namespace WireMock.Owin { public IMapping Mapping { get; set; } - public RequestMatchResult RequestMatchResult { get; set; } + public IRequestMatchResult RequestMatchResult { get; set; } } } \ No newline at end of file diff --git a/src/WireMock.Net/Owin/WireMockMiddleware.cs b/src/WireMock.Net/Owin/WireMockMiddleware.cs index 94ed7bca..80dc8d12 100644 --- a/src/WireMock.Net/Owin/WireMockMiddleware.cs +++ b/src/WireMock.Net/Owin/WireMockMiddleware.cs @@ -72,7 +72,7 @@ namespace WireMock.Owin var request = await _requestMapper.MapAsync(ctx.Request, _options).ConfigureAwait(false); var logRequest = false; - ResponseMessage response = null; + IResponseMessage response = null; (MappingMatcherResult Match, MappingMatcherResult Partial) result = (null, null); try { @@ -192,7 +192,7 @@ namespace WireMock.Owin await CompletedTask.ConfigureAwait(false); } - private async Task SendToWebhooksAsync(IMapping mapping, RequestMessage request, ResponseMessage response) + private async Task SendToWebhooksAsync(IMapping mapping, IRequestMessage request, IResponseMessage response) { for (int index = 0; index < mapping.Webhooks.Length; index++) { diff --git a/src/WireMock.Net/Pact/Models/V2/Interaction.cs b/src/WireMock.Net/Pact/Models/V2/Interaction.cs new file mode 100644 index 00000000..66feeaa7 --- /dev/null +++ b/src/WireMock.Net/Pact/Models/V2/Interaction.cs @@ -0,0 +1,13 @@ +namespace WireMock.Pact.Models.V2 +{ + public class Interaction + { + public string Description { get; set; } = string.Empty; + + public string ProviderState { get; set; } + + public Request Request { get; set; } = new Request(); + + public Response Response { get; set; } = new Response(); + } +} \ No newline at end of file diff --git a/src/WireMock.Net/Pact/Models/V2/MatchingRule.cs b/src/WireMock.Net/Pact/Models/V2/MatchingRule.cs new file mode 100644 index 00000000..f5b147a4 --- /dev/null +++ b/src/WireMock.Net/Pact/Models/V2/MatchingRule.cs @@ -0,0 +1,25 @@ +namespace WireMock.Pact.Models.V2 +{ + public class MatchingRule + { + /// + /// type or regex + /// + public string Match { get; set; } = "type"; + + /// + /// Used for Match = "type" + /// + public string Min { get; set; } + + /// + /// Used for Match = "type" + /// + public string Max { get; set; } + + /// + /// Used for Match = "regex" + /// + public string Regex { get; set; } + } +} \ No newline at end of file diff --git a/src/WireMock.Net/Pact/Models/V2/Metadata.cs b/src/WireMock.Net/Pact/Models/V2/Metadata.cs new file mode 100644 index 00000000..fbae2808 --- /dev/null +++ b/src/WireMock.Net/Pact/Models/V2/Metadata.cs @@ -0,0 +1,9 @@ +namespace WireMock.Pact.Models.V2 +{ + public class Metadata + { + public string PactSpecificationVersion { get; set; } + + public PactSpecification PactSpecification { get; set; } = new PactSpecification(); + } +} \ No newline at end of file diff --git a/src/WireMock.Net/Pact/Models/V2/Pact.cs b/src/WireMock.Net/Pact/Models/V2/Pact.cs new file mode 100644 index 00000000..9c75f80a --- /dev/null +++ b/src/WireMock.Net/Pact/Models/V2/Pact.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; + +namespace WireMock.Pact.Models.V2 +{ + public class Pact + { + public Pacticipant Consumer { get; set; } + + public List Interactions { get; set; } = new List(); + + public Metadata Metadata { get; set; } + + public Pacticipant Provider { get; set; } + } +} \ No newline at end of file diff --git a/src/WireMock.Net/Pact/Models/V2/PactRust.cs b/src/WireMock.Net/Pact/Models/V2/PactRust.cs new file mode 100644 index 00000000..70347ca9 --- /dev/null +++ b/src/WireMock.Net/Pact/Models/V2/PactRust.cs @@ -0,0 +1,11 @@ +namespace WireMock.Pact.Models.V2 +{ + public class PactRust + { + public string Ffi { get; set; } + + public string Mockserver { get; set; } + + public string Models { get; set; } + } +} \ No newline at end of file diff --git a/src/WireMock.Net/Pact/Models/V2/PactSpecification.cs b/src/WireMock.Net/Pact/Models/V2/PactSpecification.cs new file mode 100644 index 00000000..de7309be --- /dev/null +++ b/src/WireMock.Net/Pact/Models/V2/PactSpecification.cs @@ -0,0 +1,7 @@ +namespace WireMock.Pact.Models.V2 +{ + public class PactSpecification + { + public string Version { get; set; } = "2.0"; + } +} \ No newline at end of file diff --git a/src/WireMock.Net/Pact/Models/V2/Pacticipant.cs b/src/WireMock.Net/Pact/Models/V2/Pacticipant.cs new file mode 100644 index 00000000..3077835e --- /dev/null +++ b/src/WireMock.Net/Pact/Models/V2/Pacticipant.cs @@ -0,0 +1,7 @@ +namespace WireMock.Pact.Models.V2 +{ + public class Pacticipant + { + public string Name { get; set; } + } +} \ No newline at end of file diff --git a/src/WireMock.Net/Pact/Models/V2/ProviderState.cs b/src/WireMock.Net/Pact/Models/V2/ProviderState.cs new file mode 100644 index 00000000..0d163cc8 --- /dev/null +++ b/src/WireMock.Net/Pact/Models/V2/ProviderState.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; + +namespace WireMock.Pact.Models.V2 +{ + public class ProviderState + { + public string Name { get; set; } + + public IDictionary Params { get; set; } + } +} \ No newline at end of file diff --git a/src/WireMock.Net/Pact/Models/V2/Request.cs b/src/WireMock.Net/Pact/Models/V2/Request.cs new file mode 100644 index 00000000..9d5f5f2b --- /dev/null +++ b/src/WireMock.Net/Pact/Models/V2/Request.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; + +namespace WireMock.Pact.Models.V2; + +public class Request +{ + public IDictionary? Headers { get; set; } + + public string Method { get; set; } = "GET"; + + public string? Path { get; set; } = "/"; + + public string? Query { get; set; } + + public object? Body { get; set; } +} \ No newline at end of file diff --git a/src/WireMock.Net/Pact/Models/V2/Response.cs b/src/WireMock.Net/Pact/Models/V2/Response.cs new file mode 100644 index 00000000..6abf9a5f --- /dev/null +++ b/src/WireMock.Net/Pact/Models/V2/Response.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; + +namespace WireMock.Pact.Models.V2; + +public class Response +{ + public object? Body { get; set; } + + public IDictionary? Headers { get; set; } + + public int Status { get; set; } = 200; +} \ No newline at end of file diff --git a/src/WireMock.Net/Pact/Models/V2/_v2.json b/src/WireMock.Net/Pact/Models/V2/_v2.json new file mode 100644 index 00000000..b4ae7349 --- /dev/null +++ b/src/WireMock.Net/Pact/Models/V2/_v2.json @@ -0,0 +1,206 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema", + "definitions": { + "headers": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + }, + "interaction": { + "additionalProperties": false, + "properties": { + "description": { + "type": "string" + }, + "providerState": { + "type": "string" + }, + "request": { + "$ref": "#/definitions/request" + }, + "response": { + "$ref": "#/definitions/response" + } + }, + "required": [ + "description", + "request", + "response" + ], + "type": "object" + }, + "interactions": { + "items": { + "$ref": "#/definitions/interaction" + }, + "type": "array" + }, + "matchingRules": { + "additionalProperties": false, + "patternProperties": { + "^\\$.*$": { + "oneOf": [ + { + "additionalProperties": false, + "properties": { + "match": { + "enum": [ "type" ], + "type": "string" + }, + "max": { + "type": "number" + }, + "min": { + "type": "number" + } + }, + "required": [ "match" ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "match": { + "enum": [ "regex" ], + "type": "string" + }, + "regex": { + "type": "string" + } + }, + "required": [ + "match", + "regex" + ], + "type": "object" + } + ] + } + }, + "type": "object" + }, + "metadata": { + "properties": { + "pactSpecification": { + "additionalProperties": false, + "properties": { + "version": { + "type": "string" + } + }, + "required": [ "version" ], + "type": "object" + }, + "pactSpecificationVersion": { + "type": "string" + }, + "pact-specification": { + "additionalProperties": false, + "properties": { + "version": { + "type": "string" + } + }, + "required": [ "version" ], + "type": "object" + } + }, + "type": "object" + }, + "pacticipant": { + "properties": { + "name": { + "type": "string" + } + }, + "required": [ "name" ], + "type": "object" + }, + "request": { + "additionalProperties": false, + "properties": { + "body": {}, + "headers": { + "$ref": "#/definitions/headers" + }, + "matchingRules": { + "$ref": "#/definitions/matchingRules" + }, + "method": { + "enum": [ + "connect", + "CONNECT", + "delete", + "DELETE", + "get", + "GET", + "head", + "HEAD", + "options", + "OPTIONS", + "post", + "POST", + "put", + "PUT", + "trace", + "TRACE" + ], + "type": "string" + }, + "path": { + "type": "string" + }, + "query": { + "pattern": "^$|^[^=&]+=[^=&]+&?$|^[^=&]+=[^=&]+(&[^=&]+=[^=&]+)*&?$", + "type": "string" + } + }, + "required": [ + "method", + "path" + ], + "type": "object" + }, + "response": { + "additionalProperties": false, + "properties": { + "body": {}, + "headers": { + "$ref": "#/definitions/headers" + }, + "matchingRules": { + "$ref": "#/definitions/matchingRules" + }, + "status": { + "maximum": 599, + "minimum": 100, + "type": "integer" + } + }, + "required": [ "status" ], + "type": "object" + } + }, + "description": "Schema for a Pact file", + "properties": { + "consumer": { + "$ref": "#/definitions/pacticipant" + }, + "interactions": { + "$ref": "#/definitions/interactions" + }, + "metadata": { + "$ref": "#/definitions/metadata" + }, + "provider": { + "$ref": "#/definitions/pacticipant" + } + }, + "required": [ + "consumer", + "interactions", + "provider" + ], + "type": "object" +} diff --git a/src/WireMock.Net/Properties/AssemblyInfo.cs b/src/WireMock.Net/Properties/AssemblyInfo.cs index 4d736963..5aa4c57c 100644 --- a/src/WireMock.Net/Properties/AssemblyInfo.cs +++ b/src/WireMock.Net/Properties/AssemblyInfo.cs @@ -1,8 +1,8 @@ -using System.Runtime.CompilerServices; +using System.Runtime.CompilerServices; [assembly: InternalsVisibleTo("WireMock.Net.Matchers.CSharpCode, PublicKey=0024000004800000940000000602000000240000525341310004000001000100e138ec44d93acac565953052636eb8d5e7e9f27ddb030590055cd1a0ab2069a5623f1f77ca907d78e0b37066ca0f6d63da7eecc3fcb65b76aa8ebeccf7ebe1d11264b8404cd9b1cbbf2c83f566e033b3e54129f6ef28daffff776ba7aebbc53c0d635ebad8f45f78eb3f7e0459023c218f003416e080f96a1a3c5ffeb56bee9e")] [assembly: InternalsVisibleTo("WireMock.Net.StandAlone, PublicKey=0024000004800000940000000602000000240000525341310004000001000100e138ec44d93acac565953052636eb8d5e7e9f27ddb030590055cd1a0ab2069a5623f1f77ca907d78e0b37066ca0f6d63da7eecc3fcb65b76aa8ebeccf7ebe1d11264b8404cd9b1cbbf2c83f566e033b3e54129f6ef28daffff776ba7aebbc53c0d635ebad8f45f78eb3f7e0459023c218f003416e080f96a1a3c5ffeb56bee9e")] [assembly: InternalsVisibleTo("WireMock.Net.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100e138ec44d93acac565953052636eb8d5e7e9f27ddb030590055cd1a0ab2069a5623f1f77ca907d78e0b37066ca0f6d63da7eecc3fcb65b76aa8ebeccf7ebe1d11264b8404cd9b1cbbf2c83f566e033b3e54129f6ef28daffff776ba7aebbc53c0d635ebad8f45f78eb3f7e0459023c218f003416e080f96a1a3c5ffeb56bee9e")] // Needed for Moq in the UnitTest project -[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")] \ No newline at end of file +[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")] \ No newline at end of file diff --git a/src/WireMock.Net/Proxy/ProxyHelper.cs b/src/WireMock.Net/Proxy/ProxyHelper.cs index a833989a..ccc069c8 100644 --- a/src/WireMock.Net/Proxy/ProxyHelper.cs +++ b/src/WireMock.Net/Proxy/ProxyHelper.cs @@ -24,10 +24,10 @@ namespace WireMock.Proxy _settings = Guard.NotNull(settings, nameof(settings)); } - public async Task<(ResponseMessage Message, IMapping Mapping)> SendAsync( + public async Task<(IResponseMessage Message, IMapping Mapping)> SendAsync( [NotNull] ProxyAndRecordSettings proxyAndRecordSettings, [NotNull] HttpClient client, - [NotNull] RequestMessage requestMessage, + [NotNull] IRequestMessage requestMessage, [NotNull] string url) { Guard.NotNull(client, nameof(client)); @@ -59,7 +59,7 @@ namespace WireMock.Proxy return (responseMessage, mapping); } - private IMapping ToMapping(ProxyAndRecordSettings proxyAndRecordSettings, RequestMessage requestMessage, ResponseMessage responseMessage) + private IMapping ToMapping(ProxyAndRecordSettings proxyAndRecordSettings, IRequestMessage requestMessage, ResponseMessage responseMessage) { string[] excludedHeaders = proxyAndRecordSettings.ExcludedHeaders ?? new string[] { }; string[] excludedCookies = proxyAndRecordSettings.ExcludedCookies ?? new string[] { }; @@ -104,7 +104,7 @@ namespace WireMock.Proxy var response = Response.Create(responseMessage); - return new Mapping(Guid.NewGuid(), string.Empty, null, _settings, request, response, 0, null, null, null, null, null, null); + return new Mapping(Guid.NewGuid(), string.Empty, string.Empty, null, _settings, request, response, 0, null, null, null, null, null, null); } } } \ No newline at end of file diff --git a/src/WireMock.Net/ResponseBuilders/IBodyResponseBuilder.cs b/src/WireMock.Net/ResponseBuilders/IBodyResponseBuilder.cs index 21a90f23..19ec4a00 100644 --- a/src/WireMock.Net/ResponseBuilders/IBodyResponseBuilder.cs +++ b/src/WireMock.Net/ResponseBuilders/IBodyResponseBuilder.cs @@ -1,4 +1,3 @@ -using JetBrains.Annotations; using System; using System.Text; using System.Threading.Tasks; @@ -17,7 +16,7 @@ namespace WireMock.ResponseBuilders /// The Body Destination format (SameAsSource, String or Bytes). /// The body encoding. /// A . - IResponseBuilder WithBody([NotNull] string body, [CanBeNull] string destination = BodyDestinationFormat.SameAsSource, [CanBeNull] Encoding encoding = null); + IResponseBuilder WithBody(string body, string? destination = BodyDestinationFormat.SameAsSource, Encoding? encoding = null); /// /// WithBody : Create a ... response based on a callback function. @@ -26,7 +25,7 @@ namespace WireMock.ResponseBuilders /// The Body Destination format (SameAsSource, String or Bytes). /// The body encoding. /// A . - IResponseBuilder WithBody([NotNull] Func bodyFactory, [CanBeNull] string destination = BodyDestinationFormat.SameAsSource, [CanBeNull] Encoding encoding = null); + IResponseBuilder WithBody(Func bodyFactory, string? destination = BodyDestinationFormat.SameAsSource, Encoding? encoding = null); /// /// WithBody : Create a ... response based on a callback function. @@ -35,7 +34,7 @@ namespace WireMock.ResponseBuilders /// The Body Destination format (SameAsSource, String or Bytes). /// The body encoding. /// A . - IResponseBuilder WithBody([NotNull] Func> bodyFactory, [CanBeNull] string destination = BodyDestinationFormat.SameAsSource, [CanBeNull] Encoding encoding = null); + IResponseBuilder WithBody(Func> bodyFactory, string? destination = BodyDestinationFormat.SameAsSource, Encoding? encoding = null); /// /// WithBody : Create a ... response based on a bytearray. @@ -44,7 +43,7 @@ namespace WireMock.ResponseBuilders /// The Body Destination format (SameAsSource, String or Bytes). /// The body encoding. /// A . - IResponseBuilder WithBody([NotNull] byte[] body, [CanBeNull] string destination = BodyDestinationFormat.SameAsSource, [CanBeNull] Encoding encoding = null); + IResponseBuilder WithBody(byte[] body, string? destination = BodyDestinationFormat.SameAsSource, Encoding? encoding = null); /// /// WithBody : Create a string response based on a object (which will be converted to a JSON string). @@ -53,7 +52,7 @@ namespace WireMock.ResponseBuilders /// The body encoding. /// Use JSON indented. /// A . - IResponseBuilder WithBodyAsJson([NotNull] object body, [CanBeNull] Encoding encoding = null, bool? indented = null); + IResponseBuilder WithBodyAsJson(object body, Encoding? encoding = null, bool? indented = null); /// /// WithBody : Create a string response based on a object (which will be converted to a JSON string). @@ -61,7 +60,7 @@ namespace WireMock.ResponseBuilders /// The body. /// Define whether child objects to be indented according to the Newtonsoft.Json.JsonTextWriter.Indentation and Newtonsoft.Json.JsonTextWriter.IndentChar settings. /// A . - IResponseBuilder WithBodyAsJson([NotNull] object body, bool indented); + IResponseBuilder WithBodyAsJson(object body, bool indented); /// /// WithBodyFromFile : Create a ... response based on a File. @@ -69,6 +68,6 @@ namespace WireMock.ResponseBuilders /// The filename. /// Defines if this file is cached in memory or retrieved from disk every time the response is created. /// A . - IResponseBuilder WithBodyFromFile([NotNull] string filename, bool cache = true); + IResponseBuilder WithBodyFromFile(string filename, bool cache = true); } } \ No newline at end of file diff --git a/src/WireMock.Net/ResponseBuilders/ICallbackResponseBuilder.cs b/src/WireMock.Net/ResponseBuilders/ICallbackResponseBuilder.cs index 27ddec15..1011cbbc 100644 --- a/src/WireMock.Net/ResponseBuilders/ICallbackResponseBuilder.cs +++ b/src/WireMock.Net/ResponseBuilders/ICallbackResponseBuilder.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Threading.Tasks; using JetBrains.Annotations; using WireMock.ResponseProviders; @@ -15,13 +15,13 @@ namespace WireMock.ResponseBuilders /// /// The . [PublicAPI] - IResponseBuilder WithCallback([NotNull] Func callbackHandler); + IResponseBuilder WithCallback([NotNull] Func callbackHandler); /// /// The async callback builder /// /// The . [PublicAPI] - IResponseBuilder WithCallback([NotNull] Func> callbackHandler); + IResponseBuilder WithCallback([NotNull] Func> callbackHandler); } } \ No newline at end of file diff --git a/src/WireMock.Net/ResponseBuilders/Response.WithCallback.cs b/src/WireMock.Net/ResponseBuilders/Response.WithCallback.cs index 438268f8..c9d9e3de 100644 --- a/src/WireMock.Net/ResponseBuilders/Response.WithCallback.cs +++ b/src/WireMock.Net/ResponseBuilders/Response.WithCallback.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Threading.Tasks; using Stef.Validation; @@ -9,35 +9,35 @@ namespace WireMock.ResponseBuilders /// /// A delegate to execute to generate the response. /// - public Func Callback { get; private set; } + public Func Callback { get; private set; } /// /// A delegate to execute to generate the response async. /// - public Func> CallbackAsync { get; private set; } + public Func> CallbackAsync { get; private set; } /// /// Defines if the method WithCallback(...) is used. /// public bool WithCallbackUsed { get; private set; } - /// - public IResponseBuilder WithCallback(Func callbackHandler) + /// + public IResponseBuilder WithCallback(Func callbackHandler) { Guard.NotNull(callbackHandler, nameof(callbackHandler)); return WithCallbackInternal(true, callbackHandler); } - /// - public IResponseBuilder WithCallback(Func> callbackHandler) + /// + public IResponseBuilder WithCallback(Func> callbackHandler) { Guard.NotNull(callbackHandler, nameof(callbackHandler)); return WithCallbackInternal(true, callbackHandler); } - private IResponseBuilder WithCallbackInternal(bool withCallbackUsed, Func callbackHandler) + private IResponseBuilder WithCallbackInternal(bool withCallbackUsed, Func callbackHandler) { Guard.NotNull(callbackHandler, nameof(callbackHandler)); @@ -47,7 +47,7 @@ namespace WireMock.ResponseBuilders return this; } - private IResponseBuilder WithCallbackInternal(bool withCallbackUsed, Func> callbackHandler) + private IResponseBuilder WithCallbackInternal(bool withCallbackUsed, Func> callbackHandler) { Guard.NotNull(callbackHandler, nameof(callbackHandler)); diff --git a/src/WireMock.Net/ResponseBuilders/Response.cs b/src/WireMock.Net/ResponseBuilders/Response.cs index f9665dc1..3ab86580 100644 --- a/src/WireMock.Net/ResponseBuilders/Response.cs +++ b/src/WireMock.Net/ResponseBuilders/Response.cs @@ -195,8 +195,8 @@ namespace WireMock.ResponseBuilders return this; } - /// - public IResponseBuilder WithBody(Func bodyFactory, string destination = BodyDestinationFormat.SameAsSource, Encoding encoding = null) + /// + public IResponseBuilder WithBody(Func bodyFactory, string destination = BodyDestinationFormat.SameAsSource, Encoding encoding = null) { Guard.NotNull(bodyFactory, nameof(bodyFactory)); @@ -211,8 +211,8 @@ namespace WireMock.ResponseBuilders }); } - /// - public IResponseBuilder WithBody(Func> bodyFactory, string destination = BodyDestinationFormat.SameAsSource, Encoding encoding = null) + /// + public IResponseBuilder WithBody(Func> bodyFactory, string destination = BodyDestinationFormat.SameAsSource, Encoding encoding = null) { Guard.NotNull(bodyFactory, nameof(bodyFactory)); @@ -383,8 +383,8 @@ namespace WireMock.ResponseBuilders return this; } - /// - public async Task<(ResponseMessage Message, IMapping Mapping)> ProvideResponseAsync(RequestMessage requestMessage, WireMockServerSettings settings) + /// + public async Task<(IResponseMessage Message, IMapping Mapping)> ProvideResponseAsync(IRequestMessage requestMessage, WireMockServerSettings settings) { Guard.NotNull(requestMessage, nameof(requestMessage)); Guard.NotNull(settings, nameof(settings)); diff --git a/src/WireMock.Net/ResponseProviders/DynamicAsyncResponseProvider.cs b/src/WireMock.Net/ResponseProviders/DynamicAsyncResponseProvider.cs index d29fbe3b..32948141 100644 --- a/src/WireMock.Net/ResponseProviders/DynamicAsyncResponseProvider.cs +++ b/src/WireMock.Net/ResponseProviders/DynamicAsyncResponseProvider.cs @@ -6,14 +6,14 @@ namespace WireMock.ResponseProviders { internal class DynamicAsyncResponseProvider : IResponseProvider { - private readonly Func> _responseMessageFunc; + private readonly Func> _responseMessageFunc; - public DynamicAsyncResponseProvider(Func> responseMessageFunc) + public DynamicAsyncResponseProvider(Func> responseMessageFunc) { _responseMessageFunc = responseMessageFunc; } - public async Task<(ResponseMessage Message, IMapping Mapping)> ProvideResponseAsync(RequestMessage requestMessage, WireMockServerSettings settings) + public async Task<(IResponseMessage Message, IMapping Mapping)> ProvideResponseAsync(IRequestMessage requestMessage, WireMockServerSettings settings) { return (await _responseMessageFunc(requestMessage).ConfigureAwait(false), null); } diff --git a/src/WireMock.Net/ResponseProviders/DynamicResponseProvider.cs b/src/WireMock.Net/ResponseProviders/DynamicResponseProvider.cs index d0b97c2d..8a9deca0 100644 --- a/src/WireMock.Net/ResponseProviders/DynamicResponseProvider.cs +++ b/src/WireMock.Net/ResponseProviders/DynamicResponseProvider.cs @@ -6,16 +6,16 @@ namespace WireMock.ResponseProviders { internal class DynamicResponseProvider : IResponseProvider { - private readonly Func _responseMessageFunc; + private readonly Func _responseMessageFunc; - public DynamicResponseProvider(Func responseMessageFunc) + public DynamicResponseProvider(Func responseMessageFunc) { _responseMessageFunc = responseMessageFunc; } - public Task<(ResponseMessage Message, IMapping Mapping)> ProvideResponseAsync(RequestMessage requestMessage, WireMockServerSettings settings) + public Task<(IResponseMessage Message, IMapping Mapping)> ProvideResponseAsync(IRequestMessage requestMessage, WireMockServerSettings settings) { - (ResponseMessage responseMessage, IMapping mapping) result = (_responseMessageFunc(requestMessage), null); + (IResponseMessage responseMessage, IMapping mapping) result = (_responseMessageFunc(requestMessage), null); return Task.FromResult(result); } } diff --git a/src/WireMock.Net/ResponseProviders/IResponseProvider.cs b/src/WireMock.Net/ResponseProviders/IResponseProvider.cs index a541b5f2..c6e7e58d 100644 --- a/src/WireMock.Net/ResponseProviders/IResponseProvider.cs +++ b/src/WireMock.Net/ResponseProviders/IResponseProvider.cs @@ -1,4 +1,4 @@ -// This source file is based on mock4net by Alexandre Victoor which is licensed under the Apache 2.0 License. +// This source file is based on mock4net by Alexandre Victoor which is licensed under the Apache 2.0 License. // For more details see 'mock4net/LICENSE.txt' and 'mock4net/readme.md' in this project root. using System.Threading.Tasks; using JetBrains.Annotations; @@ -17,6 +17,6 @@ namespace WireMock.ResponseProviders /// The request. /// The WireMockServerSettings. /// The including a new (optional) . - Task<(ResponseMessage Message, IMapping Mapping)> ProvideResponseAsync([NotNull] RequestMessage requestMessage, [NotNull] WireMockServerSettings settings); + Task<(IResponseMessage Message, IMapping Mapping)> ProvideResponseAsync([NotNull] IRequestMessage requestMessage, [NotNull] WireMockServerSettings settings); } } \ No newline at end of file diff --git a/src/WireMock.Net/ResponseProviders/ProxyAsyncResponseProvider.cs b/src/WireMock.Net/ResponseProviders/ProxyAsyncResponseProvider.cs index bdc6d537..020633aa 100644 --- a/src/WireMock.Net/ResponseProviders/ProxyAsyncResponseProvider.cs +++ b/src/WireMock.Net/ResponseProviders/ProxyAsyncResponseProvider.cs @@ -6,16 +6,16 @@ namespace WireMock.ResponseProviders { internal class ProxyAsyncResponseProvider : IResponseProvider { - private readonly Func> _responseMessageFunc; + private readonly Func> _responseMessageFunc; private readonly WireMockServerSettings _settings; - public ProxyAsyncResponseProvider(Func> responseMessageFunc, WireMockServerSettings settings) + public ProxyAsyncResponseProvider(Func> responseMessageFunc, WireMockServerSettings settings) { _responseMessageFunc = responseMessageFunc; _settings = settings; } - public async Task<(ResponseMessage Message, IMapping Mapping)> ProvideResponseAsync(RequestMessage requestMessage, WireMockServerSettings settings) + public async Task<(IResponseMessage Message, IMapping Mapping)> ProvideResponseAsync(IRequestMessage requestMessage, WireMockServerSettings settings) { return (await _responseMessageFunc(requestMessage, _settings).ConfigureAwait(false), null); } diff --git a/src/WireMock.Net/Serialization/JsonSerializationConstants.cs b/src/WireMock.Net/Serialization/JsonSerializationConstants.cs index 5e02fb3e..848bd6af 100644 --- a/src/WireMock.Net/Serialization/JsonSerializationConstants.cs +++ b/src/WireMock.Net/Serialization/JsonSerializationConstants.cs @@ -20,5 +20,11 @@ namespace WireMock.Serialization { DateParseHandling = DateParseHandling.None }; + + public static readonly JsonSerializerSettings JsonSerializerSettingsPact = new JsonSerializerSettings + { + Formatting = Formatting.Indented, + NullValueHandling = NullValueHandling.Ignore + }; } } \ No newline at end of file diff --git a/src/WireMock.Net/Serialization/LogEntryMapper.cs b/src/WireMock.Net/Serialization/LogEntryMapper.cs index 5266537a..d3f46075 100644 --- a/src/WireMock.Net/Serialization/LogEntryMapper.cs +++ b/src/WireMock.Net/Serialization/LogEntryMapper.cs @@ -1,4 +1,4 @@ -using System.Linq; +using System.Linq; using WireMock.Admin.Mappings; using WireMock.Admin.Requests; using WireMock.Logging; @@ -29,8 +29,8 @@ namespace WireMock.Serialization if (logEntry.RequestMessage.BodyData != null) { - logRequestModel.DetectedBodyType = logEntry.RequestMessage.BodyData.DetectedBodyType.ToString(); - logRequestModel.DetectedBodyTypeFromContentType = logEntry.RequestMessage.BodyData.DetectedBodyTypeFromContentType.ToString(); + logRequestModel.DetectedBodyType = logEntry.RequestMessage.BodyData.DetectedBodyType?.ToString(); + logRequestModel.DetectedBodyTypeFromContentType = logEntry.RequestMessage.BodyData.DetectedBodyTypeFromContentType?.ToString(); switch (logEntry.RequestMessage.BodyData.DetectedBodyType) { diff --git a/src/WireMock.Net/Serialization/MappingConverter.cs b/src/WireMock.Net/Serialization/MappingConverter.cs index a33bfc05..3e23db77 100644 --- a/src/WireMock.Net/Serialization/MappingConverter.cs +++ b/src/WireMock.Net/Serialization/MappingConverter.cs @@ -40,6 +40,7 @@ namespace WireMock.Serialization Guid = mapping.Guid, TimeSettings = TimeSettingsMapper.Map(mapping.TimeSettings), Title = mapping.Title, + Description = mapping.Description, Priority = mapping.Priority != 0 ? mapping.Priority : (int?)null, Scenario = mapping.Scenario, WhenStateIs = mapping.ExecutionConditionState, diff --git a/src/WireMock.Net/Serialization/MappingToFileSaver.cs b/src/WireMock.Net/Serialization/MappingToFileSaver.cs index 708d2661..ad527070 100644 --- a/src/WireMock.Net/Serialization/MappingToFileSaver.cs +++ b/src/WireMock.Net/Serialization/MappingToFileSaver.cs @@ -1,51 +1,49 @@ using System.IO; using System.Linq; -using JetBrains.Annotations; using Newtonsoft.Json; -using WireMock.Settings; using Stef.Validation; +using WireMock.Settings; -namespace WireMock.Serialization +namespace WireMock.Serialization; + +internal class MappingToFileSaver { - internal class MappingToFileSaver + private readonly WireMockServerSettings _settings; + private readonly MappingConverter _mappingConverter; + + public MappingToFileSaver(WireMockServerSettings settings, MappingConverter mappingConverter) { - private readonly WireMockServerSettings _settings; - private readonly MappingConverter _mappingConverter; + Guard.NotNull(settings); + Guard.NotNull(mappingConverter); - public MappingToFileSaver(WireMockServerSettings settings, MappingConverter mappingConverter) + _settings = settings; + _mappingConverter = mappingConverter; + } + + public void SaveMappingToFile(IMapping mapping, string? folder = null) + { + if (folder == null) { - Guard.NotNull(settings); - Guard.NotNull(mappingConverter); - - _settings = settings; - _mappingConverter = mappingConverter; + folder = _settings.FileSystemHandler.GetMappingFolder(); } - public void SaveMappingToFile(IMapping mapping, [CanBeNull] string folder = null) + if (!_settings.FileSystemHandler.FolderExists(folder)) { - if (folder == null) - { - folder = _settings.FileSystemHandler.GetMappingFolder(); - } - - if (!_settings.FileSystemHandler.FolderExists(folder)) - { - _settings.FileSystemHandler.CreateFolder(folder); - } - - var model = _mappingConverter.ToMappingModel(mapping); - string filename = (!string.IsNullOrEmpty(mapping.Title) ? SanitizeFileName(mapping.Title) : mapping.Guid.ToString()) + ".json"; - - string path = Path.Combine(folder, filename); - - _settings.Logger.Info("Saving Mapping file {0}", filename); - - _settings.FileSystemHandler.WriteMappingFile(path, JsonConvert.SerializeObject(model, JsonSerializationConstants.JsonSerializerSettingsDefault)); + _settings.FileSystemHandler.CreateFolder(folder); } - private static string SanitizeFileName(string name, char replaceChar = '_') - { - return Path.GetInvalidFileNameChars().Aggregate(name, (current, c) => current.Replace(c, replaceChar)); - } + var model = _mappingConverter.ToMappingModel(mapping); + string filename = (!string.IsNullOrEmpty(mapping.Title) ? SanitizeFileName(mapping.Title) : mapping.Guid.ToString()) + ".json"; + + string path = Path.Combine(folder, filename); + + _settings.Logger.Info("Saving Mapping file {0}", filename); + + _settings.FileSystemHandler.WriteMappingFile(path, JsonConvert.SerializeObject(model, JsonSerializationConstants.JsonSerializerSettingsDefault)); + } + + private static string SanitizeFileName(string name, char replaceChar = '_') + { + return Path.GetInvalidFileNameChars().Aggregate(name, (current, c) => current.Replace(c, replaceChar)); } } \ No newline at end of file diff --git a/src/WireMock.Net/Server/IRespondWithAProvider.cs b/src/WireMock.Net/Server/IRespondWithAProvider.cs index a75068e3..327f397b 100644 --- a/src/WireMock.Net/Server/IRespondWithAProvider.cs +++ b/src/WireMock.Net/Server/IRespondWithAProvider.cs @@ -38,6 +38,13 @@ namespace WireMock.Server /// The . IRespondWithAProvider WithTitle(string title); + /// + /// Define a description for this mapping. + /// + /// The description. + /// The . + IRespondWithAProvider WithDescription(string description); + /// /// Define the full filepath for this mapping. /// diff --git a/src/WireMock.Net/Server/RespondWithAProvider.cs b/src/WireMock.Net/Server/RespondWithAProvider.cs index 05f39b2a..4240e49e 100644 --- a/src/WireMock.Net/Server/RespondWithAProvider.cs +++ b/src/WireMock.Net/Server/RespondWithAProvider.cs @@ -21,6 +21,7 @@ namespace WireMock.Server { private int _priority; private string _title; + private string _description; private string _path; private string _executionConditionState; private string _nextState; @@ -58,16 +59,16 @@ namespace WireMock.Server /// The provider. public void RespondWith(IResponseProvider provider) { - _registrationCallback(new Mapping(Guid, _title, _path, _settings, _requestMatcher, provider, _priority, _scenario, _executionConditionState, _nextState, _timesInSameState, Webhooks, TimeSettings), _saveToFile); + _registrationCallback(new Mapping(Guid, _title, _description, _path, _settings, _requestMatcher, provider, _priority, _scenario, _executionConditionState, _nextState, _timesInSameState, Webhooks, TimeSettings), _saveToFile); } - /// + /// public IRespondWithAProvider WithGuid(string guid) { return WithGuid(Guid.Parse(guid)); } - /// + /// public IRespondWithAProvider WithGuid(Guid guid) { Guid = guid; @@ -75,7 +76,7 @@ namespace WireMock.Server return this; } - /// + /// public IRespondWithAProvider WithTitle(string title) { _title = title; @@ -83,6 +84,14 @@ namespace WireMock.Server return this; } + /// + public IRespondWithAProvider WithDescription(string description) + { + _description = description; + + return this; + } + /// public IRespondWithAProvider WithPath(string path) { @@ -91,7 +100,7 @@ namespace WireMock.Server return this; } - /// + /// public IRespondWithAProvider AtPriority(int priority) { _priority = priority; @@ -99,7 +108,7 @@ namespace WireMock.Server return this; } - /// + /// public IRespondWithAProvider InScenario(string scenario) { _scenario = scenario; @@ -107,13 +116,13 @@ namespace WireMock.Server return this; } - /// + /// public IRespondWithAProvider InScenario(int scenario) { return InScenario(scenario.ToString()); } - /// + /// public IRespondWithAProvider WhenStateIs(string state) { if (string.IsNullOrEmpty(_scenario)) @@ -126,13 +135,13 @@ namespace WireMock.Server return this; } - /// + /// public IRespondWithAProvider WhenStateIs(int state) { return WhenStateIs(state.ToString()); } - /// + /// public IRespondWithAProvider WillSetStateTo(string state, int? times = 1) { if (string.IsNullOrEmpty(_scenario)) @@ -146,7 +155,7 @@ namespace WireMock.Server return this; } - /// + /// public IRespondWithAProvider WillSetStateTo(int state, int? times = 1) { return WillSetStateTo(state.ToString(), times); @@ -162,7 +171,7 @@ namespace WireMock.Server return this; } - /// + /// public IRespondWithAProvider WithWebhook(params IWebhook[] webhooks) { Guard.HasNoNulls(webhooks, nameof(webhooks)); @@ -172,7 +181,7 @@ namespace WireMock.Server return this; } - /// + /// public IRespondWithAProvider WithWebhook( [NotNull] string url, [CanBeNull] string method = "post", @@ -196,7 +205,7 @@ namespace WireMock.Server return this; } - /// + /// public IRespondWithAProvider WithWebhook( [NotNull] string url, [CanBeNull] string method = "post", diff --git a/src/WireMock.Net/Server/WireMockServer.Admin.cs b/src/WireMock.Net/Server/WireMockServer.Admin.cs index da1569cf..29874619 100644 --- a/src/WireMock.Net/Server/WireMockServer.Admin.cs +++ b/src/WireMock.Net/Server/WireMockServer.Admin.cs @@ -44,12 +44,12 @@ public partial class WireMockServer private const string AdminScenarios = "/__admin/scenarios"; private const string QueryParamReloadStaticMappings = "reloadStaticMappings"; - private readonly Guid _proxyMappingGuid = new Guid("e59914fd-782e-428e-91c1-4810ffb86567"); + private readonly Guid _proxyMappingGuid = new("e59914fd-782e-428e-91c1-4810ffb86567"); private readonly RegexMatcher _adminRequestContentTypeJson = new ContentTypeMatcher(ContentTypeJson, true); - private readonly RegexMatcher _adminMappingsGuidPathMatcher = new RegexMatcher(@"^\/__admin\/mappings\/([0-9A-Fa-f]{8}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{12})$"); - private readonly RegexMatcher _adminRequestsGuidPathMatcher = new RegexMatcher(@"^\/__admin\/requests\/([0-9A-Fa-f]{8}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{12})$"); + private readonly RegexMatcher _adminMappingsGuidPathMatcher = new(@"^\/__admin\/mappings\/([0-9A-Fa-f]{8}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{12})$"); + private readonly RegexMatcher _adminRequestsGuidPathMatcher = new(@"^\/__admin\/requests\/([0-9A-Fa-f]{8}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{12})$"); - private EnhancedFileSystemWatcher _enhancedFileSystemWatcher; + private EnhancedFileSystemWatcher? _enhancedFileSystemWatcher; #region InitAdmin private void InitAdmin() @@ -108,7 +108,7 @@ public partial class WireMockServer #region StaticMappings /// [PublicAPI] - public void SaveStaticMappings([CanBeNull] string folder = null) + public void SaveStaticMappings(string? folder = null) { foreach (var mapping in Mappings.Where(m => !m.IsAdminInterface)) { @@ -118,7 +118,7 @@ public partial class WireMockServer /// [PublicAPI] - public void ReadStaticMappings([CanBeNull] string folder = null) + public void ReadStaticMappings(string? folder = null) { if (folder == null) { @@ -207,8 +207,7 @@ public partial class WireMockServer #endregion #region Proxy and Record - [CanBeNull] - private HttpClient _httpClientForProxy; + private HttpClient? _httpClientForProxy; private void InitProxyAndRecord(WireMockServerSettings settings) { @@ -230,7 +229,7 @@ public partial class WireMockServer proxyRespondProvider.RespondWith(new ProxyAsyncResponseProvider(ProxyAndRecordAsync, settings)); } - private async Task ProxyAndRecordAsync(RequestMessage requestMessage, WireMockServerSettings settings) + private async Task ProxyAndRecordAsync(IRequestMessage requestMessage, WireMockServerSettings settings) { var requestUri = new Uri(requestMessage.Url); var proxyUri = new Uri(settings.ProxyAndRecordSettings.Url); @@ -263,7 +262,7 @@ public partial class WireMockServer #endregion #region Settings - private ResponseMessage SettingsGet(RequestMessage requestMessage) + private IResponseMessage SettingsGet(IRequestMessage requestMessage) { var model = new SettingsModel { @@ -290,7 +289,7 @@ public partial class WireMockServer return ToJson(model); } - private ResponseMessage SettingsUpdate(RequestMessage requestMessage) + private IResponseMessage SettingsUpdate(IRequestMessage requestMessage) { var settings = DeserializeObject(requestMessage); @@ -335,7 +334,7 @@ public partial class WireMockServer #endregion Settings #region Mapping/{guid} - private ResponseMessage MappingGet(RequestMessage requestMessage) + private IResponseMessage MappingGet(IRequestMessage requestMessage) { Guid guid = ParseGuidFromRequestMessage(requestMessage); var mapping = Mappings.FirstOrDefault(m => !m.IsAdminInterface && m.Guid == guid); @@ -351,7 +350,7 @@ public partial class WireMockServer return ToJson(model); } - private ResponseMessage MappingPut(RequestMessage requestMessage) + private IResponseMessage MappingPut(IRequestMessage requestMessage) { Guid guid = ParseGuidFromRequestMessage(requestMessage); @@ -361,7 +360,7 @@ public partial class WireMockServer return ResponseMessageBuilder.Create("Mapping added or updated", 200, guidFromPut); } - private ResponseMessage MappingDelete(RequestMessage requestMessage) + private IResponseMessage MappingDelete(IRequestMessage requestMessage) { Guid guid = ParseGuidFromRequestMessage(requestMessage); @@ -373,14 +372,14 @@ public partial class WireMockServer return ResponseMessageBuilder.Create("Mapping not found", 404); } - private Guid ParseGuidFromRequestMessage(RequestMessage requestMessage) + private Guid ParseGuidFromRequestMessage(IRequestMessage requestMessage) { return Guid.Parse(requestMessage.Path.Substring(AdminMappings.Length + 1)); } #endregion Mapping/{guid} #region Mappings - private ResponseMessage MappingsSave(RequestMessage requestMessage) + private IResponseMessage MappingsSave(IRequestMessage requestMessage) { SaveStaticMappings(); @@ -392,12 +391,12 @@ public partial class WireMockServer return Mappings.Where(m => !m.IsAdminInterface).Select(_mappingConverter.ToMappingModel); } - private ResponseMessage MappingsGet(RequestMessage requestMessage) + private IResponseMessage MappingsGet(IRequestMessage requestMessage) { return ToJson(ToMappingModels()); } - private ResponseMessage MappingsPost(RequestMessage requestMessage) + private IResponseMessage MappingsPost(IRequestMessage requestMessage) { try { @@ -427,7 +426,7 @@ public partial class WireMockServer } } - private Guid? ConvertMappingAndRegisterAsRespondProvider(MappingModel mappingModel, Guid? guid = null, string path = null) + private Guid? ConvertMappingAndRegisterAsRespondProvider(MappingModel mappingModel, Guid? guid = null, string? path = null) { Guard.NotNull(mappingModel, nameof(mappingModel)); Guard.NotNull(mappingModel.Request, nameof(mappingModel.Request)); @@ -494,7 +493,7 @@ public partial class WireMockServer return respondProvider.Guid; } - private ResponseMessage MappingsDelete(RequestMessage requestMessage) + private IResponseMessage MappingsDelete(IRequestMessage requestMessage) { if (!string.IsNullOrEmpty(requestMessage.Body)) { @@ -519,7 +518,7 @@ public partial class WireMockServer } } - private IEnumerable MappingsDeleteMappingFromBody(RequestMessage requestMessage) + private IEnumerable MappingsDeleteMappingFromBody(IRequestMessage requestMessage) { var deletedGuids = new List(); @@ -555,7 +554,7 @@ public partial class WireMockServer return deletedGuids; } - private ResponseMessage MappingsReset(RequestMessage requestMessage) + private IResponseMessage MappingsReset(IRequestMessage requestMessage) { ResetMappings(); @@ -575,7 +574,7 @@ public partial class WireMockServer #endregion Mappings #region Request/{guid} - private ResponseMessage RequestGet(RequestMessage requestMessage) + private IResponseMessage RequestGet(IRequestMessage requestMessage) { Guid guid = ParseGuidFromRequestMessage(requestMessage); var entry = LogEntries.FirstOrDefault(r => !r.RequestMessage.Path.StartsWith("/__admin/") && r.Guid == guid); @@ -591,7 +590,7 @@ public partial class WireMockServer return ToJson(model); } - private ResponseMessage RequestDelete(RequestMessage requestMessage) + private IResponseMessage RequestDelete(IRequestMessage requestMessage) { Guid guid = ParseGuidFromRequestMessage(requestMessage); @@ -605,7 +604,7 @@ public partial class WireMockServer #endregion Request/{guid} #region Requests - private ResponseMessage RequestsGet(RequestMessage requestMessage) + private IResponseMessage RequestsGet(IRequestMessage requestMessage) { var result = LogEntries .Where(r => !r.RequestMessage.Path.StartsWith("/__admin/")) @@ -614,7 +613,7 @@ public partial class WireMockServer return ToJson(result); } - private ResponseMessage RequestsDelete(RequestMessage requestMessage) + private IResponseMessage RequestsDelete(IRequestMessage requestMessage) { ResetLogEntries(); @@ -623,7 +622,7 @@ public partial class WireMockServer #endregion Requests #region Requests/find - private ResponseMessage RequestsFind(RequestMessage requestMessage) + private IResponseMessage RequestsFind(IRequestMessage requestMessage) { var requestModel = DeserializeObject(requestMessage); @@ -646,7 +645,7 @@ public partial class WireMockServer #endregion Requests/find #region Scenarios - private ResponseMessage ScenariosGet(RequestMessage requestMessage) + private IResponseMessage ScenariosGet(IRequestMessage requestMessage) { var scenariosStates = Scenarios.Values.Select(s => new ScenarioStateModel { @@ -660,7 +659,7 @@ public partial class WireMockServer return ToJson(scenariosStates, true); } - private ResponseMessage ScenariosReset(RequestMessage requestMessage) + private IResponseMessage ScenariosReset(IRequestMessage requestMessage) { ResetScenarios(); @@ -668,7 +667,29 @@ public partial class WireMockServer } #endregion - private IRequestBuilder InitRequestBuilder(RequestModel requestModel, bool pathOrUrlRequired) + /// + /// This stores details about the consumer of the interaction. + /// + /// the consumer + [PublicAPI] + public WireMockServer WithConsumer(string consumer) + { + Consumer = consumer; + return this; + } + + /// + /// This stores details about the provider of the interaction. + /// + /// the provider + [PublicAPI] + public WireMockServer WithProvider(string provider) + { + Provider = provider; + return this; + } + + private IRequestBuilder? InitRequestBuilder(RequestModel requestModel, bool pathOrUrlRequired) { IRequestBuilder requestBuilder = Request.Create(); @@ -743,7 +764,7 @@ public partial class WireMockServer headerModel.Name, headerModel.IgnoreCase == true, headerModel.RejectOnMatch == true ? MatchBehaviour.RejectOnMatch : MatchBehaviour.AcceptOnMatch, - headerModel.Matchers.Select(_matcherMapper.Map).OfType().ToArray() + headerModel.Matchers!.Select(_matcherMapper.Map).OfType().ToArray() ); } } @@ -756,16 +777,16 @@ public partial class WireMockServer cookieModel.Name, cookieModel.IgnoreCase == true, cookieModel.RejectOnMatch == true ? MatchBehaviour.RejectOnMatch : MatchBehaviour.AcceptOnMatch, - cookieModel.Matchers.Select(_matcherMapper.Map).OfType().ToArray()); + cookieModel.Matchers!.Select(_matcherMapper.Map).OfType().ToArray()); } } if (requestModel.Params != null) { - foreach (var paramModel in requestModel.Params.Where(p => p != null && p.Matchers != null)) + foreach (var paramModel in requestModel.Params.Where(p => p is { Matchers: { } })) { bool ignoreCase = paramModel.IgnoreCase == true; - requestBuilder = requestBuilder.WithParam(paramModel.Name, ignoreCase, paramModel.Matchers.Select(_matcherMapper.Map).OfType().ToArray()); + requestBuilder = requestBuilder.WithParam(paramModel.Name, ignoreCase, paramModel.Matchers!.Select(_matcherMapper.Map).OfType().ToArray()); } } @@ -897,12 +918,12 @@ public partial class WireMockServer }; } - private Encoding ToEncoding(EncodingModel encodingModel) + private Encoding? ToEncoding(EncodingModel? encodingModel) { return encodingModel != null ? Encoding.GetEncoding(encodingModel.CodePage) : null; } - private T DeserializeObject(RequestMessage requestMessage) + private T? DeserializeObject(IRequestMessage requestMessage) { if (requestMessage?.BodyData?.DetectedBodyType == BodyType.String) { @@ -917,9 +938,9 @@ public partial class WireMockServer return default(T); } - private T[] DeserializeRequestMessageToArray(RequestMessage requestMessage) + private T[] DeserializeRequestMessageToArray(IRequestMessage requestMessage) { - if (requestMessage?.BodyData?.DetectedBodyType == BodyType.Json) + if (requestMessage.BodyData?.DetectedBodyType == BodyType.Json) { var bodyAsJson = requestMessage.BodyData.BodyAsJson; diff --git a/src/WireMock.Net/Server/WireMockServer.AdminFiles.cs b/src/WireMock.Net/Server/WireMockServer.AdminFiles.cs index e9db1a4a..e7b0f4be 100644 --- a/src/WireMock.Net/Server/WireMockServer.AdminFiles.cs +++ b/src/WireMock.Net/Server/WireMockServer.AdminFiles.cs @@ -13,7 +13,7 @@ namespace WireMock.Server private static readonly Encoding[] FileBodyIsString = { Encoding.UTF8, Encoding.ASCII }; #region Files/{filename} - private ResponseMessage FilePost(RequestMessage requestMessage) + private IResponseMessage FilePost(IRequestMessage requestMessage) { string filename = GetFileNameFromRequestMessage(requestMessage); @@ -28,7 +28,7 @@ namespace WireMock.Server return ResponseMessageBuilder.Create("File created"); } - private ResponseMessage FilePut(RequestMessage requestMessage) + private IResponseMessage FilePut(IRequestMessage requestMessage) { string filename = GetFileNameFromRequestMessage(requestMessage); @@ -43,7 +43,7 @@ namespace WireMock.Server return ResponseMessageBuilder.Create("File updated"); } - private ResponseMessage FileGet(RequestMessage requestMessage) + private IResponseMessage FileGet(IRequestMessage requestMessage) { string filename = GetFileNameFromRequestMessage(requestMessage); @@ -79,7 +79,7 @@ namespace WireMock.Server /// Note: Response is returned with no body as a head request doesn't accept a body, only the status code. /// /// The request message. - private ResponseMessage FileHead(RequestMessage requestMessage) + private IResponseMessage FileHead(IRequestMessage requestMessage) { string filename = GetFileNameFromRequestMessage(requestMessage); @@ -92,7 +92,7 @@ namespace WireMock.Server return ResponseMessageBuilder.Create(204); } - private ResponseMessage FileDelete(RequestMessage requestMessage) + private IResponseMessage FileDelete(IRequestMessage requestMessage) { string filename = GetFileNameFromRequestMessage(requestMessage); @@ -106,7 +106,7 @@ namespace WireMock.Server return ResponseMessageBuilder.Create("File deleted."); } - private string GetFileNameFromRequestMessage(RequestMessage requestMessage) + private string GetFileNameFromRequestMessage(IRequestMessage requestMessage) { return Path.GetFileName(requestMessage.Path.Substring(AdminFiles.Length + 1)); } diff --git a/src/WireMock.Net/Server/WireMockServer.ImportWireMockOrg.cs b/src/WireMock.Net/Server/WireMockServer.ImportWireMockOrg.cs index 5730e978..044e48f2 100644 --- a/src/WireMock.Net/Server/WireMockServer.ImportWireMockOrg.cs +++ b/src/WireMock.Net/Server/WireMockServer.ImportWireMockOrg.cs @@ -21,7 +21,7 @@ namespace WireMock.Server /// /// The path to the WireMock.org mapping json file. [PublicAPI] - public void ReadStaticWireMockOrgMappingAndAddOrUpdate([NotNull] string path) + public void ReadStaticWireMockOrgMappingAndAddOrUpdate(string path) { Guard.NotNull(path, nameof(path)); @@ -44,7 +44,7 @@ namespace WireMock.Server } } - private ResponseMessage MappingsPostWireMockOrg(RequestMessage requestMessage) + private IResponseMessage MappingsPostWireMockOrg(IRequestMessage requestMessage) { try { diff --git a/src/WireMock.Net/Server/WireMockServer.Pact.cs b/src/WireMock.Net/Server/WireMockServer.Pact.cs new file mode 100644 index 00000000..197ed057 --- /dev/null +++ b/src/WireMock.Net/Server/WireMockServer.Pact.cs @@ -0,0 +1,167 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using WireMock.Admin.Mappings; +using WireMock.Pact.Models.V2; +using WireMock.Util; + +namespace WireMock.Server; + +public partial class WireMockServer +{ + private const string DefaultPath = "/"; + private const string DefaultMethod = "GET"; + private const int DefaultStatus = 200; + private const string DefaultConsumer = "Default Consumer"; + private const string DefaultProvider = "Default Provider"; + + /// + /// Save the mappings as a Pact Json file V2. + /// + /// The folder to save the pact file. + /// The filename for the .json file [optional]. + public void SavePact(string folder, string? filename = null) + { + var consumer = Consumer ?? DefaultConsumer; + var provider = Provider ?? DefaultProvider; + + filename ??= $"{consumer} - {provider}.json"; + + var pact = new Pact.Models.V2.Pact + { + Consumer = new Pacticipant { Name = consumer }, + Provider = new Pacticipant { Name = provider } + }; + + foreach (var mapping in MappingModels) + { + var interaction = new Interaction + { + Description = mapping.Description, + ProviderState = mapping.Title, + Request = MapRequest(mapping.Request), + Response = MapResponse(mapping.Response) + }; + + pact.Interactions.Add(interaction); + } + + var bytes = JsonUtils.SerializeAsPactFile(pact); + _settings.FileSystemHandler.WriteFile(folder, filename, bytes); + } + + private static Request MapRequest(RequestModel request) + { + string path; + switch (request.Path) + { + case string pathAsString: + path = pathAsString; + break; + + case PathModel pathModel: + path = GetPatternAsStringFromMatchers(pathModel.Matchers, DefaultPath); + break; + + default: + path = DefaultPath; + break; + } + + return new Request + { + Method = request.Methods?.FirstOrDefault() ?? DefaultMethod, + Path = path, + Query = MapQueryParameters(request.Params), + Headers = MapRequestHeaders(request.Headers), + Body = MapBody(request.Body) + }; + } + + private static Response MapResponse(ResponseModel? response) + { + if (response == null) + { + return new Response(); + } + + return new Response + { + Status = MapStatusCode(response.StatusCode), + Headers = MapResponseHeaders(response.Headers), + Body = response.BodyAsJson + }; + } + + private static int MapStatusCode(object? statusCode) + { + if (statusCode is string statusCodeAsString) + { + return int.TryParse(statusCodeAsString, out var statusCodeAsInt) ? statusCodeAsInt : DefaultStatus; + } + + if (statusCode != null) + { + // Convert to Int32 because Newtonsoft deserializes an 'object' with a number value to a long. + return Convert.ToInt32(statusCode); + } + + return DefaultStatus; + } + + private static string? MapQueryParameters(IList? queryParameters) + { + if (queryParameters == null) + { + return null; + } + + var values = queryParameters + .Where(qp => qp.Matchers != null && qp.Matchers.Any() && qp.Matchers[0].Pattern is string) + .Select(param => $"{Uri.EscapeDataString(param.Name)}={Uri.EscapeDataString((string)param.Matchers![0].Pattern)}"); + + return string.Join("&", values); + } + + private static IDictionary? MapRequestHeaders(IList? headers) + { + if (headers == null) + { + return null; + } + + var validHeaders = headers.Where(h => h.Matchers != null && h.Matchers.Any() && h.Matchers[0].Pattern is string); + return validHeaders.ToDictionary(x => x.Name, y => (string)y.Matchers![0].Pattern); + } + + private static IDictionary? MapResponseHeaders(IDictionary? headers) + { + if (headers == null) + { + return null; + } + + var validHeaders = headers.Where(h => h.Value is string); + return validHeaders.ToDictionary(x => x.Key, y => (string)y.Value); + } + + private static object? MapBody(BodyModel? body) + { + if (body == null || body.Matcher.Name != "JsonMatcher") + { + return null; + } + + return body.Matcher.Pattern; + } + + private static string GetPatternAsStringFromMatchers(MatcherModel[]? matchers, string defaultValue) + { + if (matchers != null && matchers.Any() && matchers[0].Pattern is string patternAsString) + { + return patternAsString; + } + + return defaultValue; + } +} \ No newline at end of file diff --git a/src/WireMock.Net/Server/WireMockServer.cs b/src/WireMock.Net/Server/WireMockServer.cs index d586f685..cb8b5950 100644 --- a/src/WireMock.Net/Server/WireMockServer.cs +++ b/src/WireMock.Net/Server/WireMockServer.cs @@ -30,7 +30,7 @@ public partial class WireMockServer : IWireMockServer private const int ServerStartDelayInMs = 100; private readonly WireMockServerSettings _settings; - private readonly IOwinSelfHost _httpServer; + private readonly IOwinSelfHost? _httpServer; private readonly IWireMockMiddlewareOptions _options = new WireMockMiddlewareOptions(); private readonly MappingConverter _mappingConverter; private readonly MatcherMapper _matcherMapper; @@ -38,7 +38,7 @@ public partial class WireMockServer : IWireMockServer /// [PublicAPI] - public bool IsStarted => _httpServer != null && _httpServer.IsStarted; + public bool IsStarted => _httpServer is { IsStarted: true }; /// [PublicAPI] @@ -54,7 +54,15 @@ public partial class WireMockServer : IWireMockServer /// [PublicAPI] - public string Url => Urls?.FirstOrDefault(); + public string? Url => Urls?.FirstOrDefault(); + + /// + [PublicAPI] + public string? Consumer { get; private set; } + + /// + [PublicAPI] + public string? Provider { get; private set; } /// /// Gets the mappings. @@ -100,9 +108,9 @@ public partial class WireMockServer : IWireMockServer /// The WireMockServerSettings. /// The . [PublicAPI] - public static WireMockServer Start([NotNull] WireMockServerSettings settings) + public static WireMockServer Start(WireMockServerSettings settings) { - Guard.NotNull(settings, nameof(settings)); + Guard.NotNull(settings); return new WireMockServer(settings); } @@ -114,7 +122,7 @@ public partial class WireMockServer : IWireMockServer /// The SSL support. /// The . [PublicAPI] - public static WireMockServer Start([CanBeNull] int? port = 0, bool ssl = false) + public static WireMockServer Start(int? port = 0, bool ssl = false) { return new WireMockServer(new WireMockServerSettings { @@ -239,7 +247,7 @@ public partial class WireMockServer : IWireMockServer if (settings.CustomCertificateDefined) { - _options.X509StoreName = settings.CertificateSettings.X509StoreName; + _options.X509StoreName = settings.CertificateSettings!.X509StoreName; _options.X509StoreLocation = settings.CertificateSettings.X509StoreLocation; _options.X509ThumbprintOrSubjectName = settings.CertificateSettings.X509StoreThumbprintOrSubjectName; _options.X509CertificateFilePath = settings.CertificateSettings.X509CertificateFilePath; @@ -308,7 +316,7 @@ public partial class WireMockServer : IWireMockServer Given(Request.Create().WithPath("/*").UsingAnyMethod()) .WithGuid(Guid.Parse("90008000-0000-4444-a17e-669cd84f1f05")) .AtPriority(1000) - .RespondWith(new DynamicResponseProvider(request => ResponseMessageBuilder.Create("No matching mapping found", 404))); + .RespondWith(new DynamicResponseProvider(_ => ResponseMessageBuilder.Create("No matching mapping found", 404))); } /// @@ -373,7 +381,7 @@ public partial class WireMockServer : IWireMockServer Guard.NotNull(audience, nameof(audience)); #if NETSTANDARD1_3 - throw new NotSupportedException("AzureADAuthentication is not supported for NETStandard 1.3"); + throw new NotSupportedException("AzureADAuthentication is not supported for NETStandard 1.3"); #else _options.AuthenticationMatcher = new AzureADAuthenticationMatcher(tenant, audience); #endif @@ -381,7 +389,7 @@ public partial class WireMockServer : IWireMockServer /// [PublicAPI] - public void SetBasicAuthentication([NotNull] string username, [NotNull] string password) + public void SetBasicAuthentication(string username, string password) { Guard.NotNull(username, nameof(username)); Guard.NotNull(password, nameof(password)); diff --git a/src/WireMock.Net/Settings/HttpClientSettings.cs b/src/WireMock.Net/Settings/HttpClientSettings.cs index 3db6a206..42805c1f 100644 --- a/src/WireMock.Net/Settings/HttpClientSettings.cs +++ b/src/WireMock.Net/Settings/HttpClientSettings.cs @@ -1,24 +1,23 @@ -namespace WireMock.Settings +namespace WireMock.Settings; + +/// +/// HttpClientSettings +/// +public class HttpClientSettings { /// - /// HttpClientSettings + /// The clientCertificate thumbprint or subject name fragment to use. + /// Example thumbprint : "D2DBF135A8D06ACCD0E1FAD9BFB28678DF7A9818". Example subject name: "www.google.com"" /// - public class HttpClientSettings - { - /// - /// The clientCertificate thumbprint or subject name fragment to use. - /// Example thumbprint : "D2DBF135A8D06ACCD0E1FAD9BFB28678DF7A9818". Example subject name: "www.google.com"" - /// - public string ClientX509Certificate2ThumbprintOrSubjectName { get; set; } + public string? ClientX509Certificate2ThumbprintOrSubjectName { get; set; } - /// - /// Defines the WebProxySettings. - /// - public WebProxySettings WebProxySettings { get; set; } + /// + /// Defines the WebProxySettings. + /// + public WebProxySettings? WebProxySettings { get; set; } - /// - /// Proxy requests should follow redirection (30x). - /// - public bool? AllowAutoRedirect { get; set; } - } + /// + /// Proxy requests should follow redirection (30x). + /// + public bool? AllowAutoRedirect { get; set; } } \ No newline at end of file diff --git a/src/WireMock.Net/Settings/WireMockCertificateSettings.cs b/src/WireMock.Net/Settings/WireMockCertificateSettings.cs index eb5aadce..c7c60eb9 100644 --- a/src/WireMock.Net/Settings/WireMockCertificateSettings.cs +++ b/src/WireMock.Net/Settings/WireMockCertificateSettings.cs @@ -15,31 +15,31 @@ namespace WireMock.Settings /// X509 StoreName (AddressBook, AuthRoot, CertificateAuthority, My, Root, TrustedPeople or TrustedPublisher) /// [PublicAPI] - public string X509StoreName { get; set; } + public string? X509StoreName { get; set; } /// /// X509 StoreLocation (CurrentUser or LocalMachine) /// [PublicAPI] - public string X509StoreLocation { get; set; } + public string? X509StoreLocation { get; set; } /// /// X509 Thumbprint or SubjectName (if not defined, the 'host' is used) /// [PublicAPI] - public string X509StoreThumbprintOrSubjectName { get; set; } + public string? X509StoreThumbprintOrSubjectName { get; set; } /// /// X509Certificate FilePath /// [PublicAPI] - public string X509CertificateFilePath { get; set; } + public string? X509CertificateFilePath { get; set; } /// /// X509Certificate Password /// [PublicAPI] - public string X509CertificatePassword { get; set; } + public string? X509CertificatePassword { get; set; } /// /// X509StoreName and X509StoreLocation should be defined diff --git a/src/WireMock.Net/Settings/WireMockServerSettings.cs b/src/WireMock.Net/Settings/WireMockServerSettings.cs index 3ada4a70..1c879870 100644 --- a/src/WireMock.Net/Settings/WireMockServerSettings.cs +++ b/src/WireMock.Net/Settings/WireMockServerSettings.cs @@ -62,13 +62,13 @@ namespace WireMock.Settings /// Gets or sets if the proxy and record settings. /// [PublicAPI] - public ProxyAndRecordSettings ProxyAndRecordSettings { get; set; } + public ProxyAndRecordSettings? ProxyAndRecordSettings { get; set; } /// /// Gets or sets the urls. /// [PublicAPI] - public string[] Urls { get; set; } + public string[]? Urls { get; set; } /// /// StartTimeout @@ -86,25 +86,25 @@ namespace WireMock.Settings /// The username needed for __admin access. /// [PublicAPI] - public string AdminUsername { get; set; } + public string? AdminUsername { get; set; } /// /// The password needed for __admin access. /// [PublicAPI] - public string AdminPassword { get; set; } + public string? AdminPassword { get; set; } /// /// The AzureAD Tenant needed for __admin access. /// [PublicAPI] - public string AdminAzureADTenant { get; set; } + public string? AdminAzureADTenant { get; set; } /// /// The AzureAD Audience / Resource for __admin access. /// [PublicAPI] - public string AdminAzureADAudience { get; set; } + public string? AdminAzureADAudience { get; set; } /// /// The RequestLog expiration in hours (optional). @@ -123,14 +123,14 @@ namespace WireMock.Settings /// [PublicAPI] [JsonIgnore] - public Action PreWireMockMiddlewareInit { get; set; } + public Action? PreWireMockMiddlewareInit { get; set; } /// /// Action which is called (with the IAppBuilder or IApplicationBuilder) after the internal WireMockMiddleware is initialized. [Optional] /// [PublicAPI] [JsonIgnore] - public Action PostWireMockMiddlewareInit { get; set; } + public Action? PostWireMockMiddlewareInit { get; set; } #if USE_ASPNETCORE /// @@ -138,7 +138,7 @@ namespace WireMock.Settings /// [PublicAPI] [JsonIgnore] - public Action AdditionalServiceRegistration { get; set; } + public Action? AdditionalServiceRegistration { get; set; } /// /// Policies to use when using CORS. By default CORS is disabled. [Optional] @@ -152,21 +152,21 @@ namespace WireMock.Settings /// [PublicAPI] [JsonIgnore] - public IWireMockLogger Logger { get; set; } + public IWireMockLogger Logger { get; set; } = null!; /// /// Handler to interact with the file system to read and write static mapping files. /// [PublicAPI] [JsonIgnore] - public IFileSystemHandler FileSystemHandler { get; set; } + public IFileSystemHandler FileSystemHandler { get; set; } = null!; /// /// Action which can be used to add additional Handlebars registrations. [Optional] /// [PublicAPI] [JsonIgnore] - public Action HandlebarsRegistrationCallback { get; set; } + public Action? HandlebarsRegistrationCallback { get; set; } /// /// Allow the usage of CSharpCodeMatcher (default is not allowed). @@ -220,7 +220,7 @@ namespace WireMock.Settings /// X509CertificateFilePath and X509CertificatePassword should be defined /// [PublicAPI] - public WireMockCertificateSettings CertificateSettings { get; set; } + public WireMockCertificateSettings? CertificateSettings { get; set; } /// /// Defines if custom CertificateSettings are defined @@ -232,7 +232,7 @@ namespace WireMock.Settings /// Defines the global IWebhookSettings to use. /// [PublicAPI] - public WebhookSettings WebhookSettings { get; set; } + public WebhookSettings? WebhookSettings { get; set; } /// /// Use the instead of the default (default set to true). @@ -250,6 +250,6 @@ namespace WireMock.Settings /// Custom matcher mappings for static mappings /// [PublicAPI, JsonIgnore] - public IDictionary> CustomMatcherMappings { get; set; } + public IDictionary>? CustomMatcherMappings { get; set; } } } \ No newline at end of file diff --git a/src/WireMock.Net/Transformers/ITransformer.cs b/src/WireMock.Net/Transformers/ITransformer.cs index f1af1fc9..cb956505 100644 --- a/src/WireMock.Net/Transformers/ITransformer.cs +++ b/src/WireMock.Net/Transformers/ITransformer.cs @@ -7,8 +7,8 @@ namespace WireMock.Transformers { interface ITransformer { - ResponseMessage Transform(RequestMessage requestMessage, ResponseMessage original, bool useTransformerForBodyAsFile, ReplaceNodeOptions options); + ResponseMessage Transform(IRequestMessage requestMessage, IResponseMessage original, bool useTransformerForBodyAsFile, ReplaceNodeOptions options); - (IBodyData BodyData, IDictionary> Headers) Transform(RequestMessage originalRequestMessage, ResponseMessage originalResponseMessage, IBodyData bodyData, IDictionary> headers, ReplaceNodeOptions options); + (IBodyData BodyData, IDictionary> Headers) Transform(IRequestMessage originalRequestMessage, IResponseMessage originalResponseMessage, IBodyData bodyData, IDictionary> headers, ReplaceNodeOptions options); } } \ No newline at end of file diff --git a/src/WireMock.Net/Transformers/Transformer.cs b/src/WireMock.Net/Transformers/Transformer.cs index 04aa2600..ea908148 100644 --- a/src/WireMock.Net/Transformers/Transformer.cs +++ b/src/WireMock.Net/Transformers/Transformer.cs @@ -18,7 +18,7 @@ namespace WireMock.Transformers _factory = factory ?? throw new ArgumentNullException(nameof(factory)); } - public (IBodyData BodyData, IDictionary> Headers) Transform(RequestMessage originalRequestMessage, ResponseMessage originalResponseMessage, IBodyData bodyData, IDictionary> headers, ReplaceNodeOptions options) + public (IBodyData BodyData, IDictionary> Headers) Transform(IRequestMessage originalRequestMessage, IResponseMessage originalResponseMessage, IBodyData bodyData, IDictionary> headers, ReplaceNodeOptions options) { var transformerContext = _factory.Create(); @@ -37,7 +37,7 @@ namespace WireMock.Transformers return (newBodyData, TransformHeaders(transformerContext, model, headers)); } - public ResponseMessage Transform(RequestMessage requestMessage, ResponseMessage original, bool useTransformerForBodyAsFile, ReplaceNodeOptions options) + public ResponseMessage Transform(IRequestMessage requestMessage, IResponseMessage original, bool useTransformerForBodyAsFile, ReplaceNodeOptions options) { var transformerContext = _factory.Create(); diff --git a/src/WireMock.Net/Util/JsonUtils.cs b/src/WireMock.Net/Util/JsonUtils.cs index ec754147..6af5b20b 100644 --- a/src/WireMock.Net/Util/JsonUtils.cs +++ b/src/WireMock.Net/Util/JsonUtils.cs @@ -1,213 +1,220 @@ -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Text; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using WireMock.Pact.Models.V2; using WireMock.Serialization; -namespace WireMock.Util +namespace WireMock.Util; + +internal static class JsonUtils { - internal static class JsonUtils + public static bool TryParseAsComplexObject(string strInput, [NotNullWhen(true)] out JToken? token) { - public static bool TryParseAsComplexObject(string strInput, out JToken token) + token = null; + + if (string.IsNullOrWhiteSpace(strInput)) { - token = null; - - if (string.IsNullOrWhiteSpace(strInput)) - { - return false; - } - - strInput = strInput.Trim(); - if ((!strInput.StartsWith("{") || !strInput.EndsWith("}")) && (!strInput.StartsWith("[") || !strInput.EndsWith("]"))) - { - return false; - } - - try - { - // Try to convert this string into a JToken - token = JToken.Parse(strInput); - return true; - } - catch - { - return false; - } + return false; } - public static string Serialize(T value) + strInput = strInput.Trim(); + if ((!strInput.StartsWith("{") || !strInput.EndsWith("}")) && (!strInput.StartsWith("[") || !strInput.EndsWith("]"))) { - return JsonConvert.SerializeObject(value, JsonSerializationConstants.JsonSerializerSettingsIncludeNullValues); + return false; } - /// - /// Load a Newtonsoft.Json.Linq.JObject from a string that contains JSON. - /// Using : DateParseHandling = DateParseHandling.None - /// - /// A System.String that contains JSON. - /// A Newtonsoft.Json.Linq.JToken populated from the string that contains JSON. - public static JToken Parse(string json) + try { - return JsonConvert.DeserializeObject(json, JsonSerializationConstants.JsonDeserializerSettingsWithDateParsingNone); + // Try to convert this string into a JToken + token = JToken.Parse(strInput); + return true; } - - /// - /// Deserializes the JSON to a .NET object. - /// Using : DateParseHandling = DateParseHandling.None - /// - /// A System.String that contains JSON. - /// The deserialized object from the JSON string. - public static object DeserializeObject(string json) + catch { - return JsonConvert.DeserializeObject(json, JsonSerializationConstants.JsonDeserializerSettingsWithDateParsingNone); - } - - /// - /// Deserializes the JSON to the specified .NET type. - /// Using : DateParseHandling = DateParseHandling.None - /// - /// A System.String that contains JSON. - /// The deserialized object from the JSON string. - public static T DeserializeObject(string json) - { - return JsonConvert.DeserializeObject(json, JsonSerializationConstants.JsonDeserializerSettingsWithDateParsingNone); - } - - public static T ParseJTokenToObject(object value) - { - switch (value) - { - case JToken tokenValue: - return tokenValue.ToObject(); - - default: - return default(T); - } - } - - public static string GenerateDynamicLinqStatement(JToken jsonObject) - { - var lines = new List(); - WalkNode(jsonObject, null, null, lines); - - return lines.First(); - } - - private static void WalkNode(JToken node, string path, string propertyName, List lines) - { - if (node.Type == JTokenType.Object) - { - ProcessObject(node, propertyName, lines); - } - else if (node.Type == JTokenType.Array) - { - ProcessArray(node, propertyName, lines); - } - else - { - ProcessItem(node, path ?? "it", propertyName, lines); - } - } - - private static void ProcessObject(JToken node, string propertyName, List lines) - { - var items = new List(); - var text = new StringBuilder("new ("); - - // In case of Object, loop all children. Do a ToArray() to avoid `Collection was modified` exceptions. - foreach (JProperty child in node.Children().ToArray()) - { - WalkNode(child.Value, child.Path, child.Name, items); - } - - text.Append(string.Join(", ", items)); - text.Append(")"); - - if (!string.IsNullOrEmpty(propertyName)) - { - text.AppendFormat(" as {0}", propertyName); - } - - lines.Add(text.ToString()); - } - - private static void ProcessArray(JToken node, string propertyName, List lines) - { - var items = new List(); - var text = new StringBuilder("(new [] { "); - - // In case of Array, loop all items. Do a ToArray() to avoid `Collection was modified` exceptions. - int idx = 0; - foreach (JToken child in node.Children().ToArray()) - { - WalkNode(child, $"{node.Path}[{idx}]", null, items); - idx++; - } - - text.Append(string.Join(", ", items)); - text.Append("})"); - - if (!string.IsNullOrEmpty(propertyName)) - { - text.AppendFormat(" as {0}", propertyName); - } - - lines.Add(text.ToString()); - } - - private static void ProcessItem(JToken node, string path, string propertyName, List lines) - { - string castText; - switch (node.Type) - { - case JTokenType.Boolean: - castText = $"bool({path})"; - break; - - case JTokenType.Date: - castText = $"DateTime({path})"; - break; - - case JTokenType.Float: - castText = $"double({path})"; - break; - - case JTokenType.Guid: - castText = $"Guid({path})"; - break; - - case JTokenType.Integer: - castText = $"long({path})"; - break; - - case JTokenType.Null: - castText = "null"; - break; - - case JTokenType.String: - castText = $"string({path})"; - break; - - case JTokenType.TimeSpan: - castText = $"TimeSpan({path})"; - break; - - case JTokenType.Uri: - castText = $"Uri({path})"; - break; - - default: - throw new NotSupportedException($"JTokenType '{node.Type}' cannot be converted to a Dynamic Linq cast operator."); - } - - if (!string.IsNullOrEmpty(propertyName)) - { - castText += $" as {propertyName}"; - } - - lines.Add(castText); + return false; } } + + public static string Serialize(object value) + { + return JsonConvert.SerializeObject(value, JsonSerializationConstants.JsonSerializerSettingsIncludeNullValues); + } + + public static byte[] SerializeAsPactFile(object value) + { + var json = JsonConvert.SerializeObject(value, JsonSerializationConstants.JsonSerializerSettingsPact); + return Encoding.UTF8.GetBytes(json); + } + + /// + /// Load a Newtonsoft.Json.Linq.JObject from a string that contains JSON. + /// Using : DateParseHandling = DateParseHandling.None + /// + /// A System.String that contains JSON. + /// A Newtonsoft.Json.Linq.JToken populated from the string that contains JSON. + public static JToken Parse(string json) + { + return JsonConvert.DeserializeObject(json, JsonSerializationConstants.JsonDeserializerSettingsWithDateParsingNone); + } + + /// + /// Deserializes the JSON to a .NET object. + /// Using : DateParseHandling = DateParseHandling.None + /// + /// A System.String that contains JSON. + /// The deserialized object from the JSON string. + public static object DeserializeObject(string json) + { + return JsonConvert.DeserializeObject(json, JsonSerializationConstants.JsonDeserializerSettingsWithDateParsingNone); + } + + /// + /// Deserializes the JSON to the specified .NET type. + /// Using : DateParseHandling = DateParseHandling.None + /// + /// A System.String that contains JSON. + /// The deserialized object from the JSON string. + public static T DeserializeObject(string json) + { + return JsonConvert.DeserializeObject(json, JsonSerializationConstants.JsonDeserializerSettingsWithDateParsingNone); + } + + public static T ParseJTokenToObject(object value) + { + switch (value) + { + case JToken tokenValue: + return tokenValue.ToObject(); + + default: + return default(T); + } + } + + public static string GenerateDynamicLinqStatement(JToken jsonObject) + { + var lines = new List(); + WalkNode(jsonObject, null, null, lines); + + return lines.First(); + } + + private static void WalkNode(JToken node, string? path, string? propertyName, List lines) + { + if (node.Type == JTokenType.Object) + { + ProcessObject(node, propertyName, lines); + } + else if (node.Type == JTokenType.Array) + { + ProcessArray(node, propertyName, lines); + } + else + { + ProcessItem(node, path ?? "it", propertyName, lines); + } + } + + private static void ProcessObject(JToken node, string? propertyName, List lines) + { + var items = new List(); + var text = new StringBuilder("new ("); + + // In case of Object, loop all children. Do a ToArray() to avoid `Collection was modified` exceptions. + foreach (JProperty child in node.Children().ToArray()) + { + WalkNode(child.Value, child.Path, child.Name, items); + } + + text.Append(string.Join(", ", items)); + text.Append(")"); + + if (!string.IsNullOrEmpty(propertyName)) + { + text.AppendFormat(" as {0}", propertyName); + } + + lines.Add(text.ToString()); + } + + private static void ProcessArray(JToken node, string? propertyName, List lines) + { + var items = new List(); + var text = new StringBuilder("(new [] { "); + + // In case of Array, loop all items. Do a ToArray() to avoid `Collection was modified` exceptions. + int idx = 0; + foreach (JToken child in node.Children().ToArray()) + { + WalkNode(child, $"{node.Path}[{idx}]", null, items); + idx++; + } + + text.Append(string.Join(", ", items)); + text.Append("})"); + + if (!string.IsNullOrEmpty(propertyName)) + { + text.AppendFormat(" as {0}", propertyName); + } + + lines.Add(text.ToString()); + } + + private static void ProcessItem(JToken node, string path, string propertyName, List lines) + { + string castText; + switch (node.Type) + { + case JTokenType.Boolean: + castText = $"bool({path})"; + break; + + case JTokenType.Date: + castText = $"DateTime({path})"; + break; + + case JTokenType.Float: + castText = $"double({path})"; + break; + + case JTokenType.Guid: + castText = $"Guid({path})"; + break; + + case JTokenType.Integer: + castText = $"long({path})"; + break; + + case JTokenType.Null: + castText = "null"; + break; + + case JTokenType.String: + castText = $"string({path})"; + break; + + case JTokenType.TimeSpan: + castText = $"TimeSpan({path})"; + break; + + case JTokenType.Uri: + castText = $"Uri({path})"; + break; + + default: + throw new NotSupportedException($"JTokenType '{node.Type}' cannot be converted to a Dynamic Linq cast operator."); + } + + if (!string.IsNullOrEmpty(propertyName)) + { + castText += $" as {propertyName}"; + } + + lines.Add(castText); + } } \ No newline at end of file diff --git a/src/WireMock.Net/Util/TinyMapperUtils.cs b/src/WireMock.Net/Util/TinyMapperUtils.cs index e5f89ed6..3bc9fb6d 100644 --- a/src/WireMock.Net/Util/TinyMapperUtils.cs +++ b/src/WireMock.Net/Util/TinyMapperUtils.cs @@ -2,29 +2,28 @@ using Nelibur.ObjectMapper; using WireMock.Admin.Settings; using WireMock.Settings; -namespace WireMock.Util +namespace WireMock.Util; + +internal sealed class TinyMapperUtils { - internal sealed class TinyMapperUtils + public static TinyMapperUtils Instance { get; } = new(); + + private TinyMapperUtils() { - public static TinyMapperUtils Instance { get; } = new TinyMapperUtils(); + TinyMapper.Bind(); + TinyMapper.Bind(); - private TinyMapperUtils() - { - TinyMapper.Bind(); - TinyMapper.Bind(); + TinyMapper.Bind(); + TinyMapper.Bind(); + } - TinyMapper.Bind(); - TinyMapper.Bind(); - } + public ProxyAndRecordSettingsModel? Map(ProxyAndRecordSettings? instance) + { + return instance == null ? null : TinyMapper.Map(instance); + } - public ProxyAndRecordSettingsModel Map(ProxyAndRecordSettings instance) - { - return instance == null ? null : TinyMapper.Map(instance); - } - - public ProxyAndRecordSettings Map(ProxyAndRecordSettingsModel model) - { - return model == null ? null : TinyMapper.Map(model); - } + public ProxyAndRecordSettings? Map(ProxyAndRecordSettingsModel? model) + { + return model == null ? null : TinyMapper.Map(model); } } \ No newline at end of file diff --git a/src/WireMock.Net/WireMock.Net.csproj b/src/WireMock.Net/WireMock.Net.csproj index 4cd6df9f..0f039b5c 100644 --- a/src/WireMock.Net/WireMock.Net.csproj +++ b/src/WireMock.Net/WireMock.Net.csproj @@ -52,6 +52,7 @@ + @@ -88,6 +89,7 @@ + @@ -98,11 +100,13 @@ + + @@ -112,17 +116,20 @@ + + + @@ -133,6 +140,12 @@ + + + WireMockServer.cs + + + diff --git a/test/WireMock.Net.Tests/Owin/WireMockMiddlewareTests.cs b/test/WireMock.Net.Tests/Owin/WireMockMiddlewareTests.cs index af712f54..0b57c5d1 100644 --- a/test/WireMock.Net.Tests/Owin/WireMockMiddlewareTests.cs +++ b/test/WireMock.Net.Tests/Owin/WireMockMiddlewareTests.cs @@ -176,7 +176,7 @@ namespace WireMock.Net.Tests.Owin _mappingMock.SetupGet(m => m.Provider).Returns(responseBuilder); _mappingMock.SetupGet(m => m.Settings).Returns(settings); - var newMappingFromProxy = new Mapping(Guid.NewGuid(), "", null, settings, Request.Create(), Response.Create(), 0, null, null, null, null, null, null); + var newMappingFromProxy = new Mapping(Guid.NewGuid(), string.Empty, string.Empty, null, settings, Request.Create(), Response.Create(), 0, null, null, null, null, null, null); _mappingMock.Setup(m => m.ProvideResponseAsync(It.IsAny())).ReturnsAsync((new ResponseMessage(), newMappingFromProxy)); var requestBuilder = Request.Create().UsingAnyMethod(); @@ -230,7 +230,7 @@ namespace WireMock.Net.Tests.Owin _mappingMock.SetupGet(m => m.Provider).Returns(responseBuilder); _mappingMock.SetupGet(m => m.Settings).Returns(settings); - var newMappingFromProxy = new Mapping(Guid.NewGuid(), "", null, settings, Request.Create(), Response.Create(), 0, null, null, null, null, null, null); + var newMappingFromProxy = new Mapping(Guid.NewGuid(), "my-title", "my-description", null, settings, Request.Create(), Response.Create(), 0, null, null, null, null, null, null); _mappingMock.Setup(m => m.ProvideResponseAsync(It.IsAny())).ReturnsAsync((new ResponseMessage(), newMappingFromProxy)); var requestBuilder = Request.Create().UsingAnyMethod(); diff --git a/test/WireMock.Net.Tests/Pact/PactTests.cs b/test/WireMock.Net.Tests/Pact/PactTests.cs new file mode 100644 index 00000000..5cce094c --- /dev/null +++ b/test/WireMock.Net.Tests/Pact/PactTests.cs @@ -0,0 +1,92 @@ +using System.IO; +using System.Net; +using WireMock.Matchers; +using WireMock.RequestBuilders; +using WireMock.ResponseBuilders; +using WireMock.Server; +using Xunit; + +namespace WireMock.Net.Tests.Pact; + +public class PactTests +{ + [Fact] + public void SavePact_Get_Request() + { + var server = WireMockServer.Start(); + server + .WithConsumer("Something API Consumer Get") + .WithProvider("Something API") + + .Given(Request.Create() + .UsingGet() + .WithPath("/tester") + .WithParam("q1", "test") + .WithParam("q2", "ok") + .WithHeader("Accept", "application/json") + ) + .WithTitle("A GET request to retrieve the something") + .RespondWith( + Response.Create() + .WithStatusCode(HttpStatusCode.OK) + .WithHeader("Content-Type", "application/json; charset=utf-8") + .WithBodyAsJson(new + { + Id = "tester", + FirstName = "Totally", + LastName = "Awesome" + }) + ); + + server.SavePact(Path.Combine("../../../", "Pact", "files"), "pact-get.json"); + } + + [Fact] + public void SavePact_Multiple_Requests() + { + var server = WireMockServer.Start(); + server + .WithConsumer("Something API Consumer Multiple") + .WithProvider("Something API") + + .Given(Request.Create() + .UsingPost() + .WithPath("/tester") + .WithParam("q1", "test") + .WithParam("q2", "ok") + .WithHeader("Accept", "application/json") + ) + .WithTitle("A GET request to retrieve the something") + .RespondWith( + Response.Create() + .WithStatusCode(HttpStatusCode.OK) + .WithHeader("Content-Type", "application/json; charset=utf-8") + .WithBodyAsJson(new + { + Id = "tester", + FirstName = "Totally", + LastName = "Awesome" + }) + ); + + server + .Given(Request.Create() + .UsingPost() + .WithPath("/add") + .WithHeader("Accept", "application/json") + .WithBody(new JsonMatcher("{ \"Id\" : \"1\", \"FirstName\" : \"Totally\" }")) + ) + .WithTitle("A Post request to add the something") + .RespondWith( + Response.Create() + .WithStatusCode(HttpStatusCode.RedirectMethod) + .WithBodyAsJson(new + { + Id = "1", + FirstName = "Totally" + }) + ); + + server.SavePact(Path.Combine("../../../", "Pact", "files"), "pact-multiple.json"); + } +} \ No newline at end of file diff --git a/test/WireMock.Net.Tests/Pact/files/pact-get.json b/test/WireMock.Net.Tests/Pact/files/pact-get.json new file mode 100644 index 00000000..e4099eb3 --- /dev/null +++ b/test/WireMock.Net.Tests/Pact/files/pact-get.json @@ -0,0 +1,32 @@ +{ + "Consumer": { + "Name": "Something API Consumer Get" + }, + "Interactions": [ + { + "ProviderState": "A GET request to retrieve the something", + "Request": { + "Headers": { + "Accept": "application/json" + }, + "Method": "GET", + "Path": "/tester", + "Query": "q1=test&q2=ok" + }, + "Response": { + "Body": { + "Id": "tester", + "FirstName": "Totally", + "LastName": "Awesome" + }, + "Headers": { + "Content-Type": "application/json; charset=utf-8" + }, + "Status": 200 + } + } + ], + "Provider": { + "Name": "Something API" + } +} \ No newline at end of file diff --git a/test/WireMock.Net.Tests/Pact/files/pact-multiple.json b/test/WireMock.Net.Tests/Pact/files/pact-multiple.json new file mode 100644 index 00000000..ddf7d594 --- /dev/null +++ b/test/WireMock.Net.Tests/Pact/files/pact-multiple.json @@ -0,0 +1,50 @@ +{ + "Consumer": { + "Name": "Something API Consumer Multiple" + }, + "Interactions": [ + { + "ProviderState": "A Post request to add the something", + "Request": { + "Headers": { + "Accept": "application/json" + }, + "Method": "POST", + "Path": "/add", + "Body": "{ \"Id\" : \"1\", \"FirstName\" : \"Totally\" }" + }, + "Response": { + "Body": { + "Id": "1", + "FirstName": "Totally" + }, + "Status": 303 + } + }, + { + "ProviderState": "A GET request to retrieve the something", + "Request": { + "Headers": { + "Accept": "application/json" + }, + "Method": "POST", + "Path": "/tester", + "Query": "q1=test&q2=ok" + }, + "Response": { + "Body": { + "Id": "tester", + "FirstName": "Totally", + "LastName": "Awesome" + }, + "Headers": { + "Content-Type": "application/json; charset=utf-8" + }, + "Status": 200 + } + } + ], + "Provider": { + "Name": "Something API" + } +} \ No newline at end of file diff --git a/test/WireMock.Net.Tests/Serialization/LogEntryMapperTests.cs b/test/WireMock.Net.Tests/Serialization/LogEntryMapperTests.cs index 0248c7b2..59bc86fc 100644 --- a/test/WireMock.Net.Tests/Serialization/LogEntryMapperTests.cs +++ b/test/WireMock.Net.Tests/Serialization/LogEntryMapperTests.cs @@ -1,4 +1,4 @@ -using FluentAssertions; +using FluentAssertions; using NFluent; using WireMock.Logging; using WireMock.Models; @@ -8,114 +8,113 @@ using WireMock.Types; using WireMock.Util; using Xunit; -namespace WireMock.Net.Tests.Serialization +namespace WireMock.Net.Tests.Serialization; + +public class LogEntryMapperTests { - public class LogEntryMapperTests + [Fact] + public void LogEntryMapper_Map_LogEntry_Check_BodyTypeBytes() { - [Fact] - public void LogEntryMapper_Map_LogEntry_Check_BodyTypeBytes() + // Assign + var logEntry = new LogEntry { - // Assign - var logEntry = new LogEntry - { - RequestMessage = new RequestMessage( - new UrlDetails("http://localhost"), - "post", - "::1", - new BodyData - { - DetectedBodyType = BodyType.Bytes, - BodyAsBytes = new byte[] { 0 } - } - ), - ResponseMessage = new ResponseMessage + RequestMessage = new RequestMessage( + new UrlDetails("http://localhost"), + "post", + "::1", + new BodyData { - BodyData = new BodyData - { - DetectedBodyType = BodyType.Bytes, - BodyAsBytes = new byte[] { 0 } - } + DetectedBodyType = BodyType.Bytes, + BodyAsBytes = new byte[] { 0 } } - }; + ), + ResponseMessage = new ResponseMessage + { + BodyData = new BodyData + { + DetectedBodyType = BodyType.Bytes, + BodyAsBytes = new byte[] { 0 } + } + } + }; - // Act - var result = LogEntryMapper.Map(logEntry); + // Act + var result = LogEntryMapper.Map(logEntry); - // Assert - Check.That(result.Request.DetectedBodyType).IsEqualTo("Bytes"); - Check.That(result.Request.DetectedBodyTypeFromContentType).IsEqualTo("None"); - Check.That(result.Request.BodyAsBytes).ContainsExactly(new byte[] { 0 }); - Check.That(result.Request.Body).IsNull(); - Check.That(result.Request.BodyAsJson).IsNull(); + // Assert + Check.That(result.Request.DetectedBodyType).IsEqualTo("Bytes"); + Check.That(result.Request.DetectedBodyTypeFromContentType).IsNull(); + Check.That(result.Request.BodyAsBytes).ContainsExactly(new byte[] { 0 }); + Check.That(result.Request.Body).IsNull(); + Check.That(result.Request.BodyAsJson).IsNull(); - Check.That(result.Response.DetectedBodyType).IsEqualTo(BodyType.Bytes); - Check.That(result.Response.DetectedBodyTypeFromContentType).IsEqualTo(BodyType.None); - Check.That(result.Response.BodyAsBytes).ContainsExactly(new byte[] { 0 }); - Check.That(result.Response.Body).IsNull(); - Check.That(result.Response.BodyAsJson).IsNull(); - Check.That(result.Response.BodyAsFile).IsNull(); - } + Check.That(result.Response.DetectedBodyType).IsEqualTo(BodyType.Bytes); + Check.That(result.Response.DetectedBodyTypeFromContentType).IsNull(); + Check.That(result.Response.BodyAsBytes).ContainsExactly(new byte[] { 0 }); + Check.That(result.Response.Body).IsNull(); + Check.That(result.Response.BodyAsJson).IsNull(); + Check.That(result.Response.BodyAsFile).IsNull(); + } - [Fact] - public void LogEntryMapper_Map_LogEntry_Check_ResponseBodyTypeFile() + [Fact] + public void LogEntryMapper_Map_LogEntry_Check_ResponseBodyTypeFile() + { + // Assign + var logEntry = new LogEntry { - // Assign - var logEntry = new LogEntry + RequestMessage = new RequestMessage(new UrlDetails("http://localhost"), "get", "::1"), + ResponseMessage = new ResponseMessage { - RequestMessage = new RequestMessage(new UrlDetails("http://localhost"), "get", "::1"), - ResponseMessage = new ResponseMessage + BodyData = new BodyData { - BodyData = new BodyData - { - DetectedBodyType = BodyType.File, - BodyAsFile = "test" - } + DetectedBodyType = BodyType.File, + BodyAsFile = "test" } - }; + } + }; - // Act - var result = LogEntryMapper.Map(logEntry); + // Act + var result = LogEntryMapper.Map(logEntry); - // Assert - Check.That(result.Request.DetectedBodyType).IsNull(); - Check.That(result.Request.DetectedBodyTypeFromContentType).IsNull(); - Check.That(result.Request.BodyAsBytes).IsNull(); - Check.That(result.Request.Body).IsNull(); - Check.That(result.Request.BodyAsJson).IsNull(); + // Assert + Check.That(result.Request.DetectedBodyType).IsNull(); + Check.That(result.Request.DetectedBodyTypeFromContentType).IsNull(); + Check.That(result.Request.BodyAsBytes).IsNull(); + Check.That(result.Request.Body).IsNull(); + Check.That(result.Request.BodyAsJson).IsNull(); - Check.That(result.Response.DetectedBodyType).IsEqualTo(BodyType.File); - Check.That(result.Response.DetectedBodyTypeFromContentType).IsEqualTo(BodyType.None); - Check.That(result.Request.BodyAsBytes).IsNull(); - Check.That(result.Response.Body).IsNull(); - Check.That(result.Response.BodyAsJson).IsNull(); - Check.That(result.Response.BodyAsFile).IsEqualTo("test"); - } + Check.That(result.Response.DetectedBodyType).IsEqualTo(BodyType.File); + Check.That(result.Response.DetectedBodyTypeFromContentType).IsNull(); + Check.That(result.Request.BodyAsBytes).IsNull(); + Check.That(result.Response.Body).IsNull(); + Check.That(result.Response.BodyAsJson).IsNull(); + Check.That(result.Response.BodyAsFile).IsEqualTo("test"); + } - [Fact] - public void LogEntryMapper_Map_LogEntry_WithFault() + [Fact] + public void LogEntryMapper_Map_LogEntry_WithFault() + { + // Assign + var logEntry = new LogEntry { - // Assign - var logEntry = new LogEntry + RequestMessage = new RequestMessage(new UrlDetails("http://localhost"), "get", "::1"), + ResponseMessage = new ResponseMessage { - RequestMessage = new RequestMessage(new UrlDetails("http://localhost"), "get", "::1"), - ResponseMessage = new ResponseMessage + BodyData = new BodyData { - BodyData = new BodyData - { - DetectedBodyType = BodyType.File, - BodyAsFile = "test" - }, - FaultType = FaultType.EMPTY_RESPONSE, - FaultPercentage = 0.5 - } - }; + DetectedBodyType = BodyType.File, + BodyAsFile = "test" + }, + FaultType = FaultType.EMPTY_RESPONSE, + FaultPercentage = 0.5 + } + }; - // Act - var result = LogEntryMapper.Map(logEntry); + // Act + var result = LogEntryMapper.Map(logEntry); - // Assert - result.Response.FaultType.Should().Be("EMPTY_RESPONSE"); - result.Response.FaultPercentage.Should().Be(0.5); - } + // Assert + result.Response.FaultType.Should().Be("EMPTY_RESPONSE"); + result.Response.FaultPercentage.Should().Be(0.5); } } \ No newline at end of file diff --git a/test/WireMock.Net.Tests/Serialization/MappingConverterTests.cs b/test/WireMock.Net.Tests/Serialization/MappingConverterTests.cs index ff7ea484..5e02ad43 100644 --- a/test/WireMock.Net.Tests/Serialization/MappingConverterTests.cs +++ b/test/WireMock.Net.Tests/Serialization/MappingConverterTests.cs @@ -52,7 +52,7 @@ namespace WireMock.Net.Tests.Serialization } } }; - var mapping = new Mapping(Guid.NewGuid(), "", null, _settings, request, response, 0, null, null, null, null, webhooks, null); + var mapping = new Mapping(Guid.NewGuid(), string.Empty, string.Empty, null, _settings, request, response, 0, null, null, null, null, webhooks, null); // Act var model = _sut.ToMappingModel(mapping); @@ -121,7 +121,7 @@ namespace WireMock.Net.Tests.Serialization } } }; - var mapping = new Mapping(Guid.NewGuid(), "", null, _settings, request, response, 0, null, null, null, null, webhooks, null); + var mapping = new Mapping(Guid.NewGuid(), string.Empty, string.Empty, null, _settings, request, response, 0, null, null, null, null, webhooks, null); // Act var model = _sut.ToMappingModel(mapping); @@ -147,13 +147,32 @@ namespace WireMock.Net.Tests.Serialization model.Webhooks[1].Request.Body.Should().Be("2"); } + [Fact] + public void ToMappingModel_WithTitle_And_Description_ReturnsCorrectModel() + { + // Assign + var title = "my-title"; + var description = "my-description"; + var request = Request.Create(); + var response = Response.Create(); + var mapping = new Mapping(Guid.NewGuid(), title, description, null, _settings, request, response, 0, null, null, null, null, null, null); + + // Act + var model = _sut.ToMappingModel(mapping); + + // Assert + model.Should().NotBeNull(); + model.Title.Should().Be(title); + model.Description.Should().Be(description); + } + [Fact] public void ToMappingModel_WithPriority_ReturnsPriority() { // Assign var request = Request.Create(); var response = Response.Create().WithBodyAsJson(new { x = "x" }).WithTransformer(); - var mapping = new Mapping(Guid.NewGuid(), "", null, _settings, request, response, 42, null, null, null, null, null, null); + var mapping = new Mapping(Guid.NewGuid(), string.Empty, string.Empty, null, _settings, request, response, 42, null, null, null, null, null, null); // Act var model = _sut.ToMappingModel(mapping); @@ -179,7 +198,7 @@ namespace WireMock.Net.Tests.Serialization End = end, TTL = ttl }; - var mapping = new Mapping(Guid.NewGuid(), "", null, _settings, request, response, 42, null, null, null, null, null, timeSettings); + var mapping = new Mapping(Guid.NewGuid(), string.Empty, string.Empty, null, _settings, request, response, 42, null, null, null, null, null, timeSettings); // Act var model = _sut.ToMappingModel(mapping); @@ -207,7 +226,7 @@ namespace WireMock.Net.Tests.Serialization { var request = Request.Create(); var response = Response.Create().WithDelay(test.Delay); - var mapping = new Mapping(Guid.NewGuid(), "", null, _settings, request, response, 42, null, null, null, null, null, null); + var mapping = new Mapping(Guid.NewGuid(), string.Empty, string.Empty, string.Empty, _settings, request, response, 42, null, null, null, null, null, null); // Act var model = _sut.ToMappingModel(mapping); @@ -225,7 +244,7 @@ namespace WireMock.Net.Tests.Serialization var delay = 1000; var request = Request.Create(); var response = Response.Create().WithDelay(delay); - var mapping = new Mapping(Guid.NewGuid(), "", null, _settings, request, response, 42, null, null, null, null, null, null); + var mapping = new Mapping(Guid.NewGuid(), string.Empty, string.Empty, null, _settings, request, response, 42, null, null, null, null, null, null); // Act var model = _sut.ToMappingModel(mapping); @@ -242,7 +261,7 @@ namespace WireMock.Net.Tests.Serialization int minimumDelay = 1000; var request = Request.Create(); var response = Response.Create().WithRandomDelay(minimumDelay); - var mapping = new Mapping(Guid.NewGuid(), "", null, _settings, request, response, 42, null, null, null, null, null, null); + var mapping = new Mapping(Guid.NewGuid(), string.Empty, string.Empty, null, _settings, request, response, 42, null, null, null, null, null, null); // Act var model = _sut.ToMappingModel(mapping); @@ -262,7 +281,7 @@ namespace WireMock.Net.Tests.Serialization int maximumDelay = 2000; var request = Request.Create(); var response = Response.Create().WithRandomDelay(minimumDelay, maximumDelay); - var mapping = new Mapping(Guid.NewGuid(), "", null, _settings, request, response, 42, null, null, null, null, null, null); + var mapping = new Mapping(Guid.NewGuid(), string.Empty, string.Empty, null, _settings, request, response, 42, null, null, null, null, null, null); // Act var model = _sut.ToMappingModel(mapping); diff --git a/test/WireMock.Net.Tests/WireMock.Net.Tests.csproj b/test/WireMock.Net.Tests/WireMock.Net.Tests.csproj index eb10c5cf..e950f5aa 100644 --- a/test/WireMock.Net.Tests/WireMock.Net.Tests.csproj +++ b/test/WireMock.Net.Tests/WireMock.Net.Tests.csproj @@ -113,4 +113,8 @@ + + + + \ No newline at end of file