diff options
34 files changed, 275 insertions, 193 deletions
@@ -4,11 +4,8 @@  Macros 1.1 custom derive to simplify struct validation inspired by [marshmallow](http://marshmallow.readthedocs.io/en/latest/) and  [Django validators](https://docs.djangoproject.com/en/1.10/ref/validators/). -It relies on the `proc_macro` feature which is stable since Rust 1.15. - -By default all args to a `validate` must be strings if you are using stable. -However, if you are using nightly, you can also activate the `attr_literals` feature to be able to use int, float and boolean as well. +It requires Rust 1.30.  A short example: @@ -31,10 +28,10 @@ struct SignupData {      phone: String,      #[validate(url)]      site: String, -    #[validate(length(min = "1"), custom = "validate_unique_username")] +    #[validate(length(min = 1), custom = "validate_unique_username")]      #[serde(rename = "firstName")]      first_name: String, -    #[validate(range(min = "18", max = "20"))] +    #[validate(range(min = 18, max = 20))]      age: u32,  } @@ -117,7 +114,7 @@ struct ContactDetails {  #[derive(Debug, Validate, Deserialize)]  struct Preference { -    #[validate(length(min = "4"))] +    #[validate(length(min = 4))]      name: String,      value: bool,  } @@ -172,21 +169,23 @@ At least one argument is required with a maximum of 2 (having `min` and `max` at  Examples:  ```rust -#[validate(length(min = "1", max = "10"))] -#[validate(length(min = "1"))] -#[validate(length(max = "10"))] -#[validate(length(equal = "10"))] +#[validate(length(min = 1, max = 10))] +#[validate(length(min = 1))] +#[validate(length(max = 10))] +#[validate(length(equal = 10))]  ```  ### 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", max = "10.8"))] -#[validate(range(min = "1.1", max = "10.8"))] +#[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 @@ -261,7 +260,7 @@ Often, some error validation can only be applied when looking at the full struct  ```rust  #[derive(Debug, Validate, Deserialize)] -#[validate(schema(function = "validate_category", skip_on_field_errors = "false"))] +#[validate(schema(function = "validate_category", skip_on_field_errors = false))]  struct CategoryData {      category: String,      name: String, @@ -298,6 +297,11 @@ For example, the following attributes all work:  ### validator +#### 0.9.0 (2019/05/xx) + +- `ValidationErrors::errors` and `ValidationErrors::field_errors` now use `&self` instead of `self` +- Move to edition 2018 +  #### 0.8.0 (2018/09/19)  - Change error type to allow use with nested validation @@ -324,6 +328,10 @@ For example, the following attributes all work:  ### validator_derive +#### 0.9.0 (2019/05/xx) + +- Use literals in macros now that it's stable -> bumping minimum Rust version to 1.30 +  #### 0.8.0 (2018/09/19)  - Allow nested validation diff --git a/validator/Cargo.toml b/validator/Cargo.toml index f107fbb..96e8104 100644 --- a/validator/Cargo.toml +++ b/validator/Cargo.toml @@ -1,12 +1,13 @@  [package]  name = "validator" -version = "0.8.0" +version = "0.9.0"  authors = ["Vincent Prouillet <prouillet.vincent@gmail.com"]  license = "MIT"  description = "Common validation functions (email, url, length, ...) and trait - to be used with `validator_derive`"  homepage = "https://github.com/Keats/validator"  repository = "https://github.com/Keats/validator"  keywords = ["validation", "api", "validator"] +edition = "2018"  [dependencies]  url = "1" diff --git a/validator/src/traits.rs b/validator/src/traits.rs index 8d0b129..cf86919 100644 --- a/validator/src/traits.rs +++ b/validator/src/traits.rs @@ -1,7 +1,7 @@  use std::borrow::Cow;  use std::collections::HashMap; -use types::ValidationErrors; +use crate::types::ValidationErrors;  /// Trait to implement if one wants to make the `length` validator  /// work for more types diff --git a/validator/src/types.rs b/validator/src/types.rs index 77033d9..09e4c7d 100644 --- a/validator/src/types.rs +++ b/validator/src/types.rs @@ -95,7 +95,8 @@ impl ValidationErrors {              .filter_map(|(i, entry)| match entry {                  Some(ValidationErrorsKind::Struct(errors)) => Some((i, errors)),                  _ => None, -            }).collect::<BTreeMap<_, _>>(); +            }) +            .collect::<BTreeMap<_, _>>();          if errors.is_empty() {              parent @@ -109,21 +110,27 @@ impl ValidationErrors {      /// Returns a map of field-level validation errors found for the struct that was validated and      /// any of it's nested structs that are tagged for validation. -    pub fn errors(self) -> HashMap<&'static str, ValidationErrorsKind> { +    pub fn errors(&self) -> &HashMap<&'static str, ValidationErrorsKind> { +        &self.0 +    } + +    /// Consume the struct, returning the validation errors found +    pub fn into_errors(self) -> HashMap<&'static str, ValidationErrorsKind> {          self.0      }      /// Returns a map of only field-level validation errors found for the struct that was validated. -    pub fn field_errors(self) -> HashMap<&'static str, Vec<ValidationError>> { +    pub fn field_errors(&self) -> HashMap<&str, &Vec<ValidationError>> {          self.0 -            .into_iter() +            .iter()              .filter_map(|(k, v)| {                  if let ValidationErrorsKind::Field(errors) = v { -                    Some((k, errors)) +                    Some((*k, errors))                  } else {                      None                  } -            }).collect() +            }) +            .collect::<HashMap<_, _>>()      }      pub fn add(&mut self, field: &'static str, error: ValidationError) { diff --git a/validator/src/validation/cards.rs b/validator/src/validation/cards.rs index 19d91ab..8c97694 100644 --- a/validator/src/validation/cards.rs +++ b/validator/src/validation/cards.rs @@ -1,6 +1,6 @@  use std::borrow::Cow; -use card_validate::Validate as CardValidate; +use crate::card_validate::Validate as CardValidate;  pub fn validate_credit_card<'a, T>(card: T) -> bool  where diff --git a/validator/src/validation/contains.rs b/validator/src/validation/contains.rs index 8c7b297..ff5d8f2 100644 --- a/validator/src/validation/contains.rs +++ b/validator/src/validation/contains.rs @@ -1,4 +1,4 @@ -use traits::Contains; +use crate::traits::Contains;  /// Validates whether the value contains the needle  /// The value needs to implement the Contains trait, which is implement on String, str and Hashmap<String> diff --git a/validator/src/validation/email.rs b/validator/src/validation/email.rs index b0b49a3..6ea2fae 100644 --- a/validator/src/validation/email.rs +++ b/validator/src/validation/email.rs @@ -2,7 +2,7 @@ use idna::domain_to_ascii;  use regex::Regex;  use std::borrow::Cow; -use validation::ip::validate_ip; +use crate::validation::ip::validate_ip;  lazy_static! {      // Regex from the specs diff --git a/validator/src/validation/ip.rs b/validator/src/validation/ip.rs index dea4260..2026cdc 100644 --- a/validator/src/validation/ip.rs +++ b/validator/src/validation/ip.rs @@ -35,10 +35,7 @@ pub fn validate_ip<'a, T>(val: T) -> bool  where      T: Into<Cow<'a, str>>,  { -    match IpAddr::from_str(val.into().as_ref()) { -        Ok(_) => true, -        Err(_) => false, -    } +    IpAddr::from_str(val.into().as_ref()).is_ok()  }  #[cfg(test)] diff --git a/validator/src/validation/length.rs b/validator/src/validation/length.rs index 8e6a5a4..58e76ff 100644 --- a/validator/src/validation/length.rs +++ b/validator/src/validation/length.rs @@ -1,5 +1,5 @@ -use traits::HasLen; -use validation::Validator; +use crate::traits::HasLen; +use crate::validation::Validator;  /// Validates the length of the value given.  /// If the validator has `equal` set, it will ignore any `min` and `max` value. 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..a5664fa 100644 --- a/validator/src/validation/range.rs +++ b/validator/src/validation/range.rs @@ -1,11 +1,25 @@ -use validation::Validator; +use crate::validation::Validator;  /// Validates that a number is in the given range  ///  /// 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/src/validation/urls.rs b/validator/src/validation/urls.rs index 56c3390..1c46c6f 100644 --- a/validator/src/validation/urls.rs +++ b/validator/src/validation/urls.rs @@ -6,10 +6,7 @@ pub fn validate_url<'a, T>(val: T) -> bool  where      T: Into<Cow<'a, str>>,  { -    match Url::parse(val.into().as_ref()) { -        Ok(_) => true, -        Err(_) => false, -    } +    Url::parse(val.into().as_ref()).is_ok()  }  #[cfg(test)] diff --git a/validator_derive/Cargo.toml b/validator_derive/Cargo.toml index 52aad39..e8e50aa 100644 --- a/validator_derive/Cargo.toml +++ b/validator_derive/Cargo.toml @@ -1,6 +1,6 @@  [package]  name = "validator_derive" -version = "0.8.0" +version = "0.9.0"  authors = ["Vincent Prouillet <prouillet.vincent@gmail.com"]  license = "MIT"  description = "Macros 1.1 implementation of #[derive(Validate)]" @@ -19,8 +19,8 @@ card = ["validator/card"]  syn = { version = "0.15", features = ["extra-traits"] }  quote = "0.6"  proc-macro2 = "0.4" -if_chain = "0" -validator = { version = "0.8", path = "../validator"} +if_chain = "1" +validator = { version = "0.9", path = "../validator"}  regex = "1"  lazy_static = "1" diff --git a/validator_derive/src/asserts.rs b/validator_derive/src/asserts.rs index 1a8dfff..a5892a8 100644 --- a/validator_derive/src/asserts.rs +++ b/validator_derive/src/asserts.rs @@ -43,7 +43,7 @@ pub static NUMBER_TYPES: [&'static str; 36] = [      "Option<Option<f64>>",  ]; -pub fn assert_string_type(name: &str, field_type: &String) { +pub fn assert_string_type(name: &str, field_type: &str) {      if field_type != "String"          && field_type != "&str"          && !COW_TYPE.is_match(field_type) @@ -59,7 +59,7 @@ pub fn assert_string_type(name: &str, field_type: &String) {      }  } -pub fn assert_type_matches(field_name: String, field_type: &String, field_type2: Option<&String>) { +pub fn assert_type_matches(field_name: String, field_type: &str, field_type2: Option<&String>) {      if let Some(t2) = field_type2 {          if field_type != t2 {              panic!("Invalid argument for `must_match` validator of field `{}`: types of field can't match", field_name); @@ -69,7 +69,7 @@ pub fn assert_type_matches(field_name: String, field_type: &String, field_type2:      }  } -pub fn assert_has_len(field_name: String, field_type: &String) { +pub fn assert_has_len(field_name: String, field_type: &str) {      if field_type != "String"          && !field_type.starts_with("Vec<")          && !field_type.starts_with("Option<Vec<") @@ -89,8 +89,8 @@ pub fn assert_has_len(field_name: String, field_type: &String) {      }  } -pub fn assert_has_range(field_name: String, field_type: &String) { -    if !NUMBER_TYPES.contains(&field_type.as_ref()) { +pub fn assert_has_range(field_name: String, field_type: &str) { +    if !NUMBER_TYPES.contains(&field_type) {          panic!(              "Validator `range` can only be used on number types but found `{}` for field `{}`",              field_type, field_name diff --git a/validator_derive/src/lib.rs b/validator_derive/src/lib.rs index 0647a7d..f3796b4 100644 --- a/validator_derive/src/lib.rs +++ b/validator_derive/src/lib.rs @@ -420,8 +420,8 @@ fn find_original_field_name(meta_items: &Vec<&syn::NestedMeta>) -> Option<String      let mut original_name = None;      for meta_item in meta_items { -        match *meta_item { -            &syn::NestedMeta::Meta(ref item) => match *item { +        match **meta_item { +            syn::NestedMeta::Meta(ref item) => match *item {                  syn::Meta::Word(_) => continue,                  syn::Meta::NameValue(syn::MetaNameValue { ref ident, ref lit, .. }) => {                      if ident == "rename" { diff --git a/validator_derive/src/lit.rs b/validator_derive/src/lit.rs index 14e3f56..41deffc 100644 --- a/validator_derive/src/lit.rs +++ b/validator_derive/src/lit.rs @@ -11,8 +11,6 @@ pub fn lit_to_string(lit: &syn::Lit) -> Option<String> {  pub fn lit_to_int(lit: &syn::Lit) -> Option<u64> {      match *lit {          syn::Lit::Int(ref s) => Some(s.value()), -        // TODO: remove when attr_literals is stable -        syn::Lit::Str(ref s) => Some(s.value().parse::<u64>().unwrap()),          _ => None,      }  } @@ -21,8 +19,6 @@ pub fn lit_to_float(lit: &syn::Lit) -> Option<f64> {      match *lit {          syn::Lit::Float(ref s) => Some(s.value()),          syn::Lit::Int(ref s) => Some(s.value() as f64), -        // TODO: remove when attr_literals is stable -        syn::Lit::Str(ref s) => Some(s.value().parse::<f64>().unwrap()),          _ => None,      }  } @@ -30,12 +26,6 @@ pub fn lit_to_float(lit: &syn::Lit) -> Option<f64> {  pub fn lit_to_bool(lit: &syn::Lit) -> Option<bool> {      match *lit {          syn::Lit::Bool(ref s) => Some(s.value), -        // TODO: remove when attr_literals is stable -        syn::Lit::Str(ref s) => if s.value() == "true" { -            Some(true) -        } else { -            Some(false) -        },          _ => None,      }  } @@ -46,3 +36,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..b94962c 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 @@ -32,7 +32,7 @@ impl FieldQuoter {              quote!(#ident)          } else if COW_TYPE.is_match(&self._type.as_ref()) {              quote!(self.#ident.as_ref()) -        } else if self._type.starts_with("&") || NUMBER_TYPES.contains(&self._type.as_ref()) { +        } else if self._type.starts_with('&') || NUMBER_TYPES.contains(&self._type.as_ref()) {              quote!(self.#ident)          } else {              quote!(&self.#ident) @@ -92,14 +92,14 @@ impl FieldQuoter {          let field_name = &self.name;          if self._type.starts_with("Vec<") {              return quote!( -                if !::validator::ValidationErrors::has_error(&result, #field_name) { -                    let results: Vec<_> = self.#field_ident.iter().map(|#field_ident| { -                        let mut result = ::std::result::Result::Ok(()); -                        #tokens -                        result -                    }).collect(); -                    result = ::validator::ValidationErrors::merge_all(result, #field_name, results); -                }); +            if !::validator::ValidationErrors::has_error(&result, #field_name) { +                let results: Vec<_> = self.#field_ident.iter().map(|#field_ident| { +                    let mut result = ::std::result::Result::Ok(()); +                    #tokens +                    result +                }).collect(); +                result = ::validator::ValidationErrors::merge_all(result, #field_name, results); +            });          }          tokens @@ -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..5f42d7b 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_none() && max.is_none() { +        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/complex.rs b/validator_derive/tests/complex.rs index 7826a49..305b0ce 100644 --- a/validator_derive/tests/complex.rs +++ b/validator_derive/tests/complex.rs @@ -29,16 +29,16 @@ fn validate_signup(data: &SignupData) -> Result<(), ValidationError> {  }  #[derive(Debug, Validate, Deserialize)] -#[validate(schema(function = "validate_signup", skip_on_field_errors = "false"))] +#[validate(schema(function = "validate_signup", skip_on_field_errors = false))]  struct SignupData {      #[validate(email)]      mail: String,      #[validate(url)]      site: String, -    #[validate(length(min = "1"), custom = "validate_unique_username")] +    #[validate(length(min = 1), custom = "validate_unique_username")]      #[serde(rename = "firstName")]      first_name: String, -    #[validate(range(min = "18", max = "20"))] +    #[validate(range(min = 18, max = 20))]      age: u32,      #[validate]      phone: Phone, @@ -58,13 +58,13 @@ struct Phone {  struct Card {      #[validate(credit_card)]      number: String, -    #[validate(range(min = "100", max = "9999"))] +    #[validate(range(min = 100, max = 9999))]      cvv: u32,  }  #[derive(Debug, Validate, Deserialize)]  struct Preference { -    #[validate(length(min = "4"))] +    #[validate(length(min = 4))]      name: String,      value: bool,  } @@ -98,7 +98,8 @@ fn failed_validation_points_to_original_field_name() {      let res = signup.validate();      // println!("{}", serde_json::to_string(&res).unwrap());      assert!(res.is_err()); -    let errs = res.unwrap_err().errors(); +    let err = res.unwrap_err(); +    let errs = err.errors();      assert!(errs.contains_key("firstName"));      if let ValidationErrorsKind::Field(ref err) = errs["firstName"] {          assert_eq!(err.len(), 1); @@ -167,13 +168,13 @@ fn test_can_validate_option_fields_with_lifetime() {      #[derive(Debug, Validate)]      struct PutStruct<'a> { -        #[validate(length(min = "1", max = "10"))] +        #[validate(length(min = 1, max = 10))]          name: Option<&'a str>, -        #[validate(length(min = "1", max = "10"))] +        #[validate(length(min = 1, max = 10))]          address: Option<Option<&'a str>>, -        #[validate(range(min = "1", max = "100"))] +        #[validate(range(min = 1, max = 100))]          age: Option<Option<usize>>, -        #[validate(range(min = "1", max = "10"))] +        #[validate(range(min = 1, max = 10))]          range: Option<usize>,          #[validate(email)]          email: Option<&'a str>, @@ -213,17 +214,17 @@ fn test_can_validate_option_fields_without_lifetime() {      #[derive(Debug, Validate)]      struct PutStruct { -        #[validate(length(min = "1", max = "10"))] +        #[validate(length(min = 1, max = 10))]          name: Option<String>, -        #[validate(length(min = "1", max = "10"))] +        #[validate(length(min = 1, max = 10))]          address: Option<Option<String>>, -        #[validate(length(min = "1", max = "10"))] +        #[validate(length(min = 1, max = 10))]          ids: Option<Vec<usize>>, -        #[validate(length(min = "1", max = "10"))] +        #[validate(length(min = 1, max = 10))]          opt_ids: Option<Option<Vec<usize>>>, -        #[validate(range(min = "1", max = "100"))] +        #[validate(range(min = 1, max = 100))]          age: Option<Option<usize>>, -        #[validate(range(min = "1", max = "10"))] +        #[validate(range(min = 1, max = 10))]          range: Option<usize>,          #[validate(email)]          email: Option<String>, @@ -281,13 +282,13 @@ fn test_works_with_question_mark_operator() {  fn test_works_with_none_values() {      #[derive(Debug, Validate)]      struct PutStruct { -        #[validate(length(min = "1", max = "10"))] +        #[validate(length(min = 1, max = 10))]          name: Option<String>, -        #[validate(length(min = "1", max = "10"))] +        #[validate(length(min = 1, max = 10))]          address: Option<Option<String>>, -        #[validate(range(min = "1", max = "100"))] +        #[validate(range(min = 1, max = 100))]          age: Option<Option<usize>>, -        #[validate(range(min = "1", max = "10"))] +        #[validate(range(min = 1, max = 10))]          range: Option<usize>,      } @@ -304,5 +305,5 @@ where      F: FnOnce(HashMap<&'static str, ValidationErrorsKind>),  {      let errors = *errors.clone(); -    f(errors.errors()); +    f(errors.errors().clone());  } diff --git a/validator_derive/tests/contains.rs b/validator_derive/tests/contains.rs index 1fd568d..77880a5 100644 --- a/validator_derive/tests/contains.rs +++ b/validator_derive/tests/contains.rs @@ -28,7 +28,8 @@ fn value_not_containing_needle_fails_validation() {      let s = TestStruct { val: String::new() };      let res = s.validate();      assert!(res.is_err()); -    let errs = res.unwrap_err().field_errors(); +    let err = res.unwrap_err(); +    let errs = err.field_errors();      assert!(errs.contains_key("val"));      assert_eq!(errs["val"].len(), 1);      assert_eq!(errs["val"][0].code, "contains"); @@ -46,7 +47,8 @@ fn can_specify_code_for_contains() {      let s = TestStruct { val: String::new() };      let res = s.validate();      assert!(res.is_err()); -    let errs = res.unwrap_err().field_errors(); +    let err = res.unwrap_err(); +    let errs = err.field_errors();      assert!(errs.contains_key("val"));      assert_eq!(errs["val"].len(), 1);      assert_eq!(errs["val"][0].code, "oops"); @@ -62,7 +64,8 @@ fn can_specify_message_for_contains() {      let s = TestStruct { val: String::new() };      let res = s.validate();      assert!(res.is_err()); -    let errs = res.unwrap_err().field_errors(); +    let err = res.unwrap_err(); +    let errs = err.field_errors();      assert!(errs.contains_key("val"));      assert_eq!(errs["val"].len(), 1);      assert_eq!(errs["val"][0].clone().message.unwrap(), "oops"); diff --git a/validator_derive/tests/credit_card.rs b/validator_derive/tests/credit_card.rs index d212c48..ca84657 100644 --- a/validator_derive/tests/credit_card.rs +++ b/validator_derive/tests/credit_card.rs @@ -30,7 +30,8 @@ fn bad_credit_card_fails_validation() {      let s = TestStruct { val: "bob".to_string() };      let res = s.validate();      assert!(res.is_err()); -    let errs = res.unwrap_err().field_errors(); +    let err = res.unwrap_err(); +    let errs = err.field_errors();      assert!(errs.contains_key("val"));      assert_eq!(errs["val"].len(), 1);      assert_eq!(errs["val"][0].code, "credit_card"); @@ -48,7 +49,8 @@ fn can_specify_code_for_credit_card() {      let s = TestStruct { val: "bob".to_string() };      let res = s.validate();      assert!(res.is_err()); -    let errs = res.unwrap_err().field_errors(); +    let err = res.unwrap_err(); +    let errs = err.field_errors();      assert!(errs.contains_key("val"));      assert_eq!(errs["val"].len(), 1);      assert_eq!(errs["val"][0].code, "oops"); @@ -65,7 +67,8 @@ fn can_specify_message_for_credit_card() {      let s = TestStruct { val: "bob".to_string() };      let res = s.validate();      assert!(res.is_err()); -    let errs = res.unwrap_err().field_errors(); +    let err = res.unwrap_err(); +    let errs = err.field_errors();      assert!(errs.contains_key("val"));      assert_eq!(errs["val"].len(), 1);      assert_eq!(errs["val"][0].clone().message.unwrap(), "oops"); diff --git a/validator_derive/tests/custom.rs b/validator_derive/tests/custom.rs index c13853d..d39cbbe 100644 --- a/validator_derive/tests/custom.rs +++ b/validator_derive/tests/custom.rs @@ -36,7 +36,8 @@ fn can_fail_custom_fn_validation() {      let s = TestStruct { val: String::new() };      let res = s.validate();      assert!(res.is_err()); -    let errs = res.unwrap_err().field_errors(); +    let err = res.unwrap_err(); +    let errs = err.field_errors();      assert!(errs.contains_key("val"));      assert_eq!(errs["val"].len(), 1);      assert_eq!(errs["val"][0].code, "meh"); @@ -53,7 +54,8 @@ fn can_specify_message_for_custom_fn() {      let s = TestStruct { val: String::new() };      let res = s.validate();      assert!(res.is_err()); -    let errs = res.unwrap_err().field_errors(); +    let err = res.unwrap_err(); +    let errs = err.field_errors();      assert!(errs.contains_key("val"));      assert_eq!(errs["val"].len(), 1);      assert_eq!(errs["val"][0].clone().message.unwrap(), "oops"); diff --git a/validator_derive/tests/email.rs b/validator_derive/tests/email.rs index 665f0da..3c3f499 100644 --- a/validator_derive/tests/email.rs +++ b/validator_derive/tests/email.rs @@ -28,7 +28,8 @@ fn bad_email_fails_validation() {      let s = TestStruct { val: "bob".to_string() };      let res = s.validate();      assert!(res.is_err()); -    let errs = res.unwrap_err().field_errors(); +    let err = res.unwrap_err(); +    let errs = err.field_errors();      assert!(errs.contains_key("val"));      assert_eq!(errs["val"].len(), 1);      assert_eq!(errs["val"][0].code, "email"); @@ -45,7 +46,8 @@ fn can_specify_code_for_email() {      let s = TestStruct { val: "bob".to_string() };      let res = s.validate();      assert!(res.is_err()); -    let errs = res.unwrap_err().field_errors(); +    let err = res.unwrap_err(); +    let errs = err.field_errors();      assert!(errs.contains_key("val"));      assert_eq!(errs["val"].len(), 1);      assert_eq!(errs["val"][0].code, "oops"); @@ -61,7 +63,8 @@ fn can_specify_message_for_email() {      let s = TestStruct { val: "bob".to_string() };      let res = s.validate();      assert!(res.is_err()); -    let errs = res.unwrap_err().field_errors(); +    let err = res.unwrap_err(); +    let errs = err.field_errors();      assert!(errs.contains_key("val"));      assert_eq!(errs["val"].len(), 1);      assert_eq!(errs["val"][0].clone().message.unwrap(), "oops"); diff --git a/validator_derive/tests/length.rs b/validator_derive/tests/length.rs index 6ad6272..df4a87c 100644 --- a/validator_derive/tests/length.rs +++ b/validator_derive/tests/length.rs @@ -8,7 +8,7 @@ use validator::Validate;  fn can_validate_length_ok() {      #[derive(Debug, Validate)]      struct TestStruct { -        #[validate(length(min = "5", max = "10"))] +        #[validate(length(min = 5, max = 10))]          val: String,      } @@ -21,14 +21,15 @@ fn can_validate_length_ok() {  fn value_out_of_length_fails_validation() {      #[derive(Debug, Validate)]      struct TestStruct { -        #[validate(length(min = "5", max = "10"))] +        #[validate(length(min = 5, max = 10))]          val: String,      }      let s = TestStruct { val: String::new() };      let res = s.validate();      assert!(res.is_err()); -    let errs = res.unwrap_err().field_errors(); +    let err = res.unwrap_err(); +    let errs = err.field_errors();      assert!(errs.contains_key("val"));      assert_eq!(errs["val"].len(), 1);      assert_eq!(errs["val"][0].code, "length"); @@ -41,13 +42,14 @@ fn value_out_of_length_fails_validation() {  fn can_specify_code_for_length() {      #[derive(Debug, Validate)]      struct TestStruct { -        #[validate(length(min = "5", max = "10", code = "oops"))] +        #[validate(length(min = 5, max = 10, code = "oops"))]          val: String,      }      let s = TestStruct { val: String::new() };      let res = s.validate();      assert!(res.is_err()); -    let errs = res.unwrap_err().field_errors(); +    let err = res.unwrap_err(); +    let errs = err.field_errors();      assert!(errs.contains_key("val"));      assert_eq!(errs["val"].len(), 1);      assert_eq!(errs["val"][0].code, "oops"); @@ -57,13 +59,14 @@ fn can_specify_code_for_length() {  fn can_specify_message_for_length() {      #[derive(Debug, Validate)]      struct TestStruct { -        #[validate(length(min = "5", max = "10", message = "oops"))] +        #[validate(length(min = 5, max = 10, message = "oops"))]          val: String,      }      let s = TestStruct { val: String::new() };      let res = s.validate();      assert!(res.is_err()); -    let errs = res.unwrap_err().field_errors(); +    let err = res.unwrap_err(); +    let errs = err.field_errors();      assert!(errs.contains_key("val"));      assert_eq!(errs["val"].len(), 1);      assert_eq!(errs["val"][0].clone().message.unwrap(), "oops"); diff --git a/validator_derive/tests/must_match.rs b/validator_derive/tests/must_match.rs index 32b3016..9b7bb10 100644 --- a/validator_derive/tests/must_match.rs +++ b/validator_derive/tests/must_match.rs @@ -31,7 +31,8 @@ fn not_matching_fails_validation() {      let res = s.validate();      assert!(res.is_err()); -    let errs = res.unwrap_err().field_errors(); +    let err = res.unwrap_err(); +    let errs = err.field_errors();      assert!(errs.contains_key("val"));      assert_eq!(errs["val"].len(), 1);      assert_eq!(errs["val"][0].code, "must_match"); @@ -50,7 +51,8 @@ fn can_specify_code_for_must_match() {      let s = TestStruct { val: "bob".to_string(), val2: "bobb".to_string() };      let res = s.validate();      assert!(res.is_err()); -    let errs = res.unwrap_err().field_errors(); +    let err = res.unwrap_err(); +    let errs = err.field_errors();      assert!(errs.contains_key("val"));      assert_eq!(errs["val"].len(), 1);      assert_eq!(errs["val"][0].code, "oops"); @@ -67,7 +69,8 @@ fn can_specify_message_for_must_match() {      let s = TestStruct { val: "bob".to_string(), val2: "bobb".to_string() };      let res = s.validate();      assert!(res.is_err()); -    let errs = res.unwrap_err().field_errors(); +    let err = res.unwrap_err(); +    let errs = err.field_errors();      assert!(errs.contains_key("val"));      assert_eq!(errs["val"].len(), 1);      assert_eq!(errs["val"][0].clone().message.unwrap(), "oops"); diff --git a/validator_derive/tests/nested.rs b/validator_derive/tests/nested.rs index a95b0ef..781f01d 100644 --- a/validator_derive/tests/nested.rs +++ b/validator_derive/tests/nested.rs @@ -11,7 +11,7 @@ use validator::{  #[derive(Debug, Validate)]  struct Root<'a> { -    #[validate(length(min = "1"))] +    #[validate(length(min = 1))]      value: String,      #[validate] @@ -20,7 +20,7 @@ struct Root<'a> {  #[derive(Debug, Validate)]  struct A { -    #[validate(length(min = "1"))] +    #[validate(length(min = 1))]      value: String,      #[validate] @@ -29,7 +29,7 @@ struct A {  #[derive(Debug, Validate)]  struct B { -    #[validate(length(min = "1"))] +    #[validate(length(min = 1))]      value: String,  } @@ -42,13 +42,13 @@ struct ParentWithOptionalChild {  #[derive(Debug, Validate)]  struct ParentWithVectorOfChildren {      #[validate] -    #[validate(length(min = "1"))] +    #[validate(length(min = 1))]      child: Vec<Child>,  }  #[derive(Debug, Validate, Serialize)]  struct Child { -    #[validate(length(min = "1"))] +    #[validate(length(min = 1))]      value: String,  } @@ -71,7 +71,8 @@ fn failed_validation_points_to_original_field_names() {      let res = root.validate();      assert!(res.is_err()); -    let errs = res.unwrap_err().errors(); +    let err = res.unwrap_err(); +    let errs = err.errors();      assert_eq!(errs.len(), 2);      assert!(errs.contains_key("value"));      if let ValidationErrorsKind::Field(ref errs) = errs["value"] { @@ -118,7 +119,8 @@ fn test_can_validate_option_fields_without_lifetime() {      let res = instance.validate();      assert!(res.is_err()); -    let errs = res.unwrap_err().errors(); +    let err = res.unwrap_err(); +    let errs = err.errors();      assert_eq!(errs.len(), 1);      assert!(errs.contains_key("child"));      if let ValidationErrorsKind::Struct(ref errs) = errs["child"] { @@ -151,7 +153,8 @@ fn test_can_validate_option_fields_with_lifetime() {      let res = instance.validate();      assert!(res.is_err()); -    let errs = res.unwrap_err().errors(); +    let err = res.unwrap_err(); +    let errs = err.errors();      assert_eq!(errs.len(), 1);      assert!(errs.contains_key("child"));      if let ValidationErrorsKind::Struct(ref errs) = errs["child"] { @@ -191,7 +194,8 @@ fn test_can_validate_vector_fields() {      let res = instance.validate();      assert!(res.is_err()); -    let errs = res.unwrap_err().errors(); +    let err = res.unwrap_err(); +    let errs = err.errors();      assert_eq!(errs.len(), 1);      assert!(errs.contains_key("child"));      if let ValidationErrorsKind::List(ref errs) = errs["child"] { @@ -228,7 +232,8 @@ fn test_field_validations_take_priority_over_nested_validations() {      let res = instance.validate();      assert!(res.is_err()); -    let errs = res.unwrap_err().errors(); +    let err = res.unwrap_err(); +    let errs = err.errors();      assert_eq!(errs.len(), 1);      assert!(errs.contains_key("child"));      if let ValidationErrorsKind::Field(ref errs) = errs["child"] { @@ -275,7 +280,8 @@ fn test_field_validation_errors_replaced_with_nested_validations_fails() {                          let mut result = Ok(());                          result = ValidationErrors::merge(result, "child", child.validate());                          result -                    }).collect(); +                    }) +                    .collect();                  result = ValidationErrors::merge_all(result, "child", results);              }              result @@ -313,7 +319,8 @@ fn test_field_validations_evaluated_after_nested_validations_fails() {                          let mut result = Ok(());                          result = ValidationErrors::merge(result, "child", child.validate());                          result -                    }).collect(); +                    }) +                    .collect();                  result = ValidationErrors::merge_all(result, "child", results);              } @@ -343,5 +350,5 @@ where      F: FnOnce(HashMap<&'static str, ValidationErrorsKind>),  {      let errors = *errors.clone(); -    f(errors.errors()); +    f(errors.errors().clone());  } diff --git a/validator_derive/tests/phone.rs b/validator_derive/tests/phone.rs index a87d037..b692a8f 100644 --- a/validator_derive/tests/phone.rs +++ b/validator_derive/tests/phone.rs @@ -30,7 +30,8 @@ fn bad_phone_fails_validation() {      let s = TestStruct { val: "bob".to_string() };      let res = s.validate();      assert!(res.is_err()); -    let errs = res.unwrap_err().field_errors(); +    let err = res.unwrap_err(); +    let errs = err.field_errors();      assert!(errs.contains_key("val"));      assert_eq!(errs["val"].len(), 1);      assert_eq!(errs["val"][0].code, "phone"); @@ -47,7 +48,8 @@ fn can_specify_code_for_phone() {      let s = TestStruct { val: "bob".to_string() };      let res = s.validate();      assert!(res.is_err()); -    let errs = res.unwrap_err().field_errors(); +    let err = res.unwrap_err(); +    let errs = err.field_errors();      assert!(errs.contains_key("val"));      assert_eq!(errs["val"].len(), 1);      assert_eq!(errs["val"][0].code, "oops"); @@ -65,7 +67,8 @@ fn can_specify_message_for_phone() {      let s = TestStruct { val: "bob".to_string() };      let res = s.validate();      assert!(res.is_err()); -    let errs = res.unwrap_err().field_errors(); +    let err = res.unwrap_err(); +    let errs = err.field_errors();      assert!(errs.contains_key("val"));      assert_eq!(errs["val"].len(), 1);      assert_eq!(errs["val"][0].clone().message.unwrap(), "oops"); diff --git a/validator_derive/tests/range.rs b/validator_derive/tests/range.rs index 4f38f18..869510a 100644 --- a/validator_derive/tests/range.rs +++ b/validator_derive/tests/range.rs @@ -8,7 +8,7 @@ use validator::Validate;  fn can_validate_range_ok() {      #[derive(Debug, Validate)]      struct TestStruct { -        #[validate(range(min = "5", max = "10"))] +        #[validate(range(min = 5, max = 10))]          val: usize,      } @@ -21,14 +21,15 @@ fn can_validate_range_ok() {  fn value_out_of_range_fails_validation() {      #[derive(Debug, Validate)]      struct TestStruct { -        #[validate(range(min = "5", max = "10"))] +        #[validate(range(min = 5, max = 10))]          val: usize,      }      let s = TestStruct { val: 11 };      let res = s.validate();      assert!(res.is_err()); -    let errs = res.unwrap_err().field_errors(); +    let err = res.unwrap_err(); +    let errs = err.field_errors();      assert!(errs.contains_key("val"));      assert_eq!(errs["val"].len(), 1);      assert_eq!(errs["val"][0].code, "range"); @@ -38,13 +39,14 @@ fn value_out_of_range_fails_validation() {  fn can_specify_code_for_range() {      #[derive(Debug, Validate)]      struct TestStruct { -        #[validate(range(min = "5", max = "10", code = "oops"))] +        #[validate(range(min = 5, max = 10, code = "oops"))]          val: usize,      }      let s = TestStruct { val: 11 };      let res = s.validate();      assert!(res.is_err()); -    let errs = res.unwrap_err().field_errors(); +    let err = res.unwrap_err(); +    let errs = err.field_errors();      assert!(errs.contains_key("val"));      assert_eq!(errs["val"].len(), 1);      assert_eq!(errs["val"][0].code, "oops"); @@ -57,13 +59,14 @@ fn can_specify_code_for_range() {  fn can_specify_message_for_range() {      #[derive(Debug, Validate)]      struct TestStruct { -        #[validate(range(min = "5", max = "10", message = "oops"))] +        #[validate(range(min = 5, max = 10, message = "oops"))]          val: usize,      }      let s = TestStruct { val: 1 };      let res = s.validate();      assert!(res.is_err()); -    let errs = res.unwrap_err().field_errors(); +    let err = res.unwrap_err(); +    let errs = err.field_errors();      assert!(errs.contains_key("val"));      assert_eq!(errs["val"].len(), 1);      assert_eq!(errs["val"][0].clone().message.unwrap(), "oops"); diff --git a/validator_derive/tests/regex.rs b/validator_derive/tests/regex.rs index a6b9e68..7e3dfc5 100644 --- a/validator_derive/tests/regex.rs +++ b/validator_derive/tests/regex.rs @@ -36,7 +36,8 @@ fn bad_value_for_regex_fails_validation() {      let s = TestStruct { val: "2".to_string() };      let res = s.validate();      assert!(res.is_err()); -    let errs = res.unwrap_err().field_errors(); +    let err = res.unwrap_err(); +    let errs = err.field_errors();      assert!(errs.contains_key("val"));      assert_eq!(errs["val"].len(), 1);      assert_eq!(errs["val"][0].code, "regex"); @@ -53,7 +54,8 @@ fn can_specify_code_for_regex() {      let s = TestStruct { val: "2".to_string() };      let res = s.validate();      assert!(res.is_err()); -    let errs = res.unwrap_err().field_errors(); +    let err = res.unwrap_err(); +    let errs = err.field_errors();      assert!(errs.contains_key("val"));      assert_eq!(errs["val"].len(), 1);      assert_eq!(errs["val"][0].code, "oops"); @@ -69,7 +71,8 @@ fn can_specify_message_for_regex() {      let s = TestStruct { val: "2".to_string() };      let res = s.validate();      assert!(res.is_err()); -    let errs = res.unwrap_err().field_errors(); +    let err = res.unwrap_err(); +    let errs = err.field_errors();      assert!(errs.contains_key("val"));      assert_eq!(errs["val"].len(), 1);      assert_eq!(errs["val"][0].clone().message.unwrap(), "oops"); 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() {} diff --git a/validator_derive/tests/schema.rs b/validator_derive/tests/schema.rs index b45f3a1..3a45711 100644 --- a/validator_derive/tests/schema.rs +++ b/validator_derive/tests/schema.rs @@ -36,7 +36,8 @@ fn can_fail_schema_fn_validation() {      let s = TestStruct { val: String::new() };      let res = s.validate();      assert!(res.is_err()); -    let errs = res.unwrap_err().field_errors(); +    let err = res.unwrap_err(); +    let errs = err.field_errors();      assert!(errs.contains_key("__all__"));      assert_eq!(errs["__all__"].len(), 1);      assert_eq!(errs["__all__"][0].code, "meh"); @@ -56,7 +57,8 @@ fn can_specify_message_for_schema_fn() {      let s = TestStruct { val: String::new() };      let res = s.validate();      assert!(res.is_err()); -    let errs = res.unwrap_err().field_errors(); +    let err = res.unwrap_err(); +    let errs = err.field_errors();      assert!(errs.contains_key("__all__"));      assert_eq!(errs["__all__"].len(), 1);      assert_eq!(errs["__all__"][0].clone().message.unwrap(), "oops"); @@ -68,10 +70,10 @@ fn can_choose_to_run_schema_validation_even_after_field_errors() {          Err(ValidationError::new("meh"))      }      #[derive(Debug, Validate)] -    #[validate(schema(function = "invalid_schema_fn", skip_on_field_errors = "false"))] +    #[validate(schema(function = "invalid_schema_fn", skip_on_field_errors = false))]      struct TestStruct {          val: String, -        #[validate(range(min = "1", max = "10"))] +        #[validate(range(min = 1, max = 10))]          num: usize,      } @@ -79,7 +81,8 @@ fn can_choose_to_run_schema_validation_even_after_field_errors() {      let res = s.validate();      assert!(res.is_err()); -    let errs = res.unwrap_err().field_errors(); +    let err = res.unwrap_err(); +    let errs = err.field_errors();      assert!(errs.contains_key("__all__"));      assert_eq!(errs["__all__"].len(), 1);      assert_eq!(errs["__all__"][0].clone().code, "meh"); diff --git a/validator_derive/tests/url.rs b/validator_derive/tests/url.rs index 0ac3cb1..3b867b9 100644 --- a/validator_derive/tests/url.rs +++ b/validator_derive/tests/url.rs @@ -28,7 +28,9 @@ fn bad_url_fails_validation() {      let s = TestStruct { val: "bob".to_string() };      let res = s.validate();      assert!(res.is_err()); -    let errs = res.unwrap_err().field_errors(); +    let err = res.unwrap_err(); + +    let errs = err.field_errors();      assert!(errs.contains_key("val"));      assert_eq!(errs["val"].len(), 1);      assert_eq!(errs["val"][0].code, "url"); @@ -44,7 +46,9 @@ fn can_specify_code_for_url() {      let s = TestStruct { val: "bob".to_string() };      let res = s.validate();      assert!(res.is_err()); -    let errs = res.unwrap_err().field_errors(); +    let err = res.unwrap_err(); + +    let errs = err.field_errors();      assert!(errs.contains_key("val"));      assert_eq!(errs["val"].len(), 1);      assert_eq!(errs["val"][0].code, "oops"); @@ -61,7 +65,8 @@ fn can_specify_message_for_url() {      let s = TestStruct { val: "bob".to_string() };      let res = s.validate();      assert!(res.is_err()); -    let errs = res.unwrap_err().field_errors(); +    let err = res.unwrap_err(); +    let errs = err.field_errors();      assert!(errs.contains_key("val"));      assert_eq!(errs["val"].len(), 1);      assert_eq!(errs["val"][0].clone().message.unwrap(), "oops");  | 
