Skip to content
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
1 change: 1 addition & 0 deletions Source/Mockolate/MockRegistration.Setup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,7 @@ public ValueStorage GetOrAdd(NamedParameterValue key, Func<ValueStorage> valueGe
}
}

[ExcludeFromCodeCoverage]
private sealed class NamedParameterValueComparer : IEqualityComparer<NamedParameterValue>
{
public static readonly NamedParameterValueComparer Instance = new();
Expand Down
6 changes: 1 addition & 5 deletions Source/Mockolate/Web/HttpClientExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,8 @@ public bool Matches(HttpRequestMessage value)
}

string requestUri1 = value.RequestUri.ToString();
string requestUri2 = requestUri1.EndsWith('/')
? requestUri1.Substring(0, requestUri1.Length - 1)
: requestUri1 + '/';

return invokableParameter.Matches(requestUri1) ||
invokableParameter.Matches(requestUri2);
(requestUri1.EndsWith('/') && invokableParameter.Matches(requestUri1.TrimEnd('/')));
}

public void InvokeCallbacks(HttpRequestMessage value)
Expand Down
5 changes: 1 addition & 4 deletions Source/Mockolate/Web/ItExtensions.Uri.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,9 @@ public bool Matches(object? value)
if (pattern is not null)
{
string requestUri1 = uri.ToString();
string requestUri2 = requestUri1.EndsWith('/')
? requestUri1.Substring(0, requestUri1.Length - 1)
: requestUri1 + '/';
Wildcard wildcard = Wildcard.Pattern(pattern, true);
if (!wildcard.Matches(requestUri1) &&
!wildcard.Matches(requestUri2))
(!requestUri1.EndsWith('/') || !wildcard.Matches(requestUri1.TrimEnd('/'))))
{
return false;
}
Expand Down
27 changes: 19 additions & 8 deletions Tests/Mockolate.Tests/MockMethods/VerifyInvokedTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,25 +17,25 @@ public async Task Equals_ShouldWork()
}

[Fact]
public async Task Equals_WithOtherOverload_ShouldWork()
public async Task Equals_ShouldWorkWithNull()
{
object obj = new();
object? obj = null;
IMethodService mock = Mock.Create<IMethodService>();

_ = mock.Equals(3);
_ = mock.Equals(null);

await That(mock.VerifyMock.Invoked.Equals(It.Is(obj))).Never();
await That(mock.VerifyMock.Invoked.Equals(It.Is(obj))).Once();
}

[Fact]
public async Task Equals_ShouldWorkWithNull()
public async Task Equals_WithOtherOverload_ShouldWork()
{
object? obj = null;
object obj = new();
IMethodService mock = Mock.Create<IMethodService>();

_ = mock.Equals(null);
_ = mock.Equals(3);

await That(mock.VerifyMock.Invoked.Equals(It.Is(obj))).Once();
await That(mock.VerifyMock.Invoked.Equals(It.Is(obj))).Never();
}

[Fact]
Expand All @@ -59,6 +59,17 @@ public async Task MethodWithDifferentName_ShouldNotMatch()
await That(sut.VerifyMock.Invoked.Subtract(It.IsAny<int>(), It.IsAny<int?>())).Never();
}

[Fact]
public async Task MethodWithDifferentName_WithParameters_ShouldNotMatch()
{
MockTests.IMyService sut = Mock.Create<MockTests.IMyService>();

sut.Subtract(1, 4);
sut.Subtract(2, 4);

await That(sut.VerifyMock.Invoked.Multiply(Match.AnyParameters())).Never();
}

[Fact]
public async Task MethodWithDifferentOverload_ShouldNotMatch()
{
Expand Down
54 changes: 54 additions & 0 deletions Tests/Mockolate.Tests/Web/HttpClientExtensionsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,60 @@ public async Task NullUri_ShouldReturnFalse()
await That(result).IsFalse();
}

[Fact]
public async Task ShouldSupportMonitoring()
{
int callbackCount = 0;
HttpClient httpClient = Mock.Create<HttpClient>();
httpClient.SetupMock.Method
.GetAsync(It.Matches("*")
.Do(_ => callbackCount++)
.Monitor(out IParameterMonitor<string> monitor))
.ReturnsAsync(new HttpResponseMessage(HttpStatusCode.OK));

await httpClient.GetAsync("https://www.aweXpect.com/foo", CancellationToken.None);
await httpClient.PostAsync("https://www.aweXpect.com/bar", null, CancellationToken.None);
await httpClient.GetAsync("https://www.aweXpect.com/baz", CancellationToken.None);

await That(monitor.Values).IsEqualTo([
"https://www.awexpect.com/foo",
"https://www.awexpect.com/baz",
]);
await That(callbackCount).IsEqualTo(2);
}

