Skip to content

Commit

Permalink
StringSyntaxAttribute support. (#72)
Browse files Browse the repository at this point in the history
  • Loading branch information
chullybun authored Mar 29, 2024
1 parent b796231 commit 0fe7670
Show file tree
Hide file tree
Showing 14 changed files with 169 additions and 2 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

Represents the **NuGet** versions.

## v4.3.1
- *Fixed*: Added `StringSyntaxAttribute` support to improve intellisense for JSON and URI specification.

## v4.3.0
- *Enhancement:* A new `MockHttpClient.WithRequestsFromResource` method enables the specification of the Request/Response configuration from a YAML/JSON embedded resource. The [`mock.unittestex.json`](./src/UnitTestEx/Schema/mock.unittestex.json) JSON schema defines content.

Expand Down
2 changes: 1 addition & 1 deletion Common.targets
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project>
<PropertyGroup>
<Version>4.3.0</Version>
<Version>4.3.1</Version>
<LangVersion>preview</LangVersion>
<Authors>Avanade</Authors>
<Company>Avanade</Company>
Expand Down
7 changes: 6 additions & 1 deletion src/UnitTestEx/Abstractions/TesterBaseT.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using Microsoft.Extensions.DependencyInjection;
using Moq;
using System;
using System.Diagnostics.CodeAnalysis;
using System.Net.Mime;
using System.Reflection;
using System.Text;
Expand Down Expand Up @@ -304,7 +305,11 @@ public ServiceBusReceivedMessage CreateServiceBusMessageFromResource(string reso
/// <param name="json">The JSON body.</param>
/// <param name="messageModify">Optional <see cref="AmqpAnnotatedMessage"/> modifier than enables the message to be further configured.</param>
/// <returns>The <see cref="ServiceBusReceivedMessage"/>.</returns>
#if NET7_0_OR_GREATER
public ServiceBusReceivedMessage CreateServiceBusMessageFromJson([StringSyntax(StringSyntaxAttribute.Json)] string json, Action<AmqpAnnotatedMessage>? messageModify = null)
#else
public ServiceBusReceivedMessage CreateServiceBusMessageFromJson(string json, Action<AmqpAnnotatedMessage>? messageModify = null)
#endif
{
var message = new AmqpAnnotatedMessage(AmqpMessageBody.FromData(new ReadOnlyMemory<byte>[] { Encoding.UTF8.GetBytes(json ?? throw new ArgumentNullException(nameof(json))) }));
message.Properties.ContentType = MediaTypeNames.Application.Json;
Expand Down Expand Up @@ -394,6 +399,6 @@ public ServiceBusReceivedMessage CreateServiceBusMessage(AmqpAnnotatedMessage me
/// <returns>The <see cref="WorkerServiceBusMessageActionsAssertor"/>.</returns>
public WorkerServiceBusMessageActionsAssertor CreateWorkerServiceBusMessageActions() => new(Implementor);

#endregion
#endregion
}
}
25 changes: 25 additions & 0 deletions src/UnitTestEx/AspNetCore/HttpTester.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

using Microsoft.AspNetCore.TestHost;
using System;
using System.Diagnostics.CodeAnalysis;
using System.Net.Http;
using System.Net.Mime;
using System.Threading.Tasks;
Expand All @@ -24,7 +25,11 @@ public class HttpTester(TesterBase owner, TestServer testServer) : HttpTesterBas
/// <param name="requestUri">The string that represents the request <see cref="Uri"/>.</param>
/// <param name="requestModifier">The optional <see cref="HttpRequestMessage"/> modifier.</param>
/// <returns>An <see cref="HttpResponseMessageAssertor"/>.</returns>
#if NET7_0_OR_GREATER
public HttpResponseMessageAssertor Run(HttpMethod httpMethod, [StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, Action<HttpRequestMessage>? requestModifier = null)
#else
public HttpResponseMessageAssertor Run(HttpMethod httpMethod, string? requestUri, Action<HttpRequestMessage>? requestModifier = null)
#endif
=> RunAsync(httpMethod, requestUri, requestModifier).GetAwaiter().GetResult();

/// <summary>
Expand All @@ -36,7 +41,11 @@ public HttpResponseMessageAssertor Run(HttpMethod httpMethod, string? requestUri
/// <param name="contentType">The content type. Defaults to <see cref="MediaTypeNames.Text.Plain"/>.</param>
/// <param name="requestModifier">The optional <see cref="HttpRequestMessage"/> modifier.</param>
/// <returns>An <see cref="HttpResponseMessageAssertor"/>.</returns>
#if NET7_0_OR_GREATER
public HttpResponseMessageAssertor Run(HttpMethod httpMethod, [StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, string? body, string? contentType = MediaTypeNames.Text.Plain, Action<HttpRequestMessage>? requestModifier = null)
#else
public HttpResponseMessageAssertor Run(HttpMethod httpMethod, string? requestUri, string? body, string? contentType = MediaTypeNames.Text.Plain, Action<HttpRequestMessage>? requestModifier = null)
#endif
=> RunAsync(httpMethod, requestUri, body, contentType, requestModifier).GetAwaiter().GetResult();

/// <summary>
Expand All @@ -47,7 +56,11 @@ public HttpResponseMessageAssertor Run(HttpMethod httpMethod, string? requestUri
/// <param name="value">The request body value.</param>
/// <param name="requestModifier">The optional <see cref="HttpRequestMessage"/> modifier.</param>
/// <returns>An <see cref="HttpResponseMessageAssertor"/>.</returns>
#if NET7_0_OR_GREATER
public HttpResponseMessageAssertor Run<T>(HttpMethod httpMethod, [StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, T? value, Action<HttpRequestMessage>? requestModifier = null)
#else
public HttpResponseMessageAssertor Run<T>(HttpMethod httpMethod, string? requestUri, T? value, Action<HttpRequestMessage>? requestModifier = null)
#endif
=> SendAsync(httpMethod, requestUri, value, requestModifier).GetAwaiter().GetResult();

/// <summary>
Expand All @@ -57,7 +70,11 @@ public HttpResponseMessageAssertor Run<T>(HttpMethod httpMethod, string? request
/// <param name="requestUri">The string that represents the request <see cref="Uri"/>.</param>
/// <param name="requestModifier">The optional <see cref="HttpRequestMessage"/> modifier.</param>
/// <returns>An <see cref="HttpResponseMessageAssertor"/>.</returns>
#if NET7_0_OR_GREATER
public Task<HttpResponseMessageAssertor> RunAsync(HttpMethod httpMethod, [StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, Action<HttpRequestMessage>? requestModifier = null)
#else
public Task<HttpResponseMessageAssertor> RunAsync(HttpMethod httpMethod, string? requestUri, Action<HttpRequestMessage>? requestModifier = null)
#endif
=> SendAsync(httpMethod, requestUri, requestModifier);

/// <summary>
Expand All @@ -69,7 +86,11 @@ public Task<HttpResponseMessageAssertor> RunAsync(HttpMethod httpMethod, string?
/// <param name="contentType">The content type. Defaults to <see cref="MediaTypeNames.Text.Plain"/>.</param>
/// <param name="requestModifier">The optional <see cref="HttpRequestMessage"/> modifier.</param>
/// <returns>An <see cref="HttpResponseMessageAssertor"/>.</returns>
#if NET7_0_OR_GREATER
public Task<HttpResponseMessageAssertor> RunAsync(HttpMethod httpMethod, [StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, string? body, string? contentType = MediaTypeNames.Text.Plain, Action<HttpRequestMessage>? requestModifier = null)
#else
public Task<HttpResponseMessageAssertor> RunAsync(HttpMethod httpMethod, string? requestUri, string? body, string? contentType = MediaTypeNames.Text.Plain, Action<HttpRequestMessage>? requestModifier = null)
#endif
=> SendAsync(httpMethod, requestUri, body, contentType, requestModifier);

/// <summary>
Expand All @@ -80,7 +101,11 @@ public Task<HttpResponseMessageAssertor> RunAsync(HttpMethod httpMethod, string?
/// <param name="value">The request body value.</param>
/// <param name="requestModifier">The optional <see cref="HttpRequestMessage"/> modifier.</param>
/// <returns>An <see cref="HttpResponseMessageAssertor"/>.</returns>
#if NET7_0_OR_GREATER
public Task<HttpResponseMessageAssertor> RunAsync<T>(HttpMethod httpMethod, [StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, T? value, Action<HttpRequestMessage>? requestModifier = null)
#else
public Task<HttpResponseMessageAssertor> RunAsync<T>(HttpMethod httpMethod, string? requestUri, T? value, Action<HttpRequestMessage>? requestModifier = null)
#endif
=> SendAsync(httpMethod, requestUri, value, requestModifier);
}
}
25 changes: 25 additions & 0 deletions src/UnitTestEx/AspNetCore/HttpTesterBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Net.Http;
using System.Net.Mime;
Expand Down Expand Up @@ -83,7 +84,11 @@ public HttpTesterBase(TesterBase owner, TestServer testServer)
/// <param name="requestUri">The string that represents the request <see cref="Uri"/>.</param>
/// <param name="requestModifier">The optional <see cref="HttpRequestMessage"/> modifier.</param>
/// <returns>The <see cref="HttpResponseMessageAssertor"/>.</returns>
#if NET7_0_OR_GREATER
protected async Task<HttpResponseMessageAssertor> SendAsync(HttpMethod httpMethod, [StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, Action<HttpRequestMessage>? requestModifier)
#else
protected async Task<HttpResponseMessageAssertor> SendAsync(HttpMethod httpMethod, string? requestUri, Action<HttpRequestMessage>? requestModifier)
#endif
{
using var client = CreateHttpClient();
var res = await new TypedHttpClient(client, JsonSerializer).SendAsync(httpMethod, requestUri, requestModifier).ConfigureAwait(false);
Expand All @@ -101,7 +106,11 @@ protected async Task<HttpResponseMessageAssertor> SendAsync(HttpMethod httpMetho
/// <param name="contentType">The content type.</param>
/// <param name="requestModifier">The optional <see cref="HttpRequestMessage"/> modifier.</param>
/// <returns>The <see cref="HttpResponseMessageAssertor"/>.</returns>
#if NET7_0_OR_GREATER
protected async Task<HttpResponseMessageAssertor> SendAsync(HttpMethod httpMethod, [StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, string? content, string? contentType, Action<HttpRequestMessage>? requestModifier)
#else
protected async Task<HttpResponseMessageAssertor> SendAsync(HttpMethod httpMethod, string? requestUri, string? content, string? contentType, Action<HttpRequestMessage>? requestModifier)
#endif
{
if (content != null && httpMethod == HttpMethod.Get)
Owner.LoggerProvider.CreateLogger("ApiTester").LogWarning("A payload within a GET request message has no defined semantics; sending a payload body on a GET request might cause some existing implementations to reject the request (see https://www.rfc-editor.org/rfc/rfc7231).");
Expand All @@ -121,7 +130,11 @@ protected async Task<HttpResponseMessageAssertor> SendAsync(HttpMethod httpMetho
/// <param name="value">The value to be JSON serialized.</param>
/// <param name="requestModifier">The optional <see cref="HttpRequestMessage"/> modifier.</param>
/// <returns>The <see cref="HttpResponseMessageAssertor"/>.</returns>
#if NET7_0_OR_GREATER
protected async Task<HttpResponseMessageAssertor> SendAsync(HttpMethod httpMethod, [StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, object? value, Action<HttpRequestMessage>? requestModifier)
#else
protected async Task<HttpResponseMessageAssertor> SendAsync(HttpMethod httpMethod, string? requestUri, object? value, Action<HttpRequestMessage>? requestModifier)
#endif
{
if (value != null && httpMethod == HttpMethod.Get)
Owner.LoggerProvider.CreateLogger("ApiTester").LogWarning("A payload within a GET request message has no defined semantics; sending a payload body on a GET request might cause some existing implementations to reject the request (see https://www.rfc-editor.org/rfc/rfc7231).");
Expand Down Expand Up @@ -181,19 +194,31 @@ public class TypedHttpClient(HttpClient client, IJsonSerializer jsonSerializer)
/// <summary>
/// Sends with no content.
/// </summary>
#if NET7_0_OR_GREATER
public async Task<HttpResponseMessage> SendAsync(HttpMethod method, [StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, Action<HttpRequestMessage>? requestModifier)
#else
public async Task<HttpResponseMessage> SendAsync(HttpMethod method, string? requestUri, Action<HttpRequestMessage>? requestModifier)
#endif
=> await SendAsync(CreateRequest(method, requestUri ?? "", null, requestModifier), default).ConfigureAwait(false);

/// <summary>
/// Sends with content.
/// </summary>
#if NET7_0_OR_GREATER
public async Task<HttpResponseMessage> SendAsync(HttpMethod method, [StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, string? content, string? contentType, Action<HttpRequestMessage>? requestModifier)
#else
public async Task<HttpResponseMessage> SendAsync(HttpMethod method, string? requestUri, string? content, string? contentType, Action<HttpRequestMessage>? requestModifier)
#endif
=> await SendAsync(CreateRequest(method, requestUri ?? "", new StringContent(content ?? string.Empty, Encoding.UTF8, contentType ?? MediaTypeNames.Text.Plain), requestModifier), default).ConfigureAwait(false);

/// <summary>
/// Sends with JSON value.
/// </summary>
#if NET7_0_OR_GREATER
public async Task<HttpResponseMessage> SendAsync(HttpMethod method, [StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, object? value, Action<HttpRequestMessage>? requestModifier)
#else
public async Task<HttpResponseMessage> SendAsync(HttpMethod method, string? requestUri, object? value, Action<HttpRequestMessage>? requestModifier)
#endif
=> await SendAsync(CreateRequest(method, requestUri ?? "", new StringContent(_jsonSerializer.Serialize(value), Encoding.UTF8, MediaTypeNames.Application.Json), requestModifier), default).ConfigureAwait(false);

/// <inheritdoc/>
Expand Down
25 changes: 25 additions & 0 deletions src/UnitTestEx/AspNetCore/HttpTesterT.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

using Microsoft.AspNetCore.TestHost;
using System;
using System.Diagnostics.CodeAnalysis;
using System.Net.Http;
using System.Net.Mime;
using System.Threading.Tasks;
Expand All @@ -25,7 +26,11 @@ public class HttpTester<TValue>(TesterBase owner, TestServer testServer) : HttpT
/// <param name="requestUri">The string that represents the request <see cref="Uri"/>.</param>
/// <param name="requestModifier">The optional <see cref="HttpRequestMessage"/> modifier.</param>
/// <returns>An <see cref="HttpResponseMessageAssertor"/>.</returns>
#if NET7_0_OR_GREATER
public HttpResponseMessageAssertor Run(HttpMethod httpMethod, [StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, Action<HttpRequestMessage>? requestModifier = null)
#else
public HttpResponseMessageAssertor Run(HttpMethod httpMethod, string? requestUri, Action<HttpRequestMessage>? requestModifier = null)
#endif
=> RunAsync(httpMethod, requestUri, requestModifier).GetAwaiter().GetResult();

/// <summary>
Expand All @@ -37,7 +42,11 @@ public HttpResponseMessageAssertor Run(HttpMethod httpMethod, string? requestUri
/// <param name="contentType">The content type. Defaults to <see cref="MediaTypeNames.Text.Plain"/>.</param>
/// <param name="requestModifier">The optional <see cref="HttpRequestMessage"/> modifier.</param>
/// <returns>An <see cref="HttpResponseMessageAssertor"/>.</returns>
#if NET7_0_OR_GREATER
public HttpResponseMessageAssertor Run(HttpMethod httpMethod, [StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, string? body, string? contentType = MediaTypeNames.Text.Plain, Action<HttpRequestMessage>? requestModifier = null)
#else
public HttpResponseMessageAssertor Run(HttpMethod httpMethod, string? requestUri, string? body, string? contentType = MediaTypeNames.Text.Plain, Action<HttpRequestMessage>? requestModifier = null)
#endif
=> RunAsync(httpMethod, requestUri, body, contentType, requestModifier).GetAwaiter().GetResult();

/// <summary>
Expand All @@ -48,7 +57,11 @@ public HttpResponseMessageAssertor Run(HttpMethod httpMethod, string? requestUri
/// <param name="value">The request body value.</param>
/// <param name="requestModifier">The optional <see cref="HttpRequestMessage"/> modifier.</param>
/// <returns>An <see cref="HttpResponseMessageAssertor"/>.</returns>
#if NET7_0_OR_GREATER
public HttpResponseMessageAssertor Run<T>(HttpMethod httpMethod, [StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, T? value, Action<HttpRequestMessage>? requestModifier = null)
#else
public HttpResponseMessageAssertor Run<T>(HttpMethod httpMethod, string? requestUri, T? value, Action<HttpRequestMessage>? requestModifier = null)
#endif
=> SendAsync(httpMethod, requestUri, value, requestModifier).GetAwaiter().GetResult();

/// <summary>
Expand All @@ -58,7 +71,11 @@ public HttpResponseMessageAssertor Run<T>(HttpMethod httpMethod, string? request
/// <param name="requestUri">The string that represents the request <see cref="Uri"/>.</param>
/// <param name="requestModifier">The optional <see cref="HttpRequestMessage"/> modifier.</param>
/// <returns>An <see cref="HttpResponseMessageAssertor"/>.</returns>
#if NET7_0_OR_GREATER
public Task<HttpResponseMessageAssertor> RunAsync(HttpMethod httpMethod, [StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, Action<HttpRequestMessage>? requestModifier = null)
#else
public Task<HttpResponseMessageAssertor> RunAsync(HttpMethod httpMethod, string? requestUri, Action<HttpRequestMessage>? requestModifier = null)
#endif
=> SendAsync(httpMethod, requestUri, requestModifier);

/// <summary>
Expand All @@ -70,7 +87,11 @@ public Task<HttpResponseMessageAssertor> RunAsync(HttpMethod httpMethod, string?
/// <param name="contentType">The content type. Defaults to <see cref="MediaTypeNames.Text.Plain"/>.</param>
/// <param name="requestModifier">The optional <see cref="HttpRequestMessage"/> modifier.</param>
/// <returns>An <see cref="HttpResponseMessageAssertor"/>.</returns>
#if NET7_0_OR_GREATER
public Task<HttpResponseMessageAssertor> RunAsync(HttpMethod httpMethod, [StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, string? body, string? contentType = MediaTypeNames.Text.Plain, Action<HttpRequestMessage>? requestModifier = null)
#else
public Task<HttpResponseMessageAssertor> RunAsync(HttpMethod httpMethod, string? requestUri, string? body, string? contentType = MediaTypeNames.Text.Plain, Action<HttpRequestMessage>? requestModifier = null)
#endif
=> SendAsync(httpMethod, requestUri, body, contentType, requestModifier);

/// <summary>
Expand All @@ -81,7 +102,11 @@ public Task<HttpResponseMessageAssertor> RunAsync(HttpMethod httpMethod, string?
/// <param name="value">The request body value.</param>
/// <param name="requestModifier">The optional <see cref="HttpRequestMessage"/> modifier.</param>
/// <returns>An <see cref="HttpResponseMessageAssertor"/>.</returns>
#if NET7_0_OR_GREATER
public Task<HttpResponseMessageAssertor> RunAsync<T>(HttpMethod httpMethod, [StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, T? value, Action<HttpRequestMessage>? requestModifier = null)
#else
public Task<HttpResponseMessageAssertor> RunAsync<T>(HttpMethod httpMethod, string? requestUri, T? value, Action<HttpRequestMessage>? requestModifier = null)
#endif
=> SendAsync(httpMethod, requestUri, value, requestModifier);
}
}
5 changes: 5 additions & 0 deletions src/UnitTestEx/Assertors/ActionResultAssertor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Microsoft.AspNetCore.Mvc.Infrastructure;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Net;
using System.Net.Mime;
using System.Reflection;
Expand Down Expand Up @@ -367,7 +368,11 @@ public ActionResultAssertor AssertJsonFromResource(string resourceName, params s
/// <param name="json">The expected JSON.</param>
/// <param name="pathsToIgnore">The JSON paths to ignore from the comparison.</param>
/// <returns>The <see cref="ActionResultAssertor"/> to support fluent-style method-chaining.</returns>
#if NET7_0_OR_GREATER
public ActionResultAssertor AssertJson([StringSyntax(StringSyntaxAttribute.Json)] string json, params string[] pathsToIgnore)
#else
public ActionResultAssertor AssertJson(string json, params string[] pathsToIgnore)
#endif
{
if (string.IsNullOrEmpty(json))
throw new ArgumentNullException(nameof(json));
Expand Down
Loading

0 comments on commit 0fe7670

Please sign in to comment.