Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: restore public API compatibility. #113

Merged
merged 1 commit into from
Sep 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion src/MockHttp/Extensions/RequestMatchingExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,19 @@ private static bool ContainsWildcard(this string value)
#endif
}

/// <summary>
/// Matches a request by specified <paramref name="requestUri" />.
/// </summary>
/// <param name="builder">The request matching builder instance.</param>
/// <param name="requestUri">The request URI or a URI wildcard.</param>
/// <returns>The request matching builder instance.</returns>
#pragma warning disable CA1054
public static RequestMatching RequestUri(this RequestMatching builder, string requestUri)
#pragma warning restore CA1054
{
return builder.RequestUri(requestUri, true);
}

/// <summary>
/// Matches a request by specified <paramref name="requestUri" />.
/// </summary>
Expand All @@ -38,7 +51,8 @@ private static bool ContainsWildcard(this string value)
/// <param name="allowWildcards"><see langword="true" /> to allow wildcards, or <see langword="false" /> if exact matching.</param>
/// <returns>The request matching builder instance.</returns>
#pragma warning disable CA1054
public static RequestMatching RequestUri(this RequestMatching builder, string requestUri, bool allowWildcards = true)
// For now, keep this internal. For coverage, and most likely, the API will change so then we'd have more to deprecate (using patterns).
internal static RequestMatching RequestUri(this RequestMatching builder, string requestUri, bool allowWildcards)
#pragma warning restore CA1054
{
if (requestUri is null)
Expand Down
98 changes: 98 additions & 0 deletions src/MockHttp/Matchers/RequestUriMatcher.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
using System.Diagnostics;
using MockHttp.Http;
using MockHttp.Patterns;
using MockHttp.Responses;
using static MockHttp.Http.UriExtensions;

namespace MockHttp.Matchers;

/// <summary>
/// Matches a request by the request URI.
/// </summary>
[Obsolete($"Replaced with {nameof(UriMatcher)}. Will be removed in next major release.")]

Check warning on line 12 in src/MockHttp/Matchers/RequestUriMatcher.cs

View workflow job for this annotation

GitHub Actions / analysis

Do not forget to remove this deprecated code someday. (https://rules.sonarsource.com/csharp/RSPEC-1133)

Check warning on line 12 in src/MockHttp/Matchers/RequestUriMatcher.cs

View workflow job for this annotation

GitHub Actions / analysis

Do not forget to remove this deprecated code someday. (https://rules.sonarsource.com/csharp/RSPEC-1133)

Check warning on line 12 in src/MockHttp/Matchers/RequestUriMatcher.cs

View workflow job for this annotation

GitHub Actions / analysis

Do not forget to remove this deprecated code someday. (https://rules.sonarsource.com/csharp/RSPEC-1133)
public class RequestUriMatcher : HttpRequestMatcher
{
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private readonly Uri _requestUri = default!;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private readonly string _formattedUri;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private readonly WildcardPattern? _uriPatternMatcher;

/// <summary>
/// Initializes a new instance of the <see cref="RequestUriMatcher" /> class using specified <paramref name="uri" />.
/// </summary>
/// <param name="uri">The request URI.</param>
public RequestUriMatcher(Uri uri)
{
_requestUri = uri.EnsureIsRooted();
_formattedUri = _requestUri.ToString();
}

/// <summary>
/// Initializes a new instance of the <see cref="RequestUriMatcher" /> class using specified <paramref name="uriString" />.
/// </summary>
/// <param name="uriString">The request URI or a URI wildcard.</param>
/// <param name="allowWildcards"><see langword="true" /> to allow wildcards, or <see langword="false" /> if exact matching.</param>
public RequestUriMatcher(string uriString, bool allowWildcards = true)
{
_formattedUri = uriString ?? throw new ArgumentNullException(nameof(uriString));

if (allowWildcards
#if NETSTANDARD2_0 || NETFRAMEWORK
&& uriString.Contains("*")
#else
&& uriString.Contains('*', StringComparison.InvariantCultureIgnoreCase)
#endif
)
{
_uriPatternMatcher = WildcardPattern.Create(uriString);
}
else
{
// If no wildcards, then must be actual uri.
_requestUri = new Uri(uriString, DotNetRelativeOrAbsolute).EnsureIsRooted();
_formattedUri = _requestUri.ToString();
}
}

/// <inheritdoc />
public override bool IsMatch(MockHttpRequestContext requestContext)
{
if (requestContext is null)
{
throw new ArgumentNullException(nameof(requestContext));
}

Uri? requestUri = requestContext.Request.RequestUri;
if (requestUri is null)
{
return false;
}

if (_uriPatternMatcher is null)
{
return IsAbsoluteUriMatch(requestUri) || IsRelativeUriMatch(requestUri);
}

return _uriPatternMatcher.Value.IsMatch(requestUri.ToString());
}

private bool IsAbsoluteUriMatch(Uri uri)
{
return _requestUri.IsAbsoluteUri && uri.Equals(_requestUri);
}

private bool IsRelativeUriMatch(Uri uri)
{
return !_requestUri.IsAbsoluteUri
&& uri.IsBaseOf(_requestUri)
&& uri.ToString().EndsWith(_requestUri.ToString(), StringComparison.Ordinal);
}

/// <inheritdoc />
public override string ToString()
{
return $"RequestUri: '{_formattedUri}'";
}
}
109 changes: 109 additions & 0 deletions test/MockHttp.Tests/Matchers/RequestUriMatcherTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
using MockHttp.Responses;

namespace MockHttp.Matchers;

public class RequestUriMatcherTests
{
[Theory]
[InlineData("", UriKind.Relative, "http://127.0.0.1/", true)]
[InlineData("relative.htm", UriKind.Relative, "http://127.0.0.1/relative.htm", true)]
[InlineData("/folder/relative.htm", UriKind.Relative, "http://127.0.0.1/relative.htm", false)]
[InlineData("relative.htm", UriKind.Relative, "http://127.0.0.1/folder/relative.htm", false)]
[InlineData("folder/relative.htm", UriKind.Relative, "http://127.0.0.1/folder/relative.htm", true)]
[InlineData("/folder/relative.htm", UriKind.Relative, "http://127.0.0.1/folder/relative.htm", true)]
[InlineData("http://127.0.0.1/absolute.htm", UriKind.Absolute, "http://127.0.0.1/absolute.htm", true)]
[InlineData("http://127.0.0.1/absolute.htm", UriKind.Absolute, "http://127.0.0.1/folder/absolute.htm", false)]
public void Given_uri_when_matching_should_match(string matchUri, UriKind uriKind, string requestUri, bool isMatch)
{
var request = new HttpRequestMessage { RequestUri = new Uri(requestUri, UriKind.Absolute) };
var sut = new RequestUriMatcher(new Uri(matchUri, uriKind));

// Act & assert
sut.IsMatch(new MockHttpRequestContext(request)).Should().Be(isMatch);
}

[Theory]
[InlineData("relative.htm", true, "http://127.0.0.1/relative.htm", true)]
[InlineData("/folder/relative.htm", true, "http://127.0.0.1/relative.htm", false)]
[InlineData("relative.htm", true, "http://127.0.0.1/folder/relative.htm", false)]
[InlineData("folder/relative.htm", true, "http://127.0.0.1/folder/relative.htm", true)]
[InlineData("/folder/relative.htm", true, "http://127.0.0.1/folder/relative.htm", true)]
[InlineData("http://127.0.0.1/absolute.htm", true, "http://127.0.0.1/absolute.htm", true)]
[InlineData("http://127.0.0.1/absolute.htm", true, "http://127.0.0.1/folder/absolute.htm", false)]
[InlineData("*.htm", true, "http://127.0.0.1/relative.htm", true)]
[InlineData("*/relative.htm", true, "http://127.0.0.1/relative.htm", true)]
[InlineData("/*/relative.htm", true, "http://127.0.0.1/folder/relative.htm", false)]
[InlineData("/*/relative.htm", true, "http://127.0.0.1/relative.htm", false)]
[InlineData("/folder/*.htm", true, "http://127.0.0.1/folder/relative.htm", false)]
[InlineData("*/folder/*.htm", true, "http://127.0.0.1/folder/relative.htm", true)]
[InlineData("/folder/*.htm", true, "http://127.0.0.1/relative.htm", false)]
[InlineData("/*/*/relative.*", true, "http://127.0.0.1/folder1/folder2/relative.htm", false)]
[InlineData("*/folder1/*/relative.*", true, "http://127.0.0.1/folder1/folder2/relative.htm", true)]
[InlineData("/*/*/relative.*", true, "http://127.0.0.1/folder1/relative.htm", false)]
[InlineData("http://127.0.0.1/*.htm", true, "http://127.0.0.1/absolute.htm", true)]
[InlineData("http://127.0.0.1/*.htm", true, "http://127.0.0.1/folder/absolute.htm", true)]
public void Given_uriString_when_matching_should_match(string uriString, bool hasWildcard, string requestUri, bool isMatch)
{
var request = new HttpRequestMessage { RequestUri = new Uri(requestUri, UriKind.Absolute) };
var sut = new RequestUriMatcher(uriString, hasWildcard);

// Act & assert
sut.IsMatch(new MockHttpRequestContext(request)).Should().Be(isMatch);
}

[Fact]
public void Given_null_uri_when_creating_matcher_should_throw()
{
Uri? uri = null;

// Act
Func<RequestUriMatcher> act = () => new RequestUriMatcher(uri!);

// Assert
act.Should()
.Throw<ArgumentNullException>()
.WithParameterName(nameof(uri));
}

[Fact]
public void Given_null_uriString_when_creating_matcher_should_throw()
{
string? uriString = null;

// Act
Func<RequestUriMatcher> act = () => new RequestUriMatcher(uriString!, false);

// Assert
act.Should()
.Throw<ArgumentNullException>()
.WithParameterName(nameof(uriString));
}

[Fact]
public void When_formatting_should_return_human_readable_representation()
{
const string expectedText = "RequestUri: '*/controller/*'";
var sut = new RequestUriMatcher("*/controller/*");

// Act
string displayText = sut.ToString();

// Assert
displayText.Should().Be(expectedText);
}

[Fact]
public void Given_null_context_when_matching_it_should_throw()
{
var sut = new RequestUriMatcher("*/controller/*");
MockHttpRequestContext? requestContext = null;

// Act
Action act = () => sut.IsMatch(requestContext!);

// Assert
act.Should()
.Throw<ArgumentNullException>()
.WithParameterName(nameof(requestContext));
}
}
Loading