diff --git a/examples/WireMock.Net.Console.MimePart/Program.cs b/examples/WireMock.Net.Console.MimePart/Program.cs index 85d66ba5..bb54bb58 100644 --- a/examples/WireMock.Net.Console.MimePart/Program.cs +++ b/examples/WireMock.Net.Console.MimePart/Program.cs @@ -9,7 +9,7 @@ namespace WireMock.Net.Console.MimePart; static class Program { - private static readonly ILoggerRepository LogRepository = LogManager.GetRepository(Assembly.GetEntryAssembly()); + private static readonly ILoggerRepository LogRepository = LogManager.GetRepository(Assembly.GetEntryAssembly()!); private static readonly ILog Log = LogManager.GetLogger(typeof(Program)); static async Task Main(params string[] args) diff --git a/examples/WireMock.Net.Console.NET8/MainApp.cs b/examples/WireMock.Net.Console.NET8/MainApp.cs index ad6e29dc..9023b526 100644 --- a/examples/WireMock.Net.Console.NET8/MainApp.cs +++ b/examples/WireMock.Net.Console.NET8/MainApp.cs @@ -1115,7 +1115,7 @@ namespace WireMock.Net.ConsoleApplication { BodyData = new BodyData { - BodyAsString = "random200or505:" + code + ", HeadersFromRequest = " + string.Join(",", request.Headers), + BodyAsString = "random200or505:" + code + ", HeadersFromRequest = " + request.Headers != null ? string.Join(",", request.Headers!.Select(h => $"{h.Key}:{h.Value}")) : "none", DetectedBodyType = BodyType.String, }, StatusCode = code diff --git a/src/WireMock.Net.Abstractions/Types/WireMockList.cs b/src/WireMock.Net.Abstractions/Types/WireMockList.cs index 23f40909..de7d0f29 100644 --- a/src/WireMock.Net.Abstractions/Types/WireMockList.cs +++ b/src/WireMock.Net.Abstractions/Types/WireMockList.cs @@ -1,11 +1,11 @@ // Copyright © WireMock.Net -using System.Linq; - namespace WireMock.Types; /// -/// A special List which overrides the ToString() to return first value. +/// A special List which overrides the ToString() to return first value in case of a single element. +/// Else it will return a comma separated list of all values. +/// If null or empty, it will return an empty string. /// /// The generic type /// @@ -61,11 +61,11 @@ public class WireMockList : List { return strValue; } - - return this[0]?.ToString(); + + return this[0]?.ToString() ?? string.Empty; default: - var strings = this.Select(x => x as string ?? x?.ToString()); + var strings = this.Select(x => x as string ?? x?.ToString() ?? string.Empty); return string.Join(", ", strings); } } diff --git a/src/WireMock.Net.Minimal/Server/AdminPaths.cs b/src/WireMock.Net.Minimal/Owin/AdminPaths.cs similarity index 95% rename from src/WireMock.Net.Minimal/Server/AdminPaths.cs rename to src/WireMock.Net.Minimal/Owin/AdminPaths.cs index ded2388e..191c5521 100644 --- a/src/WireMock.Net.Minimal/Server/AdminPaths.cs +++ b/src/WireMock.Net.Minimal/Owin/AdminPaths.cs @@ -12,29 +12,48 @@ internal sealed class AdminPaths(string? adminPath) : IAdminPaths private readonly string _prefix = adminPath ?? DefaultAdminPathPrefix; public string Files => $"{_prefix}/files"; + public string Health => $"{_prefix}/health"; + public string Mappings => $"{_prefix}/mappings"; + public string MappingsCode => $"{_prefix}/mappings/code"; + public string MappingsWireMockOrg => $"{_prefix}/mappings/wiremock.org"; + public string Requests => $"{_prefix}/requests"; + public string Settings => $"{_prefix}/settings"; + public string Scenarios => $"{_prefix}/scenarios"; + public string OpenApi => $"{_prefix}/openapi"; + public string ProtoDefinitions => $"{_prefix}/protodefinitions"; private string PrefixRegexEscaped => Regex.Escape(_prefix); + public RegexMatcher MappingsGuidPathMatcher => new($@"^{PrefixRegexEscaped}\/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}})$"); + public RegexMatcher MappingsGuidEnablePathMatcher => new($@"^{PrefixRegexEscaped}\/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}})\/enable$"); + public RegexMatcher MappingsGuidDisablePathMatcher => new($@"^{PrefixRegexEscaped}\/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}})\/disable$"); + public RegexMatcher MappingsCodeGuidPathMatcher => new($@"^{PrefixRegexEscaped}\/mappings\/code\/([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}})$"); + public RegexMatcher RequestsGuidPathMatcher => new($@"^{PrefixRegexEscaped}\/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}})$"); + public RegexMatcher ScenariosNameMatcher => new($@"^{PrefixRegexEscaped}\/scenarios\/.+$"); + public RegexMatcher ScenariosNameWithStateMatcher => new($@"^{PrefixRegexEscaped}\/scenarios\/.+\/state$"); + public RegexMatcher ScenariosNameWithResetMatcher => new($@"^{PrefixRegexEscaped}\/scenarios\/.+\/reset$"); + public RegexMatcher FilesFilenamePathMatcher => new($@"^{PrefixRegexEscaped}\/files\/.+$"); + public RegexMatcher ProtoDefinitionsIdPathMatcher => new($@"^{PrefixRegexEscaped}\/protodefinitions\/.+$"); - public bool Includes(string? path) => !string.IsNullOrEmpty(path) && path.StartsWith($"{_prefix}/"); + public bool Includes(string? path) => path?.StartsWith($"{_prefix}/") ?? false; public override string ToString() => _prefix; -} +} \ No newline at end of file diff --git a/src/WireMock.Net.Minimal/Owin/IAdminPaths.cs b/src/WireMock.Net.Minimal/Owin/IAdminPaths.cs index 67c9f186..c0f8b8ce 100644 --- a/src/WireMock.Net.Minimal/Owin/IAdminPaths.cs +++ b/src/WireMock.Net.Minimal/Owin/IAdminPaths.cs @@ -5,24 +5,44 @@ namespace WireMock.Owin; internal interface IAdminPaths { string Files { get; } + string Health { get; } + string Mappings { get; } + string MappingsCode { get; } + string MappingsWireMockOrg { get; } + RegexMatcher MappingsGuidPathMatcher { get; } + RegexMatcher MappingsGuidEnablePathMatcher { get; } + RegexMatcher MappingsGuidDisablePathMatcher { get; } + RegexMatcher MappingsCodeGuidPathMatcher { get; } + RegexMatcher RequestsGuidPathMatcher { get; } + RegexMatcher ScenariosNameMatcher { get; } + RegexMatcher ScenariosNameWithStateMatcher { get; } + RegexMatcher ScenariosNameWithResetMatcher { get; } + RegexMatcher FilesFilenamePathMatcher { get; } + RegexMatcher ProtoDefinitionsIdPathMatcher { get; } + string Requests { get; } + string Settings { get; } + string Scenarios { get; } + string OpenApi { get; } + string ProtoDefinitions { get; } + bool Includes(string? path); } \ No newline at end of file diff --git a/test/WireMock.Net.Tests/Abstractions/WireMockListTests.cs b/test/WireMock.Net.Tests/Abstractions/WireMockListTests.cs new file mode 100644 index 00000000..ea268778 --- /dev/null +++ b/test/WireMock.Net.Tests/Abstractions/WireMockListTests.cs @@ -0,0 +1,411 @@ +// Copyright © WireMock.Net + +using WireMock.Types; + +namespace WireMock.Net.Tests.Abstractions; + +public class WireMockListTests +{ + #region String Generic Type Tests + + [Fact] + public void WireMockListOfString_Constructor_Empty_ShouldCreateEmptyList() + { + // Act + var list = new WireMockList(); + + // Assert + list.Should().BeEmpty(); + list.Count.Should().Be(0); + } + + [Fact] + public void WireMockListOfString_Constructor_WithSingleString_ShouldCreateListWithOneElement() + { + // Arrange + var value = "test"; + + // Act + var list = new WireMockList(value); + + // Assert + list.Should().HaveCount(1); + list[0].Should().Be("test"); + } + + [Fact] + public void WireMockListOfString_Constructor_WithMultipleStrings_ShouldCreateListWithAllElements() + { + // Arrange + var values = new[] { "value1", "value2", "value3" }; + + // Act + var list = new WireMockList(values); + + // Assert + list.Should().HaveCount(3); + list.Should().ContainInOrder("value1", "value2", "value3"); + } + + [Fact] + public void WireMockListOfString_Constructor_WithIEnumerable_ShouldCreateListWithAllElements() + { + // Arrange + var values = new List { "a", "b", "c" }; + + // Act + var list = new WireMockList(values); + + // Assert + list.Should().HaveCount(3); + list.Should().ContainInOrder("a", "b", "c"); + } + + [Fact] + public void WireMockListOfString_ToString_WhenEmpty_ShouldReturnEmptyString() + { + // Arrange + var list = new WireMockList(); + + // Act + var result = list.ToString(); + + // Assert + result.Should().Be(string.Empty); + } + + [Fact] + public void WireMockListOfString_ToString_WhenSingleElement_ShouldReturnElementValue() + { + // Arrange + var list = new WireMockList("singleValue"); + + // Act + var result = list.ToString(); + + // Assert + result.Should().Be("singleValue"); + } + + [Fact] + public void WireMockListOfString_ToString_WhenMultipleElements_ShouldReturnCommaSeparatedValues() + { + // Arrange + var list = new WireMockList("value1", "value2", "value3"); + + // Act + var result = list.ToString(); + + // Assert + result.Should().Be("value1, value2, value3"); + } + + [Fact] + public void WireMockListOfString_ImplicitOperator_WithSingleValue_ShouldCreateList() + { + // Act + WireMockList list = "testValue"; + + // Assert + list.Should().HaveCount(1); + list[0].Should().Be("testValue"); + } + + [Fact] + public void WireMockListOfString_ImplicitOperator_WithArray_ShouldCreateList() + { + // Arrange + var values = new[] { "first", "second", "third" }; + + // Act + WireMockList list = values; + + // Assert + list.Should().HaveCount(3); + list.Should().ContainInOrder("first", "second", "third"); + } + + #endregion + + #region Object Generic Type Tests + + [Fact] + public void WireMockListOfObject_Constructor_Empty_ShouldCreateEmptyList() + { + // Act + var list = new WireMockList(); + + // Assert + list.Should().BeEmpty(); + list.Count.Should().Be(0); + } + + [Fact] + public void WireMockListOfObject_Constructor_WithSingleObject_ShouldCreateListWithOneElement() + { + // Arrange + var obj = new { Name = "Test", Value = 123 }; + + // Act + var list = new WireMockList(obj); + + // Assert + list.Should().HaveCount(1); + list[0].Should().Be(obj); + } + + [Fact] + public void WireMockListOfObject_Constructor_WithMultipleObjects_ShouldCreateListWithAllElements() + { + // Arrange + var obj1 = new object(); + var obj2 = new object(); + var obj3 = new object(); + var values = new[] { obj1, obj2, obj3 }; + + // Act + var list = new WireMockList(values); + + // Assert + list.Should().HaveCount(3); + list.Should().ContainInOrder(obj1, obj2, obj3); + } + + [Fact] + public void WireMockListOfObject_Constructor_WithIEnumerable_ShouldCreateListWithAllElements() + { + // Arrange + var values = new List + { + "string", + 123, + 45.67, + true, + null + }; + + // Act + var list = new WireMockList(values); + + // Assert + list.Should().HaveCount(5); + list.Should().ContainInOrder("string", 123, 45.67, true, null); + } + + [Fact] + public void WireMockListOfObject_ToString_WhenEmpty_ShouldReturnEmptyString() + { + // Arrange + var list = new WireMockList(); + + // Act + var result = list.ToString(); + + // Assert + result.Should().Be(string.Empty); + } + + [Fact] + public void WireMockListOfObject_ToString_WhenSingleString_ShouldReturnString() + { + // Arrange + var list = new WireMockList("singleString"); + + // Act + var result = list.ToString(); + + // Assert + result.Should().Be("singleString"); + } + + [Fact] + public void WireMockListOfObject_ToString_WhenSingleObject_ShouldReturnObjectToString() + { + // Arrange + var obj = new { Name = "Test" }; + var list = new WireMockList(obj); + + // Act + var result = list.ToString(); + + // Assert + result.Should().Contain("Name"); + result.Should().Contain("Test"); + } + + [Fact] + public void WireMockListOfObject_ToString_WhenSingleInt_ShouldReturnIntAsString() + { + // Arrange + var list = new WireMockList(42); + + // Act + var result = list.ToString(); + + // Assert + result.Should().Be("42"); + } + + [Fact] + public void WireMockListOfObject_ToString_WhenMultipleElements_ShouldReturnCommaSeparatedValues() + { + // Arrange + var list = new WireMockList("text", 123, 45.67); + + // Act + var result = list.ToString(); + + // Assert + result.Should().Be($"text, 123, {45.67}"); + } + + [Fact] + public void WireMockListOfObject_ToString_WithMixedTypes_ShouldReturnCommaSeparatedStringRepresentation() + { + // Arrange + var list = new WireMockList + { + "string", + 123, + 45.67, + true + }; + + // Act + var result = list.ToString(); + + // Assert + result.Should().Be($"string, 123, {45.67}, True"); + } + + [Fact] + public void WireMockListOfObject_ToString_WithNullValue_ShouldReturnEmptyStringForNull() + { + // Arrange + var list = new WireMockList + { + "value1", + null, + "value3" + }; + + // Act + var result = list.ToString(); + + // Assert + result.Should().Be("value1, , value3"); + } + + [Fact] + public void WireMockListOfObject_ImplicitOperator_WithSingleValue_ShouldCreateList() + { + // Arrange + var obj = new { Id = 1 }; + + // Act + WireMockList list = obj; + + // Assert + list.Should().HaveCount(1); + list[0].Should().Be(obj); + } + + [Fact] + public void WireMockListOfObject_ImplicitOperator_WithArray_ShouldCreateList() + { + // Arrange + var values = new object[] { "first", 2, 3.0 }; + + // Act + WireMockList list = values; + + // Assert + list.Should().HaveCount(3); + list.Should().ContainInOrder("first", 2, 3.0); + } + + #endregion + + #region List Operations Tests + + [Fact] + public void WireMockListOfString_Add_ShouldAddElement() + { + // Arrange + var list = new WireMockList("initial"); + + // Act + list.Add("new"); + + // Assert + list.Should().HaveCount(2); + list[1].Should().Be("new"); + } + + [Fact] + public void WireMockListOfString_Remove_ShouldRemoveElement() + { + // Arrange + var list = new WireMockList("value1", "value2", "value3"); + + // Act + var removed = list.Remove("value2"); + + // Assert + removed.Should().BeTrue(); + list.Should().HaveCount(2); + list.Should().ContainInOrder("value1", "value3"); + } + + #endregion + + #region Edge Cases + + [Fact] + public void WireMockListOfString_ToString_WithEmptyString_ShouldReturnEmptyString() + { + // Arrange + var list = new WireMockList(""); + + // Act + var result = list.ToString(); + + // Assert + result.Should().Be(""); + } + + [Fact] + public void WireMockListOfString_Constructor_WithNull_ShouldThrow() + { + // Act & Assert + var act = () => new WireMockList(null!); + act.Should().Throw(); + } + + [Fact] + public void WireMockListOfObject_ImplicitOperator_WithNull_ShouldCreateListWithNullElement() + { + // Act + WireMockList list = (null as object)!; + + // Assert + list.Should().HaveCount(1); + list[0].Should().BeNull(); + } + + [Fact] + public void WireMockListOfObject_ToString_WhenSingleNullObject_ShouldReturnEmptyString() + { + // Arrange + object? nullObj = null; + var list = new WireMockList(nullObj!); + + // Act + var result = list.ToString(); + + // Assert + result.Should().Be(string.Empty); + } + + #endregion +} \ No newline at end of file diff --git a/test/WireMock.Net.Tests/WireMock.Net.Tests.csproj b/test/WireMock.Net.Tests/WireMock.Net.Tests.csproj index 88ed07aa..8d015e5b 100644 --- a/test/WireMock.Net.Tests/WireMock.Net.Tests.csproj +++ b/test/WireMock.Net.Tests/WireMock.Net.Tests.csproj @@ -158,4 +158,8 @@ + + + + \ No newline at end of file