Skip to content

Commit

Permalink
Fix ChildRules with hierarchies #2165
Browse files Browse the repository at this point in the history
  • Loading branch information
JeremySkinner committed Oct 11, 2023
1 parent c28c5a4 commit a437761
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 2 deletions.
39 changes: 39 additions & 0 deletions src/FluentValidation.Tests/ChildRulesTests.cs
Expand Up @@ -20,6 +20,7 @@

namespace FluentValidation.Tests;

using System;
using System.Collections.Generic;
using Xunit;

Expand Down Expand Up @@ -121,6 +122,14 @@ public class ChildRulesTests {
result.IsValid.ShouldBeFalse();
}

[Fact]
public void Doesnt_throw_InvalidCastException() {
// See https://github.com/FluentValidation/FluentValidation/issues/2165
var validator = new RootValidator();
var result = validator.Validate(new Root { Data = new() { Value = -1 }});
result.Errors.Count.ShouldEqual(1);
}

private class RulesetChildRulesValidator : AbstractValidator<Person> {
public RulesetChildRulesValidator() {
RuleSet("testing", () => {
Expand Down Expand Up @@ -163,4 +172,34 @@ public class Baz {
}
}

public class Root {
public Bar Data {get; set;} = null;
}

public class Base {
public int Value {get; set;}
}

public class Bar : Base {
public int BarValue {get; set;}
}

public class RootValidator : AbstractValidator<Root> {
public RootValidator() {
RuleFor(x => x).ChildRules(RootRules());
}

public static Action<InlineValidator<Base>> BaseRules() {
return rules => {
rules.RuleFor(x => x.Value).NotEqual(-1);
};
}

public static Action<InlineValidator<Root>> RootRules() {
return rules => {
rules.RuleFor(x => x.Data).ChildRules(BaseRules());
};
}
}

}
2 changes: 1 addition & 1 deletion src/FluentValidation/DefaultValidatorExtensions.cs
Expand Up @@ -1204,7 +1204,7 @@ public static partial class DefaultValidatorExtensions {
public static IRuleBuilderOptions<T, TProperty> ChildRules<T, TProperty>(this IRuleBuilder<T, TProperty> ruleBuilder, Action<InlineValidator<TProperty>> action) {
if (action == null) throw new ArgumentNullException(nameof(action));
var validator = new ChildRulesContainer<TProperty>();
var parentValidator = ((RuleBuilder<T, TProperty>) ruleBuilder).ParentValidator;
var parentValidator = ((IRuleBuilderInternal<T>) ruleBuilder).ParentValidator;

string[] ruleSets;

Expand Down
6 changes: 5 additions & 1 deletion src/FluentValidation/Syntax.cs
Expand Up @@ -113,6 +113,10 @@ public interface IConditionBuilder {
void Otherwise(Action action);
}

internal interface IRuleBuilderInternal<T, out TProperty> {
internal interface IRuleBuilderInternal<T, out TProperty> : IRuleBuilderInternal<T> {
IValidationRule<T, TProperty> Rule { get; }
}

internal interface IRuleBuilderInternal<T> {
AbstractValidator<T> ParentValidator { get; }
}

0 comments on commit a437761

Please sign in to comment.