Skip to content

Commit

Permalink
Fix enumerable not getting IServiceProvider (#62)
Browse files Browse the repository at this point in the history
- Bump to version 0.9.1 & f
- Bump to net8.0
- Use target-typed new
  • Loading branch information
DamianEdwards authored Apr 20, 2024
1 parent ce56e98 commit 612ed4a
Show file tree
Hide file tree
Showing 9 changed files with 80 additions and 34 deletions.
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

0 comments on commit 612ed4a

Please sign in to comment.