Check if the path is valid when using WithPath(...) (#1377)

This commit is contained in:
Stef Heyenrath
2025-11-08 09:02:00 +01:00
committed by GitHub
parent dfeabf228e
commit 21601889e0
12 changed files with 82 additions and 10 deletions

View File

@@ -22,7 +22,7 @@ public class MatcherModel
public object? Pattern { get; set; }
/// <summary>
/// Gets or sets the patterns. Can be array of strings (default) or an array of objects.
/// Gets or sets the patterns. Can be an array of strings (default) or an array of objects.
/// </summary>
public object[]? Patterns { get; set; }

View File

@@ -1,6 +1,7 @@
// Copyright © WireMock.Net
using System;
using WireMock.Validators;
// ReSharper disable once CheckNamespace
namespace WireMock.Admin.Mappings;
@@ -94,9 +95,14 @@ public partial class RequestModelBuilder
}
/// <summary>
/// Set the Path.
/// Set the Path. Must start with a forward slash (/).
/// </summary>
public RequestModelBuilder WithPath(string value) => WithPath(() => value);
public RequestModelBuilder WithPath(string value)
{
PathValidator.ValidateAndThrow(value);
return WithPath(() => value);
}
/// <summary>
/// Set the Path.

View File

@@ -0,0 +1,19 @@
// Copyright © WireMock.Net
using System;
namespace WireMock.Validators;
public static class PathValidator
{
/// <summary>
/// A valid path must start with a '/' and cannot be null, empty or whitespace.
/// </summary>
public static void ValidateAndThrow(string? path, string? paramName = null)
{
if (string.IsNullOrWhiteSpace(path) || path?.StartsWith("/") == false)
{
throw new ArgumentException("Path must start with a '/' and cannot be null, empty or whitespace.", paramName ?? nameof(path));
}
}
}

View File

@@ -4,6 +4,7 @@ using System;
using Stef.Validation;
using WireMock.Matchers;
using WireMock.Matchers.Request;
using WireMock.Validators;
namespace WireMock.RequestBuilders;
@@ -34,6 +35,10 @@ public partial class Request
public IRequestBuilder WithPath(MatchOperator matchOperator, params string[] paths)
{
Guard.NotNullOrEmpty(paths);
foreach (var path in paths)
{
PathValidator.ValidateAndThrow(path, nameof(paths));
}
_requestMatchers.Add(new RequestMessagePathMatcher(MatchBehaviour.AcceptOnMatch, matchOperator, paths));
return this;

View File

@@ -109,7 +109,7 @@ public partial class MappingConverterTests
var guid = new Guid("8e7b9ab7-e18e-4502-8bc9-11e6679811cc");
var request = Request.Create()
.UsingGet()
.WithPath("test_path")
.WithPath("/test_path")
.WithParam("q", "42")
.WithClientIP("112.123.100.99")
.WithHeader("h-key", "h-value")

View File

@@ -1,7 +1,7 @@
builder
.Given(Request.Create()
.UsingMethod("GET")
.WithPath(new WildcardMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, "test_path", false, WireMock.Matchers.MatchOperator.Or))
.WithPath(new WildcardMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, "/test_path", false, WireMock.Matchers.MatchOperator.Or))
.WithParam("q", new ExactMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, false, WireMock.Matchers.MatchOperator.And, "42"))
.WithClientIP("112.123.100.99")
.WithHeader("h-key", "h-value", true)

View File

@@ -2,7 +2,7 @@
builder
.Given(Request.Create()
.UsingMethod("GET")
.WithPath(new WildcardMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, "test_path", false, WireMock.Matchers.MatchOperator.Or))
.WithPath(new WildcardMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, "/test_path", false, WireMock.Matchers.MatchOperator.Or))
.WithParam("q", new ExactMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, false, WireMock.Matchers.MatchOperator.And, "42"))
.WithClientIP("112.123.100.99")
.WithHeader("h-key", "h-value", true)

View File

@@ -1,7 +1,7 @@
server
.Given(Request.Create()
.UsingMethod("GET")
.WithPath(new WildcardMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, "test_path", false, WireMock.Matchers.MatchOperator.Or))
.WithPath(new WildcardMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, "/test_path", false, WireMock.Matchers.MatchOperator.Or))
.WithParam("q", new ExactMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, false, WireMock.Matchers.MatchOperator.And, "42"))
.WithClientIP("112.123.100.99")
.WithHeader("h-key", "h-value", true)

View File

@@ -2,7 +2,7 @@
server
.Given(Request.Create()
.UsingMethod("GET")
.WithPath(new WildcardMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, "test_path", false, WireMock.Matchers.MatchOperator.Or))
.WithPath(new WildcardMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, "/test_path", false, WireMock.Matchers.MatchOperator.Or))
.WithParam("q", new ExactMatcher(WireMock.Matchers.MatchBehaviour.AcceptOnMatch, false, WireMock.Matchers.MatchOperator.And, "42"))
.WithClientIP("112.123.100.99")
.WithHeader("h-key", "h-value", true)

View File

@@ -9,7 +9,7 @@
Matchers: [
{
Name: WildcardMatcher,
Pattern: x,
Pattern: /x,
IgnoreCase: false
}
]

View File

@@ -56,7 +56,7 @@ public class ProxyMappingConverterTests
var request = Request.Create()
.UsingPost()
.WithPath("x")
.WithPath("/x")
.WithParam("p1", "p1-v")
.WithParam("p2", "p2-v")
.WithHeader("Content-Type", new ContentTypeMatcher("text/plain"))

View File

@@ -0,0 +1,42 @@
// Copyright © WireMock.Net
using System;
using System.Diagnostics.CodeAnalysis;
using FluentAssertions;
using WireMock.Validators;
using Xunit;
namespace WireMock.Net.Tests.Validators;
[ExcludeFromCodeCoverage]
public class PathValidatorTests
{
[Fact]
public void ValidateAndThrow_ValidPath_DoesNotThrow()
{
Action act = () => PathValidator.ValidateAndThrow("/valid/path");
act.Should().NotThrow();
}
[Theory]
[InlineData(null)]
[InlineData("")]
[InlineData("\r")]
[InlineData("\n")]
[InlineData("\t")]
public void ValidateAndThrow_InvalidPath_ThrowsArgumentException_WithDefaultParamName(string? path)
{
Action act = () => PathValidator.ValidateAndThrow(path);
var ex = act.Should().Throw<ArgumentException>().Which;
ex.Message.Should().StartWith("Path must start with a '/' and cannot be null, empty or whitespace.");
ex.ParamName.Should().Be("path");
}
[Fact]
public void ValidateAndThrow_NoLeadingSlash_ThrowsArgumentException_WithProvidedParamName()
{
Action act = () => PathValidator.ValidateAndThrow("noSlash", "myParam");
var ex = act.Should().Throw<ArgumentException>().Which;
ex.ParamName.Should().Be("myParam");
}
}