From fde4f8ef69f765f22921c194eb0535d52a85f27c Mon Sep 17 00:00:00 2001
From: Sergio <7523246+Sergio1192@users.noreply.github.com>
Date: Thu, 25 May 2023 09:25:51 +0200
Subject: [PATCH] develop into master (#90)
* Create get request when it has an object with some list
* DateTime as a primitive type but using custom formatter (#81)
* Fixing codeQL alerts (#82)
* feature: Get url (#83)
* In IncludeContentAsFormUrlEncoded and PrimitiveParameterActionTokenizer explicit conversion for floats (#84)
Create random ParamWithSeveralTypes
More tests
* Add new CreateHttpApiRequest with TActionResponse (#85)
Fix CodeQL alerts
Test
* Add net7.0 Target Version (#86)
* Add net7.0 Target Version
Update nugets
* add net 7 in workflows
* update global.json
* remove extra builds ci.yml
* ReadContentAsAsync allows string type (#87)
Tests for HttpResponseMessageExtensions
* Allow send a IFormFile (#88)
* Allow IFormFile
Refactor IncludeContentAsFormUrlEncoded
Remove Newtonsoft.Json dependecy
* Update documentation
* Refactor GivenFile
* Update version to 3.5.0 (#89)
* Add DateTimeOffset to IsDateTime function (#91)
Move TypeExtensions
---
.github/workflows/ci.yml | 9 +-
.github/workflows/codeql-analysis.yml | 2 +-
.github/workflows/nuget.yml | 1 +
Directory.Build.props | 4 +-
Directory.Packages.props | 63 +-
README.md | 78 +-
global.json | 6 +-
src/Acheve.TestHost/Acheve.TestHost.csproj | 6 -
.../AuthenticationBuilderExtensions.cs | 0
.../{ => Extensions}/HttpClientExtensions.cs | 0
.../HttpResponseMessageExtensions.cs | 47 +
.../Extensions/RequestBuilderExtensions.cs | 153 +
.../Extensions/TestServerExtensions.cs | 59 +
.../Extensions/TypeExtensions.cs | 33 +
.../HttpResponseMessageExtensions.cs | 38 -
.../IncludeContentAsFormUrlEncoded.cs | 67 -
.../RequestBuilderExtensions.cs | 139 -
.../IncludeContentAsFormUrlEncoded.cs | 85 +
.../IncludeContentAsJson.cs | 8 +-
.../{ => RequestContent}/NotIncludeContent.cs | 0
.../RequestContentOptions.cs | 0
.../Routing/TestServerAction.cs | 12 +-
.../ComplexParameterActionTokenizer.cs | 80 +-
.../EnumerableParameterActionTokenizer.cs | 46 +
.../PrimitiveParameterActionTokenizer.cs | 89 +-
.../Tokenizers/TestServerTokenCollection.cs | 89 +-
.../Routing/Tokenizers/TypeExtensions.cs | 28 -
src/Acheve.TestHost/Routing/UriDiscover.cs | 300 +-
.../Security/DefaultClaimsEncoder.cs | 53 +-
src/Acheve.TestHost/TestServerExtensions.cs | 204 --
.../Routing/Builders/BugsController.cs | 172 +-
.../Routing/Builders/ValuesV4Controller.cs | 129 +-
.../Routing/Builders/ValuesV5Controller.cs | 143 +-
.../HttpResponseMessageExtensionsTests.cs | 74 +
.../Routing/Models/ParamWithFile.cs | 20 +
.../Routing/Models/ParamWithSeveralTypes.cs | 86 +
.../Routing/RequestBuilderExtensionsTests.cs | 233 +-
.../Routing/TestServerExtensionsTests.cs | 2795 +++++++++--------
38 files changed, 2949 insertions(+), 2402 deletions(-)
rename src/Acheve.TestHost/{ => Extensions}/AuthenticationBuilderExtensions.cs (100%)
rename src/Acheve.TestHost/{ => Extensions}/HttpClientExtensions.cs (100%)
create mode 100644 src/Acheve.TestHost/Extensions/HttpResponseMessageExtensions.cs
create mode 100644 src/Acheve.TestHost/Extensions/RequestBuilderExtensions.cs
create mode 100644 src/Acheve.TestHost/Extensions/TestServerExtensions.cs
create mode 100644 src/Acheve.TestHost/Extensions/TypeExtensions.cs
delete mode 100644 src/Acheve.TestHost/HttpResponseMessageExtensions.cs
delete mode 100644 src/Acheve.TestHost/IncludeContentAsFormUrlEncoded.cs
delete mode 100644 src/Acheve.TestHost/RequestBuilderExtensions.cs
create mode 100644 src/Acheve.TestHost/RequestContent/IncludeContentAsFormUrlEncoded.cs
rename src/Acheve.TestHost/{ => RequestContent}/IncludeContentAsJson.cs (88%)
rename src/Acheve.TestHost/{ => RequestContent}/NotIncludeContent.cs (100%)
rename src/Acheve.TestHost/{ => RequestContent}/RequestContentOptions.cs (100%)
create mode 100644 src/Acheve.TestHost/Routing/Tokenizers/EnumerableParameterActionTokenizer.cs
delete mode 100644 src/Acheve.TestHost/Routing/Tokenizers/TypeExtensions.cs
delete mode 100644 src/Acheve.TestHost/TestServerExtensions.cs
create mode 100644 tests/UnitTests/Acheve.TestHost/Routing/HttpResponseMessageExtensionsTests.cs
create mode 100644 tests/UnitTests/Acheve.TestHost/Routing/Models/ParamWithFile.cs
create mode 100644 tests/UnitTests/Acheve.TestHost/Routing/Models/ParamWithSeveralTypes.cs
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index faef6dd..9cd19a7 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -26,13 +26,10 @@ jobs:
3.1.417
5.0.101
6.0.300
+ 7.0.302
- - name: Build .NET 3.1
- run: dotnet build -c $BUILD_CONFIG --framework netcoreapp3.1
- - name: Build .NET 5.0
- run: dotnet build -c $BUILD_CONFIG --framework net5.0
- - name: Build .NET 6.0
- run: dotnet build -c $BUILD_CONFIG --framework net6.0
+ - name: Build
+ run: dotnet build -c $BUILD_CONFIG
- name: Test
run: dotnet test -c $BUILD_CONFIG --no-build
\ No newline at end of file
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index adb7021..f41fbef 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -2,7 +2,7 @@ name: "CodeQL"
on:
push:
- branches: [ "master" ]
+ branches: [ "master", "develop" ]
pull_request:
branches: [ "master", "develop" ]
workflow_dispatch:
diff --git a/.github/workflows/nuget.yml b/.github/workflows/nuget.yml
index e1cbab7..10de10e 100644
--- a/.github/workflows/nuget.yml
+++ b/.github/workflows/nuget.yml
@@ -21,6 +21,7 @@ jobs:
3.1.417
5.0.101
6.0.300
+ 7.0.302
- name: Build
run: dotnet build -c $BUILD_CONFIG
diff --git a/Directory.Build.props b/Directory.Build.props
index 2d9ff8f..3f7e2bb 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -1,12 +1,12 @@
- netcoreapp3.1;net5.0;net6.0
+ netcoreapp3.1;net5.0;net6.0;net7.0
latest
true
- 3.4.0
+ 3.5.0
Apache-2.0
http://github.com/xabaril/Acheve.TestHost
diff --git a/Directory.Packages.props b/Directory.Packages.props
index f89b0bb..608ec0f 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -1,35 +1,32 @@
-
- 3.1.25
-
-
-
- 5.0.17
-
-
-
- 6.0.5
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+ 3.1.32
+
+
+ 5.0.17
+
+
+ 6.0.16
+
+
+ 7.0.5
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index 69d8bc1..9c8e9f9 100644
--- a/README.md
+++ b/README.md
@@ -2,11 +2,11 @@
[![Build status](https://github.com/Xabaril/Acheve.TestHost/actions/workflows/nuget.yml/badge.svg)](https://github.com/Xabaril/Acheve.TestHost/actions/workflows/nuget.yml/badge.svg) [![NuGet](https://img.shields.io/nuget/v/acheve.testhost.svg)](https://www.nuget.org/packages/acheve.testhost/)
-NuGet package to improve AspNetCore TestServer experiences
+NuGet package to improve AspNetCore TestServer experiences
Unit testing your Mvc controllers is not enough to verify the correctness of your WebApi. Are the filters working? Is the correct status code sent when that condition is reached? Is the user authorized to request that endpoint?
-The NuGet package [Microsoft.AspNetCore.TestHost](https://www.nuget.org/packages/Microsoft.AspNetCore.TestHost/) allows you to create an in memory server that exposes an HttpClient to be able to send request to the server. All in memory, all in the same process. Fast. It's the best way to create integration tests in your Mvc application. But at this moment this library has some gaps that *Acheve* try to fill.
+The NuGet package [Microsoft.AspNetCore.TestHost](https://www.nuget.org/packages/Microsoft.AspNetCore.TestHost/) allows you to create an in memory server that exposes an HttpClient to be able to send request to the server. All in memory, all in the same process. Fast. It's the best way to create integration tests in your Mvc application. But at this moment this library has some gaps that _Acheve_ try to fill.
## Get started
@@ -66,29 +66,29 @@ the claims for authenticated calls to the WebApi.
In the TestServer startup class you shoud incude the authentication service and add the .Net Core new AUthentication middleware:
- ```csharp
- public class TestStartup
- {
- public void ConfigureServices(IServiceCollection services)
- {
- services.AddAuthentication(options =>
- {
- options.DefaultScheme = TestServerDefaults.AuthenticationScheme;
- })
- .AddTestServer();
-
- var mvcCoreBuilder = services.AddMvcCore();
- ApiConfiguration.ConfigureCoreMvc(mvcCoreBuilder);
- }
-
- // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
- public void Configure(IApplicationBuilder app)
- {
- app.UseAuthentication();
-
- app.UseMvcWithDefaultRoute();
- }
- }
+```csharp
+ public class TestStartup
+ {
+ public void ConfigureServices(IServiceCollection services)
+ {
+ services.AddAuthentication(options =>
+ {
+ options.DefaultScheme = TestServerDefaults.AuthenticationScheme;
+ })
+ .AddTestServer();
+
+ var mvcCoreBuilder = services.AddMvcCore();
+ ApiConfiguration.ConfigureCoreMvc(mvcCoreBuilder);
+ }
+
+ // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
+ public void Configure(IApplicationBuilder app)
+ {
+ app.UseAuthentication();
+
+ app.UseMvcWithDefaultRoute();
+ }
+ }
```
And in your tests you can use an HttpClient with default credentials or build
@@ -178,7 +178,7 @@ var response = await _server.CreateRequest("api/values/public")
In general, in our tests a new simple API class is created to hide this uri and improve the code.
```csharp
- // some code on tests
+ // some code on tests
var response = await _server.CreateRequest(Api.Values.Public)
.GetAsync();
@@ -199,7 +199,7 @@ The main problems on this approach are:
1. If any route convention is changed all integration test will fail.
1. If you refactor any parameter order the integration test will fail.
-With *Acheve* you can create the uri dynamically using the attribute routing directly from your controllers.
+With _Acheve_ you can create the uri dynamically using the attribute routing directly from your controllers.
```csharp
var response = await _server.CreateHttpApiRequest(controller=>controller.PublicValues())
@@ -208,7 +208,7 @@ var response = await _server.CreateHttpApiRequest(controller=>
## About adding extra query parameters
-The package has a *RequestBuilder* extension to add a new query parameter: *AddQueryParameter*.
+The package has a _RequestBuilder_ extension to add a new query parameter: _AddQueryParameter_.
```csharp
[Fact]
@@ -221,9 +221,9 @@ public async Task MyFirstTest()
}
```
-## About removin query parameters
+## About removing query parameters
-The package has a *RequestBuilder* extension to remove a query parameter: *RemoveQueryParameter*.
+The package has a _RequestBuilder_ extension to remove a query parameter: _RemoveQueryParameter_.
```csharp
[Fact]
@@ -236,12 +236,26 @@ public async Task MyFirstTest()
}
```
+## About sending files
+
+The package has a _TestServer_ extension to get a test file: _GivenFile_.
+
+```csharp
+[Fact]
+public async Task MyFirstTest()
+{
+ ...
+ var file = server.GivenFile();
+ ...
+}
+```
+
## Improving assertions in API responses
The package has HttpResponseMessage extension to help us assert the response.
-- *IsSuccessStatusCodeOrThrow*: Throw exception with the response content in the message.
-- *ReadContentAsAsync*: Read the response content and cast it.
+- _IsSuccessStatusCodeOrThrow_: Throw exception with the response content in the message.
+- _ReadContentAsAsync_: Read the response content and cast it.
```csharp
[Fact]
diff --git a/global.json b/global.json
index 58d7ecc..fb292b5 100644
--- a/global.json
+++ b/global.json
@@ -1,7 +1,7 @@
{
- "projects": [ "src", "test", "samples" ],
+ "projects": ["src", "test", "samples"],
"sdk": {
- "version": "6.0.300",
+ "version": "6.0.000",
"rollForward": "latestMajor"
}
-}
\ No newline at end of file
+}
diff --git a/src/Acheve.TestHost/Acheve.TestHost.csproj b/src/Acheve.TestHost/Acheve.TestHost.csproj
index e69405c..a1d0bd1 100644
--- a/src/Acheve.TestHost/Acheve.TestHost.csproj
+++ b/src/Acheve.TestHost/Acheve.TestHost.csproj
@@ -3,11 +3,6 @@
$(NetCoreTargetVersion)
-
-
-
-
-
@@ -15,7 +10,6 @@
-
diff --git a/src/Acheve.TestHost/AuthenticationBuilderExtensions.cs b/src/Acheve.TestHost/Extensions/AuthenticationBuilderExtensions.cs
similarity index 100%
rename from src/Acheve.TestHost/AuthenticationBuilderExtensions.cs
rename to src/Acheve.TestHost/Extensions/AuthenticationBuilderExtensions.cs
diff --git a/src/Acheve.TestHost/HttpClientExtensions.cs b/src/Acheve.TestHost/Extensions/HttpClientExtensions.cs
similarity index 100%
rename from src/Acheve.TestHost/HttpClientExtensions.cs
rename to src/Acheve.TestHost/Extensions/HttpClientExtensions.cs
diff --git a/src/Acheve.TestHost/Extensions/HttpResponseMessageExtensions.cs b/src/Acheve.TestHost/Extensions/HttpResponseMessageExtensions.cs
new file mode 100644
index 0000000..d427507
--- /dev/null
+++ b/src/Acheve.TestHost/Extensions/HttpResponseMessageExtensions.cs
@@ -0,0 +1,47 @@
+using System.Text.Json;
+using System.Threading.Tasks;
+
+namespace System.Net.Http;
+
+public static class HttpResponseMessageExtensions
+{
+ ///
+ /// Try to extract the error message in the response content in case the response status code is not success.
+ ///
+ /// The HttpResponseMessage instance
+ ///
+ public static async Task IsSuccessStatusCodeOrThrow(this HttpResponseMessage response)
+ {
+ if (response.IsSuccessStatusCode)
+ {
+ return;
+ }
+
+ var content = await response.Content.ReadAsStringAsync();
+
+ throw new Exception($"Response status does not indicate success: {response.StatusCode:D} ({response.StatusCode}); \r\n{content}");
+ }
+
+ ///
+ /// Read HttpResponseMessage and convert to T Class
+ ///
+ /// Class type or primitive type
+ /// The HttpResponseMessage instance
+ /// T class object
+ public static async Task ReadContentAsAsync(this HttpResponseMessage responseMessage)
+ {
+ var content = await responseMessage.Content.ReadAsStringAsync();
+
+ if (typeof(T) == typeof(string))
+ {
+ content = $"\"{content}\"";
+ }
+
+ var json = JsonSerializer.Deserialize(content, new JsonSerializerOptions()
+ {
+ PropertyNameCaseInsensitive = true
+ });
+
+ return json;
+ }
+}
\ No newline at end of file
diff --git a/src/Acheve.TestHost/Extensions/RequestBuilderExtensions.cs b/src/Acheve.TestHost/Extensions/RequestBuilderExtensions.cs
new file mode 100644
index 0000000..7878385
--- /dev/null
+++ b/src/Acheve.TestHost/Extensions/RequestBuilderExtensions.cs
@@ -0,0 +1,153 @@
+using Acheve.TestHost;
+using Microsoft.Net.Http.Headers;
+using System;
+using System.Collections.Generic;
+using System.Security.Claims;
+using System.Text.RegularExpressions;
+
+namespace Microsoft.AspNetCore.TestHost;
+
+public static class RequestBuilderExtensions
+{
+ ///
+ /// Adds an Authentication header to the with the provided claims using
+ /// "TestServer" as authentication scheme.
+ ///
+ /// The requestBuilder instance
+ /// The claims collection that represents the user identity
+ ///
+ public static RequestBuilder WithIdentity(this RequestBuilder requestBuilder, IEnumerable claims)
+ {
+ return requestBuilder.WithIdentity(
+ claims,
+ TestServerDefaults.AuthenticationScheme);
+ }
+
+ ///
+ /// Adds an Authentication header to the with the provided claims
+ /// and authentication scheme.
+ ///
+ /// The requestBuilder instance
+ /// The claims collection that represents the user identity
+ /// The authentication scheme
+ ///
+ public static RequestBuilder WithIdentity(this RequestBuilder requestBuilder, IEnumerable claims, string scheme)
+ {
+ if (string.IsNullOrWhiteSpace(scheme))
+ {
+ throw new ArgumentNullException(nameof(scheme));
+ }
+
+ var headerName = AuthenticationHeaderHelper.GetHeaderName(scheme);
+
+ requestBuilder.AddHeader(
+ headerName,
+ $"{scheme} {DefautClaimsEncoder.Encode(claims)}");
+
+ return requestBuilder;
+ }
+
+ ///
+ /// Get the header string for the provided claims
+ ///
+ /// The requestBuilder instance
+ /// The claims collection that represents the user identity
+ ///
+ public static string GetHeaderForIdentity(this RequestBuilder requestBuilder, IEnumerable claims)
+ {
+ return requestBuilder.GetHeaderForIdentity(
+ claims,
+ TestServerDefaults.AuthenticationScheme);
+ }
+
+ ///
+ /// Get the header string for the provided claims
+ ///
+ /// The requestBuilder instance
+ /// The claims collection that represents the user identity
+ /// The authentication scheme
+ ///
+ public static string GetHeaderForIdentity(this RequestBuilder _, IEnumerable claims, string scheme)
+ {
+ if (string.IsNullOrWhiteSpace(scheme))
+ {
+ throw new ArgumentNullException(nameof(scheme));
+ }
+
+ var headerName = AuthenticationHeaderHelper.GetHeaderName(scheme);
+
+ var header = new NameValueHeaderValue(
+ headerName,
+ $"{TestServerDefaults.AuthenticationScheme} {DefautClaimsEncoder.Encode(claims)}");
+
+ return header.ToString();
+ }
+
+ ///
+ /// Add the given parameter and value to the request
+ ///
+ /// Type of the value to be casted to string
+ /// The requestBuilder instance
+ /// Parameter name
+ /// Parameter value
+ /// RequestBuilder instance
+ public static RequestBuilder AddQueryParameter(this RequestBuilder requestBuilder, string name, T value)
+ {
+ requestBuilder.And(configure =>
+ {
+ var separatoChar = '?';
+ if (configure.RequestUri.ToString().Contains(separatoChar))
+ separatoChar = '&';
+
+ configure.RequestUri = new Uri($"{configure.RequestUri}{separatoChar}{Uri.EscapeDataString(name)}={Uri.EscapeDataString(value.ToString())}", UriKind.Relative);
+ });
+
+ return requestBuilder;
+ }
+
+ ///
+ /// Remove the given parameter from the request
+ ///
+ /// The requestBuilder instance
+ /// Parameter name
+ /// RequestBuilder instance
+ public static RequestBuilder RemoveQueryParameter(this RequestBuilder requestBuilder, string name)
+ {
+ requestBuilder.And(configure =>
+ {
+ var regexOptions = RegexOptions.Compiled | RegexOptions.IgnoreCase;
+ var isTheLastParameter = new Regex(@$"[?|&]{name}=[^&]+$", regexOptions);
+ var isTheFistParamaeterAndHasOtherParamaters = new Regex(@$"[?]{name}=[^&]+[&]", regexOptions);
+ var isTheMiddleParameter = new Regex(@$"[&]{name}=[^&]+[&]", regexOptions);
+
+ var newUri = configure.RequestUri.ToString()
+ .ReplaceRegex(isTheLastParameter, string.Empty)
+ .ReplaceRegex(isTheFistParamaeterAndHasOtherParamaters, "?")
+ .ReplaceRegex(isTheMiddleParameter, "&");
+
+ configure.RequestUri = new Uri(newUri, UriKind.Relative);
+ });
+
+ return requestBuilder;
+ }
+
+ ///
+ /// Get url from the HttpRequest
+ ///
+ /// The requestBuilder instance
+ /// Url
+ public static string GetUrl(this RequestBuilder requestBuilder)
+ {
+ string url = null;
+ requestBuilder.And(
+ configure => url = configure.RequestUri.ToString()
+ );
+
+ return url;
+ }
+
+ private static string ReplaceRegex(this string value, Regex regex, string replacement)
+ {
+ return regex.Replace(value, replacement);
+ }
+}
diff --git a/src/Acheve.TestHost/Extensions/TestServerExtensions.cs b/src/Acheve.TestHost/Extensions/TestServerExtensions.cs
new file mode 100644
index 0000000..105f69a
--- /dev/null
+++ b/src/Acheve.TestHost/Extensions/TestServerExtensions.cs
@@ -0,0 +1,59 @@
+using Acheve.TestHost.Routing;
+using Microsoft.AspNetCore.Http;
+using System;
+using System.IO;
+using System.Linq.Expressions;
+using System.Text;
+
+namespace Microsoft.AspNetCore.TestHost;
+
+public static class TestServerExtensions
+{
+ ///
+ /// Create a configured automatically
+ /// with the generated uri from the .
+ /// At this moment this method only resolver HTTP API using ASP.NET CORE Attribute Routing
+ ///
+ /// The controller to use
+ /// The TestServer
+ /// The action selector used to discover the uri
+ /// The optional token values used to create the uri
+ /// Determines if [FromBody] arguments are included as request content.
+ /// By default they are included as application/json content
+ /// RequestBuilder configured automatically
+ public static RequestBuilder CreateHttpApiRequest(this TestServer server,
+ Expression> actionSelector,
+ object tokenValues = null,
+ RequestContentOptions contentOptions = null)
+ where TController : class
+ => UriDiscover.CreateHttpApiRequest(server, actionSelector, tokenValues, contentOptions);
+
+ ///
+ /// Create a configured automatically
+ /// with the generated uri from the .
+ /// At this moment this method only resolver HTTP API using ASP.NET CORE Attribute Routing
+ ///
+ /// The controller to use
+ /// actionSelector response type
+ /// The TestServer
+ /// The action selector used to discover the uri
+ /// The optional token values used to create the uri
+ /// Determines if [FromBody] arguments are included as request content.
+ /// By default they are included as application/json content
+ /// RequestBuilder configured automatically
+ public static RequestBuilder CreateHttpApiRequest(this TestServer server,
+ Expression> actionSelector,
+ object tokenValues = null,
+ RequestContentOptions contentOptions = null)
+ where TController : class
+ => UriDiscover.CreateHttpApiRequest(server, actionSelector, tokenValues, contentOptions);
+
+ public static IFormFile GivenFile(this TestServer _, string parameterName = "file", string filename = "test.txt", string content = "test")
+ {
+ var stream = new MemoryStream(Encoding.UTF8.GetBytes(content));
+
+ IFormFile file = new FormFile(stream, 0, stream.Length, parameterName, filename);
+
+ return file;
+ }
+}
diff --git a/src/Acheve.TestHost/Extensions/TypeExtensions.cs b/src/Acheve.TestHost/Extensions/TypeExtensions.cs
new file mode 100644
index 0000000..6464836
--- /dev/null
+++ b/src/Acheve.TestHost/Extensions/TypeExtensions.cs
@@ -0,0 +1,33 @@
+using System.Collections;
+using System.Linq;
+
+namespace System;
+
+internal static class TypeExtensions
+{
+ internal static bool IsPrimitiveType(this Type typeToInspect)
+ {
+ var type = Nullable.GetUnderlyingType(typeToInspect) ?? typeToInspect;
+
+ return type.IsPrimitive
+ || type == typeof(string)
+ || type == typeof(decimal)
+ || type == typeof(Guid)
+ || type.IsDateTime();
+ }
+
+ internal static bool IsDateTime(this Type typeToInspect)
+ {
+ return typeToInspect == typeof(DateTime) || typeToInspect == typeof(DateTimeOffset);
+ }
+
+ internal static bool IsEnumerable(this Type typeToInspect)
+ {
+ return typeof(IEnumerable).IsAssignableFrom(typeToInspect) && typeToInspect != typeof(string);
+ }
+
+ internal static Type GetEnumerableElementType(this Type typeToInspect)
+ {
+ return typeToInspect.GetElementType() ?? typeToInspect.GetGenericArguments().FirstOrDefault();
+ }
+}
\ No newline at end of file
diff --git a/src/Acheve.TestHost/HttpResponseMessageExtensions.cs b/src/Acheve.TestHost/HttpResponseMessageExtensions.cs
deleted file mode 100644
index 601e1de..0000000
--- a/src/Acheve.TestHost/HttpResponseMessageExtensions.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-using Newtonsoft.Json;
-using System.Threading.Tasks;
-
-namespace System.Net.Http
-{
- public static class HttpResponseMessageExtensions
- {
- ///
- /// Try to extract the error message in the response content in case the response status code is not success.
- ///
- /// The httpResponseMessage instance
- ///
- public static async Task IsSuccessStatusCodeOrThrow(this HttpResponseMessage response)
- {
- if (response.IsSuccessStatusCode)
- {
- return;
- }
-
- var content = await response.Content.ReadAsStringAsync();
-
- throw new Exception($"Response status does not indicate success: {response.StatusCode:D} ({response.StatusCode}); \r\n{content}");
- }
-
- ///
- /// Read HttpResponseMessage and convert to T Class
- ///
- /// Class
- /// The httpResponseMessage instance
- /// T class object
- public static async Task ReadContentAsAsync(this HttpResponseMessage responseMessage)
- {
- var json = await responseMessage.Content.ReadAsStringAsync();
-
- return JsonConvert.DeserializeObject(json);
- }
- }
-}
\ No newline at end of file
diff --git a/src/Acheve.TestHost/IncludeContentAsFormUrlEncoded.cs b/src/Acheve.TestHost/IncludeContentAsFormUrlEncoded.cs
deleted file mode 100644
index 1e1d773..0000000
--- a/src/Acheve.TestHost/IncludeContentAsFormUrlEncoded.cs
+++ /dev/null
@@ -1,67 +0,0 @@
-using Newtonsoft.Json.Linq;
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.Linq;
-using System.Net.Http;
-
-namespace Microsoft.AspNetCore.TestHost
-{
- ///
- /// An implementation of that includes
- /// the [FromForm] parameter as
- ///
- public class IncludeContentAsFormUrlEncoded : RequestContentOptions
- {
- ///
- public override bool IncludeFromBodyAsContent => false;
-
- ///
- public override bool IncludeFromFormAsContent => true;
-
- ///
- public override Func ContentBuilder =>
- content => new FormUrlEncodedContent(ToKeyValue(content));
-
- private IDictionary ToKeyValue(object metaToken)
- {
- if (metaToken == null)
- {
- return null;
- }
-
- if (!(metaToken is JToken token))
- {
- return ToKeyValue(JObject.FromObject(metaToken));
- }
-
- if (token.HasValues)
- {
- var contentData = new Dictionary();
- foreach (var child in token.Children().ToList())
- {
- var childContent = ToKeyValue(child);
- if (childContent != null)
- {
- contentData = contentData.Concat(childContent)
- .ToDictionary(k => k.Key, v => v.Value);
- }
- }
-
- return contentData;
- }
-
- var jValue = token as JValue;
- if (jValue?.Value == null)
- {
- return null;
- }
-
- var value = jValue?.Type == JTokenType.Date ?
- jValue?.ToString("o", CultureInfo.InvariantCulture) :
- jValue?.ToString(CultureInfo.InvariantCulture);
-
- return new Dictionary { { token.Path, value } };
- }
- }
-}
diff --git a/src/Acheve.TestHost/RequestBuilderExtensions.cs b/src/Acheve.TestHost/RequestBuilderExtensions.cs
deleted file mode 100644
index 844558d..0000000
--- a/src/Acheve.TestHost/RequestBuilderExtensions.cs
+++ /dev/null
@@ -1,139 +0,0 @@
-using Acheve.TestHost;
-using Microsoft.Net.Http.Headers;
-using System;
-using System.Collections.Generic;
-using System.Security.Claims;
-using System.Text.RegularExpressions;
-
-namespace Microsoft.AspNetCore.TestHost
-{
- public static class RequestBuilderExtensions
- {
- ///
- /// Adds an Authentication header to the with the provided claims using
- /// "TestServer" as authentication scheme.
- ///
- /// The requestBuilder instance
- /// The claims collection that represents the user identity
- ///
- public static RequestBuilder WithIdentity(this RequestBuilder requestBuilder, IEnumerable claims)
- {
- return requestBuilder.WithIdentity(
- claims,
- TestServerDefaults.AuthenticationScheme);
- }
-
- ///
- /// Adds an Authentication header to the with the provided claims
- /// and authentication scheme.
- ///
- /// The requestBuilder instance
- /// The claims collection that represents the user identity
- /// The authentication scheme
- ///
- public static RequestBuilder WithIdentity(this RequestBuilder requestBuilder, IEnumerable claims, string scheme)
- {
- if (string.IsNullOrWhiteSpace(scheme))
- {
- throw new ArgumentNullException(nameof(scheme));
- }
-
- var headerName = AuthenticationHeaderHelper.GetHeaderName(scheme);
-
- requestBuilder.AddHeader(
- headerName,
- $"{scheme} {DefautClaimsEncoder.Encode(claims)}");
-
- return requestBuilder;
- }
-
- ///
- /// Get the header string for the provided claims
- ///
- /// The requestBuilder instance
- /// The claims collection that represents the user identity
- ///
- public static string GetHeaderForIdentity(this RequestBuilder requestBuilder, IEnumerable claims)
- {
- return requestBuilder.GetHeaderForIdentity(
- claims,
- TestServerDefaults.AuthenticationScheme);
- }
-
- ///
- /// Get the header string for the provided claims
- ///
- /// The requestBuilder instance
- /// The claims collection that represents the user identity
- /// The authentication scheme
- ///
- public static string GetHeaderForIdentity(this RequestBuilder requestBuilder, IEnumerable claims, string scheme)
- {
- if (string.IsNullOrWhiteSpace(scheme))
- {
- throw new ArgumentNullException(nameof(scheme));
- }
-
- var headerName = AuthenticationHeaderHelper.GetHeaderName(scheme);
-
- var header = new NameValueHeaderValue(
- headerName,
- $"{TestServerDefaults.AuthenticationScheme} {DefautClaimsEncoder.Encode(claims)}");
-
- return header.ToString();
- }
-
- ///
- /// Add the given parameter and value to the request
- ///
- /// Type of the value to be casted to string
- /// The requestBuilder instance
- /// Parameter name
- /// Parameter value
- /// RequestBuilder instance
- public static RequestBuilder AddQueryParameter(this RequestBuilder requestBuilder, string name, T value)
- {
- requestBuilder.And(configure =>
- {
- var separatoChar = '?';
- if (configure.RequestUri.ToString().Contains(separatoChar))
- separatoChar = '&';
-
- configure.RequestUri = new Uri($"{configure.RequestUri}{separatoChar}{Uri.EscapeDataString(name)}={Uri.EscapeDataString(value.ToString())}", UriKind.Relative);
- });
-
- return requestBuilder;
- }
-
- ///
- /// Remove the given parameter from the request
- ///
- /// The requestBuilder instance
- /// Parameter name
- /// RequestBuilder instance
- public static RequestBuilder RemoveQueryParameter(this RequestBuilder requestBuilder, string name)
- {
- requestBuilder.And(configure =>
- {
- var regexOptions = RegexOptions.Compiled | RegexOptions.IgnoreCase;
- var isTheLastParameter = new Regex(@$"[?|&]{name}=[^&]+$", regexOptions);
- var isTheFistParamaeterAndHasOtherParamaters = new Regex(@$"[?]{name}=[^&]+[&]", regexOptions);
- var isTheMiddleParameter = new Regex(@$"[&]{name}=[^&]+[&]", regexOptions);
-
- var newUri = configure.RequestUri.ToString()
- .ReplaceRegex(isTheLastParameter, string.Empty)
- .ReplaceRegex(isTheFistParamaeterAndHasOtherParamaters, "?")
- .ReplaceRegex(isTheMiddleParameter, "&");
-
- configure.RequestUri = new Uri(newUri, UriKind.Relative);
- });
-
- return requestBuilder;
- }
-
- private static string ReplaceRegex(this string value, Regex regex, string replacement)
- {
- return regex.Replace(value, replacement);
- }
- }
-}
diff --git a/src/Acheve.TestHost/RequestContent/IncludeContentAsFormUrlEncoded.cs b/src/Acheve.TestHost/RequestContent/IncludeContentAsFormUrlEncoded.cs
new file mode 100644
index 0000000..e019c5c
--- /dev/null
+++ b/src/Acheve.TestHost/RequestContent/IncludeContentAsFormUrlEncoded.cs
@@ -0,0 +1,85 @@
+using Microsoft.AspNetCore.Http;
+using System;
+using System.Collections;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Net.Http;
+using System.Threading;
+
+namespace Microsoft.AspNetCore.TestHost;
+
+///
+/// An implementation of that includes
+/// the [FromForm] parameter as
+///
+public class IncludeContentAsFormUrlEncoded : RequestContentOptions
+{
+ ///
+ public override bool IncludeFromBodyAsContent => false;
+
+ ///
+ public override bool IncludeFromFormAsContent => true;
+
+ ///
+ public override Func ContentBuilder =>
+ content => GetMultipartFormDataContent(content);
+
+ private MultipartFormDataContent GetMultipartFormDataContent(object data)
+ {
+ if (data is null)
+ {
+ return new MultipartFormDataContent();
+ }
+
+ var multipartContent = new MultipartFormDataContent();
+ AddToMultipartFormDataContent(multipartContent, data);
+
+ return multipartContent;
+ }
+
+ private void AddToMultipartFormDataContent(MultipartFormDataContent multipartContent, object data, string propertyName = null)
+ {
+ switch (data)
+ {
+ case CancellationToken:
+ break;
+ case IFormFile file:
+ using (var ms = new MemoryStream())
+ {
+ file.CopyTo(ms);
+ var fileContent = new ByteArrayContent(ms.ToArray());
+
+ multipartContent.Add(fileContent, file.Name, file.FileName);
+ }
+ break;
+ case object when data.GetType().IsPrimitiveType():
+ multipartContent.Add(new StringContent(PrimitiveValueToString(data)), propertyName);
+ break;
+ case object when data.GetType().IsEnumerable():
+ foreach (var item in (IList)data)
+ {
+ AddToMultipartFormDataContent(multipartContent, item, propertyName);
+ }
+ break;
+ default:
+ data.GetType().GetProperties().ToList().ForEach(p =>
+ {
+ var pName = string.IsNullOrEmpty(propertyName) ? p.Name : $"{propertyName}.{p.Name}";
+ var value = p.GetValue(data);
+ if (value is not null)
+ {
+ AddToMultipartFormDataContent(multipartContent, value, pName);
+ }
+ });
+ break;
+ }
+ }
+
+ private static string PrimitiveValueToString(T value)
+ => value switch
+ {
+ (DateTime or DateTimeOffset) and IFormattable dateTimeValue => dateTimeValue.ToString("o", CultureInfo.InvariantCulture),
+ _ => value.ToString()
+ };
+}
diff --git a/src/Acheve.TestHost/IncludeContentAsJson.cs b/src/Acheve.TestHost/RequestContent/IncludeContentAsJson.cs
similarity index 88%
rename from src/Acheve.TestHost/IncludeContentAsJson.cs
rename to src/Acheve.TestHost/RequestContent/IncludeContentAsJson.cs
index 7a767b9..338ebcc 100644
--- a/src/Acheve.TestHost/IncludeContentAsJson.cs
+++ b/src/Acheve.TestHost/RequestContent/IncludeContentAsJson.cs
@@ -1,7 +1,7 @@
-using Newtonsoft.Json;
-using System;
+using System;
using System.Net.Http;
using System.Text;
+using System.Text.Json;
namespace Microsoft.AspNetCore.TestHost
{
@@ -13,14 +13,14 @@ public class IncludeContentAsJson : RequestContentOptions
{
///
public override bool IncludeFromBodyAsContent => true;
-
+
///
public override bool IncludeFromFormAsContent => false;
///
public override Func ContentBuilder =>
content => new StringContent(
- JsonConvert.SerializeObject(content),
+ JsonSerializer.Serialize(content),
Encoding.UTF8,
"application/json");
}
diff --git a/src/Acheve.TestHost/NotIncludeContent.cs b/src/Acheve.TestHost/RequestContent/NotIncludeContent.cs
similarity index 100%
rename from src/Acheve.TestHost/NotIncludeContent.cs
rename to src/Acheve.TestHost/RequestContent/NotIncludeContent.cs
diff --git a/src/Acheve.TestHost/RequestContentOptions.cs b/src/Acheve.TestHost/RequestContent/RequestContentOptions.cs
similarity index 100%
rename from src/Acheve.TestHost/RequestContentOptions.cs
rename to src/Acheve.TestHost/RequestContent/RequestContentOptions.cs
diff --git a/src/Acheve.TestHost/Routing/TestServerAction.cs b/src/Acheve.TestHost/Routing/TestServerAction.cs
index c51d31a..3cc6243 100644
--- a/src/Acheve.TestHost/Routing/TestServerAction.cs
+++ b/src/Acheve.TestHost/Routing/TestServerAction.cs
@@ -1,4 +1,5 @@
-using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -35,12 +36,17 @@ public void AddArgument(int order, Expression expression, bool activeBodyApiCont
isFromBody = true;
}
- var isCancellationToken = argument.ParameterType == typeof(System.Threading.CancellationToken);
- if (isCancellationToken)
+ if (argument.ParameterType == typeof(System.Threading.CancellationToken))
{
isFromBody = isFromForm = isFromHeader = false;
}
+ if (argument.ParameterType == typeof(IFormFile))
+ {
+ isFromForm = true;
+ isFromBody = isFromHeader = false;
+ }
+
if (!ArgumentValues.ContainsKey(order))
{
if (IsNullable(argument.ParameterType))
diff --git a/src/Acheve.TestHost/Routing/Tokenizers/ComplexParameterActionTokenizer.cs b/src/Acheve.TestHost/Routing/Tokenizers/ComplexParameterActionTokenizer.cs
index 2612011..b2fa0b5 100644
--- a/src/Acheve.TestHost/Routing/Tokenizers/ComplexParameterActionTokenizer.cs
+++ b/src/Acheve.TestHost/Routing/Tokenizers/ComplexParameterActionTokenizer.cs
@@ -1,58 +1,68 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using System;
+using System.Collections;
using System.Linq;
using System.Reflection;
-namespace Acheve.TestHost.Routing.Tokenizers
+namespace Acheve.TestHost.Routing.Tokenizers;
+
+class ComplexParameterActionTokenizer
+ : ITokenizer
{
- class ComplexParameterActionTokenizer
- : ITokenizer
+ public void AddTokens(TestServerAction action, TestServerTokenCollection tokens) where TController : class
{
- public void AddTokens(TestServerAction action, TestServerTokenCollection tokens) where TController : class
+ var parameters = action.MethodInfo.GetParameters();
+
+ for (int i = 0; i < parameters.Length; i++)
{
- var parameters = action.MethodInfo.GetParameters();
+ var type = parameters[i].ParameterType;
+ var argument = action.ArgumentValues.Any(x => x.Key == i) ? action.ArgumentValues[i] : null;
+ var instance = argument?.Instance;
- for (int i = 0; i < parameters.Length; i++)
+ if (instance is null || type.IsPrimitiveType() || IgnoreBind(parameters[i]) || !IsQueryOrRouteParameter(argument))
{
- var type = parameters[i].ParameterType;
- var instance = action.ArgumentValues.Any(x => x.Key == i) ? action.ArgumentValues[i].Instance : null;
+ continue;
+ }
- if (instance != null && !type.IsPrimitiveType())
+ foreach (var property in type.GetProperties())
+ {
+ var value = property.GetValue(instance);
+ if (value == null)
{
- if (!IgnoreBind(parameters[i]))
- {
- foreach (var property in type.GetProperties())
- {
- var tokenName = property.Name.ToLowerInvariant();
- var value = property.GetValue(instance);
-
- if (value != null)
- {
- tokens.AddToken(tokenName, value.ToString(), isConventional: false);
- }
- }
- }
+ continue;
}
+
+ var tokenName = property.Name.ToLowerInvariant();
+ string tokenValue =
+ property.PropertyType.IsEnumerable() && property.PropertyType.GetEnumerableElementType().IsPrimitiveType() ?
+ EnumerableParameterActionTokenizer.GetTokenValue((IList)value, tokenName) :
+ PrimitiveParameterActionTokenizer.PrimitiveValueToString(value);
+
+ tokens.AddToken(tokenName, tokenValue, isConventional: false);
}
}
+ }
- bool IgnoreBind(ParameterInfo parameter)
- {
- var attributes = parameter.GetCustomAttributes(false);
+ private static bool IgnoreBind(ParameterInfo parameter)
+ {
+ var attributes = parameter.GetCustomAttributes(false);
- foreach (var attribute in attributes)
+ foreach (var attribute in attributes)
+ {
+ switch (attribute)
{
- switch (attribute)
- {
- case FromBodyAttribute body: return true;
- case FromFormAttribute form: return true;
- case BindNeverAttribute bind: return true;
- default: continue;
- }
+ case FromBodyAttribute:
+ case FromFormAttribute:
+ case BindNeverAttribute:
+ return true;
+ default: continue;
}
-
- return false;
}
+
+ return false;
}
+
+ private static bool IsQueryOrRouteParameter(TestServerArgument argument)
+ => !(argument.IsFromHeader || argument.IsFromForm || argument.IsFromBody);
}
diff --git a/src/Acheve.TestHost/Routing/Tokenizers/EnumerableParameterActionTokenizer.cs b/src/Acheve.TestHost/Routing/Tokenizers/EnumerableParameterActionTokenizer.cs
new file mode 100644
index 0000000..f440790
--- /dev/null
+++ b/src/Acheve.TestHost/Routing/Tokenizers/EnumerableParameterActionTokenizer.cs
@@ -0,0 +1,46 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace Acheve.TestHost.Routing.Tokenizers;
+
+internal class EnumerableParameterActionTokenizer
+ : ITokenizer
+{
+ public void AddTokens(TestServerAction action, TestServerTokenCollection tokens)
+ where TController : class
+ {
+ var parameters = action.MethodInfo.GetParameters();
+
+ for (var i = 0; i < parameters.Length; i++)
+ {
+ var parameterType = parameters[i].ParameterType;
+ if (!parameterType.IsEnumerable() || !parameterType.GetEnumerableElementType().IsPrimitiveType())
+ {
+ continue;
+ }
+
+ var arrayValues = (IList)action.ArgumentValues[i].Instance;
+ if (arrayValues == null || arrayValues.Count == 0)
+ {
+ continue;
+ }
+
+ var tokenName = parameters[i].Name.ToLowerInvariant();
+ var tokenValue = GetTokenValue(arrayValues, tokenName);
+ tokens.AddToken(tokenName, tokenValue, isConventional: false);
+ }
+ }
+
+ public static string GetTokenValue(IList array, string tokenName)
+ {
+ var list = new List();
+
+ foreach (var element in array)
+ {
+ list.Add(PrimitiveParameterActionTokenizer.PrimitiveValueToString(element));
+ }
+
+ return string.Join($"&{tokenName}=", list);
+ }
+}
\ No newline at end of file
diff --git a/src/Acheve.TestHost/Routing/Tokenizers/PrimitiveParameterActionTokenizer.cs b/src/Acheve.TestHost/Routing/Tokenizers/PrimitiveParameterActionTokenizer.cs
index 4736442..bf3f671 100644
--- a/src/Acheve.TestHost/Routing/Tokenizers/PrimitiveParameterActionTokenizer.cs
+++ b/src/Acheve.TestHost/Routing/Tokenizers/PrimitiveParameterActionTokenizer.cs
@@ -1,74 +1,55 @@
using Microsoft.AspNetCore.Mvc;
using System;
-using System.Collections;
-using System.Collections.Generic;
+using System.Globalization;
using System.Linq;
using System.Reflection;
+using System.Text.Json;
-namespace Acheve.TestHost.Routing.Tokenizers
+namespace Acheve.TestHost.Routing.Tokenizers;
+
+internal class PrimitiveParameterActionTokenizer
+ : ITokenizer
{
- internal class PrimitiveParameterActionTokenizer
- : ITokenizer
+ public void AddTokens(TestServerAction action, TestServerTokenCollection tokens)
+ where TController : class
{
- public void AddTokens(TestServerAction action, TestServerTokenCollection tokens)
- where TController : class
- {
- var parameters = action.MethodInfo.GetParameters();
+ ParameterInfo[] parameters = action.MethodInfo.GetParameters();
- for (var i = 0; i < parameters.Length; i++)
+ for (int i = 0; i < parameters.Length; i++)
+ {
+ var parameter = parameters[i];
+ if (IgnoreHeader(parameter))
{
- if (!IgnoreHeader(parameters[i]))
- {
- var tokenName = parameters[i].Name.ToLowerInvariant();
- var parameterType = parameters[i].ParameterType;
-
- if (parameterType.IsPrimitiveType())
- {
- var tokenValue = action.ArgumentValues.Any(x => x.Key == i) ? action.ArgumentValues[i].Instance : null;
-
- if (tokenValue != null)
- {
- tokens.AddToken(tokenName, tokenValue.ToString(), isConventional: false);
- }
- }
- else if (parameterType.IsEnumerable()
- && parameterType.GetEnumerableElementType().IsPrimitiveType())
- {
- var arrayValues = (Array)action.ArgumentValues[i].Instance;
-
- if (arrayValues != null
- && arrayValues.Length != 0)
- {
- var tokenValue = GetTokenValue(arrayValues, tokenName);
- tokens.AddToken(tokenName, tokenValue, isConventional: false);
- }
- }
- }
+ continue;
}
- }
- private bool IgnoreHeader(ParameterInfo parameter)
- {
- var attributes = parameter.GetCustomAttributes(false);
-
- if (attributes.Any(a => a.GetType() == typeof(FromHeaderAttribute)))
+ Type parameterType = parameter.ParameterType;
+ if (!parameterType.IsPrimitiveType())
{
- return true;
+ continue;
}
- return false;
- }
-
- private string GetTokenValue(Array array, string tokenName)
- {
- var list = new List();
-
- foreach (var element in array)
+ object tokenValue = action.ArgumentValues.Any(x => x.Key == i) ? action.ArgumentValues[i].Instance : null;
+ if (tokenValue == null)
{
- list.Add(element.ToString());
+ continue;
}
- return string.Join($"&{tokenName}=", list);
+ string tokenName = parameter.Name.ToLowerInvariant();
+ tokens.AddToken(tokenName, PrimitiveValueToString(tokenValue), isConventional: false);
}
}
+
+ public static string PrimitiveValueToString(T value)
+ => value switch
+ {
+ (DateTime or DateTimeOffset) and IFormattable dateTimeValue => dateTimeValue.ToString("o", CultureInfo.InvariantCulture),
+ float or double or long or decimal => JsonSerializer.Serialize(value),
+ _ => value.ToString()
+ };
+
+ private static bool IgnoreHeader(ParameterInfo parameter)
+ => parameter
+ .GetCustomAttributes(false)
+ .Any(a => a.GetType() == typeof(FromHeaderAttribute));
}
\ No newline at end of file
diff --git a/src/Acheve.TestHost/Routing/Tokenizers/TestServerTokenCollection.cs b/src/Acheve.TestHost/Routing/Tokenizers/TestServerTokenCollection.cs
index f6dced7..91a6e5b 100644
--- a/src/Acheve.TestHost/Routing/Tokenizers/TestServerTokenCollection.cs
+++ b/src/Acheve.TestHost/Routing/Tokenizers/TestServerTokenCollection.cs
@@ -1,71 +1,56 @@
using System.Collections.Generic;
using System.Linq;
-namespace Acheve.TestHost.Routing.Tokenizers
+namespace Acheve.TestHost.Routing.Tokenizers;
+
+public class TestServerTokenCollection
{
- public class TestServerTokenCollection
+ private readonly Dictionary _activeTokens = new();
+
+ public bool ContainsToken(string tokenName)
{
- Dictionary _activeTokens;
+ return _activeTokens.ContainsKey(tokenName);
+ }
- public TestServerTokenCollection()
+ public void AddToken(string tokenName, string tokenValue, bool isConventional = false)
+ {
+ if (!ContainsToken(tokenName))
{
- _activeTokens = new Dictionary();
+ _activeTokens.Add(tokenName,
+ new TestServerToken(tokenName, tokenValue, isConventional));
}
+ }
- public bool ContainsToken(string tokenName)
- {
- return _activeTokens.ContainsKey(tokenName);
- }
+ public TestServerToken Find(string tokenName)
+ => ContainsToken(tokenName) ? _activeTokens[tokenName] : default;
- public void AddToken(string tokenName, string tokenValue, bool isConventional = false)
- {
- if (!ContainsToken(tokenName))
- {
- _activeTokens.Add(tokenName,
- new TestServerToken(tokenName, tokenValue, isConventional));
- }
- }
+ public IEnumerable GetConventionalTokens()
+ {
+ return _activeTokens.Values
+ .Where(token => token.IsConventional);
+ }
- public TestServerToken Find(string tokenName)
- {
- if (ContainsToken(tokenName))
- {
- return _activeTokens[tokenName];
- }
- else
- {
- return default(TestServerToken);
- }
- }
+ public IEnumerable GetNonConventionalTokens()
+ {
+ return _activeTokens.Values
+ .Where(token => !token.IsConventional);
+ }
- public IEnumerable GetConventionalTokens()
- {
- return _activeTokens.Values
- .Where(token => token.IsConventional);
- }
+ public IEnumerable GetUnusedTokens()
+ {
+ return _activeTokens.Values
+ .Where(token => !token.IsConventional && !token.Used);
+ }
- public IEnumerable GetNonConventionalTokens()
- {
- return _activeTokens.Values
- .Where(token => !token.IsConventional);
- }
+ public static TestServerTokenCollection FromDictionary(Dictionary tokenKV)
+ {
+ var tokens = new TestServerTokenCollection();
- public IEnumerable GetUnusedTokens()
+ foreach (var item in tokenKV)
{
- return _activeTokens.Values
- .Where(token => !token.IsConventional && !token.Used);
+ tokens.AddToken(item.Key, item.Value, isConventional: false);
}
- public static TestServerTokenCollection FromDictionary(Dictionary tokenKV)
- {
- var tokens = new TestServerTokenCollection();
-
- foreach (var item in tokenKV)
- {
- tokens.AddToken(item.Key, item.Value, isConventional: false);
- }
-
- return tokens;
- }
+ return tokens;
}
}
diff --git a/src/Acheve.TestHost/Routing/Tokenizers/TypeExtensions.cs b/src/Acheve.TestHost/Routing/Tokenizers/TypeExtensions.cs
deleted file mode 100644
index bb95861..0000000
--- a/src/Acheve.TestHost/Routing/Tokenizers/TypeExtensions.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-using System.Collections;
-using System.Linq;
-
-namespace System
-{
- internal static class TypeExtensions
- {
- internal static bool IsPrimitiveType(this Type typeToInspect)
- {
- var type = Nullable.GetUnderlyingType(typeToInspect) ?? typeToInspect;
-
- return type.IsPrimitive
- || type == typeof(string)
- || type == typeof(decimal)
- || type == typeof(Guid);
- }
-
- internal static bool IsEnumerable(this Type typeToInspect)
- {
- return typeof(IEnumerable).IsAssignableFrom(typeToInspect);
- }
-
- internal static Type GetEnumerableElementType(this Type typeToInspect)
- {
- return typeToInspect.GetElementType() ?? typeToInspect.GetGenericArguments().FirstOrDefault();
- }
- }
-}
\ No newline at end of file
diff --git a/src/Acheve.TestHost/Routing/UriDiscover.cs b/src/Acheve.TestHost/Routing/UriDiscover.cs
index e705716..4a96346 100644
--- a/src/Acheve.TestHost/Routing/UriDiscover.cs
+++ b/src/Acheve.TestHost/Routing/UriDiscover.cs
@@ -1,98 +1,274 @@
using Acheve.TestHost.Routing.AttributeTemplates;
using Acheve.TestHost.Routing.Tokenizers;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.TestHost;
+using System;
using System.Collections.Generic;
using System.Linq;
+using System.Linq.Expressions;
+using System.Reflection;
-namespace Acheve.TestHost.Routing
+namespace Acheve.TestHost.Routing;
+
+internal static class UriDiscover
{
- static class UriDiscover
+ private static readonly IEnumerable _tokenizers = new List()
+ {
+ new PrimitiveParameterActionTokenizer(),
+ new EnumerableParameterActionTokenizer(),
+ new ComplexParameterActionTokenizer(),
+ new DefaultConventionalTokenizer()
+ };
+
+ public static RequestBuilder CreateHttpApiRequest(TestServer server,
+ LambdaExpression actionSelector,
+ object tokenValues = null,
+ RequestContentOptions contentOptions = null)
+ where TController : class
{
- static IEnumerable _tokenizers;
+ if (!IsController())
+ {
+ throw new InvalidOperationException($"The type {typeof(TController).FullName} is not a valid MVC controller.");
+ }
+
+ if (actionSelector == null)
+ {
+ throw new ArgumentNullException(nameof(actionSelector));
+ }
+
+ var action = GetTestServerAction(actionSelector);
+
+ if (!IsValidActionMethod(action.MethodInfo))
+ {
+ throw new InvalidOperationException($"The action selector is not a valid action for MVC Controller.");
+ }
+
+ //the uri discover use only attribute route conventions.
- static UriDiscover()
+ var validUri = Discover(action, tokenValues);
+
+ var requestBuilder = server.CreateRequest(validUri);
+
+ // Include content as Json by default
+ contentOptions ??= action.ArgumentValues.Values.Any(a => a.IsFromForm) ? new IncludeContentAsFormUrlEncoded() : new IncludeContentAsJson();
+
+ if (contentOptions.IncludeFromBodyAsContent)
{
- _tokenizers = new List()
- {
- new PrimitiveParameterActionTokenizer(),
- new ComplexParameterActionTokenizer(),
- new DefaultConventionalTokenizer()
- };
+ AddFromBodyArgumentsToRequestBody(requestBuilder, action, contentOptions);
}
- public static string Discover(TestServerAction action,object tokenValues)
- where TController:class
+ if (contentOptions.IncludeFromFormAsContent)
{
- //at this moment only the first route is considered..
+ AddFromFormArgumentsToRequestForm(requestBuilder, action, contentOptions);
+ }
- var testServerTokens = AddTokens(action, tokenValues);
+ AddFromHeaderArgumentsToRequestForm(requestBuilder, action);
- var controllerTemplate = new AttributeControllerRouteTemplates()
- .GetTemplates(action, testServerTokens)
- .FirstOrDefault();
+ return requestBuilder;
+ }
+
+ private static string Discover(TestServerAction action, object tokenValues)
+ where TController : class
+ {
+ //at this moment only the first route is considered..
- var verbsTemplate = new AttributeVerbsTemplate()
- .GetTemplates(action, testServerTokens)
- .FirstOrDefault();
+ var testServerTokens = AddTokens(action, tokenValues);
- var routeTemplate = new AttributeRouteTemplates()
- .GetTemplates(action, testServerTokens)
- .FirstOrDefault();
+ var controllerTemplate = new AttributeControllerRouteTemplates()
+ .GetTemplates(action, testServerTokens)
+ .FirstOrDefault();
- var queryStringTemplate = new QueryStringTemplate()
- .GetTemplates(action, testServerTokens)
- .FirstOrDefault();
+ var verbsTemplate = new AttributeVerbsTemplate()
+ .GetTemplates(action, testServerTokens)
+ .FirstOrDefault();
- var template = (verbsTemplate ?? routeTemplate);
+ var routeTemplate = new AttributeRouteTemplates()
+ .GetTemplates(action, testServerTokens)
+ .FirstOrDefault();
- if (template != null)
- {
- if (IsTildeOverride(template, out string overrideTemplate))
- {
- return $"{overrideTemplate}{queryStringTemplate}";
- }
- else
- {
- return $"{controllerTemplate}/{template}{queryStringTemplate}";
- }
- }
+ var queryStringTemplate = new QueryStringTemplate()
+ .GetTemplates(action, testServerTokens)
+ .FirstOrDefault();
+ var template = (verbsTemplate ?? routeTemplate);
+
+ if (template is null)
+ {
return $"{controllerTemplate}{queryStringTemplate}";
}
- static TestServerTokenCollection AddTokens(TestServerAction action, object tokenValues)
- where TController : class
+ return IsTildeOverride(template, out string overrideTemplate) ?
+ $"{overrideTemplate}{queryStringTemplate}" :
+ $"{controllerTemplate}/{template}{queryStringTemplate}";
+ }
+
+ private static TestServerTokenCollection AddTokens(TestServerAction action, object tokenValues)
+ where TController : class
+ {
+ var dictionaryTokenValues = new Dictionary();
+
+ if (tokenValues != null)
{
- var dictionaryTokenValues = new Dictionary();
+ dictionaryTokenValues = tokenValues.GetType()
+ .GetProperties()
+ .ToDictionary(p => p.Name.ToLowerInvariant(), p => p.GetValue(tokenValues).ToString());
+ }
+
+ var testServerTokens = TestServerTokenCollection.FromDictionary(dictionaryTokenValues);
- if (tokenValues != null)
- {
- dictionaryTokenValues = tokenValues.GetType()
- .GetProperties()
- .ToDictionary(p => p.Name.ToLowerInvariant(), p => p.GetValue(tokenValues).ToString());
- }
+ foreach (var tokeniker in _tokenizers)
+ {
+ tokeniker.AddTokens(action, testServerTokens);
+ }
- var testServerTokens = TestServerTokenCollection.FromDictionary(dictionaryTokenValues);
+ return testServerTokens;
+ }
+
+ private static bool IsTildeOverride(string template, out string overrideTemplate)
+ {
+ const string TILDE = "~";
- foreach (var tokeniker in _tokenizers)
- {
- tokeniker.AddTokens(action, testServerTokens);
- }
+ overrideTemplate = null;
+ var isTildeOverride = template.StartsWith(TILDE);
- return testServerTokens;
+ if (isTildeOverride)
+ {
+ overrideTemplate = template[2..]; // remove ~/
}
- static bool IsTildeOverride(string template, out string overrideTemplate)
+
+ return isTildeOverride;
+ }
+
+ private static bool IsController()
+ {
+ const string ControllerTypeNameSuffix = "Controller";
+
+ var typeInfo = typeof(TController);
+
+ if (!typeInfo.IsClass)
+ {
+ return false;
+ }
+
+ if (typeInfo.IsAbstract)
+ {
+ return false;
+ }
+
+ if (!typeInfo.IsPublic)
{
- const string TILDE = "~";
+ return false;
+ }
- overrideTemplate = null;
- var isTildeOverride = template.StartsWith(TILDE);
+ if (typeInfo.ContainsGenericParameters)
+ {
+ return false;
+ }
- if (isTildeOverride)
- {
- overrideTemplate = template.Substring(2); // remove ~/
- }
+ if (typeInfo.IsDefined(typeof(NonControllerAttribute)))
+ {
+ return false;
+ }
- return isTildeOverride;
+ if (!typeInfo.Name.EndsWith(ControllerTypeNameSuffix, StringComparison.OrdinalIgnoreCase) &&
+
+ !typeInfo.IsDefined(typeof(ControllerAttribute)))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ private static bool IsValidActionMethod(MethodInfo methodInfo)
+ {
+ if (!methodInfo.IsPublic)
+ {
+ return false;
+ }
+
+ if (methodInfo.IsStatic)
+ {
+ return false;
+ }
+
+ if (methodInfo.IsAbstract && !methodInfo.IsVirtual)
+ {
+ return false;
+ }
+
+ if (methodInfo.IsDefined(typeof(NonActionAttribute)))
+ {
+ return false;
+ }
+
+
+ return true;
+ }
+
+ private static TestServerAction GetTestServerAction(LambdaExpression actionSelector)
+ {
+ if (actionSelector.NodeType != ExpressionType.Lambda)
+ {
+ throw new InvalidOperationException($"The action selector is not a valid lambda expression");
+ }
+
+ var methodCall = (MethodCallExpression)actionSelector.Body;
+
+ var action = new TestServerAction(methodCall.Method);
+ bool haveAttributeApiController = typeof(TController).GetTypeInfo().GetCustomAttribute(typeof(ApiControllerAttribute)) != null;
+ bool isGetOrDelete = action.MethodInfo.GetCustomAttributes().FirstOrDefault(attr => attr.GetType() == typeof(HttpGetAttribute)
+ || attr.GetType() == typeof(HttpDeleteAttribute)) != null;
+
+ var index = 0;
+
+ foreach (var item in methodCall.Arguments)
+ {
+ action.AddArgument(index, item, haveAttributeApiController && !isGetOrDelete);
+
+ ++index;
+ }
+
+ return action;
+ }
+
+ private static void AddFromBodyArgumentsToRequestBody(
+ RequestBuilder requestBuilder,
+ TestServerAction action,
+ RequestContentOptions contentOptions)
+ {
+ var fromBodyArgument = action.ArgumentValues.Values.SingleOrDefault(x => x.IsFromBody);
+
+ if (fromBodyArgument != null)
+ {
+ requestBuilder.And(x => x.Content =
+ contentOptions.ContentBuilder(fromBodyArgument.Instance));
+ }
+ }
+
+ private static void AddFromFormArgumentsToRequestForm(
+ RequestBuilder requestBuilder,
+ TestServerAction action,
+ RequestContentOptions contentOptions)
+ {
+ var fromFormArgument = action.ArgumentValues.Values.SingleOrDefault(x => x.IsFromForm);
+
+ if (fromFormArgument != null)
+ {
+ requestBuilder.And(x => x.Content =
+ contentOptions.ContentBuilder(fromFormArgument.Instance));
+ }
+ }
+
+ private static void AddFromHeaderArgumentsToRequestForm(
+ RequestBuilder requestBuilder,
+ TestServerAction action)
+ {
+ var fromHeaderArguments = action.ArgumentValues.Values.Where(x => x.IsFromHeader);
+
+ foreach (var fromHeaderArgument in fromHeaderArguments)
+ {
+ requestBuilder.And(x => x.Headers.Add(fromHeaderArgument.HeaderName, fromHeaderArgument.Instance.ToString()));
}
}
}
diff --git a/src/Acheve.TestHost/Security/DefaultClaimsEncoder.cs b/src/Acheve.TestHost/Security/DefaultClaimsEncoder.cs
index d8618db..6c1548f 100644
--- a/src/Acheve.TestHost/Security/DefaultClaimsEncoder.cs
+++ b/src/Acheve.TestHost/Security/DefaultClaimsEncoder.cs
@@ -4,41 +4,40 @@
using System.Linq;
using System.Security.Claims;
-namespace Acheve.TestHost
+namespace Acheve.TestHost;
+
+internal static class DefautClaimsEncoder
{
- internal static class DefautClaimsEncoder
+ public static string Encode(IEnumerable claims)
{
- public static string Encode(IEnumerable claims)
- {
- var ticket = new AuthenticationTicket(
- principal: new ClaimsPrincipal(
- new ClaimsIdentity(claims)),
- authenticationScheme: "TestServer");
+ var ticket = new AuthenticationTicket(
+ principal: new ClaimsPrincipal(
+ new ClaimsIdentity(claims)),
+ authenticationScheme: "TestServer");
- var serializer = new TicketSerializer();
- var bytes = serializer.Serialize(ticket);
+ var serializer = new TicketSerializer();
+ var bytes = serializer.Serialize(ticket);
- return Convert.ToBase64String(bytes);
- }
+ return Convert.ToBase64String(bytes);
+ }
- public static IEnumerable Decode(string encodedValue)
+ public static IEnumerable Decode(string encodedValue)
+ {
+ if (string.IsNullOrEmpty(encodedValue))
{
- if (string.IsNullOrEmpty(encodedValue))
- {
- return Enumerable.Empty();
- }
+ return Enumerable.Empty();
+ }
- var serializer = new TicketSerializer();
- try
- {
- var ticket = serializer.Deserialize(Convert.FromBase64String(encodedValue));
+ var serializer = new TicketSerializer();
+ try
+ {
+ var ticket = serializer.Deserialize(Convert.FromBase64String(encodedValue));
- return ticket.Principal.Claims;
- }
- catch (Exception)
- {
- return Enumerable.Empty();
- }
+ return ticket.Principal.Claims;
+ }
+ catch
+ {
+ return Enumerable.Empty();
}
}
}
diff --git a/src/Acheve.TestHost/TestServerExtensions.cs b/src/Acheve.TestHost/TestServerExtensions.cs
deleted file mode 100644
index 8b8d1da..0000000
--- a/src/Acheve.TestHost/TestServerExtensions.cs
+++ /dev/null
@@ -1,204 +0,0 @@
-using Acheve.TestHost.Routing;
-using Microsoft.AspNetCore.Mvc;
-using System;
-using System.Linq;
-using System.Linq.Expressions;
-using System.Reflection;
-
-namespace Microsoft.AspNetCore.TestHost
-{
- public static class TestServerExtensions
- {
- ///
- /// Create a configured automatically
- /// with the generated uri from the .
- /// At this moment this method only resolver HTTP API using ASP.NET CORE Attribute Routing
- ///
- /// The controller to use
- /// The TestServer
- /// The action selector used to discover the uri
- /// The optional token values used to create the uri
- /// Determines if [FromBody] arguments are included as request content.
- /// By default they are included as application/json content
- ///
- public static RequestBuilder CreateHttpApiRequest(this TestServer server,
- Expression> actionSelector,
- object tokenValues = null,
- RequestContentOptions contentOptions = null)
- where TController : class
- {
- if (!IsController())
- {
- throw new InvalidOperationException($"The type {typeof(TController).FullName} is not a valid MVC controller.");
- }
-
- if (actionSelector == null)
- {
- throw new ArgumentNullException(nameof(actionSelector));
- }
-
- // Include content as Json by default
- contentOptions = contentOptions ?? new IncludeContentAsJson();
-
- var action = GetTestServerAction(actionSelector);
-
- if (!IsValidActionMethod(action.MethodInfo))
- {
- throw new InvalidOperationException($"The action selector is not a valid action for MVC Controller.");
- }
-
- //the uri discover use only attribute route conventions.
-
- var validUri = UriDiscover.Discover(action, tokenValues);
-
- var requestBuilder = server.CreateRequest(validUri);
-
- if (contentOptions.IncludeFromBodyAsContent)
- {
- AddFromBodyArgumentsToRequestBody(requestBuilder, action, contentOptions);
- }
-
- if (contentOptions.IncludeFromFormAsContent)
- {
- AddFromFormArgumentsToRequestForm(requestBuilder, action, contentOptions);
- }
-
- AddFromHeaderArgumentsToRequestForm(requestBuilder, action);
-
- return requestBuilder;
- }
-
- private static bool IsController()
- {
- const string ControllerTypeNameSuffix = "Controller";
-
- var typeInfo = typeof(TController);
-
- if (!typeInfo.IsClass)
- {
- return false;
- }
-
- if (typeInfo.IsAbstract)
- {
- return false;
- }
-
- if (!typeInfo.IsPublic)
- {
- return false;
- }
-
- if (typeInfo.ContainsGenericParameters)
- {
- return false;
- }
-
- if (typeInfo.IsDefined(typeof(NonControllerAttribute)))
- {
- return false;
- }
-
- if (!typeInfo.Name.EndsWith(ControllerTypeNameSuffix, StringComparison.OrdinalIgnoreCase) &&
-
- !typeInfo.IsDefined(typeof(ControllerAttribute)))
- {
- return false;
- }
-
- return true;
- }
-
- private static bool IsValidActionMethod(MethodInfo methodInfo)
- {
- if (!methodInfo.IsPublic)
- {
- return false;
- }
-
- if (methodInfo.IsStatic)
- {
- return false;
- }
-
- if (methodInfo.IsAbstract && !methodInfo.IsVirtual)
- {
- return false;
- }
-
- if (methodInfo.IsDefined(typeof(NonActionAttribute)))
- {
- return false;
- }
-
-
- return true;
- }
-
- private static TestServerAction GetTestServerAction(Expression> actionSelector)
- {
- if (actionSelector.NodeType != ExpressionType.Lambda)
- {
- throw new InvalidOperationException($"The action selector is not a valid lambda expression");
- }
-
- var methodCall = (MethodCallExpression)actionSelector.Body;
-
- var action = new TestServerAction(methodCall.Method);
- bool haveAttributeApiController = typeof(TController).GetTypeInfo().GetCustomAttribute(typeof(ApiControllerAttribute)) != null;
- bool isGetOrDelete = action.MethodInfo.GetCustomAttributes().FirstOrDefault(attr => attr.GetType() == typeof(HttpGetAttribute)
- || attr.GetType() == typeof(HttpDeleteAttribute)) != null;
-
- var index = 0;
-
- foreach (var item in methodCall.Arguments)
- {
- action.AddArgument(index, item, haveAttributeApiController && !isGetOrDelete);
-
- ++index;
- }
-
- return action;
- }
-
- private static void AddFromBodyArgumentsToRequestBody(
- RequestBuilder requestBuilder,
- TestServerAction action,
- RequestContentOptions contentOptions)
- {
- var fromBodyArgument = action.ArgumentValues.Values.SingleOrDefault(x => x.IsFromBody);
-
- if (fromBodyArgument != null)
- {
- requestBuilder.And(x => x.Content =
- contentOptions.ContentBuilder(fromBodyArgument.Instance));
- }
- }
-
- private static void AddFromFormArgumentsToRequestForm(
- RequestBuilder requestBuilder,
- TestServerAction action,
- RequestContentOptions contentOptions)
- {
- var fromFormArgument = action.ArgumentValues.Values.SingleOrDefault(x => x.IsFromForm);
-
- if (fromFormArgument != null)
- {
- requestBuilder.And(x => x.Content =
- contentOptions.ContentBuilder(fromFormArgument.Instance));
- }
- }
-
- private static void AddFromHeaderArgumentsToRequestForm(
- RequestBuilder requestBuilder,
- TestServerAction action)
- {
- var fromHeaderArguments = action.ArgumentValues.Values.Where(x => x.IsFromHeader);
-
- foreach (var fromHeaderArgument in fromHeaderArguments)
- {
- requestBuilder.And(x => x.Headers.Add(fromHeaderArgument.HeaderName, fromHeaderArgument.Instance.ToString()));
- }
- }
- }
-}
diff --git a/tests/UnitTests/Acheve.TestHost/Routing/Builders/BugsController.cs b/tests/UnitTests/Acheve.TestHost/Routing/Builders/BugsController.cs
index 3cdd7a6..22ba79d 100644
--- a/tests/UnitTests/Acheve.TestHost/Routing/Builders/BugsController.cs
+++ b/tests/UnitTests/Acheve.TestHost/Routing/Builders/BugsController.cs
@@ -1,81 +1,109 @@
using Microsoft.AspNetCore.Mvc;
using System;
-using System.Collections;
using System.Collections.Generic;
using UnitTests.Acheve.TestHost.Routing.Models;
-namespace UnitTests.Acheve.TestHost.Builders
+namespace UnitTests.Acheve.TestHost.Builders;
+
+[Route("api/[controller]")]
+[ApiController]
+public class BugsController
+ : ControllerBase
{
- [Route("api/[controller]")]
- [ApiController]
- public class BugsController
- : ControllerBase
+ [HttpGet("{param1}/{param2}")]
+ public IActionResult GuidSupport(string param1, Guid param2)
+ {
+ return Ok();
+ }
+
+ [HttpGet("{param_1:guid}/{param_2:int}")]
+ public IActionResult UnderDashSupport(Guid param_1, int param_2)
+ {
+ return Ok();
+ }
+
+ [HttpGet("nullableQueryParams")]
+ public ActionResult NullableQueryParams(bool? param1, Guid? param2)
+ {
+ return Ok(new NullableQueryParamsResponse { Param1 = param1, Param2 = param2 });
+ }
+
+ [HttpGet("arrayGuid")]
+ public ActionResult GuidArraySupport([FromQuery] Guid[] param1)
+ {
+ return Ok(param1);
+ }
+
+ [HttpGet("arrayInt")]
+ public ActionResult IntArraySupport([FromQuery] int[] param1)
+ {
+ return Ok(param1);
+ }
+
+ [HttpGet("arrayString")]
+ public ActionResult StringArraySupport([FromQuery] string[] param1)
+ {
+ return Ok(param1);
+ }
+
+ [HttpGet("arrayPerson")]
+ public ActionResult PersonArraySupport([FromQuery] Person[] param1)
{
- [HttpGet("{param1}/{param2}")]
- public IActionResult GuidSupport(string param1, Guid param2)
- {
- return Ok();
- }
-
- [HttpGet("{param_1:guid}/{param_2:int}")]
- public IActionResult UnderDashSupport(Guid param_1, int param_2)
- {
- return Ok();
- }
-
- [HttpGet("nullableQueryParams")]
- public ActionResult NullableQueryParams(bool? param1, Guid? param2)
- {
- return Ok(new NullableQueryParamsResponse { Param1 = param1, Param2 = param2 });
- }
-
- [HttpGet("arrayGuid")]
- public ActionResult GuidArraySupport([FromQuery] Guid[] param1)
- {
- return Ok(param1);
- }
-
- [HttpGet("arrayInt")]
- public ActionResult IntArraySupport([FromQuery] int[] param1)
- {
- return Ok(param1);
- }
-
- [HttpGet("arrayString")]
- public ActionResult StringArraySupport([FromQuery] string[] param1)
- {
- return Ok(param1);
- }
-
- [HttpGet("arrayPerson")]
- public ActionResult PersonArraySupport([FromQuery] Person[] param1)
- {
- return Ok(param1);
- }
-
- [HttpPost("{test_id:guid}")]
- public ActionResult AllowRouterAndBodyParams([FromRoute] Guid test_id, [FromBody] Person person)
- {
- return Ok(new RouterAndBodyParamsResponse { TestId = test_id, Person = person });
- }
-
- [HttpGet("{param1:int:min(1)}/params/{param2:int:min(1)}")]
- public ActionResult GetWithSeveralColon(int param1, int param2)
- {
- return Ok($"{param1}/{param2}");
- }
-
- [HttpGet(nameof(GetWithListParam))]
- public ActionResult> GetWithListParam([FromQuery] IEnumerable param)
- {
- return Ok(param);
- }
-
- [HttpGet]
- [Route("[action]")]
- public ActionResult> ActionNameInRoute()
- {
- return Ok();
- }
+ return Ok(param1);
}
+
+ [HttpPost("{test_id:guid}")]
+ public ActionResult AllowRouterAndBodyParams([FromRoute] Guid test_id, [FromBody] Person person)
+ {
+ return Ok(new RouterAndBodyParamsResponse { TestId = test_id, Person = person });
+ }
+
+ [HttpGet("{param1:int:min(1)}/params/{param2:int:min(1)}")]
+ public ActionResult GetWithSeveralColon(int param1, int param2)
+ {
+ return Ok($"{param1}/{param2}");
+ }
+
+ [HttpGet]
+ [Route("[action]")]
+ public IActionResult ActionNameInRoute()
+ {
+ return Ok();
+ }
+
+ [HttpGet(nameof(GetWithObject))]
+ public ActionResult GetWithObject([FromQuery] ParamWithSeveralTypes param)
+ => Ok(param);
+
+ [HttpPost(nameof(PostWithObject))]
+ public ActionResult PostWithObject([FromBody] ParamWithSeveralTypes param)
+ => Ok(param);
+
+ [HttpPost(nameof(PostWithObjectFromForm))]
+ public ActionResult PostWithObjectFromForm([FromForm] ParamWithSeveralTypes param)
+ => Ok(param);
+
+ [HttpGet(nameof(GetWithListParam))]
+ public ActionResult> GetWithListParam([FromQuery] IEnumerable param)
+ => Ok(param);
+
+ [HttpPost(nameof(PostWithListParam))]
+ public ActionResult> PostWithListParam([FromBody] IEnumerable param)
+ => Ok(param);
+
+ [HttpGet(nameof(GetWithDatetimeParam))]
+ public ActionResult GetWithDatetimeParam([FromQuery] DateTime param)
+ => Ok(param);
+
+ [HttpPost(nameof(PostWithDatetimeParam))]
+ public ActionResult PostWithDatetimeParam([FromBody] DateTime param)
+ => Ok(param);
+
+ [HttpGet(nameof(GetWithDatetimeListParam))]
+ public ActionResult> GetWithDatetimeListParam([FromQuery] IEnumerable param)
+ => Ok(param);
+
+ [HttpPost(nameof(PostWithDatetimeListParam))]
+ public ActionResult> PostWithDatetimeListParam([FromBody] IEnumerable param)
+ => Ok(param);
}
\ No newline at end of file
diff --git a/tests/UnitTests/Acheve.TestHost/Routing/Builders/ValuesV4Controller.cs b/tests/UnitTests/Acheve.TestHost/Routing/Builders/ValuesV4Controller.cs
index a85b59e..8f05545 100644
--- a/tests/UnitTests/Acheve.TestHost/Routing/Builders/ValuesV4Controller.cs
+++ b/tests/UnitTests/Acheve.TestHost/Routing/Builders/ValuesV4Controller.cs
@@ -1,83 +1,82 @@
using Microsoft.AspNetCore.Mvc;
-namespace UnitTests.Acheve.TestHost.Builders
+namespace UnitTests.Acheve.TestHost.Builders;
+
+[Route("api/values")]
+[ApiController]
+public class ValuesV4Controller
+ : ControllerBase
{
- [Route("api/values")]
- [ApiController]
- public class ValuesV4Controller
- : ControllerBase
+ [HttpGet("~/get1/{index}")]
+ public IActionResult Get1(int index)
{
- [HttpGet("~/get1/{index}")]
- public IActionResult Get1(int index)
- {
- return Ok();
- }
+ return Ok();
+ }
- [HttpPost("~/post1/{index}")]
- public IActionResult Post1(int index)
- {
- return Ok();
- }
+ [HttpPost("~/post1/{index}")]
+ public IActionResult Post1(int index)
+ {
+ return Ok();
+ }
- [HttpPost("~/put1/{index}")]
- public IActionResult Put1(int index)
- {
- return Ok();
- }
+ [HttpPut("~/put1/{index}")]
+ public IActionResult Put1(int index)
+ {
+ return Ok();
+ }
- [HttpPost("~/delete1/{index}")]
- public IActionResult Delete1(int index)
- {
- return Ok();
- }
+ [HttpDelete("~/delete1/{index}")]
+ public IActionResult Delete1(int index)
+ {
+ return Ok();
+ }
- [HttpGet("~/get2/{index}")]
- public IActionResult Get2(int index,Pagination pagination)
- {
- return Ok();
- }
+ [HttpGet("~/get2/{index}")]
+ public IActionResult Get2(int index, Pagination pagination)
+ {
+ return Ok();
+ }
- [HttpPost("~/post2/{index}")]
- public IActionResult Post2(int index, Pagination pagination)
- {
- return Ok();
- }
+ [HttpPost("~/post2/{index}")]
+ public IActionResult Post2(int index, Pagination pagination)
+ {
+ return Ok();
+ }
- [HttpPost("~/put2/{index}")]
- public IActionResult Put2(int index, Pagination pagination)
- {
- return Ok();
- }
+ [HttpPut("~/put2/{index}")]
+ public IActionResult Put2(int index, Pagination pagination)
+ {
+ return Ok();
+ }
- [HttpPost("~/delete2/{index}")]
- public IActionResult Delete2(int index, Pagination pagination)
- {
- return Ok();
- }
+ [HttpDelete("~/delete2/{index}")]
+ public IActionResult Delete2(int index, Pagination pagination)
+ {
+ return Ok();
+ }
- [Route("~/get3/{index}"),HttpGet]
- public IActionResult Get3(int index, Pagination pagination)
- {
- return Ok();
- }
+ [Route("~/get3/{index}"), HttpGet]
+ public IActionResult Get3(int index, Pagination pagination)
+ {
+ return Ok();
+ }
- [Route("~/post3/{index}"),HttpPost]
- public IActionResult Post3(int index, Pagination pagination)
- {
- return Ok();
- }
+ [Route("~/post3/{index}"), HttpPost]
+ public IActionResult Post3(int index, Pagination pagination)
+ {
+ return Ok();
+ }
- [Route("~/put3/{index}"),HttpPut]
- public IActionResult Put3(int index, Pagination pagination)
- {
- return Ok();
- }
+ [Route("~/put3/{index}"), HttpPut]
+ public IActionResult Put3(int index, Pagination pagination)
+ {
+ return Ok();
+ }
- [Route("~/delete3/{index}"),HttpPost]
- public IActionResult Delete3(int index, Pagination pagination)
- {
- return Ok();
- }
+ [Route("~/delete3/{index}"), HttpDelete]
+ public IActionResult Delete3(int index, Pagination pagination)
+ {
+ return Ok();
}
}
diff --git a/tests/UnitTests/Acheve.TestHost/Routing/Builders/ValuesV5Controller.cs b/tests/UnitTests/Acheve.TestHost/Routing/Builders/ValuesV5Controller.cs
index abdda17..5b747f9 100644
--- a/tests/UnitTests/Acheve.TestHost/Routing/Builders/ValuesV5Controller.cs
+++ b/tests/UnitTests/Acheve.TestHost/Routing/Builders/ValuesV5Controller.cs
@@ -1,71 +1,114 @@
-using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using System.IO;
using System.Threading;
+using System.Threading.Tasks;
+using UnitTests.Acheve.TestHost.Routing.Models;
-namespace UnitTests.Acheve.TestHost.Builders
+namespace UnitTests.Acheve.TestHost.Builders;
+
+[Route("api/values")]
+[ApiController]
+public class ValuesV5Controller : ControllerBase
{
- [Route("api/values")]
- [ApiController]
- public class ValuesV5Controller : ControllerBase
+ [HttpPost]
+ public IActionResult Post1(Pagination pagination)
{
- [HttpPost]
- public IActionResult Post1(Pagination pagination)
+ return Ok();
+ }
+
+ [HttpPost("{id:int}")]
+ public IActionResult Post2(int id, Pagination pagination1)
+ {
+ if (pagination1 == null)
{
- return Ok();
+ return BadRequest();
}
- [HttpPost("{id:int}")]
- public IActionResult Post2(int id, Pagination pagination1)
- {
- if (pagination1 == null)
- {
- return BadRequest();
- }
+ return Ok();
+ }
- return Ok();
+ [HttpPost("{id}")]
+ public IActionResult Post3(string id, Pagination pagination1)
+ {
+ if (pagination1 == null || string.IsNullOrWhiteSpace(id))
+ {
+ return BadRequest();
}
- [HttpPost("{id}")]
- public IActionResult Post3(string id, Pagination pagination1)
- {
- if (pagination1 == null || string.IsNullOrWhiteSpace(id))
- {
- return BadRequest();
- }
+ return Ok();
+ }
- return Ok();
+ [HttpPatch("{id:int}")]
+ public IActionResult Patch1(int id, Pagination pagination1)
+ {
+ if (pagination1 == null)
+ {
+ return BadRequest();
}
- [HttpPatch("{id:int}")]
- public IActionResult Patch1(int id, Pagination pagination1)
- {
- if (pagination1 == null)
- {
- return BadRequest();
- }
+ return Ok();
+ }
- return Ok();
- }
-
- [HttpGet(nameof(GetWithCancellationToken))]
- public ActionResult GetWithCancellationToken([FromQuery] string value, CancellationToken cancellationToken)
+ [HttpGet(nameof(GetWithCancellationToken))]
+ public ActionResult GetWithCancellationToken([FromQuery] string value, CancellationToken cancellationToken)
+ {
+ if (cancellationToken.IsCancellationRequested)
{
- if (cancellationToken.IsCancellationRequested)
- {
- return BadRequest();
- }
-
- return Ok(value);
+ return BadRequest();
}
- [HttpPost(nameof(PostWithCancellationToken))]
- public ActionResult PostWithCancellationToken([FromBody] string value, CancellationToken cancellationToken)
+ return Ok(value);
+ }
+
+ [HttpPost(nameof(PostWithCancellationToken))]
+ public ActionResult PostWithCancellationToken([FromBody] string value, CancellationToken cancellationToken)
+ {
+ if (cancellationToken.IsCancellationRequested)
{
- if (cancellationToken.IsCancellationRequested)
- {
- return BadRequest();
- }
-
- return Ok(value);
+ return BadRequest();
}
+
+ return Ok(value);
+ }
+
+ [HttpGet(nameof(GetBadRequest))]
+ public IActionResult GetBadRequest()
+ {
+ return BadRequest();
+ }
+
+ [HttpGet(nameof(GetOk))]
+ public IActionResult GetOk()
+ {
+ return Ok();
+ }
+
+ [HttpPost(nameof(PostFile))]
+ public async Task> PostFile(IFormFile file)
+ {
+ if (file is null)
+ return BadRequest();
+
+ var content = await ReadFormFile(file);
+
+ return Ok(content);
+ }
+
+ [HttpPost(nameof(PostObjectWithFile))]
+ public async Task> PostObjectWithFile([FromForm] ParamWithFile model)
+ {
+ if (model is null)
+ return BadRequest();
+
+ var content = await ReadFormFile(model.File);
+
+ return Ok($"{model.Id}+{content}");
+ }
+
+ private static async Task ReadFormFile(IFormFile file)
+ {
+ using var reader = new StreamReader(file.OpenReadStream());
+ return await reader.ReadToEndAsync();
}
}
diff --git a/tests/UnitTests/Acheve.TestHost/Routing/HttpResponseMessageExtensionsTests.cs b/tests/UnitTests/Acheve.TestHost/Routing/HttpResponseMessageExtensionsTests.cs
new file mode 100644
index 0000000..1de3d2d
--- /dev/null
+++ b/tests/UnitTests/Acheve.TestHost/Routing/HttpResponseMessageExtensionsTests.cs
@@ -0,0 +1,74 @@
+using FluentAssertions;
+using Microsoft.AspNetCore.TestHost;
+using System;
+using System.Net.Http;
+using System.Threading.Tasks;
+using UnitTests.Acheve.TestHost.Builders;
+using UnitTests.Acheve.TestHost.Routing.Models;
+using Xunit;
+
+namespace UnitTests.Acheve.TestHost.Routing;
+
+public class HttpResponseMessageExtensionsTests
+{
+ [Fact]
+ public async Task IsSuccessStatusCodeOrThrow_throw_exception()
+ {
+ var server = new TestServerBuilder()
+ .UseDefaultStartup()
+ .Build();
+
+ var request = server.CreateHttpApiRequest(controller => controller.GetBadRequest());
+ var responseMessage = await request.GetAsync();
+
+ var isSuccessFunc = () => responseMessage.IsSuccessStatusCodeOrThrow();
+ await isSuccessFunc.Should().ThrowAsync();
+ }
+
+ [Fact]
+ public async Task IsSuccessStatusCodeOrThrow_not_throw_exception()
+ {
+ var server = new TestServerBuilder()
+ .UseDefaultStartup()
+ .Build();
+
+ var request = server.CreateHttpApiRequest(controller => controller.GetOk());
+ var responseMessage = await request.GetAsync();
+
+ var isSuccessFunc = () => responseMessage.IsSuccessStatusCodeOrThrow();
+ await isSuccessFunc.Should().NotThrowAsync();
+ }
+
+ [Fact]
+ public async Task ReadContentAsAsync_return_complex_object()
+ {
+ var server = new TestServerBuilder()
+ .UseDefaultStartup()
+ .Build();
+
+ var model = ParamWithSeveralTypes.CreateRandom();
+ var request = server.CreateHttpApiRequest(controller => controller.GetWithObject(model));
+ var responseMessage = await request.GetAsync();
+
+ var response = await responseMessage.ReadContentAsAsync();
+
+ response.Should().Be(model);
+ }
+
+ [Fact]
+ public async Task ReadContentAsAsync_return_string()
+ {
+ var server = new TestServerBuilder()
+ .UseDefaultStartup()
+ .Build();
+
+ var param1 = 1;
+ var param2 = 1;
+ var request = server.CreateHttpApiRequest(controller => controller.GetWithSeveralColon(param1, param2));
+ var responseMessage = await request.GetAsync();
+
+ var response = await responseMessage.ReadContentAsAsync();
+
+ response.Should().Be($"{param1}/{param2}");
+ }
+}
diff --git a/tests/UnitTests/Acheve.TestHost/Routing/Models/ParamWithFile.cs b/tests/UnitTests/Acheve.TestHost/Routing/Models/ParamWithFile.cs
new file mode 100644
index 0000000..c052242
--- /dev/null
+++ b/tests/UnitTests/Acheve.TestHost/Routing/Models/ParamWithFile.cs
@@ -0,0 +1,20 @@
+using Microsoft.AspNetCore.Http;
+using System;
+
+namespace UnitTests.Acheve.TestHost.Routing.Models;
+
+public class ParamWithFile
+{
+ public int Id { get; set; }
+ public IFormFile File { get; set; }
+
+ public ParamWithFile() { }
+
+ public ParamWithFile(IFormFile file)
+ {
+ var random = new Random();
+
+ Id = random.Next();
+ File = file;
+ }
+}
diff --git a/tests/UnitTests/Acheve.TestHost/Routing/Models/ParamWithSeveralTypes.cs b/tests/UnitTests/Acheve.TestHost/Routing/Models/ParamWithSeveralTypes.cs
new file mode 100644
index 0000000..a8a1702
--- /dev/null
+++ b/tests/UnitTests/Acheve.TestHost/Routing/Models/ParamWithSeveralTypes.cs
@@ -0,0 +1,86 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace UnitTests.Acheve.TestHost.Routing.Models;
+
+public sealed class ParamWithSeveralTypes : IEquatable
+{
+ public string StringValue { get; set; }
+ public int IntValue { get; set; }
+ public double DoubleValue { get; set; }
+ public bool BooleanValue { get; set; }
+ public DateTime DateTimeValue { get; set; }
+
+ public IEnumerable StringValues { get; set; }
+ public IEnumerable IntValues { get; set; }
+ public IEnumerable DoubleValues { get; set; }
+ public IEnumerable BooleanValues { get; set; }
+ public IEnumerable DateTimeValues { get; set; }
+
+ public static ParamWithSeveralTypes CreateRandom()
+ {
+ var random = new Random();
+
+ var getRandomEnumerable = () => Enumerable.Repeat(0, random.Next(1, 10));
+ var getRandomString = () => Guid.NewGuid().ToString();
+ var getRandomInt = () => random.Next();
+ var getRandomDouble = () => random.NextDouble();
+ var getRandomBool = () => random.Next() % 2 == 0;
+ var getRandomDateTime = () => new DateTime(
+ random.Next(1900, 2900),
+ random.Next(1, 12),
+ random.Next(1, 28),
+ random.Next(23),
+ random.Next(59),
+ random.Next(59),
+ random.Next(999));
+
+ return new()
+ {
+ StringValue = getRandomString(),
+ IntValue = getRandomInt(),
+ DoubleValue = getRandomDouble(),
+ BooleanValue = getRandomBool(),
+ DateTimeValue = getRandomDateTime(),
+
+ StringValues = getRandomEnumerable().Select(_ => getRandomString()).ToList(),
+ IntValues = getRandomEnumerable().Select(_ => getRandomInt()).ToList(),
+ DoubleValues = getRandomEnumerable().Select(_ => getRandomDouble()).ToList(),
+ BooleanValues = getRandomEnumerable().Select(_ => getRandomBool()).ToList(),
+ DateTimeValues = getRandomEnumerable().Select(_ => getRandomDateTime()).ToList(),
+ };
+ }
+
+ public bool Equals(ParamWithSeveralTypes other)
+ => other != null
+ && StringValue == other.StringValue
+ && IntValue == other.IntValue
+ && (DoubleValue - other.DoubleValue) < 0.0001
+ && BooleanValue == other.BooleanValue
+ && DateTimeValue == other.DateTimeValue
+ && StringValues.SequenceEqual(other.StringValues)
+ && IntValues.SequenceEqual(other.IntValues)
+ && DoubleValues.SequenceEqual(other.DoubleValues)
+ && BooleanValues.SequenceEqual(other.BooleanValues)
+ && DateTimeValues.SequenceEqual(other.DateTimeValues);
+
+ public override bool Equals(object obj)
+ => Equals(obj as ParamWithSeveralTypes);
+
+ public override int GetHashCode()
+ {
+ var hash = new HashCode();
+ hash.Add(StringValue);
+ hash.Add(IntValue);
+ hash.Add(DoubleValue);
+ hash.Add(BooleanValue);
+ hash.Add(DateTimeValue);
+ hash.Add(StringValues);
+ hash.Add(IntValues);
+ hash.Add(DoubleValues);
+ hash.Add(BooleanValues);
+ hash.Add(DateTimeValues);
+ return hash.ToHashCode();
+ }
+}
diff --git a/tests/UnitTests/Acheve.TestHost/Routing/RequestBuilderExtensionsTests.cs b/tests/UnitTests/Acheve.TestHost/Routing/RequestBuilderExtensionsTests.cs
index bfdcb4e..76f857c 100644
--- a/tests/UnitTests/Acheve.TestHost/Routing/RequestBuilderExtensionsTests.cs
+++ b/tests/UnitTests/Acheve.TestHost/Routing/RequestBuilderExtensionsTests.cs
@@ -6,154 +6,169 @@
using UnitTests.Acheve.TestHost.Builders;
using Xunit;
-namespace UnitTests.Acheve.TestHost.Routing
+namespace UnitTests.Acheve.TestHost.Routing;
+
+public class RequestBuilderExtensionsTests
{
- public class RequestBuilderExtensionsTests
+ public const string BASE_PATH = "api/values/";
+
+ [Fact]
+ public async Task Create_request_and_add_parameter()
{
- public const string BASE_PATH = "api/values/";
+ var server = new TestServerBuilder()
+ .UseDefaultStartup()
+ .Build();
- [Fact]
- public async Task Create_request_and_add_parameter()
- {
- var server = new TestServerBuilder()
- .UseDefaultStartup()
- .Build();
+ var id = new Random().Next(1, 100);
- var id = new Random().Next(1, 100);
+ var request = server.CreateHttpApiRequest(controller => controller.GetParameterFromRequestQuery())
+ .AddQueryParameter(nameof(id), id);
- var request = server.CreateHttpApiRequest(controller => controller.GetParameterFromRequestQuery())
- .AddQueryParameter(nameof(id), id);
+ var responseMessage = await request.GetAsync();
- var responseMessage = await request.GetAsync();
+ responseMessage.EnsureSuccessStatusCode();
+ var response = await responseMessage.Content.ReadAsStringAsync();
- responseMessage.EnsureSuccessStatusCode();
- var response = await responseMessage.Content.ReadAsStringAsync();
+ response.Should().Be(id.ToString());
+ }
- response.Should().Be(id.ToString());
- }
+ [Fact]
+ public async Task Create_request_and_add_additional_parameter()
+ {
+ var server = new TestServerBuilder()
+ .UseDefaultStartup()
+ .Build();
- [Fact]
- public async Task Create_request_and_add_additional_parameter()
- {
- var server = new TestServerBuilder()
- .UseDefaultStartup()
- .Build();
+ var id1 = new Random().Next(1, 100);
+ var id2 = new Random().Next(1, 100);
- var id1 = new Random().Next(1, 100);
- var id2 = new Random().Next(1, 100);
+ var request = server.CreateHttpApiRequest(controller => controller.GetAdditionalParameterFromRequestQuery(id1))
+ .AddQueryParameter(nameof(id2), id2);
- var request = server.CreateHttpApiRequest(controller => controller.GetAdditionalParameterFromRequestQuery(id1))
- .AddQueryParameter(nameof(id2), id2);
+ var responseMessage = await request.GetAsync();
- var responseMessage = await request.GetAsync();
+ responseMessage.EnsureSuccessStatusCode();
+ var response = await responseMessage.Content.ReadAsStringAsync();
- responseMessage.EnsureSuccessStatusCode();
- var response = await responseMessage.Content.ReadAsStringAsync();
+ response.Should().Be(JsonSerializer.Serialize(new { id1 = id1.ToString(), id2 = id2.ToString() }));
+ }
- response.Should().Be(JsonSerializer.Serialize(new { id1 = id1.ToString(), id2 = id2.ToString() }));
- }
+ [Fact]
+ public async Task Create_request_and_add_parameter_when_you_have_path_parameter()
+ {
+ var server = new TestServerBuilder()
+ .UseDefaultStartup()
+ .Build();
- [Fact]
- public async Task Create_request_and_add_parameter_when_you_have_path_parameter()
- {
- var server = new TestServerBuilder()
- .UseDefaultStartup()
- .Build();
+ var id1 = new Random().Next(1, 100);
+ var id2 = new Random().Next(1, 100);
- var id1 = new Random().Next(1, 100);
- var id2 = new Random().Next(1, 100);
+ var request = server.CreateHttpApiRequest(controller => controller.GetAdditionalParameterFromRequestQueryAndPath(id1))
+ .AddQueryParameter(nameof(id2), id2);
- var request = server.CreateHttpApiRequest(controller => controller.GetAdditionalParameterFromRequestQueryAndPath(id1))
- .AddQueryParameter(nameof(id2), id2);
+ var responseMessage = await request.GetAsync();
- var responseMessage = await request.GetAsync();
+ responseMessage.EnsureSuccessStatusCode();
+ var response = await responseMessage.Content.ReadAsStringAsync();
- responseMessage.EnsureSuccessStatusCode();
- var response = await responseMessage.Content.ReadAsStringAsync();
+ response.Should().Be(JsonSerializer.Serialize(new { id1 = id1.ToString(), id2 = id2.ToString() }));
+ }
- response.Should().Be(JsonSerializer.Serialize(new { id1 = id1.ToString(), id2 = id2.ToString() }));
- }
+ [Fact]
+ public void Remove_parameter_when_you_have_one_parameter()
+ {
+ var server = new TestServerBuilder()
+ .UseDefaultStartup()
+ .Build();
- [Fact]
- public void Remove_parameter_when_you_have_one_parameter()
- {
- var server = new TestServerBuilder()
- .UseDefaultStartup()
- .Build();
+ const string PARAMETER_TO_REMOVE = "parameter1";
+ const string URL = BASE_PATH + "?" + PARAMETER_TO_REMOVE + "=valueParameter1";
- const string PARAMETER_TO_REMOVE = "parameter1";
- const string URL = BASE_PATH + "?" + PARAMETER_TO_REMOVE + "=valueParameter1";
+ var requestBuilder = server.CreateRequest(URL)
+ .RemoveQueryParameter(PARAMETER_TO_REMOVE);
- var requestBuilder = server.CreateRequest(URL)
- .RemoveQueryParameter(PARAMETER_TO_REMOVE);
+ var requestUrl = requestBuilder.GetRequest().RequestUri.ToString();
- var requestUrl = requestBuilder.GetRequest().RequestUri.ToString();
+ const string EXPECTED_URL = BASE_PATH;
+ requestUrl.Should().Be(EXPECTED_URL);
+ }
- const string EXPECTED_URL = BASE_PATH;
- requestUrl.Should().Be(EXPECTED_URL);
- }
+ [Fact]
+ public void Remove_last_parameter_when_you_have_two_parameter()
+ {
+ var server = new TestServerBuilder()
+ .UseDefaultStartup()
+ .Build();
- [Fact]
- public void Remove_last_parameter_when_you_have_two_parameter()
- {
- var server = new TestServerBuilder()
- .UseDefaultStartup()
- .Build();
+ const string PARAMETER_TO_REMOVE = "parameter2";
+ const string URL_FIRST_PART = "?parameter1=valueParameter1";
+ const string URL = BASE_PATH + URL_FIRST_PART + "&" + PARAMETER_TO_REMOVE + "=valueParameter2";
- const string PARAMETER_TO_REMOVE = "parameter2";
- const string URL_FIRST_PART = "?parameter1=valueParameter1";
- const string URL = BASE_PATH + URL_FIRST_PART + "&" + PARAMETER_TO_REMOVE + "=valueParameter2";
+ var requestBuilder = server.CreateRequest(URL)
+ .RemoveQueryParameter(PARAMETER_TO_REMOVE);
- var requestBuilder = server.CreateRequest(URL)
- .RemoveQueryParameter(PARAMETER_TO_REMOVE);
+ var requestUrl = requestBuilder.GetRequest().RequestUri.ToString();
- var requestUrl = requestBuilder.GetRequest().RequestUri.ToString();
+ const string EXPECTED_URL = BASE_PATH + URL_FIRST_PART;
+ requestUrl.Should().Be(EXPECTED_URL);
+ }
- const string EXPECTED_URL = BASE_PATH + URL_FIRST_PART;
- requestUrl.Should().Be(EXPECTED_URL);
- }
+ [Fact]
+ public void Remove_first_parameter_when_you_have_two_parameter()
+ {
+ var server = new TestServerBuilder()
+ .UseDefaultStartup()
+ .Build();
- [Fact]
- public void Remove_first_parameter_when_you_have_two_parameter()
- {
- var server = new TestServerBuilder()
- .UseDefaultStartup()
- .Build();
+ const string PARAMETER_TO_REMOVE = "parameter1";
+ const string URL_LAST_PART = "parameter2=valueParameter2";
+ const string URL = BASE_PATH + "?" + PARAMETER_TO_REMOVE + "=valueParameter1&" + URL_LAST_PART;
- const string PARAMETER_TO_REMOVE = "parameter1";
- const string URL_LAST_PART = "parameter2=valueParameter2";
- const string URL = BASE_PATH + "?" + PARAMETER_TO_REMOVE + "=valueParameter1&" + URL_LAST_PART;
+ var requestBuilder = server.CreateRequest(URL)
+ .RemoveQueryParameter(PARAMETER_TO_REMOVE);
- var requestBuilder = server.CreateRequest(URL)
- .RemoveQueryParameter(PARAMETER_TO_REMOVE);
+ var requestUrl = requestBuilder.GetRequest().RequestUri.ToString();
- var requestUrl = requestBuilder.GetRequest().RequestUri.ToString();
+ const string EXPECTED_URL = BASE_PATH + "?" + URL_LAST_PART;
+ requestUrl.Should().Be(EXPECTED_URL);
+ }
+
+ [Theory]
+ [InlineData("?parameter1=valueParameter1&", "parameter2=valueParameter2")]
+ [InlineData("?parameter1=valueParameter1&", "parameter2=valueParameter2¶meter3=valueParametere")]
+ [InlineData("?parameter1=valueParameter1¶meter2=valueParameter2&", "parameter3=valueParameter3")]
+ [InlineData("?parameter1=valueParameter1¶meter2=valueParameter2&", "parameter3=valueParameter3¶meter4=valueParameter4")]
+ public void Remove_parameter_when_is_beetween_parameters(string urlFirstPart, string urlLastPart)
+ {
+ var server = new TestServerBuilder()
+ .UseDefaultStartup()
+ .Build();
- const string EXPECTED_URL = BASE_PATH + "?" + URL_LAST_PART;
- requestUrl.Should().Be(EXPECTED_URL);
- }
+ const string PARAMETER_TO_REMOVE = "parameterA";
+ string url = BASE_PATH + urlFirstPart + PARAMETER_TO_REMOVE + "=valueParameterA&" + urlLastPart;
- [Theory]
- [InlineData("?parameter1=valueParameter1&", "parameter2=valueParameter2")]
- [InlineData("?parameter1=valueParameter1&", "parameter2=valueParameter2¶meter3=valueParametere")]
- [InlineData("?parameter1=valueParameter1¶meter2=valueParameter2&", "parameter3=valueParameter3")]
- [InlineData("?parameter1=valueParameter1¶meter2=valueParameter2&", "parameter3=valueParameter3¶meter4=valueParameter4")]
- public void Remove_parameter_when_is_beetween_parameters(string urlFirstPart, string urlLastPart)
- {
- var server = new TestServerBuilder()
- .UseDefaultStartup()
- .Build();
+ var requestBuilder = server.CreateRequest(url)
+ .RemoveQueryParameter(PARAMETER_TO_REMOVE);
- const string PARAMETER_TO_REMOVE = "parameterA";
- string url = BASE_PATH + urlFirstPart + PARAMETER_TO_REMOVE + "=valueParameterA&" + urlLastPart;
+ var requestUrl = requestBuilder.GetRequest().RequestUri.ToString();
+
+ string expectedUrl = BASE_PATH + urlFirstPart + urlLastPart;
+ requestUrl.Should().Be(expectedUrl);
+ }
+
+ [Fact]
+ public void Create_request_and_get_url()
+ {
+ var server = new TestServerBuilder()
+ .UseDefaultStartup()
+ .Build();
- var requestBuilder = server.CreateRequest(url)
- .RemoveQueryParameter(PARAMETER_TO_REMOVE);
+ var id = new Random().Next(1, 100);
- var requestUrl = requestBuilder.GetRequest().RequestUri.ToString();
+ var request = server.CreateHttpApiRequest(controller => controller.GetParameterFromRequestQuery())
+ .AddQueryParameter(nameof(id), id);
+ var uri = request.GetUrl();
- string expectedUrl = BASE_PATH + urlFirstPart + urlLastPart;
- requestUrl.Should().Be(expectedUrl);
- }
+ uri.Should().Be($"api/values/getparameterfromrequestquery?id={id}");
}
}
diff --git a/tests/UnitTests/Acheve.TestHost/Routing/TestServerExtensionsTests.cs b/tests/UnitTests/Acheve.TestHost/Routing/TestServerExtensionsTests.cs
index 7939294..607e853 100644
--- a/tests/UnitTests/Acheve.TestHost/Routing/TestServerExtensionsTests.cs
+++ b/tests/UnitTests/Acheve.TestHost/Routing/TestServerExtensionsTests.cs
@@ -13,1760 +13,1935 @@
using UnitTests.Acheve.TestHost.Routing.Models;
using Xunit;
-namespace UnitTests.Acheve.TestHost.Routing
+namespace UnitTests.Acheve.TestHost.Routing;
+
+public class CreateApiRequestShould
{
- public class create_api_request_should
+ public const string BASE_PATH = "api/";
+ public const string BASE_PATH_BUGS = BASE_PATH + "bugs";
+ public const string BASE_PATH_VALUES = BASE_PATH + "values";
+
+ [Fact]
+ public void Throw_when_controller_is_not_a_valid_controller()
{
- public const string BASE_PATH = "api/";
- public const string BASE_PATH_BUGS = BASE_PATH + "bugs";
- public const string BASE_PATH_VALUES = BASE_PATH + "values";
+ var server = new TestServerBuilder()
+ .UseDefaultStartup()
+ .Build();
- [Fact]
- public void throw_when_controller_is_not_a_valid_controller()
+ Assert.Throws(() =>
+ {
+ server.CreateHttpApiRequest(controller => controller.SomeAction());
+ });
+ Assert.Throws(() =>
+ {
+ server.CreateHttpApiRequest(controller => controller.SomeAction());
+ });
+ Assert.Throws(() =>
+ {
+ server.CreateHttpApiRequest(controller => controller.SomeAction());
+ });
+ Assert.Throws(() =>
+ {
+ server.CreateHttpApiRequest(controller => controller.SomeAction());
+ });
+ Assert.Throws(() =>
{
- var server = new TestServerBuilder()
- .UseDefaultStartup()
- .Build();
+ server.CreateHttpApiRequest(controller => controller.SomeAction());
+ });
+ }
- Assert.Throws(() =>
- {
- server.CreateHttpApiRequest(controller => controller.SomeAction());
- });
- Assert.Throws(() =>
- {
- server.CreateHttpApiRequest(controller => controller.SomeAction());
- });
- Assert.Throws(() =>
- {
- server.CreateHttpApiRequest(controller => controller.SomeAction());
- });
- Assert.Throws(() =>
- {
- server.CreateHttpApiRequest(controller => controller.SomeAction());
- });
- Assert.Throws(() =>
- {
- server.CreateHttpApiRequest(controller => controller.SomeAction());
- });
- }
+ [Fact]
+ public void Throw_when_the_action_selector_is_null()
+ {
+ var server = new TestServerBuilder()
+ .UseDefaultStartup()
+ .Build();
- [Fact]
- public void throw_when_the_action_selector_is_null()
+ Assert.Throws(() =>
{
- var server = new TestServerBuilder()
- .UseDefaultStartup()
- .Build();
+ server.CreateHttpApiRequest(null);
+ });
+ }
- Assert.Throws(() =>
- {
- server.CreateHttpApiRequest(null);
- });
- }
+ [Fact]
+ public void Create_valid_request_for_primitive_parameter_action()
+ {
+ var server = new TestServerBuilder()
+ .UseDefaultStartup()
+ .Build();
- [Fact]
- public void create_valid_request_for_primitive_parameter_action()
- {
- var server = new TestServerBuilder()
- .UseDefaultStartup()
- .Build();
+ var request = server.CreateHttpApiRequest(
+ controller => controller.Get(0));
- var request = server.CreateHttpApiRequest(
- controller => controller.Get(0));
+ request.GetConfiguredAddress()
+ .Should().Be($"{BASE_PATH_VALUES}?id=0");
+ }
- request.GetConfiguredAddress()
- .Should().Be($"{BASE_PATH_VALUES}?id=0");
- }
+ [Fact]
+ public void Create_valid_request_for_string_as_primitive_parameter_tokenizer_action()
+ {
+ var server = new TestServerBuilder()
+ .UseDefaultStartup()
+ .Build();
- [Fact]
- public void create_valid_request_for_string_as_primitive_parameter_tokenizer_action()
- {
- var server = new TestServerBuilder()
- .UseDefaultStartup()
- .Build();
+ var request = server.CreateHttpApiRequest(
+ controller => controller.GetStringAsParameter("unai"));
- var request = server.CreateHttpApiRequest(
- controller => controller.GetStringAsParameter("unai"));
+ request.GetConfiguredAddress()
+ .Should().Be($"{BASE_PATH_VALUES}/stringasprimitive?value=unai");
+ }
- request.GetConfiguredAddress()
- .Should().Be($"{BASE_PATH_VALUES}/stringasprimitive?value=unai");
- }
+ [Fact]
+ public void Create_valid_request_for_string_as_primitive_parameter_tokenizer_action_with_case()
+ {
+ var server = new TestServerBuilder()
+ .UseDefaultStartup()
+ .Build();
- [Fact]
- public void create_valid_request_for_string_as_primitive_parameter_tokenizer_action_with_case()
- {
- var server = new TestServerBuilder()
- .UseDefaultStartup()
- .Build();
+ var request = server.CreateHttpApiRequest(
+ controller => controller.GetStringAsParameter("Uppercase"));
- var request = server.CreateHttpApiRequest(
- controller => controller.GetStringAsParameter("Uppercase"));
+ request.GetConfiguredAddress()
+ .Should().Be($"{BASE_PATH_VALUES}/stringasprimitive?value=Uppercase");
+ }
- request.GetConfiguredAddress()
- .Should().Be($"{BASE_PATH_VALUES}/stringasprimitive?value=Uppercase");
- }
+ [Fact]
+ public void Create_valid_request_for_string_as_decimal_parameter_tokenizer_action()
+ {
+ var server = new TestServerBuilder()
+ .UseDefaultStartup()
+ .Build();
- [Fact]
- public void create_valid_request_for_string_as_decimal_parameter_tokenizer_action()
- {
- var server = new TestServerBuilder()
- .UseDefaultStartup()
- .Build();
+ var request = server.CreateHttpApiRequest(
+ controller => controller.GetDecimalAsParameter(2m));
- var request = server.CreateHttpApiRequest(
- controller => controller.GetDecimalAsParameter(2m));
+ request.GetConfiguredAddress()
+ .Should().Be($"{BASE_PATH_VALUES}/decimalasprimitive?value=2");
+ }
- request.GetConfiguredAddress()
- .Should().Be($"{BASE_PATH_VALUES}/decimalasprimitive?value=2");
- }
+ [Fact]
+ public void Create_valid_request_for_conventional_action_with_extra_parameters()
+ {
+ var server = new TestServerBuilder()
+ .UseDefaultStartup()
+ .Build();
- [Fact]
- public void create_valid_request_for_conventional_action_with_extra_parameters()
- {
- var server = new TestServerBuilder()
- .UseDefaultStartup()
- .Build();
+ var request = server.CreateHttpApiRequest(
+ controller => controller.Get(0), new { Version = "v1" });
- var request = server.CreateHttpApiRequest(
- controller => controller.Get(0), new { Version = "v1" });
+ request.GetConfiguredAddress()
+ .Should().Be("api/v1/values?id=0");
+ }
- request.GetConfiguredAddress()
- .Should().Be("api/v1/values?id=0");
- }
+ [Fact]
+ public void Create_valid_request_using_verbs_templates()
+ {
+ var server = new TestServerBuilder()
+ .UseDefaultStartup()
+ .Build();
- [Fact]
- public void create_valid_request_using_verbs_templates()
- {
- var server = new TestServerBuilder()
- .UseDefaultStartup()
- .Build();
+ var requestGet = server.CreateHttpApiRequest(
+ controller => controller.Get2(0));
- var requestGet = server.CreateHttpApiRequest(
- controller => controller.Get2(0));
+ var requestPut = server.CreateHttpApiRequest(
+ controller => controller.Put2(1));
- var requestPut = server.CreateHttpApiRequest(
- controller => controller.Put2(1));
+ var requestPost = server.CreateHttpApiRequest(
+ controller => controller.Post2(2));
- var requestPost = server.CreateHttpApiRequest(
- controller => controller.Post2(2));
+ var requestDelete = server.CreateHttpApiRequest(
+ controller => controller.Delete2(3));
- var requestDelete = server.CreateHttpApiRequest(
- controller => controller.Delete2(3));
+ requestGet.GetConfiguredAddress()
+ .Should().Be($"{BASE_PATH_VALUES}/overridemethodname?id=0");
- requestGet.GetConfiguredAddress()
- .Should().Be($"{BASE_PATH_VALUES}/overridemethodname?id=0");
+ requestPut.GetConfiguredAddress()
+ .Should().Be($"{BASE_PATH_VALUES}/overridemethodname?id=1");
- requestPut.GetConfiguredAddress()
- .Should().Be($"{BASE_PATH_VALUES}/overridemethodname?id=1");
+ requestPost.GetConfiguredAddress()
+ .Should().Be($"{BASE_PATH_VALUES}/overridemethodname?id=2");
- requestPost.GetConfiguredAddress()
- .Should().Be($"{BASE_PATH_VALUES}/overridemethodname?id=2");
+ requestDelete.GetConfiguredAddress()
+ .Should().Be($"{BASE_PATH_VALUES}/overridemethodname?id=3");
+ }
- requestDelete.GetConfiguredAddress()
- .Should().Be($"{BASE_PATH_VALUES}/overridemethodname?id=3");
- }
+ [Fact]
+ public void Create_valid_request_using_verbs_and_parameters()
+ {
+ var server = new TestServerBuilder()
+ .UseDefaultStartup()
+ .Build();
- [Fact]
- public void create_valid_request_using_verbs_and_parameters()
- {
- var server = new TestServerBuilder()
- .UseDefaultStartup()
- .Build();
+ var requestGet = server.CreateHttpApiRequest(
+ controller => controller.Get3(0));
- var requestGet = server.CreateHttpApiRequest(
- controller => controller.Get3(0));
+ var requestPut = server.CreateHttpApiRequest(
+ controller => controller.Put3(1));
- var requestPut = server.CreateHttpApiRequest(
- controller => controller.Put3(1));
+ var requestPost = server.CreateHttpApiRequest(
+ controller => controller.Post3(2));
- var requestPost = server.CreateHttpApiRequest(
- controller => controller.Post3(2));
+ var requestDelete = server.CreateHttpApiRequest(
+ controller => controller.Delete3(3));
- var requestDelete = server.CreateHttpApiRequest(
- controller => controller.Delete3(3));
+ requestGet.GetConfiguredAddress()
+ .Should().Be($"{BASE_PATH_VALUES}/overridemethodname/0");
- requestGet.GetConfiguredAddress()
- .Should().Be($"{BASE_PATH_VALUES}/overridemethodname/0");
+ requestPut.GetConfiguredAddress()
+ .Should().Be($"{BASE_PATH_VALUES}/overridemethodname/1");
- requestPut.GetConfiguredAddress()
- .Should().Be($"{BASE_PATH_VALUES}/overridemethodname/1");
+ requestPost.GetConfiguredAddress()
+ .Should().Be($"{BASE_PATH_VALUES}/overridemethodname/2");
- requestPost.GetConfiguredAddress()
- .Should().Be($"{BASE_PATH_VALUES}/overridemethodname/2");
+ requestDelete.GetConfiguredAddress()
+ .Should().Be($"{BASE_PATH_VALUES}/overridemethodname/3");
+ }
- requestDelete.GetConfiguredAddress()
- .Should().Be($"{BASE_PATH_VALUES}/overridemethodname/3");
- }
+ [Fact]
+ public void Create_valid_request_using_verbs_and_extra_parameters()
+ {
+ var server = new TestServerBuilder()
+ .UseDefaultStartup()
+ .Build();
- [Fact]
- public void create_valid_request_using_verbs_and_extra_parameters()
- {
- var server = new TestServerBuilder()
- .UseDefaultStartup()
- .Build();
+ var requestGet = server.CreateHttpApiRequest(
+ controller => controller.Get4(0), new { version = "v1" });
- var requestGet = server.CreateHttpApiRequest(
- controller => controller.Get4(0), new { version = "v1" });
+ var requestPut = server.CreateHttpApiRequest(
+ controller => controller.Put4(1), new { version = "v1" });
- var requestPut = server.CreateHttpApiRequest(
- controller => controller.Put4(1), new { version = "v1" });
+ var requestPost = server.CreateHttpApiRequest(
+ controller => controller.Post4(2), new { version = "v1" });
- var requestPost = server.CreateHttpApiRequest(
- controller => controller.Post4(2), new { version = "v1" });
+ var requestDelete = server.CreateHttpApiRequest(
+ controller => controller.Delete4(3), new { version = "v1" });
- var requestDelete = server.CreateHttpApiRequest(
- controller => controller.Delete4(3), new { version = "v1" });
+ requestGet.GetConfiguredAddress()
+ .Should().Be($"{BASE_PATH_VALUES}/overridemethodname/v1/0");
- requestGet.GetConfiguredAddress()
- .Should().Be($"{BASE_PATH_VALUES}/overridemethodname/v1/0");
+ requestPut.GetConfiguredAddress()
+ .Should().Be($"{BASE_PATH_VALUES}/overridemethodname/v1/1");
- requestPut.GetConfiguredAddress()
- .Should().Be($"{BASE_PATH_VALUES}/overridemethodname/v1/1");
+ requestPost.GetConfiguredAddress()
+ .Should().Be($"{BASE_PATH_VALUES}/overridemethodname/v1/2");
- requestPost.GetConfiguredAddress()
- .Should().Be($"{BASE_PATH_VALUES}/overridemethodname/v1/2");
+ requestDelete.GetConfiguredAddress()
+ .Should().Be($"{BASE_PATH_VALUES}/overridemethodname/v1/3");
+ }
- requestDelete.GetConfiguredAddress()
- .Should().Be($"{BASE_PATH_VALUES}/overridemethodname/v1/3");
- }
+ [Fact]
+ public void Create_valid_request_using_verbs_and_extra_parameters_with_different_case()
+ {
+ var server = new TestServerBuilder()
+ .UseDefaultStartup()
+ .Build();
- [Fact]
- public void create_valid_request_using_verbs_and_extra_parameters_with_different_case()
- {
- var server = new TestServerBuilder()
- .UseDefaultStartup()
- .Build();
+ var requestGet = server.CreateHttpApiRequest(
+ controller => controller.Get4(0), new { Version = "v1" });
- var requestGet = server.CreateHttpApiRequest(
- controller => controller.Get4(0), new { Version = "v1" });
+ requestGet.GetConfiguredAddress()
+ .Should().Be($"{BASE_PATH_VALUES}/overridemethodname/v1/0");
+ }
- requestGet.GetConfiguredAddress()
- .Should().Be($"{BASE_PATH_VALUES}/overridemethodname/v1/0");
- }
+ [Fact]
+ public void Create_valid_request_using_route_templates()
+ {
+ var server = new TestServerBuilder()
+ .UseDefaultStartup()
+ .Build();
- [Fact]
- public void create_valid_request_using_route_templates()
- {
- var server = new TestServerBuilder()
- .UseDefaultStartup()
- .Build();
+ var requestGet = server.CreateHttpApiRequest(
+ controller => controller.Get5(0));
- var requestGet = server.CreateHttpApiRequest(
- controller => controller.Get5(0));
+ var requestPut = server.CreateHttpApiRequest(
+ controller => controller.Put5(0));
- var requestPut = server.CreateHttpApiRequest(
- controller => controller.Put5(0));
+ var requestPost = server.CreateHttpApiRequest(
+ controller => controller.Post5(0));
- var requestPost = server.CreateHttpApiRequest(
- controller => controller.Post5(0));
+ var requestDelete = server.CreateHttpApiRequest(
+ controller => controller.Delete5(0));
- var requestDelete = server.CreateHttpApiRequest(
- controller => controller.Delete5(0));
+ requestGet.GetConfiguredAddress()
+ .Should().Be($"{BASE_PATH_VALUES}/overrideroutetemplatemethodname?id=0");
- requestGet.GetConfiguredAddress()
- .Should().Be($"{BASE_PATH_VALUES}/overrideroutetemplatemethodname?id=0");
+ requestPut.GetConfiguredAddress()
+ .Should().Be($"{BASE_PATH_VALUES}/overrideroutetemplatemethodname?id=0");
- requestPut.GetConfiguredAddress()
- .Should().Be($"{BASE_PATH_VALUES}/overrideroutetemplatemethodname?id=0");
+ requestPost.GetConfiguredAddress()
+ .Should().Be($"{BASE_PATH_VALUES}/overrideroutetemplatemethodname?id=0");
- requestPost.GetConfiguredAddress()
- .Should().Be($"{BASE_PATH_VALUES}/overrideroutetemplatemethodname?id=0");
+ requestDelete.GetConfiguredAddress()
+ .Should().Be($"{BASE_PATH_VALUES}/overrideroutetemplatemethodname?id=0");
+ }
- requestDelete.GetConfiguredAddress()
- .Should().Be($"{BASE_PATH_VALUES}/overrideroutetemplatemethodname?id=0");
- }
+ [Fact]
+ public void Create_valid_request_using_route_templates_with_parameters_and_extra_parameters()
+ {
+ var server = new TestServerBuilder()
+ .UseDefaultStartup()
+ .Build();
- [Fact]
- public void create_valid_request_using_route_templates_with_parameters_and_extra_parameters()
- {
- var server = new TestServerBuilder()
- .UseDefaultStartup()
- .Build();
+ var requestGet = server.CreateHttpApiRequest(
+ controller => controller.Get6(0), new { version = "v1" });
- var requestGet = server.CreateHttpApiRequest(
- controller => controller.Get6(0), new { version = "v1" });
+ var requestPut = server.CreateHttpApiRequest(
+ controller => controller.Put6(1), new { version = "v1" });
- var requestPut = server.CreateHttpApiRequest(
- controller => controller.Put6(1), new { version = "v1" });
+ var requestPost = server.CreateHttpApiRequest(
+ controller => controller.Post6(2), new { version = "v1" });
- var requestPost = server.CreateHttpApiRequest(
- controller => controller.Post6(2), new { version = "v1" });
+ var requestDelete = server.CreateHttpApiRequest(
+ controller => controller.Delete6(3), new { version = "v1" });
- var requestDelete = server.CreateHttpApiRequest(
- controller => controller.Delete6(3), new { version = "v1" });
+ requestGet.GetConfiguredAddress()
+ .Should().Be($"{BASE_PATH_VALUES}/overrideroutetemplatemethodname/v1/0");
- requestGet.GetConfiguredAddress()
- .Should().Be($"{BASE_PATH_VALUES}/overrideroutetemplatemethodname/v1/0");
+ requestPut.GetConfiguredAddress()
+ .Should().Be($"{BASE_PATH_VALUES}/overrideroutetemplatemethodname/v1/1");
- requestPut.GetConfiguredAddress()
- .Should().Be($"{BASE_PATH_VALUES}/overrideroutetemplatemethodname/v1/1");
+ requestPost.GetConfiguredAddress()
+ .Should().Be($"{BASE_PATH_VALUES}/overrideroutetemplatemethodname/v1/2");
- requestPost.GetConfiguredAddress()
- .Should().Be($"{BASE_PATH_VALUES}/overrideroutetemplatemethodname/v1/2");
+ requestDelete.GetConfiguredAddress()
+ .Should().Be($"{BASE_PATH_VALUES}/overrideroutetemplatemethodname/v1/3");
+ }
- requestDelete.GetConfiguredAddress()
- .Should().Be($"{BASE_PATH_VALUES}/overrideroutetemplatemethodname/v1/3");
- }
+ [Fact]
+ public void Create_valid_request_using_route_templates_and_parameters_with_route_constraints()
+ {
+ var server = new TestServerBuilder()
+ .UseDefaultStartup()
+ .Build();
- [Fact]
- public void create_valid_request_using_route_templates_and_parameters_with_route_constraints()
- {
- var server = new TestServerBuilder()
- .UseDefaultStartup()
- .Build();
+ var requestGet = server.CreateHttpApiRequest(
+ controller => controller.Get7(0));
- var requestGet = server.CreateHttpApiRequest(
- controller => controller.Get7(0));
+ var requestPut = server.CreateHttpApiRequest(
+ controller => controller.Put7(1));
- var requestPut = server.CreateHttpApiRequest(
- controller => controller.Put7(1));
+ var requestPost = server.CreateHttpApiRequest(
+ controller => controller.Post7(2));
- var requestPost = server.CreateHttpApiRequest(
- controller => controller.Post7(2));
+ var requestDelete = server.CreateHttpApiRequest(
+ controller => controller.Delete7(3));
- var requestDelete = server.CreateHttpApiRequest(
- controller => controller.Delete7(3));
+ requestGet.GetConfiguredAddress()
+ .Should().Be($"{BASE_PATH_VALUES}/overrideroutetemplatemethodname/0");
- requestGet.GetConfiguredAddress()
- .Should().Be($"{BASE_PATH_VALUES}/overrideroutetemplatemethodname/0");
+ requestPut.GetConfiguredAddress()
+ .Should().Be($"{BASE_PATH_VALUES}/overrideroutetemplatemethodname/1");
- requestPut.GetConfiguredAddress()
- .Should().Be($"{BASE_PATH_VALUES}/overrideroutetemplatemethodname/1");
+ requestPost.GetConfiguredAddress()
+ .Should().Be($"{BASE_PATH_VALUES}/overrideroutetemplatemethodname/2");
- requestPost.GetConfiguredAddress()
- .Should().Be($"{BASE_PATH_VALUES}/overrideroutetemplatemethodname/2");
+ requestDelete.GetConfiguredAddress()
+ .Should().Be($"{BASE_PATH_VALUES}/overrideroutetemplatemethodname/3");
+ }
- requestDelete.GetConfiguredAddress()
- .Should().Be($"{BASE_PATH_VALUES}/overrideroutetemplatemethodname/3");
- }
+ [Fact]
+ public void Create_valid_request_using_verbs_and_parameters_with_route_constraints()
+ {
+ var server = new TestServerBuilder()
+ .UseDefaultStartup()
+ .Build();
- [Fact]
- public void create_valid_request_using_verbs_and_parameters_with_route_constraints()
- {
- var server = new TestServerBuilder()
- .UseDefaultStartup()
- .Build();
+ var requestGet = server.CreateHttpApiRequest(
+ controller => controller.Get8(0));
- var requestGet = server.CreateHttpApiRequest(
- controller => controller.Get8(0));
+ var requestPut = server.CreateHttpApiRequest(
+ controller => controller.Put8(1));
- var requestPut = server.CreateHttpApiRequest(
- controller => controller.Put8(1));
+ var requestPost = server.CreateHttpApiRequest(
+ controller => controller.Post8(2));
- var requestPost = server.CreateHttpApiRequest(
- controller => controller.Post8(2));
+ var requestDelete = server.CreateHttpApiRequest(
+ controller => controller.Delete8(3));
- var requestDelete = server.CreateHttpApiRequest(
- controller => controller.Delete8(3));
+ requestGet.GetConfiguredAddress()
+ .Should().Be($"{BASE_PATH_VALUES}/overridemethodname/0");
- requestGet.GetConfiguredAddress()
- .Should().Be($"{BASE_PATH_VALUES}/overridemethodname/0");
+ requestPut.GetConfiguredAddress()
+ .Should().Be($"{BASE_PATH_VALUES}/overridemethodname/1");
- requestPut.GetConfiguredAddress()
- .Should().Be($"{BASE_PATH_VALUES}/overridemethodname/1");
+ requestPost.GetConfiguredAddress()
+ .Should().Be($"{BASE_PATH_VALUES}/overridemethodname/2");
- requestPost.GetConfiguredAddress()
- .Should().Be($"{BASE_PATH_VALUES}/overridemethodname/2");
+ requestDelete.GetConfiguredAddress()
+ .Should().Be($"{BASE_PATH_VALUES}/overridemethodname/3");
+ }
- requestDelete.GetConfiguredAddress()
- .Should().Be($"{BASE_PATH_VALUES}/overridemethodname/3");
- }
+ [Fact]
+ public void Create_valid_request_using_verbs_when_parameters_are_not_primitives()
+ {
+ var server = new TestServerBuilder()
+ .UseDefaultStartup()
+ .Build();
- [Fact]
- public void create_valid_request_using_verbs_when_parameters_are_not_primitives()
+ var complexParameter = new Pagination()
{
- var server = new TestServerBuilder()
- .UseDefaultStartup()
- .Build();
+ PageCount = 10,
+ PageIndex = 1
+ };
- var complexParameter = new Pagination()
- {
- PageCount = 10,
- PageIndex = 1
- };
+ var requestGet = server.CreateHttpApiRequest(
+ controller => controller.Get2(complexParameter));
- var requestGet = server.CreateHttpApiRequest(
- controller => controller.Get2(complexParameter));
+ requestGet.GetConfiguredAddress()
+ .Should().Be($"{BASE_PATH_VALUES}/get2/1/10");
+ }
- requestGet.GetConfiguredAddress()
- .Should().Be($"{BASE_PATH_VALUES}/get2/1/10");
- }
+ [Fact]
+ public void Create_valid_request_using_verbs_when_parameters_are_not_primitives_with_null_properties()
+ {
+ var server = new TestServerBuilder()
+ .UseDefaultStartup()
+ .Build();
- [Fact]
- public void create_valid_request_using_verbs_when_parameters_are_not_primitives_with_null_properties()
+ var complexParameter = new Pagination()
{
- var server = new TestServerBuilder()
- .UseDefaultStartup()
- .Build();
+ PageIndex = 1
+ };
- var complexParameter = new Pagination()
- {
- PageIndex = 1
- };
+ var requestGet = server.CreateHttpApiRequest(
+ controller => controller.Get2(complexParameter));
- var requestGet = server.CreateHttpApiRequest(
- controller => controller.Get2(complexParameter));
+ requestGet.GetConfiguredAddress()
+ .Should().Be($"{BASE_PATH_VALUES}/get2/1");
+ }
- requestGet.GetConfiguredAddress()
- .Should().Be($"{BASE_PATH_VALUES}/get2/1");
- }
+ [Fact]
+ public void Create_valid_request_using_verbs_and_query_string_when_parameters_are_not_primitives()
+ {
+ var server = new TestServerBuilder()
+ .UseDefaultStartup()
+ .Build();
- [Fact]
- public void create_valid_request_using_verbs_and_query_string_when_parameters_are_not_primitives()
+ var complexParameter = new Pagination()
{
- var server = new TestServerBuilder()
- .UseDefaultStartup()
- .Build();
+ PageCount = 10,
+ PageIndex = 1
+ };
- var complexParameter = new Pagination()
- {
- PageCount = 10,
- PageIndex = 1
- };
+ var requestGet = server.CreateHttpApiRequest(
+ controller => controller.Get1(complexParameter));
- var requestGet = server.CreateHttpApiRequest(
- controller => controller.Get1(complexParameter));
+ requestGet.GetConfiguredAddress()
+ .Should().Be($"{BASE_PATH_VALUES}/get1?pageindex=1&pagecount=10");
+ }
- requestGet.GetConfiguredAddress()
- .Should().Be($"{BASE_PATH_VALUES}/get1?pageindex=1&pagecount=10");
- }
+ [Fact]
+ public void Create_valid_request_using_verbs_and_query_string_when_parameters_are_not_primitives_with_null_properties()
+ {
+ var server = new TestServerBuilder()
+ .UseDefaultStartup()
+ .Build();
- [Fact]
- public void create_valid_request_using_verbs_and_query_string_when_parameters_are_not_primitives_with_null_properties()
+ var complexParameter = new Pagination()
{
- var server = new TestServerBuilder()
- .UseDefaultStartup()
- .Build();
+ PageIndex = 1
+ };
- var complexParameter = new Pagination()
- {
- PageIndex = 1
- };
+ var requestGet = server.CreateHttpApiRequest(
+ controller => controller.Get1(complexParameter));
- var requestGet = server.CreateHttpApiRequest(
- controller => controller.Get1(complexParameter));
+ requestGet.GetConfiguredAddress()
+ .Should().Be($"{BASE_PATH_VALUES}/get1?pageindex=1");
+ }
- requestGet.GetConfiguredAddress()
- .Should().Be($"{BASE_PATH_VALUES}/get1?pageindex=1");
- }
+ [Fact]
+ public void Create_valid_request_using_route_when_parameters_are_not_primitives()
+ {
+ var server = new TestServerBuilder()
+ .UseDefaultStartup()
+ .Build();
- [Fact]
- public void create_valid_request_using_route_when_parameters_are_not_primitives()
+ var complexParameter = new Pagination()
{
- var server = new TestServerBuilder()
- .UseDefaultStartup()
- .Build();
+ PageCount = 10,
+ PageIndex = 1
+ };
- var complexParameter = new Pagination()
- {
- PageCount = 10,
- PageIndex = 1
- };
+ var requestGet = server.CreateHttpApiRequest(
+ controller => controller.Get4(complexParameter));
- var requestGet = server.CreateHttpApiRequest(
- controller => controller.Get4(complexParameter));
+ requestGet.GetConfiguredAddress()
+ .Should().Be($"{BASE_PATH_VALUES}/get4/1/10");
+ }
- requestGet.GetConfiguredAddress()
- .Should().Be($"{BASE_PATH_VALUES}/get4/1/10");
- }
+ [Fact]
+ public void Create_valid_request_using_verbs_query_string_and_from_header()
+ {
+ var server = new TestServerBuilder()
+ .UseDefaultStartup()
+ .Build();
- [Fact]
- public void create_valid_request_using_verbs_query_string_and_from_header()
+ var complexParameter = new Pagination()
{
- var server = new TestServerBuilder()
- .UseDefaultStartup()
- .Build();
+ PageCount = 10,
+ PageIndex = 1
+ };
- var complexParameter = new Pagination()
- {
- PageCount = 10,
- PageIndex = 1
- };
+ var header = "HeaderCustom";
+ var numberHeader = 1;
- var header = "HeaderCustom";
- var numberHeader = 1;
+ var request = server.CreateHttpApiRequest(
+ controller => controller.Get5(header, complexParameter));
- var request = server.CreateHttpApiRequest(
- controller => controller.Get5(header, complexParameter));
+ var requestMultipleHeader = server.CreateHttpApiRequest(
+ controller => controller.Get6(header, numberHeader, complexParameter));
- var requestMultipleHeader = server.CreateHttpApiRequest