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