diff options
| author | Vincent Prouillet | 2019-07-13 16:42:14 +0200 |
|---|---|---|
| committer | GitHub | 2019-07-13 16:42:14 +0200 |
| commit | 87cf7cdac24dd0d4ea83a8a88640da95ae7ac93a (patch) | |
| tree | e11ce4ab7dc807ffb1464d13f329ccec4a6a62db | |
| parent | 4b9fe3939b106c151bff11e490a41212559f9a4a (diff) | |
| parent | 0877c01f9a1bf5bcda3e3b235730f4d09982d8d2 (diff) | |
| download | validator-87cf7cdac24dd0d4ea83a8a88640da95ae7ac93a.tar.bz2 | |
Merge pull request #72 from Keats/next
Next version
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"); |
