jprochazk / garde

A powerful validation library for Rust
Apache License 2.0
479 stars 28 forks source link

Explicit handling of whitespace with length #132

Open MLNW opened 1 month ago

MLNW commented 1 month ago

I just started using garde and hit a road block with the length validation. I want to ensure a string is neither too short nor too long. That is simple. Until whitespace is involved.

This is my basic new type struct:

#[derive(Validate)]
#[garde(transparent)]
pub struct UserName(#[garde(length(graphemes, min = 3, max = 256))] String);

I have these two tests for the scenario:

    #[test]
    fn whitespace_only_names_are_rejected() {
        let name = "     \t\t\t".to_string();

        let result = UserName::new(name);

        assert_err!(&result);
        assert_eq!("value must not be blank\n", result.unwrap_err().to_string());
    }

    #[test]
    fn empty_string_is_rejected() {
        let name = "".to_string();

        let result = TenantName::new(name);

        assert_err!(&result);
        assert_eq!("length is lower than 3\n", result.unwrap_err().to_string());
    }

The first test fails with:

assertion failed, expected Err(..), got Ok(UserName("     \t\t\t")) 

Okay, the provided string does have a length within the specified range. So I implemented a custom validator:

pub fn is_not_blank(value: &str, _context: &()) -> garde::Result {
    if value.trim().is_empty() {
        return Err(garde::Error::new("value must not be blank"));
    }
    Ok(())
}

#[derive(Validate)]
#[garde(transparent)]
pub struct UserName(#[garde(custom(is_not_blank), length(graphemes, min = 3, max = 256))] String);

Now the second test fails with:

 assertion `left == right` failed
   left: "length is lower than 3\n"
  right: "value must not be blank\nlength is lower than 3\n"

It would be great if there was a way to explicitly handle white space in the length check or have one validation supersede another. In this case for example the string is blank so it should only report that right?

jprochazk commented 1 month ago

garde applies all validations and aggregates all failures in one report. You're using length(graphemes), so it's correctly failing in the first test.

There is an issue open for a mode that would stop on the first failure #1

MLNW commented 1 month ago

Your response makes sense. Would it be possible to include an option to treat surrounding whitespace as zero length in the length check? Then one wouldn't have to implement a custom validation for it.

Being able to stop early would also be appreciated.

jprochazk commented 1 month ago

Would it be possible to include an option to treat surrounding whitespace as zero length in the length check?

I think this is better handled either by rejecting the whitespace using client-side validation, or using a custom validator as you have done. garde is not really intended for use cases where you need to modify the data in some way before validating it.