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

Fix enumerable not getting IServiceProvider #62

Merged
merged 1 commit into from
Apr 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions global.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"sdk": {
"version": "7.0.100",
"rollForward": "feature"
"version": "8.0.100",
"rollForward": "latestFeature"
}
}
8 changes: 8 additions & 0 deletions nuget.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<!--To inherit the global NuGet package sources remove the <clear/> line below -->
<clear />
<add key="nuget" value="https://api.nuget.org/v3/index.json" />
</packageSources>
</configuration>
2 changes: 1 addition & 1 deletion src/Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project>

<PropertyGroup>
<VersionPrefix>0.9.0</VersionPrefix>
<VersionPrefix>0.9.1</VersionPrefix>
<!-- VersionSuffix used for local builds -->
<VersionSuffix>dev</VersionSuffix>
<!-- VersionSuffix to be used for CI builds -->
Expand Down
21 changes: 2 additions & 19 deletions src/MiniValidation/MiniValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,7 @@ private static async Task<bool> TryValidateImpl(
if (target is IEnumerable)
{
RuntimeHelpers.EnsureSufficientExecutionStack();
var task = TryValidateEnumerable(target, recurse, allowAsync, workingErrors, validatedObjects, validationResults, prefix, currentDepth);
var task = TryValidateEnumerable(target, serviceProvider, recurse, allowAsync, workingErrors, validatedObjects, validationResults, prefix, currentDepth);
ThrowIfAsyncNotAllowed(task, allowAsync);
isValid = await task.ConfigureAwait(false) && isValid;
}
Expand All @@ -434,7 +434,7 @@ private static async Task<bool> TryValidateImpl(
if (propertyDetails.IsEnumerable)
{
var thePrefix = $"{prefix}{propertyDetails.Name}";
var task = TryValidateEnumerable(propertyValue, recurse, allowAsync, workingErrors, validatedObjects, validationResults, thePrefix, currentDepth);
var task = TryValidateEnumerable(propertyValue, serviceProvider, recurse, allowAsync, workingErrors, validatedObjects, validationResults, thePrefix, currentDepth);
ThrowIfAsyncNotAllowed(task, allowAsync);
isValid = await task.ConfigureAwait(false) && isValid;
}
Expand Down Expand Up @@ -521,23 +521,6 @@ private static void ThrowIfAsyncNotAllowed(bool allowAsync)
}
}