[Theory]
[InlineData("*aweXpect.com")]
[InlineData("*aweXpect.com/")]
public async Task TrailingSlash_ShouldBeIgnored(string matchPattern)
{
HttpClient httpClient = Mock.Create<HttpClient>();
httpClient.SetupMock.Method
.GetAsync(It.Matches(matchPattern))
.ReturnsAsync(new HttpResponseMessage(HttpStatusCode.OK));

HttpResponseMessage result =
await httpClient.GetAsync("https://www.aweXpect.com", CancellationToken.None);

await That(result.StatusCode)
.IsEqualTo(HttpStatusCode.OK);
}

[Fact]
public async Task TrailingSlash_WhenNotPresent_ShouldNotBeAdded()
{
HttpClient httpClient = Mock.Create<HttpClient>();
httpClient.SetupMock.Method
.GetAsync(It.Matches("*www.aweXpect.com/foo/"))
.ReturnsAsync(new HttpResponseMessage(HttpStatusCode.OK));

HttpResponseMessage result =
await httpClient.GetAsync("https://www.aweXpect.com/foo", CancellationToken.None);

await That(result.StatusCode)
.IsEqualTo(HttpStatusCode.NotImplemented);
}

private sealed class InvalidParameter : IParameter<string?>
{
public IParameter<string?> Do(Action<string?> callback)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,12 @@ public async Task EqualTo_ShouldCheckForEquality(byte[] body, byte[] expected, b

await That(result.StatusCode).IsEqualTo(expectSuccess ? HttpStatusCode.OK : HttpStatusCode.NotImplemented);
}

#if !NETFRAMEWORK
[Fact]
public async Task ShouldSupportMonitoring()
{
int callbackCount = 0;
List<ByteArrayContent> responses =
[
new([]),
Expand All @@ -71,7 +72,9 @@ public async Task ShouldSupportMonitoring()
];
HttpClient httpClient = Mock.Create<HttpClient>();
httpClient.SetupMock.Method.PostAsync(It.IsAny<Uri>(),
It.IsBinaryContent().Monitor(out IParameterMonitor<HttpContent?> monitor));
It.IsBinaryContent()
.Do(_ => callbackCount++)
.Monitor(out IParameterMonitor<HttpContent?> monitor));

foreach (ByteArrayContent response in responses)
{
Expand All @@ -81,6 +84,7 @@ public async Task ShouldSupportMonitoring()
await That(
(await Task.WhenAll(monitor.Values.Select(c => c!.ReadAsByteArrayAsync()))).Select(x => x.Length))
.IsEqualTo([0, 1, 3,]);
await That(callbackCount).IsEqualTo(3);
}
#endif

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public sealed class IsStringContentTests
[Fact]
public async Task ShouldSupportMonitoring()
{
int callbackCount = 0;
List<StringContent> responses =
[
new("", Encoding.UTF8, "application/json"),
Expand All @@ -26,7 +27,9 @@ public async Task ShouldSupportMonitoring()
];
HttpClient httpClient = Mock.Create<HttpClient>();
httpClient.SetupMock.Method.PostAsync(It.IsAny<Uri>(),
It.IsStringContent("application/json").Monitor(out IParameterMonitor<HttpContent?> monitor));
It.IsStringContent("application/json")
.Do(_ => callbackCount++)
.Monitor(out IParameterMonitor<HttpContent?> monitor));

foreach (StringContent response in responses)
{
Expand All @@ -35,6 +38,7 @@ public async Task ShouldSupportMonitoring()

await That(await Task.WhenAll(monitor.Values.Select(c => c!.ReadAsStringAsync())))
.IsEqualTo(["", "foo", "bar",]);
await That(callbackCount).IsEqualTo(3);
}
#endif

Expand Down
41 changes: 40 additions & 1 deletion Tests/Mockolate.Tests/Web/ItExtensionsTests.UriTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,11 @@ public async Task ForHttps_ShouldVerifyHttpsScheme(string uri, bool expectMatch)
[Fact]
public async Task ShouldSupportMonitoring()
{
int callbackCount = 0;
HttpClient httpClient = Mock.Create<HttpClient>();
httpClient.SetupMock.Method.GetAsync(It.IsUri().Monitor(out IParameterMonitor<Uri?> monitor));
httpClient.SetupMock.Method.GetAsync(It.IsUri()
.Do(_ => callbackCount++)
.Monitor(out IParameterMonitor<Uri?> monitor));

await httpClient.GetAsync("https://www.aweXpect.com", CancellationToken.None);
await httpClient.GetAsync("https://www.aweXpect.com/foo", CancellationToken.None);
Expand All @@ -59,6 +62,7 @@ await That(monitor.Values.Select(u => u?.ToString()))
"https://www.aweXpect.com/foo",
"https://www.aweXpect.com/bar",
]).IgnoringCase();
await That(callbackCount).IsEqualTo(3);
}

