Add some more tests for WireMockList + move AdminPaths.cs file (#1491)

This commit is contained in:
Stef Heyenrath
2026-07-18 09:48:41 +02:00
committed by GitHub
parent 5e1c126e34
commit 8260dba641
7 changed files with 464 additions and 10 deletions
@@ -9,7 +9,7 @@ namespace WireMock.Net.Console.MimePart;
static class Program 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)); private static readonly ILog Log = LogManager.GetLogger(typeof(Program));
static async Task Main(params string[] args) static async Task Main(params string[] args)
@@ -1115,7 +1115,7 @@ namespace WireMock.Net.ConsoleApplication
{ {
BodyData = new BodyData 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, DetectedBodyType = BodyType.String,
}, },
StatusCode = code StatusCode = code
@@ -1,11 +1,11 @@
// Copyright © WireMock.Net // Copyright © WireMock.Net
using System.Linq;
namespace WireMock.Types; namespace WireMock.Types;
/// <summary> /// <summary>
/// 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.
/// </summary> /// </summary>
/// <typeparam name="T">The generic type</typeparam> /// <typeparam name="T">The generic type</typeparam>
/// <seealso cref="List{T}" /> /// <seealso cref="List{T}" />
@@ -62,10 +62,10 @@ public class WireMockList<T> : List<T>
return strValue; return strValue;
} }
return this[0]?.ToString(); return this[0]?.ToString() ?? string.Empty;
default: 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); return string.Join(", ", strings);
} }
} }
@@ -12,29 +12,48 @@ internal sealed class AdminPaths(string? adminPath) : IAdminPaths
private readonly string _prefix = adminPath ?? DefaultAdminPathPrefix; private readonly string _prefix = adminPath ?? DefaultAdminPathPrefix;
public string Files => $"{_prefix}/files"; public string Files => $"{_prefix}/files";
public string Health => $"{_prefix}/health"; public string Health => $"{_prefix}/health";
public string Mappings => $"{_prefix}/mappings"; public string Mappings => $"{_prefix}/mappings";
public string MappingsCode => $"{_prefix}/mappings/code"; public string MappingsCode => $"{_prefix}/mappings/code";
public string MappingsWireMockOrg => $"{_prefix}/mappings/wiremock.org"; public string MappingsWireMockOrg => $"{_prefix}/mappings/wiremock.org";
public string Requests => $"{_prefix}/requests"; public string Requests => $"{_prefix}/requests";
public string Settings => $"{_prefix}/settings"; public string Settings => $"{_prefix}/settings";
public string Scenarios => $"{_prefix}/scenarios"; public string Scenarios => $"{_prefix}/scenarios";
public string OpenApi => $"{_prefix}/openapi"; public string OpenApi => $"{_prefix}/openapi";
public string ProtoDefinitions => $"{_prefix}/protodefinitions"; public string ProtoDefinitions => $"{_prefix}/protodefinitions";
private string PrefixRegexEscaped => Regex.Escape(_prefix); 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 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 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 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 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 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 ScenariosNameMatcher => new($@"^{PrefixRegexEscaped}\/scenarios\/.+$");
public RegexMatcher ScenariosNameWithStateMatcher => new($@"^{PrefixRegexEscaped}\/scenarios\/.+\/state$"); public RegexMatcher ScenariosNameWithStateMatcher => new($@"^{PrefixRegexEscaped}\/scenarios\/.+\/state$");
public RegexMatcher ScenariosNameWithResetMatcher => new($@"^{PrefixRegexEscaped}\/scenarios\/.+\/reset$"); public RegexMatcher ScenariosNameWithResetMatcher => new($@"^{PrefixRegexEscaped}\/scenarios\/.+\/reset$");
public RegexMatcher FilesFilenamePathMatcher => new($@"^{PrefixRegexEscaped}\/files\/.+$"); public RegexMatcher FilesFilenamePathMatcher => new($@"^{PrefixRegexEscaped}\/files\/.+$");
public RegexMatcher ProtoDefinitionsIdPathMatcher => new($@"^{PrefixRegexEscaped}\/protodefinitions\/.+$"); 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; public override string ToString() => _prefix;
} }
@@ -5,24 +5,44 @@ namespace WireMock.Owin;
internal interface IAdminPaths internal interface IAdminPaths
{ {
string Files { get; } string Files { get; }
string Health { get; } string Health { get; }
string Mappings { get; } string Mappings { get; }
string MappingsCode { get; } string MappingsCode { get; }
string MappingsWireMockOrg { get; } string MappingsWireMockOrg { get; }
RegexMatcher MappingsGuidPathMatcher { get; } RegexMatcher MappingsGuidPathMatcher { get; }
RegexMatcher MappingsGuidEnablePathMatcher { get; } RegexMatcher MappingsGuidEnablePathMatcher { get; }
RegexMatcher MappingsGuidDisablePathMatcher { get; } RegexMatcher MappingsGuidDisablePathMatcher { get; }
RegexMatcher MappingsCodeGuidPathMatcher { get; } RegexMatcher MappingsCodeGuidPathMatcher { get; }
RegexMatcher RequestsGuidPathMatcher { get; } RegexMatcher RequestsGuidPathMatcher { get; }
RegexMatcher ScenariosNameMatcher { get; } RegexMatcher ScenariosNameMatcher { get; }
RegexMatcher ScenariosNameWithStateMatcher { get; } RegexMatcher ScenariosNameWithStateMatcher { get; }
RegexMatcher ScenariosNameWithResetMatcher { get; } RegexMatcher ScenariosNameWithResetMatcher { get; }
RegexMatcher FilesFilenamePathMatcher { get; } RegexMatcher FilesFilenamePathMatcher { get; }
RegexMatcher ProtoDefinitionsIdPathMatcher { get; } RegexMatcher ProtoDefinitionsIdPathMatcher { get; }
string Requests { get; } string Requests { get; }
string Settings { get; } string Settings { get; }
string Scenarios { get; } string Scenarios { get; }
string OpenApi { get; } string OpenApi { get; }
string ProtoDefinitions { get; } string ProtoDefinitions { get; }
bool Includes(string? path); bool Includes(string? path);
} }
@@ -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<string>();
// 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<string>(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<string>(values);
// Assert
list.Should().HaveCount(3);
list.Should().ContainInOrder("value1", "value2", "value3");
}
[Fact]
public void WireMockListOfString_Constructor_WithIEnumerable_ShouldCreateListWithAllElements()
{
// Arrange
var values = new List<string> { "a", "b", "c" };
// Act
var list = new WireMockList<string>(values);
// Assert
list.Should().HaveCount(3);
list.Should().ContainInOrder("a", "b", "c");
}
[Fact]
public void WireMockListOfString_ToString_WhenEmpty_ShouldReturnEmptyString()
{
// Arrange
var list = new WireMockList<string>();
// Act
var result = list.ToString();
// Assert
result.Should().Be(string.Empty);
}
[Fact]
public void WireMockListOfString_ToString_WhenSingleElement_ShouldReturnElementValue()
{
// Arrange
var list = new WireMockList<string>("singleValue");
// Act
var result = list.ToString();
// Assert
result.Should().Be("singleValue");
}
[Fact]
public void WireMockListOfString_ToString_WhenMultipleElements_ShouldReturnCommaSeparatedValues()
{
// Arrange
var list = new WireMockList<string>("value1", "value2", "value3");
// Act
var result = list.ToString();
// Assert
result.Should().Be("value1, value2, value3");
}
[Fact]
public void WireMockListOfString_ImplicitOperator_WithSingleValue_ShouldCreateList()
{
// Act
WireMockList<string> 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<string> 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<object>();
// 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<object>(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<object>(values);
// Assert
list.Should().HaveCount(3);
list.Should().ContainInOrder(obj1, obj2, obj3);
}
[Fact]
public void WireMockListOfObject_Constructor_WithIEnumerable_ShouldCreateListWithAllElements()
{
// Arrange
var values = new List<object?>
{
"string",
123,
45.67,
true,
null
};
// Act
var list = new WireMockList<object?>(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<object>();
// Act
var result = list.ToString();
// Assert
result.Should().Be(string.Empty);
}
[Fact]
public void WireMockListOfObject_ToString_WhenSingleString_ShouldReturnString()
{
// Arrange
var list = new WireMockList<object>("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<object>(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<object>(42);
// Act
var result = list.ToString();
// Assert
result.Should().Be("42");
}
[Fact]
public void WireMockListOfObject_ToString_WhenMultipleElements_ShouldReturnCommaSeparatedValues()
{
// Arrange
var list = new WireMockList<object>("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<object>
{
"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<object?>
{
"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<object> 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<object> 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<string>("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<string>("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<string>("");
// Act
var result = list.ToString();
// Assert
result.Should().Be("");
}
[Fact]
public void WireMockListOfString_Constructor_WithNull_ShouldThrow()
{
// Act & Assert
var act = () => new WireMockList<string?>(null!);
act.Should().Throw<ArgumentNullException>();
}
[Fact]
public void WireMockListOfObject_ImplicitOperator_WithNull_ShouldCreateListWithNullElement()
{
// Act
WireMockList<object> 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<object>(nullObj!);
// Act
var result = list.ToString();
// Assert
result.Should().Be(string.Empty);
}
#endregion
}
@@ -158,4 +158,8 @@
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" /> <Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Folder Include="Types\" />
</ItemGroup>
</Project> </Project>