#if NET6_0_OR_GREATER
private static async ValueTask<bool> TryValidateEnumerable(
#else
private static async Task<bool> TryValidateEnumerable(
#endif
object target,
bool recurse,
bool allowAsync,
Dictionary<string, List<string>> workingErrors,
Dictionary<object, bool?> validatedObjects,
List<ValidationResult>? validationResults,
string? prefix = null,
int currentDepth = 0)
{
return await TryValidateEnumerable(target, null, recurse, allowAsync, workingErrors, validatedObjects, validationResults, prefix, currentDepth);
}

#if NET6_0_OR_GREATER
private static async ValueTask<bool> TryValidateEnumerable(
#else
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
<TargetFrameworks Condition=" $([MSBuild]::IsOsPlatform('Windows')) ">net471;net6.0;net7.0</TargetFrameworks>
<TargetFrameworks>net6.0;net7.0;net8.0</TargetFrameworks>
<TargetFrameworks Condition=" $([MSBuild]::IsOsPlatform('Windows')) ">net471;net6.0;net7.0;net8.0</TargetFrameworks>
<LangVersion>10.0</LangVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
Expand Down
16 changes: 8 additions & 8 deletions tests/MiniValidation.UnitTests/Recursion.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public void Valid_When_Child_Invalid_And_Property_Decorated_With_SkipRecursion()
[Fact]
public void Invalid_When_Enumerable_Item_Invalid_When_Recurse_Default()
{
var thingToValidate = new List<TestType> { new TestType { Child = new TestChildType { RequiredCategory = null, MinLengthFive = "123" } } };
var thingToValidate = new List<TestType> { new() { Child = new TestChildType { RequiredCategory = null, MinLengthFive = "123" } } };

var result = MiniValidator.TryValidate(thingToValidate, out var errors);

Expand All @@ -76,7 +76,7 @@ public void Invalid_When_Enumerable_Item_Invalid_When_Recurse_Default()
[Fact]
public void Invalid_When_Enumerable_Item_Invalid_When_Recurse_True()
{
var thingToValidate = new List<TestType> { new TestType { Child = new TestChildType { RequiredCategory = null, MinLengthFive = "123" } } };
var thingToValidate = new List<TestType> { new() { Child = new TestChildType { RequiredCategory = null, MinLengthFive = "123" } } };

var result = MiniValidator.TryValidate(thingToValidate, recurse: true, out var errors);

Expand All @@ -87,7 +87,7 @@ public void Invalid_When_Enumerable_Item_Invalid_When_Recurse_True()
[Fact]
public void Valid_When_Enumerable_Item_Invalid_When_Recurse_False()
{
var thingToValidate = new List<TestType> { new TestType { Child = new TestChildType { RequiredCategory = null, MinLengthFive = "123" } } };
var thingToValidate = new List<TestType> { new() { Child = new TestChildType { RequiredCategory = null, MinLengthFive = "123" } } };

var result = MiniValidator.TryValidate(thingToValidate, recurse: false, out _);

Expand All @@ -97,7 +97,7 @@ public void Valid_When_Enumerable_Item_Invalid_When_Recurse_False()
[Fact]
public void Valid_When_Enumerable_Item_Has_Invalid_Descendant_But_Property_Decorated_With_SkipRecursion()
{
var thingToValidate = new List<TestType> { new TestType { SkippedChild = new() { RequiredCategory = null } } };
var thingToValidate = new List<TestType> { new() { SkippedChild = new() { RequiredCategory = null } } };

var result = MiniValidator.TryValidate(thingToValidate, recurse: true, out _);

Expand Down Expand Up @@ -129,8 +129,8 @@ public void Error_Message_Keys_For_Root_Enumerable_Are_Formatted_Correctly()
{
var thingToValidate = new List<TestType>
{
new TestType() ,
new TestType { RequiredName = null, TenOrMore = 5 },
new() ,
new() { RequiredName = null, TenOrMore = 5 },
};

var result = MiniValidator.TryValidate(thingToValidate, recurse: true, out var errors);
Expand Down Expand Up @@ -162,8 +162,8 @@ public void First_Error_In_Root_Enumerable_Returns_Immediately()
{
var thingToValidate = new List<TestType>
{
new TestType { RequiredName = null },
new TestType { RequiredName = null },
new() { RequiredName = null },
new() { RequiredName = null },
};

var result = MiniValidator.TryValidate(thingToValidate, recurse: true, out var errors);
Expand Down
5 changes: 5 additions & 0 deletions tests/MiniValidation.UnitTests/TestTypes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@ public IEnumerable<ValidationResult> Validate(ValidationContext validationContex
}
}

class TestClassWithEnumerable<TEnumerable>
{
public IEnumerable<TEnumerable>? Enumerable { get; set; }
}

class TestClassLevelAsyncValidatableOnlyType : IAsyncValidatableObject
{
public int TwentyOrMore { get; set; } = 20;
Expand Down
52 changes: 51 additions & 1 deletion tests/MiniValidation.UnitTests/TryValidate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ public void Validator_DisplayAttribute_Name_Used_In_Error_Message_For_Record()
[Fact]
public void List_Invalid_When_Entry_Invalid()
{
var collectionToValidate = new List<TestType> { new TestType { RequiredName = null } };
var collectionToValidate = new List<TestType> { new() { RequiredName = null } };

var result = MiniValidator.TryValidate(collectionToValidate, out var errors);

Expand Down Expand Up @@ -396,6 +396,56 @@ public async Task TryValidateAsync_With_ServiceProvider()
Assert.Equal(nameof(IServiceProvider), errors.Keys.First());
}

[Fact]
public void TryValidate_Enumerable_With_ServiceProvider()
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton<TestService>();
var serviceProvider = serviceCollection.BuildServiceProvider();

var thingToValidate = new TestClassWithEnumerable<TestClassLevelValidatableOnlyTypeWithServiceProvider>
{
Enumerable = new List<TestClassLevelValidatableOnlyTypeWithServiceProvider>
{
new()
}
};

var result = MiniValidator.TryValidate(thingToValidate, serviceProvider, out var errors);
Assert.True(result);

errors.Clear();
result = MiniValidator.TryValidate(thingToValidate, out errors);
Assert.False(result);
Assert.Equal(1, errors.Count);
Assert.Equal($"{nameof(TestClassWithEnumerable<object>.Enumerable)}.[0].{nameof(IServiceProvider)}", errors.Keys.First());
}

[Fact]
public async Task TryValidateAsync_Enumerable_With_ServiceProvider()
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton<TestService>();
var serviceProvider = serviceCollection.BuildServiceProvider();

var thingToValidate = new TestClassWithEnumerable<TestClassLevelValidatableOnlyTypeWithServiceProvider>
{
Enumerable = new List<TestClassLevelValidatableOnlyTypeWithServiceProvider>
{
new()
}
};

var (isValid, errors) = await MiniValidator.TryValidateAsync(thingToValidate, serviceProvider);
Assert.True(isValid);

errors.Clear();
(isValid, errors) = await MiniValidator.TryValidateAsync(thingToValidate);
Assert.False(isValid);
Assert.Equal(1, errors.Count);
Assert.Equal($"{nameof(TestClassWithEnumerable<object>.Enumerable)}.[0].{nameof(IServiceProvider)}", errors.Keys.First());
}

[Fact]
public async Task TryValidateAsync_With_Attribute_Attached_Via_TypeDescriptor()
{
Expand Down
2 changes: 1 addition & 1 deletion tests/MiniValidation.UnitTests/TypeDescriptorExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public static void AttachAttribute(this Type type, string propertyName, Func<Pro
// From https://stackoverflow.com/questions/12143650/how-to-add-property-level-attribute-to-the-typedescriptor-at-runtime
internal class PropertyOverridingTypeDescriptor : CustomTypeDescriptor
{
private readonly Dictionary<string, PropertyDescriptor> overridePds = new Dictionary<string, PropertyDescriptor>();
private readonly Dictionary<string, PropertyDescriptor> overridePds = new();

public PropertyOverridingTypeDescriptor(ICustomTypeDescriptor parent)
: base(parent)
Expand Down
Loading