Skip to content
Draft
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
7 changes: 7 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
* text=auto
*.cs text diff=csharp
*.cshtml text diff=html
*.csx text diff=csharp
*.sln text eol=crlf
*.slnx text eol=crlf
*.csproj text eol=crlf
83 changes: 0 additions & 83 deletions TestableHttpClient.sln

This file was deleted.

29 changes: 29 additions & 0 deletions TestableHttpClient.slnx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<Solution>
<Configurations>
<Platform Name="Any CPU" />
<Platform Name="x64" />
<Platform Name="x86" />
</Configurations>
<Folder Name="/Solution Items/">
<File Path=".editorconfig" />
<File Path=".gitattributes" />
<File Path=".gitignore" />
<File Path="CHANGELOG.md" />
<File Path="CONTRIBUTING.md" />
<File Path="LICENSE" />
<File Path="README.md" />
<File Path="SECURITY.md" />
<File Path="Directory.Build.props" />
<File Path="global.json" />
<File Path="version.json" />
</Folder>
<Folder Name="/src/">
<Project Path="src/TestableHttpClient/TestableHttpClient.csproj" />
</Folder>
<Folder Name="/test/">
<Project Path="test/TestableHttpClient.IntegrationTests/TestableHttpClient.IntegrationTests.csproj" />
<Project Path="test/TestableHttpClient.Tests/TestableHttpClient.Tests.csproj" />
<File Path="test/Directory.Build.props" />
<File Path="test/Directory.Build.targets" />
</Folder>
</Solution>
3 changes: 3 additions & 0 deletions global.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,8 @@
"version": "10.0.100",
"allowPrerelease": false,
"rollForward": "latestMajor"
},
"test": {
"runner": "Microsoft.Testing.Platform"
}
}
5 changes: 2 additions & 3 deletions src/TestableHttpClient/HttpHeadersExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,13 @@ internal static bool HasHeader(this HttpHeaders headers, string headerName)
return headers.TryGetValues(headerName, out _);
}