[Theory]
Expand All @@ -84,9 +88,42 @@ public async Task ShouldVerifyFullUriWithWildcardMatch(string uri, string patter
await That(result.StatusCode).IsEqualTo(expectMatch ? HttpStatusCode.OK : HttpStatusCode.NotImplemented);
}

[Theory]
[InlineData("*aweXpect.com")]
[InlineData("*aweXpect.com/")]
public async Task TrailingSlash_ShouldBeIgnored(string matchPattern)
{
HttpClient httpClient = Mock.Create<HttpClient>();
httpClient.SetupMock.Method
.GetAsync(It.IsUri(matchPattern))
.ReturnsAsync(new HttpResponseMessage(HttpStatusCode.OK));

HttpResponseMessage result =
await httpClient.GetAsync("https://www.aweXpect.com", CancellationToken.None);

await That(result.StatusCode)
.IsEqualTo(HttpStatusCode.OK);
}

[Fact]
public async Task TrailingSlash_WhenNotPresent_ShouldNotBeAdded()
{
HttpClient httpClient = Mock.Create<HttpClient>();
httpClient.SetupMock.Method
.GetAsync(It.IsUri("*www.aweXpect.com/foo/"))
.ReturnsAsync(new HttpResponseMessage(HttpStatusCode.OK));

HttpResponseMessage result =
await httpClient.GetAsync("https://www.aweXpect.com/foo", CancellationToken.None);

await That(result.StatusCode)
.IsEqualTo(HttpStatusCode.NotImplemented);
}

[Theory]
[InlineData("https://www.aweXpect.com/foo/bar?x=123&y=234", "www.awexpect.com", true)]
[InlineData("https://www.aweXpect.com/foo/bar?x=123&y=234", "*awexpect*", true)]
[InlineData("https://www.aweXpect.com/foo/bar?x=123&y=234", "*aweXpect*", true)]
[InlineData("http://www.aweXpect.com/foo/bar?x=123&y=234", "mockolate.com", false)]
public async Task WithHost_ShouldVerifyHost(string uri, string hostPattern, bool expectMatch)
{
Expand All @@ -103,6 +140,7 @@ public async Task WithHost_ShouldVerifyHost(string uri, string hostPattern, bool
[Theory]
[InlineData("https://www.aweXpect.com/foo/bar?x=123&y=234", "/foo/bar", true)]
[InlineData("https://www.aweXpect.com/foo/bar?x=123&y=234", "*foo*", true)]
[InlineData("https://www.aweXpect.com/foo/bar?x=123&y=234", "*FOO*", true)]
[InlineData("https://www.aweXpect.com/foo/bar?x=123&y=234", "*bar*", true)]
[InlineData("http://www.aweXpect.com/foo/bar?x=123&y=234", "*baz*", false)]
public async Task WithPath_ShouldVerifyPath(string uri, string pathPattern, bool expectMatch)
Expand Down Expand Up @@ -139,6 +177,7 @@ public async Task WithPort_ShouldVerifyPort(string uri, int port, bool expectMat
[InlineData("https://www.aweXpect.com/foo/bar?x=123&y=234", "?x=123&y=234", true)]
[InlineData("https://www.aweXpect.com/foo/bar?x=123&y=234", "*123*", true)]
[InlineData("https://www.aweXpect.com/foo/bar?x=123&y=234", "*x=*y=*", true)]
[InlineData("https://www.aweXpect.com/foo/bar?x=123&y=234", "*X=*Y=*", true)]
[InlineData("http://www.aweXpect.com/foo/bar?x=123&y=234", "*z=*", false)]
public async Task WithQuery_ShouldVerifyQuery(string uri, string queryPattern, bool expectMatch)
{
Expand Down
Loading