Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Develop into master #97

Merged
merged 36 commits into from
Jun 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
651326a
If the method is abstract and virtual is a correct method (#72)
Sergio1192 Aug 2, 2022
f65be9c
Fix enumerable parameter (#74)
Sergio1192 Sep 13, 2022
f817b67
Add RemoveQueryParameter extension method (#75)
Sergio1192 Sep 15, 2022
c2f870d
CancellationTOken always is a query paramater (#76)
Sergio1192 Sep 21, 2022
706ab47
Version 3.4.0 (#77)
Sergio1192 Sep 21, 2022
387b500
Action convection name (#79)
Sergio1192 Oct 4, 2022
d169c53
Merge branch 'develop' of https://github.com/Xabaril/Acheve.TestHost …
Sergio1192 Feb 22, 2023
994cb8f
Create get request when it has an object with some list
Sergio1192 Feb 22, 2023
29ab302
Merge branch 'develop' of https://github.com/Xabaril/Acheve.TestHost …
Sergio1192 Feb 22, 2023
99f0c8a
DateTime as a primitive type but using custom formatter (#81)
Sergio1192 Mar 1, 2023
060a58c
Merge branch 'develop' of https://github.com/Xabaril/Acheve.TestHost …
Sergio1192 Mar 1, 2023
ed138ab
Fixing codeQL alerts (#82)
Sergio1192 Mar 12, 2023
a85bb25
Merge branch 'develop' of https://github.com/Xabaril/Acheve.TestHost …
Sergio1192 Mar 12, 2023
de91f82
feature: Get url (#83)
Sergio1192 Mar 19, 2023
35fa8de
Merge branch 'develop' of https://github.com/Xabaril/Acheve.TestHost …
Sergio1192 Mar 20, 2023
15ea0b2
In IncludeContentAsFormUrlEncoded and PrimitiveParameterActionTokeniz…
Sergio1192 May 20, 2023
2563705
Merge branch 'develop' of https://github.com/Xabaril/Acheve.TestHost …
Sergio1192 May 20, 2023
e204431
Add new CreateHttpApiRequest with TActionResponse (#85)
Sergio1192 May 20, 2023
026d100
Merge branch 'develop' of https://github.com/Xabaril/Acheve.TestHost …
Sergio1192 May 20, 2023
92af8db
Add net7.0 Target Version (#86)
Sergio1192 May 20, 2023
ec294cc
Merge branch 'develop' of https://github.com/Xabaril/Acheve.TestHost …
Sergio1192 May 20, 2023
85a2b9c
ReadContentAsAsync allows string type (#87)
Sergio1192 May 21, 2023
e6d41cc
Merge branch 'develop' of https://github.com/Xabaril/Acheve.TestHost …
Sergio1192 May 21, 2023
e18e22f
Allow send a IFormFile (#88)
Sergio1192 May 22, 2023
d035170
Merge branch 'develop' of https://github.com/Xabaril/Acheve.TestHost …
Sergio1192 May 22, 2023
d5aa032
Update version to 3.5.0 (#89)
Sergio1192 May 22, 2023
5b4e075
Merge branch 'develop' of https://github.com/Xabaril/Acheve.TestHost …
Sergio1192 May 22, 2023
2018abc
Add DateTimeOffset to IsDateTime function (#91)
Sergio1192 May 22, 2023
fb8e0f3
Merge branch 'develop' of https://github.com/Xabaril/Acheve.TestHost …
Sergio1192 May 22, 2023
0f613c2
Allow dispatch workflows manually
Sergio1192 May 25, 2023
316d22c
Update to Net8 (#92)
Sergio1192 May 3, 2024
afb09ea
Different froms in object (#93)
Sergio1192 May 13, 2024
97f4d69
Version 4.0.0 (#94)
Sergio1192 May 13, 2024
a4fc44a
Merge with master
Sergio1192 May 14, 2024
d2fef41
Fix IsDateTime (#96)
Sergio1192 May 14, 2024
df4b701
Send ContentType and ContentDisposition (#98)
Sergio1192 Jun 11, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,12 @@ jobs:
uses: actions/setup-dotnet@v2
with:
dotnet-version: |
3.1.417
5.0.101
6.0.300
7.0.302
6.0.421
7.0.408
8.0.204

- name: Build
run: dotnet build -c $BUILD_CONFIG

- name: Test
run: dotnet test -c $BUILD_CONFIG --no-build
run: dotnet test -c $BUILD_CONFIG --no-build
7 changes: 3 additions & 4 deletions .github/workflows/nuget.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,9 @@ jobs:
uses: actions/setup-dotnet@v2
with:
dotnet-version: |
3.1.417
5.0.101
6.0.300
7.0.302
6.0.421
7.0.408
8.0.204

- name: Build
run: dotnet build -c $BUILD_CONFIG
Expand Down
4 changes: 2 additions & 2 deletions Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
<Project>
<PropertyGroup Label="SDK Versions">
<NetCoreTargetVersion>netcoreapp3.1;net5.0;net6.0;net7.0</NetCoreTargetVersion>
<NetCoreTargetVersion>net6.0;net7.0;net8.0</NetCoreTargetVersion>
<LangVersion>latest</LangVersion>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>

<PropertyGroup Label="Package information">
<Version>3.5.0</Version>
<Version>4.0.0</Version>

<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
<PackageProjectUrl>http://github.com/xabaril/Acheve.TestHost</PackageProjectUrl>
Expand Down
25 changes: 11 additions & 14 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
<Project>
<PropertyGroup Label=".Net version" Condition=" '$(TargetFramework)' == 'netcoreapp3.1' ">
<NetCoreVersion>3.1.32</NetCoreVersion>
</PropertyGroup>
<PropertyGroup Label=".Net version" Condition=" '$(TargetFramework)' == 'net5.0' ">
<NetCoreVersion>5.0.17</NetCoreVersion>
</PropertyGroup>
<PropertyGroup Label=".Net version" Condition=" '$(TargetFramework)' == 'net6.0' ">
<NetCoreVersion>6.0.16</NetCoreVersion>
<NetCoreVersion>6.0.29</NetCoreVersion>
</PropertyGroup>
<PropertyGroup Label=".Net version" Condition=" '$(TargetFramework)' == 'net7.0' ">
<NetCoreVersion>7.0.5</NetCoreVersion>
<NetCoreVersion>7.0.18</NetCoreVersion>
</PropertyGroup>
<PropertyGroup Label=".Net version" Condition=" '$(TargetFramework)' == 'net8.0' ">
<NetCoreVersion>8.0.4</NetCoreVersion>
</PropertyGroup>
<ItemGroup Label="General Dependencies">
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
Expand All @@ -20,13 +17,13 @@
</ItemGroup>
<ItemGroup Label="Testing Dependencies">
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="$(NetCoreVersion)" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.6.0" />
<PackageVersion Include="FluentAssertions" Version="6.11.0" />
<PackageVersion Include="xunit" Version="2.4.2" />
<PackageVersion Include="xunit.runner.visualstudio" Version="2.4.5" />
<PackageVersion Include="coverlet.collector" Version="3.2.0" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageVersion Include="FluentAssertions" Version="6.12.0" />
<PackageVersion Include="xunit" Version="2.8.0" />
<PackageVersion Include="xunit.runner.visualstudio" Version="2.8.0" />
<PackageVersion Include="coverlet.collector" Version="6.0.2" />
</ItemGroup>
<ItemGroup Label="Github Dependencies">
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="1.1.1" />
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="8.0.0" />
</ItemGroup>
</Project>
2 changes: 1 addition & 1 deletion global.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"projects": ["src", "test", "samples"],
"sdk": {
"version": "6.0.000",
"version": "8.0.000",
"rollForward": "latestMajor"
}
}
13 changes: 11 additions & 2 deletions src/Acheve.TestHost/Extensions/TestServerExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using Acheve.TestHost.Routing;
using Microsoft.AspNetCore.Http;
using Microsoft.Net.Http.Headers;
using System;
using System.IO;
using System.Linq.Expressions;
using System.Net.Mime;
using System.Text;

namespace Microsoft.AspNetCore.TestHost;
Expand Down Expand Up @@ -48,11 +50,18 @@ public static RequestBuilder CreateHttpApiRequest<TController, TActionResponse>(
where TController : class
=> UriDiscover.CreateHttpApiRequest<TController>(server, actionSelector, tokenValues, contentOptions);

public static IFormFile GivenFile(this TestServer _, string parameterName = "file", string filename = "test.txt", string content = "test")
public static IFormFile GivenFile(this TestServer _, string parameterName = "file", string filename = "test.txt", string content = "test", string contentType = MediaTypeNames.Text.Plain)
{
var stream = new MemoryStream(Encoding.UTF8.GetBytes(content));

IFormFile file = new FormFile(stream, 0, stream.Length, parameterName, filename);
IFormFile file = new FormFile(stream, 0, stream.Length, parameterName, filename)
{
Headers = new HeaderDictionary()
{
[HeaderNames.ContentType] = contentType
},
ContentType = contentType
};

return file;
}
Expand Down
6 changes: 5 additions & 1 deletion src/Acheve.TestHost/Extensions/TypeExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@ internal static bool IsPrimitiveType(this Type typeToInspect)

internal static bool IsDateTime(this Type typeToInspect)
{
return typeToInspect == typeof(DateTime) || typeToInspect == typeof(DateTimeOffset);
return typeToInspect == typeof(DateTime) ||
typeToInspect == typeof(DateTimeOffset) ||
typeToInspect == typeof(DateOnly) ||
typeToInspect == typeof(TimeSpan) ||
typeToInspect == typeof(TimeOnly);
}

internal static bool IsEnumerable(this Type typeToInspect)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
using System;
using System.Collections;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;

namespace Microsoft.AspNetCore.TestHost;
Expand Down Expand Up @@ -45,13 +45,13 @@ private void AddToMultipartFormDataContent(MultipartFormDataContent multipartCon
case CancellationToken:
break;
case IFormFile file:
using (var ms = new MemoryStream())
{
file.CopyTo(ms);
var fileContent = new ByteArrayContent(ms.ToArray());
var fileContent = new StreamContent(file.OpenReadStream());
if (!string.IsNullOrEmpty(file.ContentType))
fileContent.Headers.ContentType = new MediaTypeHeaderValue(file.ContentType);
if (!string.IsNullOrEmpty(file.ContentDisposition))
fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue(file.ContentDisposition);

multipartContent.Add(fileContent, file.Name, file.FileName);
}
multipartContent.Add(fileContent, file.Name, file.FileName);
break;
case object when data.GetType().IsPrimitiveType():
multipartContent.Add(new StringContent(PrimitiveValueToString(data)), propertyName);
Expand Down
129 changes: 100 additions & 29 deletions src/Acheve.TestHost/Routing/TestServerAction.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using System;
using System.Collections.Generic;
using System.Linq;
Expand All @@ -23,29 +24,7 @@ public TestServerAction(MethodInfo methodInfo)
public void AddArgument(int order, Expression expression, bool activeBodyApiController)
{
var argument = MethodInfo.GetParameters()[order];
var isFromBody = argument.GetCustomAttributes<FromBodyAttribute>().Any();
var isFromForm = argument.GetCustomAttributes<FromFormAttribute>().Any();
var isFromHeader = argument.GetCustomAttributes<FromHeaderAttribute>().Any();
var isFromRoute = argument.GetCustomAttributes<FromRouteAttribute>().Any();

bool isPrimitive = argument.ParameterType.IsPrimitiveType();
bool hasNoAttributes = !isFromBody && !isFromForm && !isFromHeader && !isFromRoute;

if (activeBodyApiController && hasNoAttributes && !isPrimitive)
{
isFromBody = true;
}

if (argument.ParameterType == typeof(System.Threading.CancellationToken))
{
isFromBody = isFromForm = isFromHeader = false;
}

if (argument.ParameterType == typeof(IFormFile))
{
isFromForm = true;
isFromBody = isFromHeader = false;
}
var (fromType, canBeObjectWithMultipleFroms, isNeverBind) = GetIsFrom(argument, activeBodyApiController, value => value.ParameterType, value => value.GetCustomAttributes());

if (!ArgumentValues.ContainsKey(order))
{
Expand All @@ -55,7 +34,7 @@ public void AddArgument(int order, Expression expression, bool activeBodyApiCont

if (expressionValue != null)
{
ArgumentValues.Add(order, new TestServerArgument(expressionValue.ToString(), isFromBody, isFromForm, isFromHeader, argument.Name));
ArgumentValues.Add(order, new TestServerArgument(expressionValue.ToString(), fromType, isNeverBind, argument.ParameterType, argument.Name));
}
}
else
Expand All @@ -64,7 +43,7 @@ public void AddArgument(int order, Expression expression, bool activeBodyApiCont
{
case ConstantExpression constant:
{
ArgumentValues.Add(order, new TestServerArgument(constant.Value?.ToString(), isFromBody, isFromForm, isFromHeader, argument.Name));
ArgumentValues.Add(order, new TestServerArgument(constant.Value?.ToString(), fromType, isNeverBind, argument.ParameterType, argument.Name));
}
break;

Expand All @@ -73,15 +52,14 @@ public void AddArgument(int order, Expression expression, bool activeBodyApiCont
var instance = Expression.Lambda(member)
.Compile()
.DynamicInvoke();

ArgumentValues.Add(order, new TestServerArgument(instance, isFromBody, isFromForm, isFromHeader, argument.Name));
AddArgumentValues(order, instance, argument.Name, fromType, isNeverBind, argument.ParameterType, canBeObjectWithMultipleFroms);
}
break;

case MethodCallExpression method:
{
var instance = Expression.Lambda(method).Compile().DynamicInvoke();
ArgumentValues.Add(order, new TestServerArgument(instance, isFromBody, isFromForm, isFromHeader, argument.Name));
AddArgumentValues(order, instance, argument.Name, fromType, isNeverBind, argument.ParameterType, canBeObjectWithMultipleFroms);
}
break;

Expand All @@ -91,6 +69,99 @@ public void AddArgument(int order, Expression expression, bool activeBodyApiCont
}
}

private bool IsNullable(Type type) => Nullable.GetUnderlyingType(type) != null;
private static bool IsNullable(Type type) => Nullable.GetUnderlyingType(type) != null;

private void AddArgumentValues(int order, object value, string argumentName,
TestServerArgumentFromType fromType, bool isNeverBind, Type type, bool canBeObjectWithMultipleFroms)
{
if (canBeObjectWithMultipleFroms)
{
var properties = value.GetType().GetProperties();
var isObjectWithMultipleFroms = properties
.SelectMany(p => p.GetCustomAttributes())
.Select(a => a.GetType())
.Any(a => a == typeof(FromBodyAttribute) || a == typeof(FromRouteAttribute) || a == typeof(FromHeaderAttribute) || a == typeof(FromQueryAttribute));
if (isObjectWithMultipleFroms)
{
foreach (var property in properties)
{
(fromType, canBeObjectWithMultipleFroms, var isNeverBindProp) = GetIsFrom(property, false, value => value.PropertyType, value => value.GetCustomAttributes());
argumentName = property.Name;
var propertyValue = property.GetValue(value);

ArgumentValues.Add(order, new TestServerArgument(propertyValue, fromType, isNeverBind || isNeverBindProp, property.PropertyType, argumentName));
order++;
}

return;
}
}

ArgumentValues.Add(order, new TestServerArgument(value, fromType, isNeverBind, type, argumentName));
}

private (TestServerArgumentFromType fromType, bool canBeObjectWithMultipleFroms, bool neverBind) GetIsFrom<T>(T value, bool activeBodyApiController, Func<T, Type> getTypeFunc, Func<T, IEnumerable<Attribute>> getAttributesFunc)
{
var fromType = TestServerArgumentFromType.None;
var type = getTypeFunc(value);
var attributes = getAttributesFunc(value);

var isFromBody = attributes.Any(a => a is FromBodyAttribute);
var isFromForm = attributes.Any(a => a is FromFormAttribute);
var isFromHeader = attributes.Any(a => a is FromHeaderAttribute);
var isFromRoute = attributes.Any(a => a is FromRouteAttribute);
var isFromQuery = attributes.Any(a => a is FromQueryAttribute);
var isBindNever = attributes.Any(a => a is BindNeverAttribute);

if (isFromBody)
{
fromType |= TestServerArgumentFromType.Body;
}
if (isFromForm)
{
fromType |= TestServerArgumentFromType.Form;
}
if (isFromHeader)
{
fromType |= TestServerArgumentFromType.Header;
}
if (isFromRoute)
{
fromType |= TestServerArgumentFromType.Route;
}
if (isFromQuery)
{
fromType |= TestServerArgumentFromType.Query;
}

bool isPrimitive = type.IsPrimitiveType();
bool hasNoAttributes = fromType == TestServerArgumentFromType.None;
bool canBeObjectWithMultipleFroms = false;
if (hasNoAttributes && !isPrimitive)
{
#if NET8_0_OR_GREATER
canBeObjectWithMultipleFroms = MethodInfo.GetParameters().Length == 1;
#else
canBeObjectWithMultipleFroms = false;
#endif

if (activeBodyApiController)
{
fromType = TestServerArgumentFromType.Body;
}
}

if (type == typeof(System.Threading.CancellationToken))
{
fromType = TestServerArgumentFromType.None;
}

if (type == typeof(IFormFile))
{
fromType = TestServerArgumentFromType.Form;
}

return (fromType, canBeObjectWithMultipleFroms, isBindNever);
}
}
}
Loading
Loading