diff options
| author | Vincent Prouillet | 2019-05-01 20:45:08 +0200 | 
|---|---|---|
| committer | GitHub | 2019-05-01 20:45:08 +0200 | 
| commit | 0a8e454014edf415513a76fc060482503b9814fb (patch) | |
| tree | 3e4d3d37c20aea45d8e74271863a6979c092100e | |
| parent | f33a34c6ed2d76ce6569a6bc40517ce9a69271d3 (diff) | |
| parent | 6e8effdaa2b47f4056a00d301a9e7a5a1a2fd8dc (diff) | |
| download | validator-0a8e454014edf415513a76fc060482503b9814fb.tar.bz2 | |
Merge pull request #71 from cazgp/feature/range-min-or-max
Issue #69: Change `range` to require only one arg
| -rw-r--r-- | README.md | 4 | ||||
| -rw-r--r-- | validator/src/validation/mod.rs | 4 | ||||
| -rw-r--r-- | validator/src/validation/range.rs | 44 | ||||
| -rw-r--r-- | validator_derive/src/lit.rs | 7 | ||||
| -rw-r--r-- | validator_derive/src/quoting.rs | 21 | ||||
| -rw-r--r-- | validator_derive/src/validation.rs | 43 | ||||
| -rw-r--r-- | validator_derive/tests/compile-fail/range/missing_arg.rs | 15 | ||||
| -rw-r--r-- | validator_derive/tests/compile-fail/range/no_args.rs | 2 | ||||
| -rw-r--r-- | validator_derive/tests/run-pass/range.rs | 4 | 
9 files changed, 93 insertions, 51 deletions
| @@ -179,14 +179,16 @@ Examples:  ```  ### range -Tests whether a number is in the given range. `range` takes 2 number arguments: `min` and `max`. +Tests whether a number is in the given range. `range` takes between 1 and 2 number arguments: `min` and `max`.  Examples:  ```rust  #[validate(range(min = "1", max = "10"))] +#[validate(range(min = "1"))]  #[validate(range(min = "1", max = "10.8"))]  #[validate(range(min = "1.1", max = "10.8"))] +#[validate(range(max = "10.8"))]  ```  ### must_match diff --git a/validator/src/validation/mod.rs b/validator/src/validation/mod.rs index 065b27e..95d9b79 100644 --- a/validator/src/validation/mod.rs +++ b/validator/src/validation/mod.rs @@ -27,8 +27,8 @@ pub enum Validator {      // No implementation in this crate, it's all in validator_derive      Regex(String),      Range { -        min: f64, -        max: f64, +        min: Option<f64>, +        max: Option<f64>,      },      // Any value that impl HasLen can be validated with Length      Length { diff --git a/validator/src/validation/range.rs b/validator/src/validation/range.rs index c643762..a89f707 100644 --- a/validator/src/validation/range.rs +++ b/validator/src/validation/range.rs @@ -5,7 +5,21 @@ use validation::Validator;  /// TODO: see if can be generic over the number type  pub fn validate_range(range: Validator, val: f64) -> bool {      match range { -        Validator::Range { min, max } => val >= min && val <= max, +        Validator::Range { min, max } => { +            if let Some(m) = min { +                if val < m { +                    return false; +                } +            } + +            if let Some(m) = max { +                if val > m { +                    return false; +                } +            } + +            true +        }          _ => unreachable!(),      }  } @@ -16,13 +30,37 @@ mod tests {      #[test]      fn test_validate_range_ok() { -        let validator = Validator::Range { min: 0.0, max: 10.0 }; +        let validator = Validator::Range { min: Some(0.0), max: Some(10.0) };          assert_eq!(validate_range(validator, 1 as f64), true);      }      #[test]      fn test_validate_range_fail() { -        let validator = Validator::Range { min: 0.0, max: 10.0 }; +        let validator = Validator::Range { min: Some(0.0), max: Some(10.0) };          assert_eq!(validate_range(validator, 20 as f64), false);      } + +    #[test] +    fn test_validate_range_min_only_valid() { +        let validator = Validator::Range { min: Some(10.0), max: None }; +        assert_eq!(validate_range(validator, 10.0), true); +    } + +    #[test] +    fn test_validate_range_min_only_invalid() { +        let validator = Validator::Range { min: Some(10.0), max: None }; +        assert_eq!(validate_range(validator, 9.0), false); +    } + +    #[test] +    fn test_validate_range_max_only_valid() { +        let validator = Validator::Range { min: None, max: Some(10.0) }; +        assert_eq!(validate_range(validator, 10.0), true); +    } + +    #[test] +    fn test_validate_range_max_only_invalid() { +        let validator = Validator::Range { min: None, max: Some(10.0) }; +        assert_eq!(validate_range(validator, 11.0), false); +    }  } diff --git a/validator_derive/src/lit.rs b/validator_derive/src/lit.rs index 14e3f56..de0e21e 100644 --- a/validator_derive/src/lit.rs +++ b/validator_derive/src/lit.rs @@ -46,3 +46,10 @@ pub fn option_u64_to_tokens(opt: Option<u64>) -> proc_macro2::TokenStream {          None => quote!(::std::option::Option::None),      }  } + +pub fn option_f64_to_tokens(opt: Option<f64>) -> proc_macro2::TokenStream { +    match opt { +        Some(ref t) => quote!(::std::option::Option::Some(#t)), +        None => quote!(::std::option::Option::None), +    } +} diff --git a/validator_derive/src/quoting.rs b/validator_derive/src/quoting.rs index f94d8fc..fa97623 100644 --- a/validator_derive/src/quoting.rs +++ b/validator_derive/src/quoting.rs @@ -3,7 +3,7 @@ use syn;  use validator::Validator;  use asserts::{COW_TYPE, NUMBER_TYPES}; -use lit::option_u64_to_tokens; +use lit::{option_f64_to_tokens, option_u64_to_tokens};  use validation::{FieldValidation, SchemaValidation};  /// Pass around all the information needed for creating a validation @@ -183,12 +183,25 @@ pub fn quote_range_validation(      let quoted_ident = field_quoter.quote_validator_param();      if let Validator::Range { min, max } = validation.validator { +        // Can't interpolate None +        let min_tokens = option_f64_to_tokens(min); +        let max_tokens = option_f64_to_tokens(max); + +        let min_err_param_quoted = if let Some(v) = min { +            quote!(err.add_param(::std::borrow::Cow::from("min"), &#v);) +        } else { +            quote!() +        }; +        let max_err_param_quoted = if let Some(v) = max { +            quote!(err.add_param(::std::borrow::Cow::from("max"), &#v);) +        } else { +            quote!() +        }; +          let quoted_error = quote_error(&validation); -        let min_err_param_quoted = quote!(err.add_param(::std::borrow::Cow::from("min"), &#min);); -        let max_err_param_quoted = quote!(err.add_param(::std::borrow::Cow::from("max"), &#max););          let quoted = quote!(              if !::validator::validate_range( -                ::validator::Validator::Range {min: #min, max: #max}, +                ::validator::Validator::Range {min: #min_tokens, max: #max_tokens},                  #quoted_ident as f64              ) {                  #quoted_error diff --git a/validator_derive/src/validation.rs b/validator_derive/src/validation.rs index a9762db..d9ad5a5 100644 --- a/validator_derive/src/validation.rs +++ b/validator_derive/src/validation.rs @@ -95,8 +95,8 @@ pub fn extract_range_validation(      field: String,      meta_items: &Vec<syn::NestedMeta>,  ) -> FieldValidation { -    let mut min = 0.0; -    let mut max = 0.0; +    let mut min = None; +    let mut max = None;      let (message, code) = extract_message_and_code("range", &field, meta_items); @@ -104,45 +104,38 @@ pub fn extract_range_validation(          panic!("Invalid attribute #[validate] on field `{}`: {}", field, msg);      }; -    // whether it has both `min` and `max` -    let mut has_min = false; -    let mut has_max = false; -      for meta_item in meta_items {          match *meta_item {              syn::NestedMeta::Meta(ref item) => match *item { -                syn::Meta::NameValue(syn::MetaNameValue { ref ident, ref lit, .. }) => match ident -                    .to_string() -                    .as_ref() -                { -                    "message" | "code" => continue, -                    "min" => { -                        min = match lit_to_float(lit) { -                                Some(s) => s, +                syn::Meta::NameValue(syn::MetaNameValue { ref ident, ref lit, .. }) => { +                    match ident.to_string().as_ref() { +                        "message" | "code" => continue, +                        "min" => { +                            min = match lit_to_float(lit) { +                                Some(s) => Some(s),                                  None => error("invalid argument type for `min` of `range` validator: only integers are allowed")                              }; -                        has_min = true; -                    } -                    "max" => { -                        max = match lit_to_float(lit) { -                                Some(s) => s, +                        } +                        "max" => { +                            max = match lit_to_float(lit) { +                                Some(s) => Some(s),                                  None => error("invalid argument type for `max` of `range` validator: only integers are allowed")                              }; -                        has_max = true; -                    } -                    v => error(&format!( +                        } +                        v => error(&format!(                          "unknown argument `{}` for validator `range` (it only has `min`, `max`)",                          v                      )), -                }, +                    } +                }                  _ => panic!("unexpected item {:?} while parsing `range` validator", item),              },              _ => unreachable!(),          }      } -    if !has_min || !has_max { -        error("Validator `range` requires 2 arguments: `min` and `max`"); +    if !min.is_some() && !max.is_some() { +        error("Validator `range` requires at least 1 argument out of `min` and `max`");      }      let validator = Validator::Range { min, max }; diff --git a/validator_derive/tests/compile-fail/range/missing_arg.rs b/validator_derive/tests/compile-fail/range/missing_arg.rs deleted file mode 100644 index 3aed1f0..0000000 --- a/validator_derive/tests/compile-fail/range/missing_arg.rs +++ /dev/null @@ -1,15 +0,0 @@ -#![feature(attr_literals)] - -#[macro_use] extern crate validator_derive; -extern crate validator; -use validator::Validate; - -#[derive(Validate)] -//~^ ERROR: proc-macro derive panicked -//~^^ HELP: Invalid attribute #[validate] on field `s`: Validator `range` requires 2 arguments: `min` and `max` -struct Test { -    #[validate(range(min = 2.0))] -    s: i32, -} - -fn main() {} diff --git a/validator_derive/tests/compile-fail/range/no_args.rs b/validator_derive/tests/compile-fail/range/no_args.rs index c2bdd03..b097b0a 100644 --- a/validator_derive/tests/compile-fail/range/no_args.rs +++ b/validator_derive/tests/compile-fail/range/no_args.rs @@ -4,7 +4,7 @@ use validator::Validate;  #[derive(Validate)]  //~^ ERROR: proc-macro derive panicked -//~^^ HELP: Invalid attribute #[validate] on field `s`: Validator `range` requires 2 arguments: `min` and `max` +//~^^ HELP: Invalid attribute #[validate] on field `s`: Validator `range` requires at least 1 argument out of `min` and `max`  struct Test {      #[validate(range())]      s: i32, diff --git a/validator_derive/tests/run-pass/range.rs b/validator_derive/tests/run-pass/range.rs index e35f3df..520dd64 100644 --- a/validator_derive/tests/run-pass/range.rs +++ b/validator_derive/tests/run-pass/range.rs @@ -24,6 +24,10 @@ struct Test {      s8: u8,      #[validate(range(min = 18.0, max = 22))]      s9: Option<u8>, +    #[validate(range(min = 18.0))] +    s10: Option<u8>, +    #[validate(range(max = 18.0))] +    s11: Option<u8>,  }  fn main() {} | 
