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

Chain rule not working when NotEmpty and Null are together with When conditions #892

Closed
renatogbp opened this issue Sep 4, 2018 · 3 comments

Comments

@renatogbp
Copy link

System Details

  • FluentValidation version: FluentValidation.AspNetCore (8.0.0)
  • Web Framework version ASP.NET Core 2.1

Issue Description

I got a really interesting behavior. I have the two test cases below:

[Fact]
public void Ctor_WhenNeverIsTrueAndAfterOcurrenceIsNotNull_HasError()
{
    // arrange
    var reccurenceEnd = new RecurrenceEnd()
    {
         IsNever = true,
         AfterOccurence = 1
     };

     // act
     var validator = GetValidator();

     // assert
     validator.ShouldHaveValidationErrorFor(p => p.AfterOccurence, reccurenceEnd);
}

[Fact]
public void Ctor_WhenNeverIsFalseAndAfterOccurenceIsNullAndByDateIsNull_HasError()
{
    // arrange
    var reccurenceEnd = new RecurrenceEnd()
    {
        IsNever = false,
        AfterOccurence = null,
        ByDate = null
    };

    // act
    var validator = GetValidator();

    // assert
    validator.ShouldHaveValidationErrorFor(p => p.AfterOccurence, reccurenceEnd);
}

private static RecurrenceEndValidator GetValidator()
{
    return new RecurrenceEndValidator();
}

On my validator, if I have the following, the first test fails and the second passes. If I change the order of the rules, the first test passes and the second fails.

RuleFor(dto => dto.AfterOccurence)
    .Cascade(CascadeMode.StopOnFirstFailure)
    .Null()
        .When(p => p.IsNever == true)
    .NotEmpty()
        .When(p => p.IsNever == false && p.ByDate == null);

If I change my validator to the following, both tests pass.

RuleFor(dto => dto.AfterOccurence)
    .Null()
        .When(p => p.IsNever);
RuleFor(dto => dto.AfterOccurence)
    .NotEmpty()
        .When(p => p.IsNever == false && p.ByDate == null);

My ReccurenceEnd Class is the follow:

using System;

public class RecurrenceEnd
{
    public bool IsNever { get; set; }

    public int? AfterOccurence { get; set; }

    public DateTime? ByDate { get; set; }
}
@JeremySkinner
Copy link
Member

JeremySkinner commented Sep 4, 2018

Hi, this is related to you use of the When condition. By default, a When condition applies to all previous validators in the same RuleFor call, so when you use a single call to RuleFor, you’re essentially doubling up on conditions.

You should either use separate calls to RuleFor (as you have in your second example), or use the other overload of When that allows you to specify ApplyConditionTo.CurrentValidator

@renatogbp
Copy link
Author

Thanks @JeremySkinner, now it make senses.
Can you give me an example about how I could use the ApplyConditionTo.CurrentValidator in this case, please?

@JeremySkinner
Copy link
Member

It's an enum value - you can just pass it as the second argument to When:

RuleFor(dto => dto.AfterOccurence)
    .Cascade(CascadeMode.StopOnFirstFailure)
    .Null()
        .When(p => p.IsNever == true)
    .NotEmpty()
        .When(p => p.IsNever == false && p.ByDate == null, ApplyConditionTo.CurrentValidator);

@lock lock bot locked and limited conversation to collaborators Sep 18, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants