From ea5563db1330bb6f9fad13718589ab7832c0910e Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Fri, 29 Jul 2022 23:02:40 +0200 Subject: [PATCH] more reformat --- .../Admin/Requests/LogEntryModel.cs | 8 +- .../Serialization/LogEntryMapper.cs | 233 ++++++------ .../Server/WireMockServer.Admin.cs | 2 +- .../WireMockServer.ImportWireMockOrg.cs | 2 +- src/WireMock.Net/Util/BytesEncodingUtils.cs | 344 +++++++++--------- src/WireMock.Net/Util/CompressionUtils.cs | 62 ++-- src/WireMock.Net/Util/DictionaryExtensions.cs | 38 +- src/WireMock.Net/Util/FileHelper.cs | 47 ++- .../Util/HttpStatusRangeParser.cs | 129 ++++--- src/WireMock.Net/Util/PortUtils.cs | 84 ++--- src/WireMock.Net/Util/QueryStringParser.cs | 45 ++- src/WireMock.Net/Util/TypeBuilderUtils.cs | 4 +- src/WireMock.Net/Util/UrlUtils.cs | 46 ++- .../Util/FileHelperTests.cs | 77 ++-- 14 files changed, 551 insertions(+), 570 deletions(-) diff --git a/src/WireMock.Net.Abstractions/Admin/Requests/LogEntryModel.cs b/src/WireMock.Net.Abstractions/Admin/Requests/LogEntryModel.cs index ac327fa65..9c4ffefa0 100644 --- a/src/WireMock.Net.Abstractions/Admin/Requests/LogEntryModel.cs +++ b/src/WireMock.Net.Abstractions/Admin/Requests/LogEntryModel.cs @@ -30,12 +30,12 @@ public class LogEntryModel /// /// The mapping unique title. /// - public string MappingTitle { get; set; } + public string? MappingTitle { get; set; } /// /// The request match result. /// - public LogRequestMatchModel RequestMatchResult { get; set; } + public LogRequestMatchModel? RequestMatchResult { get; set; } /// /// The partial mapping unique identifier. @@ -45,10 +45,10 @@ public class LogEntryModel /// /// The partial mapping unique title. /// - public string PartialMappingTitle { get; set; } + public string? PartialMappingTitle { get; set; } /// /// The partial request match result. /// - public LogRequestMatchModel PartialRequestMatchResult { get; set; } + public LogRequestMatchModel? PartialRequestMatchResult { get; set; } } \ No newline at end of file diff --git a/src/WireMock.Net/Serialization/LogEntryMapper.cs b/src/WireMock.Net/Serialization/LogEntryMapper.cs index d3f46075e..9299b4fc1 100644 --- a/src/WireMock.Net/Serialization/LogEntryMapper.cs +++ b/src/WireMock.Net/Serialization/LogEntryMapper.cs @@ -6,143 +6,142 @@ using WireMock.ResponseBuilders; using WireMock.Types; -namespace WireMock.Serialization +namespace WireMock.Serialization; + +internal static class LogEntryMapper { - internal static class LogEntryMapper + public static LogEntryModel Map(ILogEntry logEntry) { - public static LogEntryModel Map(ILogEntry logEntry) + var logRequestModel = new LogRequestModel { - var logRequestModel = new LogRequestModel - { - DateTime = logEntry.RequestMessage.DateTime, - ClientIP = logEntry.RequestMessage.ClientIP, - Path = logEntry.RequestMessage.Path, - AbsolutePath = logEntry.RequestMessage.AbsolutePath, - Url = logEntry.RequestMessage.Url, - AbsoluteUrl = logEntry.RequestMessage.AbsoluteUrl, - ProxyUrl = logEntry.RequestMessage.ProxyUrl, - Query = logEntry.RequestMessage.Query, - Method = logEntry.RequestMessage.Method, - Headers = logEntry.RequestMessage.Headers, - Cookies = logEntry.RequestMessage.Cookies - }; - - if (logEntry.RequestMessage.BodyData != null) + DateTime = logEntry.RequestMessage.DateTime, + ClientIP = logEntry.RequestMessage.ClientIP, + Path = logEntry.RequestMessage.Path, + AbsolutePath = logEntry.RequestMessage.AbsolutePath, + Url = logEntry.RequestMessage.Url, + AbsoluteUrl = logEntry.RequestMessage.AbsoluteUrl, + ProxyUrl = logEntry.RequestMessage.ProxyUrl, + Query = logEntry.RequestMessage.Query, + Method = logEntry.RequestMessage.Method, + Headers = logEntry.RequestMessage.Headers, + Cookies = logEntry.RequestMessage.Cookies + }; + + if (logEntry.RequestMessage.BodyData != null) + { + logRequestModel.DetectedBodyType = logEntry.RequestMessage.BodyData.DetectedBodyType?.ToString(); + logRequestModel.DetectedBodyTypeFromContentType = logEntry.RequestMessage.BodyData.DetectedBodyTypeFromContentType?.ToString(); + + switch (logEntry.RequestMessage.BodyData.DetectedBodyType) { - logRequestModel.DetectedBodyType = logEntry.RequestMessage.BodyData.DetectedBodyType?.ToString(); - logRequestModel.DetectedBodyTypeFromContentType = logEntry.RequestMessage.BodyData.DetectedBodyTypeFromContentType?.ToString(); + case BodyType.String: + logRequestModel.Body = logEntry.RequestMessage.BodyData.BodyAsString; + break; + + case BodyType.Json: + logRequestModel.Body = logEntry.RequestMessage.BodyData.BodyAsString; // In case of Json, do also save the Body as string (backwards compatible) + logRequestModel.BodyAsJson = logEntry.RequestMessage.BodyData.BodyAsJson; + break; + + case BodyType.Bytes: + logRequestModel.BodyAsBytes = logEntry.RequestMessage.BodyData.BodyAsBytes; + break; + } - switch (logEntry.RequestMessage.BodyData.DetectedBodyType) + logRequestModel.BodyEncoding = logEntry.RequestMessage.BodyData.Encoding != null + ? new EncodingModel { - case BodyType.String: - logRequestModel.Body = logEntry.RequestMessage.BodyData.BodyAsString; - break; - - case BodyType.Json: - logRequestModel.Body = logEntry.RequestMessage.BodyData.BodyAsString; // In case of Json, do also save the Body as string (backwards compatible) - logRequestModel.BodyAsJson = logEntry.RequestMessage.BodyData.BodyAsJson; - break; - - case BodyType.Bytes: - logRequestModel.BodyAsBytes = logEntry.RequestMessage.BodyData.BodyAsBytes; - break; + EncodingName = logEntry.RequestMessage.BodyData.Encoding.EncodingName, + CodePage = logEntry.RequestMessage.BodyData.Encoding.CodePage, + WebName = logEntry.RequestMessage.BodyData.Encoding.WebName } + : null; + } - logRequestModel.BodyEncoding = logEntry.RequestMessage.BodyData.Encoding != null - ? new EncodingModel - { - EncodingName = logEntry.RequestMessage.BodyData.Encoding.EncodingName, - CodePage = logEntry.RequestMessage.BodyData.Encoding.CodePage, - WebName = logEntry.RequestMessage.BodyData.Encoding.WebName - } - : null; - } + var logResponseModel = new LogResponseModel + { + StatusCode = logEntry.ResponseMessage.StatusCode, + Headers = logEntry.ResponseMessage.Headers + }; - var logResponseModel = new LogResponseModel - { - StatusCode = logEntry.ResponseMessage.StatusCode, - Headers = logEntry.ResponseMessage.Headers - }; + if (logEntry.ResponseMessage.FaultType != FaultType.NONE) + { + logResponseModel.FaultType = logEntry.ResponseMessage.FaultType.ToString(); + logResponseModel.FaultPercentage = logEntry.ResponseMessage.FaultPercentage; + } - if (logEntry.ResponseMessage.FaultType != FaultType.NONE) - { - logResponseModel.FaultType = logEntry.ResponseMessage.FaultType.ToString(); - logResponseModel.FaultPercentage = logEntry.ResponseMessage.FaultPercentage; - } + if (logEntry.ResponseMessage.BodyData != null) + { + logResponseModel.BodyOriginal = logEntry.ResponseMessage.BodyOriginal; + logResponseModel.BodyDestination = logEntry.ResponseMessage.BodyDestination; - if (logEntry.ResponseMessage.BodyData != null) - { - logResponseModel.BodyOriginal = logEntry.ResponseMessage.BodyOriginal; - logResponseModel.BodyDestination = logEntry.ResponseMessage.BodyDestination; + logResponseModel.DetectedBodyType = logEntry.ResponseMessage.BodyData.DetectedBodyType; + logResponseModel.DetectedBodyTypeFromContentType = logEntry.ResponseMessage.BodyData.DetectedBodyTypeFromContentType; - logResponseModel.DetectedBodyType = logEntry.ResponseMessage.BodyData.DetectedBodyType; - logResponseModel.DetectedBodyTypeFromContentType = logEntry.ResponseMessage.BodyData.DetectedBodyTypeFromContentType; + switch (logEntry.ResponseMessage.BodyData.DetectedBodyType) + { + case BodyType.String: + logResponseModel.Body = logEntry.ResponseMessage.BodyData.BodyAsString; + break; + + case BodyType.Json: + logResponseModel.BodyAsJson = logEntry.ResponseMessage.BodyData.BodyAsJson; + break; + + case BodyType.Bytes: + logResponseModel.BodyAsBytes = logEntry.ResponseMessage.BodyData.BodyAsBytes; + break; + + case BodyType.File: + logResponseModel.BodyAsFile = logEntry.ResponseMessage.BodyData.BodyAsFile; + logResponseModel.BodyAsFileIsCached = logEntry.ResponseMessage.BodyData.BodyAsFileIsCached; + break; + } - switch (logEntry.ResponseMessage.BodyData.DetectedBodyType) + logResponseModel.BodyEncoding = logEntry.ResponseMessage.BodyData.Encoding != null + ? new EncodingModel { - case BodyType.String: - logResponseModel.Body = logEntry.ResponseMessage.BodyData.BodyAsString; - break; - - case BodyType.Json: - logResponseModel.BodyAsJson = logEntry.ResponseMessage.BodyData.BodyAsJson; - break; - - case BodyType.Bytes: - logResponseModel.BodyAsBytes = logEntry.ResponseMessage.BodyData.BodyAsBytes; - break; - - case BodyType.File: - logResponseModel.BodyAsFile = logEntry.ResponseMessage.BodyData.BodyAsFile; - logResponseModel.BodyAsFileIsCached = logEntry.ResponseMessage.BodyData.BodyAsFileIsCached; - break; + EncodingName = logEntry.ResponseMessage.BodyData.Encoding.EncodingName, + CodePage = logEntry.ResponseMessage.BodyData.Encoding.CodePage, + WebName = logEntry.ResponseMessage.BodyData.Encoding.WebName } + : null; + } - logResponseModel.BodyEncoding = logEntry.ResponseMessage.BodyData.Encoding != null - ? new EncodingModel - { - EncodingName = logEntry.ResponseMessage.BodyData.Encoding.EncodingName, - CodePage = logEntry.ResponseMessage.BodyData.Encoding.CodePage, - WebName = logEntry.ResponseMessage.BodyData.Encoding.WebName - } - : null; - } + return new LogEntryModel + { + Guid = logEntry.Guid, + Request = logRequestModel, + Response = logResponseModel, + + MappingGuid = logEntry.MappingGuid, + MappingTitle = logEntry.MappingTitle, + RequestMatchResult = Map(logEntry.RequestMatchResult), + + PartialMappingGuid = logEntry.PartialMappingGuid, + PartialMappingTitle = logEntry.PartialMappingTitle, + PartialRequestMatchResult = Map(logEntry.PartialMatchResult) + }; + } - return new LogEntryModel - { - Guid = logEntry.Guid, - Request = logRequestModel, - Response = logResponseModel, - - MappingGuid = logEntry.MappingGuid, - MappingTitle = logEntry.MappingTitle, - RequestMatchResult = Map(logEntry.RequestMatchResult), - - PartialMappingGuid = logEntry.PartialMappingGuid, - PartialMappingTitle = logEntry.PartialMappingTitle, - PartialRequestMatchResult = Map(logEntry.PartialMatchResult) - }; + private static LogRequestMatchModel? Map(IRequestMatchResult? matchResult) + { + if (matchResult == null) + { + return null; } - private static LogRequestMatchModel Map(IRequestMatchResult matchResult) + return new LogRequestMatchModel { - if (matchResult == null) + IsPerfectMatch = matchResult.IsPerfectMatch, + TotalScore = matchResult.TotalScore, + TotalNumber = matchResult.TotalNumber, + AverageTotalScore = matchResult.AverageTotalScore, + MatchDetails = matchResult.MatchDetails.Select(md => new { - return null; - } - - return new LogRequestMatchModel - { - IsPerfectMatch = matchResult.IsPerfectMatch, - TotalScore = matchResult.TotalScore, - TotalNumber = matchResult.TotalNumber, - AverageTotalScore = matchResult.AverageTotalScore, - MatchDetails = matchResult.MatchDetails.Select(md => new - { - Name = md.MatcherType.Name.Replace("RequestMessage", string.Empty), - Score = md.Score - } as object).ToList() - }; - } + Name = md.MatcherType.Name.Replace("RequestMessage", string.Empty), + Score = md.Score + } as object).ToList() + }; } } \ No newline at end of file diff --git a/src/WireMock.Net/Server/WireMockServer.Admin.cs b/src/WireMock.Net/Server/WireMockServer.Admin.cs index 6d8fb11a9..79ef9f334 100644 --- a/src/WireMock.Net/Server/WireMockServer.Admin.cs +++ b/src/WireMock.Net/Server/WireMockServer.Admin.cs @@ -185,7 +185,7 @@ public bool ReadStaticMappingAndAddOrUpdate(string path) string filenameWithoutExtension = Path.GetFileNameWithoutExtension(path); - if (FileHelper.TryReadMappingFileWithRetryAndDelay(_settings.FileSystemHandler, path, out string value)) + if (FileHelper.TryReadMappingFileWithRetryAndDelay(_settings.FileSystemHandler, path, out var value)) { var mappingModels = DeserializeJsonToArray(value); foreach (var mappingModel in mappingModels) diff --git a/src/WireMock.Net/Server/WireMockServer.ImportWireMockOrg.cs b/src/WireMock.Net/Server/WireMockServer.ImportWireMockOrg.cs index fccb0bd8b..4ac38764c 100644 --- a/src/WireMock.Net/Server/WireMockServer.ImportWireMockOrg.cs +++ b/src/WireMock.Net/Server/WireMockServer.ImportWireMockOrg.cs @@ -27,7 +27,7 @@ public void ReadStaticWireMockOrgMappingAndAddOrUpdate(string path) string filenameWithoutExtension = Path.GetFileNameWithoutExtension(path); - if (FileHelper.TryReadMappingFileWithRetryAndDelay(_settings.FileSystemHandler, path, out string value)) + if (FileHelper.TryReadMappingFileWithRetryAndDelay(_settings.FileSystemHandler, path, out var value)) { var mappings = DeserializeJsonToArray(value); foreach (var mapping in mappings) diff --git a/src/WireMock.Net/Util/BytesEncodingUtils.cs b/src/WireMock.Net/Util/BytesEncodingUtils.cs index 8635448b6..97904d918 100644 --- a/src/WireMock.Net/Util/BytesEncodingUtils.cs +++ b/src/WireMock.Net/Util/BytesEncodingUtils.cs @@ -1,230 +1,230 @@ -using System; +using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Text; -namespace WireMock.Util +namespace WireMock.Util; + +/// +/// Based on: +/// http://utf8checker.codeplex.com +/// https://github.com/0x53A/Mvvm/blob/master/src/Mvvm/src/Utf8Checker.cs +/// +/// References: +/// http://anubis.dkuug.dk/JTC1/SC2/WG2/docs/n1335 +/// http://www.cl.cam.ac.uk/~mgk25/ucs/ISO-10646-UTF-8.html +/// http://www.unicode.org/versions/corrigendum1.html +/// http://www.ietf.org/rfc/rfc2279.txt +/// +public static class BytesEncodingUtils { /// - /// Based on: - /// http://utf8checker.codeplex.com - /// https://github.com/0x53A/Mvvm/blob/master/src/Mvvm/src/Utf8Checker.cs - /// - /// References: - /// http://anubis.dkuug.dk/JTC1/SC2/WG2/docs/n1335 - /// http://www.cl.cam.ac.uk/~mgk25/ucs/ISO-10646-UTF-8.html - /// http://www.unicode.org/versions/corrigendum1.html - /// http://www.ietf.org/rfc/rfc2279.txt + /// Tries the get the Encoding from an array of bytes. /// - public static class BytesEncodingUtils + /// The bytes. + /// The output encoding. + public static bool TryGetEncoding(byte[] bytes, [NotNullWhen(true)] out Encoding? encoding) { - /// - /// Tries the get the Encoding from an array of bytes. - /// - /// The bytes. - /// The output encoding. - public static bool TryGetEncoding(byte[] bytes, out Encoding encoding) - { - encoding = null; - if (bytes.All(b => b < 80)) - { - encoding = Encoding.ASCII; - return true; - } + encoding = null; + if (bytes.All(b => b < 80)) + { + encoding = Encoding.ASCII; + return true; + } - if (StartsWith(bytes, new byte[] { 0xff, 0xfe, 0x00, 0x00 })) - { - encoding = Encoding.UTF32; - return true; - } + if (StartsWith(bytes, new byte[] { 0xff, 0xfe, 0x00, 0x00 })) + { + encoding = Encoding.UTF32; + return true; + } - if (StartsWith(bytes, new byte[] { 0xfe, 0xff })) - { - encoding = Encoding.BigEndianUnicode; - return true; - } + if (StartsWith(bytes, new byte[] { 0xfe, 0xff })) + { + encoding = Encoding.BigEndianUnicode; + return true; + } - if (StartsWith(bytes, new byte[] { 0xff, 0xfe })) - { - encoding = Encoding.Unicode; - return true; - } + if (StartsWith(bytes, new byte[] { 0xff, 0xfe })) + { + encoding = Encoding.Unicode; + return true; + } - if (StartsWith(bytes, new byte[] { 0xef, 0xbb, 0xbf })) - { - encoding = Encoding.UTF8; - return true; - } + if (StartsWith(bytes, new byte[] { 0xef, 0xbb, 0xbf })) + { + encoding = Encoding.UTF8; + return true; + } - if (IsUtf8(bytes, bytes.Length)) + if (IsUtf8(bytes, bytes.Length)) + { + encoding = new UTF8Encoding(false); + return true; + } + + return false; + } + + private static bool StartsWith(IEnumerable data, IReadOnlyCollection other) + { + byte[] arraySelf = data.Take(other.Count).ToArray(); + return other.SequenceEqual(arraySelf); + } + + private static bool IsUtf8(IReadOnlyList buffer, int length) + { + int position = 0; + int bytes = 0; + while (position < length) + { + if (!IsValid(buffer, position, length, ref bytes)) { - encoding = new UTF8Encoding(false); - return true; + return false; } + position += bytes; + } + return true; + } - return false; +#pragma warning disable S3776 // Cognitive Complexity of methods should not be too high + private static bool IsValid(IReadOnlyList buffer, int position, int length, ref int bytes) + { + if (length > buffer.Count) + { + throw new ArgumentException("Invalid length"); } - private static bool StartsWith(IEnumerable data, IReadOnlyCollection other) + if (position > length - 1) { - byte[] arraySelf = data.Take(other.Count).ToArray(); - return other.SequenceEqual(arraySelf); + bytes = 0; + return true; } - private static bool IsUtf8(IReadOnlyList buffer, int length) + byte ch = buffer[position]; + if (ch <= 0x7F) { - int position = 0; - int bytes = 0; - while (position < length) + bytes = 1; + return true; + } + + if (ch >= 0xc2 && ch <= 0xdf) + { + if (position >= length - 2) { - if (!IsValid(buffer, position, length, ref bytes)) - { - return false; - } - position += bytes; + bytes = 0; + return false; } + + if (buffer[position + 1] < 0x80 || buffer[position + 1] > 0xbf) + { + bytes = 0; + return false; + } + + bytes = 2; return true; } -#pragma warning disable S3776 // Cognitive Complexity of methods should not be too high - private static bool IsValid(IReadOnlyList buffer, int position, int length, ref int bytes) + if (ch == 0xe0) { - if (length > buffer.Count) + if (position >= length - 3) { - throw new ArgumentException("Invalid length"); + bytes = 0; + return false; } - if (position > length - 1) + if (buffer[position + 1] < 0xa0 || buffer[position + 1] > 0xbf || + buffer[position + 2] < 0x80 || buffer[position + 2] > 0xbf) { bytes = 0; - return true; + return false; } - byte ch = buffer[position]; - if (ch <= 0x7F) + bytes = 3; + return true; + } + + if (ch >= 0xe1 && ch <= 0xef) + { + if (position >= length - 3) { - bytes = 1; - return true; + bytes = 0; + return false; } - if (ch >= 0xc2 && ch <= 0xdf) + if (buffer[position + 1] < 0x80 || buffer[position + 1] > 0xbf || + buffer[position + 2] < 0x80 || buffer[position + 2] > 0xbf) { - if (position >= length - 2) - { - bytes = 0; - return false; - } - - if (buffer[position + 1] < 0x80 || buffer[position + 1] > 0xbf) - { - bytes = 0; - return false; - } - - bytes = 2; - return true; + bytes = 0; + return false; } - if (ch == 0xe0) + bytes = 3; + return true; + } + + if (ch == 0xf0) + { + if (position >= length - 4) + { + bytes = 0; + return false; + } + + if (buffer[position + 1] < 0x90 || buffer[position + 1] > 0xbf || + buffer[position + 2] < 0x80 || buffer[position + 2] > 0xbf || + buffer[position + 3] < 0x80 || buffer[position + 3] > 0xbf) { - if (position >= length - 3) - { - bytes = 0; - return false; - } - - if (buffer[position + 1] < 0xa0 || buffer[position + 1] > 0xbf || - buffer[position + 2] < 0x80 || buffer[position + 2] > 0xbf) - { - bytes = 0; - return false; - } - - bytes = 3; - return true; + bytes = 0; + return false; } - if (ch >= 0xe1 && ch <= 0xef) + bytes = 4; + return true; + } + + if (ch == 0xf4) + { + if (position >= length - 4) { - if (position >= length - 3) - { - bytes = 0; - return false; - } - - if (buffer[position + 1] < 0x80 || buffer[position + 1] > 0xbf || - buffer[position + 2] < 0x80 || buffer[position + 2] > 0xbf) - { - bytes = 0; - return false; - } - - bytes = 3; - return true; + bytes = 0; + return false; } - if (ch == 0xf0) + if (buffer[position + 1] < 0x80 || buffer[position + 1] > 0x8f || + buffer[position + 2] < 0x80 || buffer[position + 2] > 0xbf || + buffer[position + 3] < 0x80 || buffer[position + 3] > 0xbf) { - if (position >= length - 4) - { - bytes = 0; - return false; - } - - if (buffer[position + 1] < 0x90 || buffer[position + 1] > 0xbf || - buffer[position + 2] < 0x80 || buffer[position + 2] > 0xbf || - buffer[position + 3] < 0x80 || buffer[position + 3] > 0xbf) - { - bytes = 0; - return false; - } - - bytes = 4; - return true; + bytes = 0; + return false; } - if (ch == 0xf4) + bytes = 4; + return true; + } + + if (ch >= 0xf1 && ch <= 0xf3) + { + if (position >= length - 4) { - if (position >= length - 4) - { - bytes = 0; - return false; - } - - if (buffer[position + 1] < 0x80 || buffer[position + 1] > 0x8f || - buffer[position + 2] < 0x80 || buffer[position + 2] > 0xbf || - buffer[position + 3] < 0x80 || buffer[position + 3] > 0xbf) - { - bytes = 0; - return false; - } - - bytes = 4; - return true; + bytes = 0; + return false; } - if (ch >= 0xf1 && ch <= 0xf3) + if (buffer[position + 1] < 0x80 || buffer[position + 1] > 0xbf || + buffer[position + 2] < 0x80 || buffer[position + 2] > 0xbf || + buffer[position + 3] < 0x80 || buffer[position + 3] > 0xbf) { - if (position >= length - 4) - { - bytes = 0; - return false; - } - - if (buffer[position + 1] < 0x80 || buffer[position + 1] > 0xbf || - buffer[position + 2] < 0x80 || buffer[position + 2] > 0xbf || - buffer[position + 3] < 0x80 || buffer[position + 3] > 0xbf) - { - bytes = 0; - return false; - } - - bytes = 4; - return true; + bytes = 0; + return false; } - return false; + bytes = 4; + return true; } + + return false; } -#pragma warning restore S3776 // Cognitive Complexity of methods should not be too high -} \ No newline at end of file +} +#pragma warning restore S3776 // Cognitive Complexity of methods should not be too high \ No newline at end of file diff --git a/src/WireMock.Net/Util/CompressionUtils.cs b/src/WireMock.Net/Util/CompressionUtils.cs index 78880ce42..40da363cf 100644 --- a/src/WireMock.Net/Util/CompressionUtils.cs +++ b/src/WireMock.Net/Util/CompressionUtils.cs @@ -1,49 +1,39 @@ -using System; +using System; using System.IO; using System.IO.Compression; -namespace WireMock.Util +namespace WireMock.Util; + +internal static class CompressionUtils { - internal static class CompressionUtils + public static byte[] Compress(string contentEncoding, byte[] data) { - public static byte[] Compress(string contentEncoding, byte[] data) - { - using (var compressedStream = new MemoryStream()) - using (var zipStream = Create(contentEncoding, compressedStream, CompressionMode.Compress)) - { - zipStream.Write(data, 0, data.Length); + using var compressedStream = new MemoryStream(); + using var zipStream = Create(contentEncoding, compressedStream, CompressionMode.Compress); + zipStream.Write(data, 0, data.Length); #if !NETSTANDARD1_3 - zipStream.Close(); + zipStream.Close(); #endif - return compressedStream.ToArray(); - } - } + return compressedStream.ToArray(); + } - public static byte[] Decompress(string contentEncoding, byte[] data) - { - using (var compressedStream = new MemoryStream(data)) - using (var zipStream = Create(contentEncoding, compressedStream, CompressionMode.Decompress)) - using (var resultStream = new MemoryStream()) - { - zipStream.CopyTo(resultStream); - return resultStream.ToArray(); - } - } + public static byte[] Decompress(string contentEncoding, byte[] data) + { + using var compressedStream = new MemoryStream(data); + using var zipStream = Create(contentEncoding, compressedStream, CompressionMode.Decompress); + using var resultStream = new MemoryStream(); + zipStream.CopyTo(resultStream); + return resultStream.ToArray(); + } - private static Stream Create(string contentEncoding, Stream stream, CompressionMode mode) + private static Stream Create(string contentEncoding, Stream stream, CompressionMode mode) + { + return contentEncoding switch { - switch (contentEncoding) - { - case "gzip": - return new GZipStream(stream, mode); - - case "deflate": - return new DeflateStream(stream, mode); - - default: - throw new NotSupportedException($"ContentEncoding '{contentEncoding}' is not supported."); - } - } + "gzip" => new GZipStream(stream, mode), + "deflate" => new DeflateStream(stream, mode), + _ => throw new NotSupportedException($"ContentEncoding '{contentEncoding}' is not supported.") + }; } } \ No newline at end of file diff --git a/src/WireMock.Net/Util/DictionaryExtensions.cs b/src/WireMock.Net/Util/DictionaryExtensions.cs index 58884fa31..aeae8ad85 100644 --- a/src/WireMock.Net/Util/DictionaryExtensions.cs +++ b/src/WireMock.Net/Util/DictionaryExtensions.cs @@ -1,32 +1,30 @@ -using System; +using System; using System.Collections.Generic; -using JetBrains.Annotations; using Stef.Validation; -namespace WireMock.Util +namespace WireMock.Util; + +/// +/// Some IDictionary Extensions +/// +public static class DictionaryExtensions { /// - /// Some IDictionary Extensions + /// Loops the dictionary and executes the specified action. /// - public static class DictionaryExtensions + /// The type of the key. + /// The type of the value. + /// The dictionary to loop (can be null). + /// The action. + public static void Loop(this IDictionary? dictionary, Action action) { - /// - /// Loops the dictionary and executes the specified action. - /// - /// The type of the key. - /// The type of the value. - /// The dictionary to loop (can be null). - /// The action. - public static void Loop(this IDictionary dictionary, [NotNull] Action action) - { - Guard.NotNull(action, nameof(action)); + Guard.NotNull(action); - if (dictionary != null) + if (dictionary != null) + { + foreach (var entry in dictionary) { - foreach (var entry in dictionary) - { - action(entry.Key, entry.Value); - } + action(entry.Key, entry.Value); } } } diff --git a/src/WireMock.Net/Util/FileHelper.cs b/src/WireMock.Net/Util/FileHelper.cs index 82b5c12bd..99a80cbbf 100644 --- a/src/WireMock.Net/Util/FileHelper.cs +++ b/src/WireMock.Net/Util/FileHelper.cs @@ -1,36 +1,35 @@ -using JetBrains.Annotations; +using System.Diagnostics.CodeAnalysis; using System.Threading; -using WireMock.Handlers; using Stef.Validation; +using WireMock.Handlers; + +namespace WireMock.Util; -namespace WireMock.Util +internal static class FileHelper { - internal static class FileHelper - { - private const int NumberOfRetries = 3; - private const int DelayOnRetry = 500; + private const int NumberOfRetries = 3; + private const int DelayOnRetry = 500; - public static bool TryReadMappingFileWithRetryAndDelay([NotNull] IFileSystemHandler handler, [NotNull] string path, out string value) - { - Guard.NotNull(handler, nameof(handler)); - Guard.NotNullOrEmpty(path, nameof(path)); + public static bool TryReadMappingFileWithRetryAndDelay(IFileSystemHandler handler, string path, [NotNullWhen(true)] out string? value) + { + Guard.NotNull(handler); + Guard.NotNullOrEmpty(path); - value = null; + value = null; - for (int i = 1; i <= NumberOfRetries; ++i) + for (int i = 1; i <= NumberOfRetries; ++i) + { + try { - try - { - value = handler.ReadMappingFile(path); - return true; - } - catch - { - Thread.Sleep(DelayOnRetry); - } + value = handler.ReadMappingFile(path); + return true; + } + catch + { + Thread.Sleep(DelayOnRetry); } - - return false; } + + return false; } } \ No newline at end of file diff --git a/src/WireMock.Net/Util/HttpStatusRangeParser.cs b/src/WireMock.Net/Util/HttpStatusRangeParser.cs index e0830acc6..a212f03a6 100644 --- a/src/WireMock.Net/Util/HttpStatusRangeParser.cs +++ b/src/WireMock.Net/Util/HttpStatusRangeParser.cs @@ -1,91 +1,90 @@ -using System; +using System; using System.Linq; using System.Net; using System.Text.RegularExpressions; -namespace WireMock.Util +namespace WireMock.Util; + +/// +/// Based on https://github.com/tmenier/Flurl/blob/129565361e135e639f1d44a35a78aea4302ac6ca/src/Flurl.Http/HttpStatusRangeParser.cs +/// +internal static class HttpStatusRangeParser { /// - /// Based on https://github.com/tmenier/Flurl/blob/129565361e135e639f1d44a35a78aea4302ac6ca/src/Flurl.Http/HttpStatusRangeParser.cs + /// Determines whether the specified pattern is match. /// - internal static class HttpStatusRangeParser + /// The pattern. (Can be null, in that case it's allowed.) + /// The value. + /// is invalid. + public static bool IsMatch(string pattern, object httpStatusCode) { - /// - /// Determines whether the specified pattern is match. - /// - /// The pattern. (Can be null, in that case it's allowed.) - /// The value. - /// is invalid. - public static bool IsMatch(string pattern, object httpStatusCode) + switch (httpStatusCode) { - switch (httpStatusCode) - { - case int statusCodeAsInteger: - return IsMatch(pattern, statusCodeAsInteger); - - case string statusCodeAsString: - return IsMatch(pattern, int.Parse(statusCodeAsString)); - } + case int statusCodeAsInteger: + return IsMatch(pattern, statusCodeAsInteger); - return false; + case string statusCodeAsString: + return IsMatch(pattern, int.Parse(statusCodeAsString)); } - /// - /// Determines whether the specified pattern is match. - /// - /// The pattern. (Can be null, in that case it's allowed.) - /// The value. - /// is invalid. - public static bool IsMatch(string pattern, HttpStatusCode httpStatusCode) + return false; + } + + /// + /// Determines whether the specified pattern is match. + /// + /// The pattern. (Can be null, in that case it's allowed.) + /// The value. + /// is invalid. + public static bool IsMatch(string pattern, HttpStatusCode httpStatusCode) + { + return IsMatch(pattern, (int)httpStatusCode); + } + + /// + /// Determines whether the specified pattern is match. + /// + /// The pattern. (Can be null, in that case it's allowed.) + /// The value. + /// is invalid. + public static bool IsMatch(string? pattern, int httpStatusCode) + { + if (pattern == null) { - return IsMatch(pattern, (int)httpStatusCode); + return true; } - /// - /// Determines whether the specified pattern is match. - /// - /// The pattern. (Can be null, in that case it's allowed.) - /// The value. - /// is invalid. - public static bool IsMatch(string pattern, int httpStatusCode) + foreach (var range in pattern.Split(',').Select(p => p.Trim())) { - if (pattern == null) - { - return true; - } - - foreach (var range in pattern.Split(',').Select(p => p.Trim())) + switch (range) { - switch (range) - { - case "": - continue; - - case "*": - return true; // special case - allow everything - } + case "": + continue; - string[] bounds = range.Split('-'); - int lower = 0; - int upper = 0; + case "*": + return true; // special case - allow everything + } - bool valid = - bounds.Length <= 2 && - int.TryParse(Regex.Replace(bounds.First().Trim(), "[*xX]", "0"), out lower) && - int.TryParse(Regex.Replace(bounds.Last().Trim(), "[*xX]", "9"), out upper); + string[] bounds = range.Split('-'); + int lower = 0; + int upper = 0; - if (!valid) - { - throw new ArgumentException($"Invalid range pattern: \"{pattern}\". Examples of allowed patterns: \"400\", \"4xx\", \"300,400-403\", \"*\"."); - } + bool valid = + bounds.Length <= 2 && + int.TryParse(Regex.Replace(bounds.First().Trim(), "[*xX]", "0"), out lower) && + int.TryParse(Regex.Replace(bounds.Last().Trim(), "[*xX]", "9"), out upper); - if (httpStatusCode >= lower && httpStatusCode <= upper) - { - return true; - } + if (!valid) + { + throw new ArgumentException($"Invalid range pattern: \"{pattern}\". Examples of allowed patterns: \"400\", \"4xx\", \"300,400-403\", \"*\"."); } - return false; + if (httpStatusCode >= lower && httpStatusCode <= upper) + { + return true; + } } + + return false; } } \ No newline at end of file diff --git a/src/WireMock.Net/Util/PortUtils.cs b/src/WireMock.Net/Util/PortUtils.cs index 6bb189984..04fcd70ef 100644 --- a/src/WireMock.Net/Util/PortUtils.cs +++ b/src/WireMock.Net/Util/PortUtils.cs @@ -1,58 +1,58 @@ -using System; +using System; +using System.Diagnostics.CodeAnalysis; using System.Net; using System.Net.Sockets; using System.Text.RegularExpressions; -namespace WireMock.Util +namespace WireMock.Util; + +/// +/// Port Utility class +/// +public static class PortUtils { + private static readonly Regex UrlDetailsRegex = new(@"^((?\w+)://)(?[^/]+?):(?\d+)\/?$", RegexOptions.Compiled); + /// - /// Port Utility class + /// Finds a free TCP port. /// - public static class PortUtils + /// see http://stackoverflow.com/questions/138043/find-the-next-tcp-port-in-net. + public static int FindFreeTcpPort() { - private static readonly Regex UrlDetailsRegex = new Regex(@"^((?\w+)://)(?[^/]+?):(?\d+)\/?$", RegexOptions.Compiled); + TcpListener? tcpListener = null; + try + { + tcpListener = new TcpListener(IPAddress.Loopback, 0); + tcpListener.Start(); - /// - /// Finds a free TCP port. - /// - /// see http://stackoverflow.com/questions/138043/find-the-next-tcp-port-in-net. - public static int FindFreeTcpPort() + return ((IPEndPoint)tcpListener.LocalEndpoint).Port; + } + finally { - TcpListener tcpListener = null; - try - { - tcpListener = new TcpListener(IPAddress.Loopback, 0); - tcpListener.Start(); - - return ((IPEndPoint)tcpListener.LocalEndpoint).Port; - } - finally - { - tcpListener?.Stop(); - } + tcpListener?.Stop(); } + } - /// - /// Extract the if-isHttps, protocol, host and port from a URL. - /// - public static bool TryExtract(string url, out bool isHttps, out string protocol, out string host, out int port) + /// + /// Extract the if-isHttps, protocol, host and port from a URL. + /// + public static bool TryExtract(string url, out bool isHttps, [NotNullWhen(true)] out string? protocol, [NotNullWhen(true)] out string? host, out int port) + { + isHttps = false; + protocol = null; + host = null; + port = default; + + var match = UrlDetailsRegex.Match(url); + if (match.Success) { - isHttps = false; - protocol = null; - host = null; - port = default; - - var match = UrlDetailsRegex.Match(url); - if (match.Success) - { - protocol = match.Groups["proto"].Value; - isHttps = protocol.StartsWith("https", StringComparison.OrdinalIgnoreCase); - host = match.Groups["host"].Value; - - return int.TryParse(match.Groups["port"].Value, out port); - } - - return false; + protocol = match.Groups["proto"].Value; + isHttps = protocol.StartsWith("https", StringComparison.OrdinalIgnoreCase); + host = match.Groups["host"].Value; + + return int.TryParse(match.Groups["port"].Value, out port); } + + return false; } } \ No newline at end of file diff --git a/src/WireMock.Net/Util/QueryStringParser.cs b/src/WireMock.Net/Util/QueryStringParser.cs index 279b62900..293fcd574 100644 --- a/src/WireMock.Net/Util/QueryStringParser.cs +++ b/src/WireMock.Net/Util/QueryStringParser.cs @@ -1,38 +1,37 @@ -using System; +using System; using System.Net; using System.Collections.Generic; using System.Linq; using WireMock.Types; -namespace WireMock.Util +namespace WireMock.Util; + +/// +/// Based on https://stackoverflow.com/questions/659887/get-url-parameters-from-a-string-in-net +/// +internal static class QueryStringParser { - /// - /// Based on https://stackoverflow.com/questions/659887/get-url-parameters-from-a-string-in-net - /// - internal static class QueryStringParser + public static IDictionary> Parse(string queryString) { - public static IDictionary> Parse(string queryString) + if (string.IsNullOrEmpty(queryString)) { - if (string.IsNullOrEmpty(queryString)) - { - return new Dictionary>(); - } + return new Dictionary>(); + } - string[] JoinParts(string[] parts) + string[] JoinParts(string[] parts) + { + if (parts.Length > 1) { - if (parts.Length > 1) - { - return parts[1].Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries); // support "?key=1,2" - } - - return new string[0]; + return parts[1].Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries); // support "?key=1,2" } - return queryString.TrimStart('?') - .Split(new[] { '&', ';' }, StringSplitOptions.RemoveEmptyEntries) // Support "?key=value;key=anotherValue" and "?key=value&key=anotherValue" - .Select(parameter => parameter.Split(new[] { '=' }, 2, StringSplitOptions.RemoveEmptyEntries)) - .GroupBy(parts => parts[0], JoinParts) - .ToDictionary(grouping => grouping.Key, grouping => new WireMockList(grouping.SelectMany(x => x).Select(WebUtility.UrlDecode))); + return new string[0]; } + + return queryString.TrimStart('?') + .Split(new[] { '&', ';' }, StringSplitOptions.RemoveEmptyEntries) // Support "?key=value;key=anotherValue" and "?key=value&key=anotherValue" + .Select(parameter => parameter.Split(new[] { '=' }, 2, StringSplitOptions.RemoveEmptyEntries)) + .GroupBy(parts => parts[0], JoinParts) + .ToDictionary(grouping => grouping.Key, grouping => new WireMockList(grouping.SelectMany(x => x).Select(WebUtility.UrlDecode))); } } \ No newline at end of file diff --git a/src/WireMock.Net/Util/TypeBuilderUtils.cs b/src/WireMock.Net/Util/TypeBuilderUtils.cs index 30fe9fbf2..d78e717fd 100644 --- a/src/WireMock.Net/Util/TypeBuilderUtils.cs +++ b/src/WireMock.Net/Util/TypeBuilderUtils.cs @@ -14,8 +14,8 @@ internal static class TypeBuilderUtils { private static readonly ConcurrentDictionary, Type> Types = new(); - private static readonly ModuleBuilder ModuleBuilder = - AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("WireMock.Net.Reflection"), AssemblyBuilderAccess.Run) + private static readonly ModuleBuilder ModuleBuilder = AssemblyBuilder + .DefineDynamicAssembly(new AssemblyName("WireMock.Net.Reflection"), AssemblyBuilderAccess.Run) .DefineDynamicModule("WireMock.Net.Reflection.Module"); public static Type BuildType(IDictionary properties, string? name = null) diff --git a/src/WireMock.Net/Util/UrlUtils.cs b/src/WireMock.Net/Util/UrlUtils.cs index 7def9ee1d..9f9ca76f9 100644 --- a/src/WireMock.Net/Util/UrlUtils.cs +++ b/src/WireMock.Net/Util/UrlUtils.cs @@ -1,5 +1,4 @@ -using System; -using JetBrains.Annotations; +using System; using WireMock.Models; using Stef.Validation; #if !USE_ASPNETCORE @@ -8,34 +7,33 @@ using Microsoft.AspNetCore.Http; #endif -namespace WireMock.Util +namespace WireMock.Util; + +internal static class UrlUtils { - internal static class UrlUtils + public static UrlDetails Parse(Uri uri, PathString pathBase) { - public static UrlDetails Parse([NotNull] Uri uri, PathString pathBase) - { - Guard.NotNull(uri, nameof(uri)); + Guard.NotNull(uri); - if (!pathBase.HasValue) - { - return new UrlDetails(uri, uri); - } + if (!pathBase.HasValue) + { + return new UrlDetails(uri, uri); + } - var builder = new UriBuilder(uri); - builder.Path = RemoveFirst(builder.Path, pathBase.Value); + var builder = new UriBuilder(uri); + builder.Path = RemoveFirst(builder.Path, pathBase.Value); - return new UrlDetails(uri, builder.Uri); - } + return new UrlDetails(uri, builder.Uri); + } - private static string RemoveFirst(string text, string search) + private static string RemoveFirst(string text, string search) + { + int pos = text.IndexOf(search, StringComparison.Ordinal); + if (pos < 0) { - int pos = text.IndexOf(search, StringComparison.Ordinal); - if (pos < 0) - { - return text; - } - - return text.Substring(0, pos) + text.Substring(pos + search.Length); + return text; } + + return text.Substring(0, pos) + text.Substring(pos + search.Length); } -} +} \ No newline at end of file diff --git a/test/WireMock.Net.Tests/Util/FileHelperTests.cs b/test/WireMock.Net.Tests/Util/FileHelperTests.cs index 97a887e97..c77f201b9 100644 --- a/test/WireMock.Net.Tests/Util/FileHelperTests.cs +++ b/test/WireMock.Net.Tests/Util/FileHelperTests.cs @@ -1,48 +1,47 @@ -using FluentAssertions; +using FluentAssertions; using Moq; using System; using WireMock.Handlers; using WireMock.Util; using Xunit; -namespace WireMock.Net.Tests.Util +namespace WireMock.Net.Tests.Util; + +public class FileHelperTests { - public class FileHelperTests + [Fact] + public void TryReadMappingFileWithRetryAndDelay_WithIFileSystemHandlerOk_ReturnsTrue() + { + // Assign + var staticMappingHandlerMock = new Mock(); + staticMappingHandlerMock.Setup(m => m.ReadMappingFile(It.IsAny())).Returns("text"); + + // Act + bool result = FileHelper.TryReadMappingFileWithRetryAndDelay(staticMappingHandlerMock.Object, @"c:\temp", out var value); + + // Assert + result.Should().BeTrue(); + value.Should().Be("text"); + + // Verify + staticMappingHandlerMock.Verify(m => m.ReadMappingFile(@"c:\temp"), Times.Once); + } + + [Fact] + public void TryReadMappingFileWithRetryAndDelay_WithIFileSystemHandlerThrows_ReturnsFalse() { - [Fact] - public void TryReadMappingFileWithRetryAndDelay_WithIFileSystemHandlerOk_ReturnsTrue() - { - // Assign - var staticMappingHandlerMock = new Mock(); - staticMappingHandlerMock.Setup(m => m.ReadMappingFile(It.IsAny())).Returns("text"); - - // Act - bool result = FileHelper.TryReadMappingFileWithRetryAndDelay(staticMappingHandlerMock.Object, @"c:\temp", out string value); - - // Assert - result.Should().BeTrue(); - value.Should().Be("text"); - - // Verify - staticMappingHandlerMock.Verify(m => m.ReadMappingFile(@"c:\temp"), Times.Once); - } - - [Fact] - public void TryReadMappingFileWithRetryAndDelay_WithIFileSystemHandlerThrows_ReturnsFalse() - { - // Assign - var staticMappingHandlerMock = new Mock(); - staticMappingHandlerMock.Setup(m => m.ReadMappingFile(It.IsAny())).Throws(); - - // Act - bool result = FileHelper.TryReadMappingFileWithRetryAndDelay(staticMappingHandlerMock.Object, @"c:\temp", out string value); - - // Assert - result.Should().BeFalse(); - value.Should().BeNull(); - - // Verify - staticMappingHandlerMock.Verify(m => m.ReadMappingFile(@"c:\temp"), Times.Exactly(3)); - } + // Assign + var staticMappingHandlerMock = new Mock(); + staticMappingHandlerMock.Setup(m => m.ReadMappingFile(It.IsAny())).Throws(); + + // Act + bool result = FileHelper.TryReadMappingFileWithRetryAndDelay(staticMappingHandlerMock.Object, @"c:\temp", out var value); + + // Assert + result.Should().BeFalse(); + value.Should().BeNull(); + + // Verify + staticMappingHandlerMock.Verify(m => m.ReadMappingFile(@"c:\temp"), Times.Exactly(3)); } -} +} \ No newline at end of file