Skip to content

Commit

Permalink
Fix the issue that the ChildRules will corrupt the RuleSets of a vali…
Browse files Browse the repository at this point in the history
…dator passed to the SetValidator (#1982)
  • Loading branch information
sumtec committed Aug 6, 2022
1 parent e201af7 commit d37d15f
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 7 deletions.
5 changes: 2 additions & 3 deletions src/FluentValidation.Tests/ChainedValidationTester.cs
Expand Up @@ -114,8 +114,7 @@ public class ChainedValidationTester {
[Fact]
public void Separate_validation_on_chained_property() {
var validator = new DepartmentValidator();
var result = validator.Validate(new Department
{
var result = validator.Validate(new Department {
Manager = new Person(),
Assistant = new Person()
});
Expand Down Expand Up @@ -171,7 +170,7 @@ public class ChainedValidationTester {
var validator = new InlineValidator<Person>();
validator.RuleFor(x => x.Address).SetValidator(addressValidator, ruleSets: "ruleset1");

var result = validator.Validate(new Person {Address = new Address()});
var result = validator.Validate(new Person { Address = new Address() });
result.Errors.Count.ShouldEqual(1);
result.Errors[0].PropertyName.ShouldEqual("Address.Line1");
}
Expand Down
47 changes: 44 additions & 3 deletions src/FluentValidation.Tests/ChildRulesTests.cs
Expand Up @@ -19,6 +19,7 @@
#endregion

namespace FluentValidation.Tests {
using FluentValidation.Results;
using System.Collections.Generic;
using Xunit;

Expand All @@ -33,11 +34,13 @@ public class ChildRulesTests {
order.RuleFor(x => x.Amount).GreaterThan(0);
});

var result = validator.Validate(new Person {Orders = new List<Order> {
var result = validator.Validate(new Person {
Orders = new List<Order> {
new Order { ProductName = null, Amount = 10 },
new Order { ProductName = "foo", Amount = 0},
new Order { ProductName = "foo", Amount = 10 }
}});
}
});

result.Errors.Count.ShouldEqual(2);
result.Errors[0].PropertyName.ShouldEqual("Orders[0].ProductName");
Expand Down Expand Up @@ -71,7 +74,24 @@ public class ChildRulesTests {
result.Errors.Count.ShouldEqual(0);
}

private class RulesetChildRulesValidator : AbstractValidator<Person> {
[Fact]
public void ChildRules_works_with_SetValidator_and_RuleSet() {
var validator = new RulesetChildValidatorRulesValidator();

// If the validator inside a child rule specifies a rule set "b",
// the rules inside the rule set "b" should not be used for the validation
// if the validation context specified the ruleset "a"
var result = validator.Validate(new Person {
Orders = new List<Order> {
new Order()
}
}, options => options.IncludeRuleSets("a"));

result.Errors.Count.ShouldEqual(1);
result.Errors[0].PropertyName.ShouldEqual("Surname");
}

private class RulesetChildRulesValidator : AbstractValidator<Person> {
public RulesetChildRulesValidator() {
RuleSet("testing", () => {
RuleFor(a => a.Surname).NotEmpty();
Expand All @@ -81,5 +101,26 @@ private class RulesetChildRulesValidator : AbstractValidator<Person> {
});
}
}

private class RulesetChildValidatorRulesValidator : AbstractValidator<Person> {
public RulesetChildValidatorRulesValidator() {
RuleSet("a, b", () => {
RuleFor(x => x.Surname).NotEmpty();
RuleFor(x => x).ChildRules(child => {
child.RuleForEach(o => o.Orders).SetValidator(new RulesetOrderValidator());
});
});
}

private class RulesetOrderValidator : AbstractValidator<Order> {
public RulesetOrderValidator() {
RuleSet("b", () => {
RuleFor(o => o.ProductName).NotEmpty();
});
}
}
}

}
}

8 changes: 7 additions & 1 deletion src/FluentValidation/DefaultValidatorExtensions.cs
Expand Up @@ -1169,8 +1169,14 @@ 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 InlineValidator<TProperty>();
var ruleSets = DefaultValidatorOptions.Configurable(ruleBuilder).RuleSets;
action(validator);
return ruleBuilder.SetValidator(validator, "*");
foreach(var rule in validator.Rules) {
if (rule.RuleSets == null) {
rule.RuleSets = ruleSets;
}
}
return ruleBuilder.SetValidator(validator);
}

/// <summary>
Expand Down

0 comments on commit d37d15f

Please sign in to comment.