internal static bool HasHeader(this HttpHeaders headers, string headerName, string headerValue)
internal static bool HasHeader(this HttpHeaders headers, string headerName, Value headerValue)
{
if (headers.TryGetValues(headerName, out var values))
{
var value = string.Join(" ", values);
return StringMatcher.Matches(value, headerValue);
return headerValue.Matches(value, false);
}

return false;
}
}
87 changes: 56 additions & 31 deletions src/TestableHttpClient/HttpRequestMessageAsserter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ internal sealed class HttpRequestMessageAsserter : IHttpRequestMessagesCheck
{
private readonly List<string> _expectedConditions = new();

private readonly RequestBuilder expectedRequestBuilder;

/// <summary>
/// Construct a new HttpRequestMessageAsserter.
/// </summary>
Expand All @@ -16,6 +18,7 @@ public HttpRequestMessageAsserter(IEnumerable<HttpRequestMessage> httpRequestMes
{
Requests = httpRequestMessages ?? throw new ArgumentNullException(nameof(httpRequestMessages));
Options = options ?? new TestableHttpMessageHandlerOptions();
expectedRequestBuilder = new RequestBuilder(Options.UriPatternMatchingOptions);
}

/// <summary>
Expand All @@ -27,9 +30,28 @@ public HttpRequestMessageAsserter(IEnumerable<HttpRequestMessage> httpRequestMes
/// </summary>
public TestableHttpMessageHandlerOptions Options { get; }

private void Assert(int? expectedCount = null)
private HttpRequestMessageAsserter Assert(int? expectedCount = null, string condition = "")
{
var actualCount = Requests.Count();
if (!string.IsNullOrEmpty(condition))
{
_expectedConditions.Add(condition);
}
return Assert(expectedCount);
}

private HttpRequestMessageAsserter Assert(int? expectedCount = null)
{
int actualCount;
Request expectedRequest = expectedRequestBuilder.Build();
try
{
actualCount = Requests.Count(expectedRequest.Equals);
}
catch (ObjectDisposedException)
{
throw new HttpRequestMessageAssertionException("Can't validate requests, because one or more requests have content that is already disposed.");
}

var pass = expectedCount switch
{
null => actualCount > 0,
Expand All @@ -38,9 +60,11 @@ private void Assert(int? expectedCount = null)

if (!pass)
{
var message = MessageBuilder.BuildMessage(expectedCount, actualCount, _expectedConditions);
var message = MessageBuilder.BuildMessage(expectedCount, actualCount, expectedRequest, _expectedConditions);
throw new HttpRequestMessageAssertionException(message);
}

return this;
}

/// <summary>
Expand All @@ -50,6 +74,7 @@ private void Assert(int? expectedCount = null)
/// <param name="condition">The name of the condition, used in the exception message.</param>
/// <returns>The <seealso cref="IHttpRequestMessagesCheck"/> for further assertions.</returns>
[AssertionMethod]
[Obsolete("WithFilter will be made internal, since it should no longer be necesary to use.")]
public IHttpRequestMessagesCheck WithFilter(Func<HttpRequestMessage, bool> requestFilter, string condition) => WithFilter(requestFilter, null, condition);

/// <summary>
Expand All @@ -60,25 +85,21 @@ private void Assert(int? expectedCount = null)
/// <param name="condition">The name of the condition, used in the exception message.</param>
/// <returns>The <seealso cref="IHttpRequestMessagesCheck"/> for further assertions.</returns>
[AssertionMethod]
[Obsolete("WithFilter will be made internal, since it should no longer be necesary to use.")]
public IHttpRequestMessagesCheck WithFilter(Func<HttpRequestMessage, bool> requestFilter, int expectedNumberOfRequests, string condition) => WithFilter(requestFilter, (int?)expectedNumberOfRequests, condition);

[AssertionMethod]
[Obsolete("WithFilter will be made internal, since it should no longer be necesary to use.")]
public IHttpRequestMessagesCheck WithFilter(Func<HttpRequestMessage, bool> requestFilter, int? expectedNumberOfRequests, string condition)
{
if (!string.IsNullOrEmpty(condition))
{
_expectedConditions.Add(condition);
}

try
{
Requests = Requests.Where(requestFilter);
Assert(expectedNumberOfRequests);
}
catch (ObjectDisposedException)
{
throw new HttpRequestMessageAssertionException("Can't validate requests, because one or more requests have content that is already disposed.");
}
Requests = Requests.Where(requestFilter);
Assert(expectedNumberOfRequests);

return this;
}

Expand All @@ -97,19 +118,13 @@ public IHttpRequestMessagesCheck WithFilter(Func<HttpRequestMessage, bool> reque
/// <returns>The <seealso cref="IHttpRequestMessagesCheck"/> for further assertions.</returns>
public IHttpRequestMessagesCheck WithRequestUri(string pattern, int expectedNumberOfRequests) => WithRequestUri(pattern, (int?)expectedNumberOfRequests);

private IHttpRequestMessagesCheck WithRequestUri(string pattern, int? expectedNumberOfRequests)
private HttpRequestMessageAsserter WithRequestUri(string pattern, int? expectedNumberOfRequests)
{
Guard.ThrowIfNullOrEmpty(pattern);

var condition = string.Empty;
if (pattern != "*")
{
condition = $"uri pattern '{pattern}'";
}
expectedRequestBuilder.WithRequestUri(pattern);

UriPattern uriPattern = UriPatternParser.Parse(pattern);

return WithFilter(x => x.RequestUri is not null && uriPattern.Matches(x.RequestUri, Options.UriPatternMatchingOptions), expectedNumberOfRequests, condition);
return Assert(expectedNumberOfRequests);
}

/// <summary>
Expand All @@ -127,11 +142,13 @@ private IHttpRequestMessagesCheck WithRequestUri(string pattern, int? expectedNu
/// <returns>The <seealso cref="IHttpRequestMessagesCheck"/> for further assertions.</returns>
public IHttpRequestMessagesCheck WithHttpMethod(HttpMethod httpMethod, int expectedNumberOfRequests) => WithHttpMethod(httpMethod, (int?)expectedNumberOfRequests);

private IHttpRequestMessagesCheck WithHttpMethod(HttpMethod httpMethod, int? expectedNumberOfRequests)
private HttpRequestMessageAsserter WithHttpMethod(HttpMethod httpMethod, int? expectedNumberOfRequests)
{
Guard.ThrowIfNull(httpMethod);

return WithFilter(x => x.HasHttpMethod(httpMethod), expectedNumberOfRequests, $"HTTP Method '{httpMethod}'");
expectedRequestBuilder.WithMethod(httpMethod);

return Assert(expectedNumberOfRequests);
}

/// <summary>
Expand All @@ -150,11 +167,13 @@ private IHttpRequestMessagesCheck WithHttpMethod(HttpMethod httpMethod, int? exp
/// <returns>The <seealso cref="IHttpRequestMessagesCheck"/> for further assertions.</returns>
public IHttpRequestMessagesCheck WithHttpVersion(Version httpVersion, int expectedNumberOfRequests) => WithHttpVersion(httpVersion, (int?)expectedNumberOfRequests);

private IHttpRequestMessagesCheck WithHttpVersion(Version httpVersion, int? expectedNumberOfRequests)
private HttpRequestMessageAsserter WithHttpVersion(Version httpVersion, int? expectedNumberOfRequests)
{
Guard.ThrowIfNull(httpVersion);

return WithFilter(x => x.HasHttpVersion(httpVersion), expectedNumberOfRequests, $"HTTP Version '{httpVersion}'");
expectedRequestBuilder.WithVersion(httpVersion);

return Assert(expectedNumberOfRequests, $"HTTP Version '{httpVersion}'");
}

/// <summary>
Expand All @@ -172,11 +191,13 @@ private IHttpRequestMessagesCheck WithHttpVersion(Version httpVersion, int? expe
/// <returns>The <seealso cref="IHttpRequestMessagesCheck"/> for further assertions.</returns>
public IHttpRequestMessagesCheck WithHeader(string headerName, int expectedNumberOfRequests) => WithHeader(headerName, (int?)expectedNumberOfRequests);

private IHttpRequestMessagesCheck WithHeader(string headerName, int? expectedNumberOfRequests)
private HttpRequestMessageAsserter WithHeader(string headerName, int? expectedNumberOfRequests)
{
Guard.ThrowIfNullOrEmpty(headerName);

return WithFilter(x => x.HasHeader(headerName), expectedNumberOfRequests, $"header '{headerName}'");
expectedRequestBuilder.WithHeader(headerName);

return Assert(expectedNumberOfRequests);
}

/// <summary>
Expand All @@ -196,12 +217,14 @@ private IHttpRequestMessagesCheck WithHeader(string headerName, int? expectedNum
/// <returns>The <seealso cref="IHttpRequestMessagesCheck"/> for further assertions.</returns>
public IHttpRequestMessagesCheck WithHeader(string headerName, string headerValue, int expectedNumberOfRequests) => WithHeader(headerName, headerValue, (int?)expectedNumberOfRequests);

private IHttpRequestMessagesCheck WithHeader(string headerName, string headerValue, int? expectedNumberOfRequests)
private HttpRequestMessageAsserter WithHeader(string headerName, string headerValue, int? expectedNumberOfRequests)
{
Guard.ThrowIfNullOrEmpty(headerName);
Guard.ThrowIfNullOrEmpty(headerValue);

return WithFilter(x => x.HasHeader(headerName, headerValue), expectedNumberOfRequests, $"header '{headerName}' and value '{headerValue}'");
expectedRequestBuilder.WithHeader(headerName, headerValue);

return Assert(expectedNumberOfRequests);
}

/// <summary>
Expand All @@ -219,10 +242,12 @@ private IHttpRequestMessagesCheck WithHeader(string headerName, string headerVal
/// <returns>The <seealso cref="IHttpRequestMessagesCheck"/> for further assertions.</returns>
public IHttpRequestMessagesCheck WithContent(string pattern, int expectedNumberOfRequests) => WithContent(pattern, (int?)expectedNumberOfRequests);

private IHttpRequestMessagesCheck WithContent(string pattern, int? expectedNumberOfRequests)
private HttpRequestMessageAsserter WithContent(string pattern, int? expectedNumberOfRequests)
{
Guard.ThrowIfNull(pattern);

return WithFilter(x => x.HasContent(pattern), expectedNumberOfRequests, $"content '{pattern}'");
expectedRequestBuilder.WithContent(pattern);

return Assert(expectedNumberOfRequests);
}
}
Loading
Loading