aboutsummaryrefslogtreecommitdiffstats
path: root/validator_derive/tests
diff options
context:
space:
mode:
Diffstat (limited to 'validator_derive/tests')
-rw-r--r--validator_derive/tests/compile-fail/no_nested_validations.rs17
-rw-r--r--validator_derive/tests/complex.rs129
-rw-r--r--validator_derive/tests/contains.rs6
-rw-r--r--validator_derive/tests/credit_card.rs6
-rw-r--r--validator_derive/tests/custom.rs4
-rw-r--r--validator_derive/tests/email.rs6
-rw-r--r--validator_derive/tests/length.rs6
-rw-r--r--validator_derive/tests/must_match.rs6
-rw-r--r--validator_derive/tests/nested.rs370
-rw-r--r--validator_derive/tests/phone.rs6
-rw-r--r--validator_derive/tests/range.rs6
-rw-r--r--validator_derive/tests/regex.rs6
-rw-r--r--validator_derive/tests/schema.rs6
-rw-r--r--validator_derive/tests/url.rs6
14 files changed, 544 insertions, 36 deletions
diff --git a/validator_derive/tests/compile-fail/no_nested_validations.rs b/validator_derive/tests/compile-fail/no_nested_validations.rs
new file mode 100644
index 0000000..788152d
--- /dev/null
+++ b/validator_derive/tests/compile-fail/no_nested_validations.rs
@@ -0,0 +1,17 @@
+#[macro_use] extern crate validator_derive;
+extern crate validator;
+use validator::Validate;
+
+#[derive(Validate)]
+//~^ ERROR: no method named `validate` found for type `Nested` in the current scope [E0599]
+//~^^ HELP: items from traits can only be used if the trait is implemented and in scope
+struct Test {
+ #[validate]
+ nested: Nested,
+}
+
+struct Nested {
+ value: String
+}
+
+fn main() {}
diff --git a/validator_derive/tests/complex.rs b/validator_derive/tests/complex.rs
index bbbc2e6..0df26c0 100644
--- a/validator_derive/tests/complex.rs
+++ b/validator_derive/tests/complex.rs
@@ -9,7 +9,8 @@ extern crate regex;
extern crate lazy_static;
use regex::Regex;
-use validator::{Validate, ValidationError, ValidationErrors};
+use validator::{Validate, ValidationError, ValidationErrors, ValidationErrorsKind};
+use std::collections::HashMap;
fn validate_unique_username(username: &str) -> Result<(), ValidationError> {
@@ -40,8 +41,34 @@ struct SignupData {
first_name: String,
#[validate(range(min = "18", max = "20"))]
age: u32,
+ #[validate]
+ phone: Phone,
+ #[validate]
+ card: Option<Card>,
+ #[validate]
+ preferences: Vec<Preference>
}
+#[derive(Debug, Validate, Deserialize)]
+struct Phone {
+ #[validate(phone)]
+ number: String
+}
+
+#[derive(Debug, Validate, Deserialize)]
+struct Card {
+ #[validate(credit_card)]
+ number: String,
+ #[validate(range(min = "100", max = "9999"))]
+ cvv: u32,
+}
+
+#[derive(Debug, Validate, Deserialize)]
+struct Preference {
+ #[validate(length(min = "4"))]
+ name: String,
+ value: bool,
+}
#[test]
fn is_fine_with_many_valid_validations() {
@@ -50,6 +77,19 @@ fn is_fine_with_many_valid_validations() {
site: "http://hello.com".to_string(),
first_name: "Bob".to_string(),
age: 18,
+ phone: Phone {
+ number: "+14152370800".to_string()
+ },
+ card: Some(Card {
+ number: "5236313877109142".to_string(),
+ cvv: 123
+ }),
+ preferences: vec![
+ Preference {
+ name: "marketing".to_string(),
+ value: false
+ },
+ ]
};
assert!(signup.validate().is_ok());
@@ -62,13 +102,82 @@ fn failed_validation_points_to_original_field_name() {
site: "http://hello.com".to_string(),
first_name: "".to_string(),
age: 18,
+ phone: Phone {
+ number: "123 invalid".to_string(),
+ },
+ card: Some(Card {
+ number: "1234567890123456".to_string(),
+ cvv: 1
+ }),
+ preferences: vec![
+ Preference {
+ name: "abc".to_string(),
+ value: true
+ },
+ ]
};
let res = signup.validate();
+ // println!("{}", serde_json::to_string(&res).unwrap());
assert!(res.is_err());
- let errs = res.unwrap_err().inner();
+ let errs = res.unwrap_err().errors();
assert!(errs.contains_key("firstName"));
- assert_eq!(errs["firstName"].len(), 1);
- assert_eq!(errs["firstName"][0].code, "length");
+ if let ValidationErrorsKind::Field(ref err) = errs["firstName"] {
+ assert_eq!(err.len(), 1);
+ assert_eq!(err[0].code, "length");
+ } else {
+ panic!("Expected field validation errors");
+ }
+ assert!(errs.contains_key("phone"));
+ if let ValidationErrorsKind::Struct(ref errs) = errs["phone"] {
+ unwrap_map(errs, |errs| {
+ assert_eq!(errs.len(), 1);
+ assert!(errs.contains_key("number"));
+ if let ValidationErrorsKind::Field(ref errs) = errs["number"] {
+ assert_eq!(errs.len(), 1);
+ assert_eq!(errs[0].code, "phone");
+ } else {
+ panic!("Expected field validation errors");
+ }
+ });
+ } else {
+ panic!("Expected struct validation errors");
+ }
+ assert!(errs.contains_key("card"));
+ if let ValidationErrorsKind::Struct(ref errs) = errs["card"] {
+ unwrap_map(errs, |errs| {
+ assert_eq!(errs.len(), 2);
+ assert!(errs.contains_key("number"));
+ if let ValidationErrorsKind::Field(ref err) = errs["number"] {
+ assert_eq!(err.len(), 1);
+ assert_eq!(err[0].code, "credit_card");
+ } else {
+ panic!("Expected field validation errors");
+ }
+ assert!(errs.contains_key("cvv"));
+ if let ValidationErrorsKind::Field(ref err) = errs["cvv"] {
+ assert_eq!(err.len(), 1);
+ assert_eq!(err[0].code, "range");
+ } else {
+ panic!("Expected field validation errors");
+ }
+ });
+ } else {
+ panic!("Expected struct validation errors");
+ }
+ assert!(errs.contains_key("preferences"));
+ if let ValidationErrorsKind::List(ref errs) = errs["preferences"] {
+ assert!(errs.contains_key(&0));
+ unwrap_map(&errs[&0], |errs| {
+ assert_eq!(errs.len(), 1);
+ assert!(errs.contains_key("name"));
+ if let ValidationErrorsKind::Field(ref err) = errs["name"] {
+ assert_eq!(err.len(), 1);
+ assert_eq!(err[0].code, "length");
+ }
+ });
+ } else {
+ panic!("Expected list validation errors");
+ }
}
#[test]
@@ -177,6 +286,11 @@ fn test_works_with_question_mark_operator() {
site: "http://hello.com".to_string(),
first_name: "Bob".to_string(),
age: 18,
+ phone: Phone {
+ number: "+14152370800".to_string()
+ },
+ card: None,
+ preferences: Vec::new(),
};
signup.validate()?;
@@ -216,4 +330,11 @@ fn test_works_with_none_values() {
assert!(p.validate().is_ok());
assert!(q.validate().is_ok());
+}
+
+fn unwrap_map<F>(errors: &Box<ValidationErrors>, f: F)
+ where F: FnOnce(HashMap<&'static str, ValidationErrorsKind>)
+{
+ let errors = *errors.clone();
+ f(errors.errors());
} \ No newline at end of file
diff --git a/validator_derive/tests/contains.rs b/validator_derive/tests/contains.rs
index 847de0f..5e9060e 100644
--- a/validator_derive/tests/contains.rs
+++ b/validator_derive/tests/contains.rs
@@ -32,7 +32,7 @@ fn value_not_containing_needle_fails_validation() {
};
let res = s.validate();
assert!(res.is_err());
- let errs = res.unwrap_err().inner();
+ let errs = res.unwrap_err().field_errors();
assert!(errs.contains_key("val"));
assert_eq!(errs["val"].len(), 1);
assert_eq!(errs["val"][0].code, "contains");
@@ -52,7 +52,7 @@ fn can_specify_code_for_contains() {
};
let res = s.validate();
assert!(res.is_err());
- let errs = res.unwrap_err().inner();
+ let errs = res.unwrap_err().field_errors();
assert!(errs.contains_key("val"));
assert_eq!(errs["val"].len(), 1);
assert_eq!(errs["val"][0].code, "oops");
@@ -70,7 +70,7 @@ fn can_specify_message_for_contains() {
};
let res = s.validate();
assert!(res.is_err());
- let errs = res.unwrap_err().inner();
+ let errs = res.unwrap_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 a430971..b1a9da3 100644
--- a/validator_derive/tests/credit_card.rs
+++ b/validator_derive/tests/credit_card.rs
@@ -34,7 +34,7 @@ fn bad_credit_card_fails_validation() {
};
let res = s.validate();
assert!(res.is_err());
- let errs = res.unwrap_err().inner();
+ let errs = res.unwrap_err().field_errors();
assert!(errs.contains_key("val"));
assert_eq!(errs["val"].len(), 1);
assert_eq!(errs["val"][0].code, "credit_card");
@@ -54,7 +54,7 @@ fn can_specify_code_for_credit_card() {
};
let res = s.validate();
assert!(res.is_err());
- let errs = res.unwrap_err().inner();
+ let errs = res.unwrap_err().field_errors();
assert!(errs.contains_key("val"));
assert_eq!(errs["val"].len(), 1);
assert_eq!(errs["val"][0].code, "oops");
@@ -73,7 +73,7 @@ fn can_specify_message_for_credit_card() {
};
let res = s.validate();
assert!(res.is_err());
- let errs = res.unwrap_err().inner();
+ let errs = res.unwrap_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 0cac75f..cd1b354 100644
--- a/validator_derive/tests/custom.rs
+++ b/validator_derive/tests/custom.rs
@@ -40,7 +40,7 @@ fn can_fail_custom_fn_validation() {
};
let res = s.validate();
assert!(res.is_err());
- let errs = res.unwrap_err().inner();
+ let errs = res.unwrap_err().field_errors();
assert!(errs.contains_key("val"));
assert_eq!(errs["val"].len(), 1);
assert_eq!(errs["val"][0].code, "meh");
@@ -59,7 +59,7 @@ fn can_specify_message_for_custom_fn() {
};
let res = s.validate();
assert!(res.is_err());
- let errs = res.unwrap_err().inner();
+ let errs = res.unwrap_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 fc05bf9..4fbc123 100644
--- a/validator_derive/tests/email.rs
+++ b/validator_derive/tests/email.rs
@@ -33,7 +33,7 @@ fn bad_email_fails_validation() {
};
let res = s.validate();
assert!(res.is_err());
- let errs = res.unwrap_err().inner();
+ let errs = res.unwrap_err().field_errors();
assert!(errs.contains_key("val"));
assert_eq!(errs["val"].len(), 1);
assert_eq!(errs["val"][0].code, "email");
@@ -52,7 +52,7 @@ fn can_specify_code_for_email() {
};
let res = s.validate();
assert!(res.is_err());
- let errs = res.unwrap_err().inner();
+ let errs = res.unwrap_err().field_errors();
assert!(errs.contains_key("val"));
assert_eq!(errs["val"].len(), 1);
assert_eq!(errs["val"][0].code, "oops");
@@ -70,7 +70,7 @@ fn can_specify_message_for_email() {
};
let res = s.validate();
assert!(res.is_err());
- let errs = res.unwrap_err().inner();
+ let errs = res.unwrap_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 892cf74..12bffc6 100644
--- a/validator_derive/tests/length.rs
+++ b/validator_derive/tests/length.rs
@@ -32,7 +32,7 @@ fn value_out_of_length_fails_validation() {
};
let res = s.validate();
assert!(res.is_err());
- let errs = res.unwrap_err().inner();
+ let errs = res.unwrap_err().field_errors();
assert!(errs.contains_key("val"));
assert_eq!(errs["val"].len(), 1);
assert_eq!(errs["val"][0].code, "length");
@@ -53,7 +53,7 @@ fn can_specify_code_for_length() {
};
let res = s.validate();
assert!(res.is_err());
- let errs = res.unwrap_err().inner();
+ let errs = res.unwrap_err().field_errors();
assert!(errs.contains_key("val"));
assert_eq!(errs["val"].len(), 1);
assert_eq!(errs["val"][0].code, "oops");
@@ -71,7 +71,7 @@ fn can_specify_message_for_length() {
};
let res = s.validate();
assert!(res.is_err());
- let errs = res.unwrap_err().inner();
+ let errs = res.unwrap_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 038616a..a8c95f9 100644
--- a/validator_derive/tests/must_match.rs
+++ b/validator_derive/tests/must_match.rs
@@ -38,7 +38,7 @@ fn not_matching_fails_validation() {
let res = s.validate();
assert!(res.is_err());
- let errs = res.unwrap_err().inner();
+ let errs = res.unwrap_err().field_errors();
assert!(errs.contains_key("val"));
assert_eq!(errs["val"].len(), 1);
assert_eq!(errs["val"][0].code, "must_match");
@@ -60,7 +60,7 @@ fn can_specify_code_for_must_match() {
};
let res = s.validate();
assert!(res.is_err());
- let errs = res.unwrap_err().inner();
+ let errs = res.unwrap_err().field_errors();
assert!(errs.contains_key("val"));
assert_eq!(errs["val"].len(), 1);
assert_eq!(errs["val"][0].code, "oops");
@@ -80,7 +80,7 @@ fn can_specify_message_for_must_match() {
};
let res = s.validate();
assert!(res.is_err());
- let errs = res.unwrap_err().inner();
+ let errs = res.unwrap_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
new file mode 100644
index 0000000..4f03714
--- /dev/null
+++ b/validator_derive/tests/nested.rs
@@ -0,0 +1,370 @@
+#[macro_use]
+extern crate validator_derive;
+extern crate validator;
+#[macro_use]
+extern crate serde_derive;
+
+use validator::{validate_length, Validate, ValidationError, ValidationErrors, ValidationErrorsKind, Validator};
+use std::{borrow::Cow, collections::HashMap};
+
+#[derive(Debug, Validate)]
+struct Root<'a> {
+ #[validate(length(min = "1"))]
+ value: String,
+
+ #[validate]
+ a: &'a A,
+}
+
+#[derive(Debug, Validate)]
+struct A {
+ #[validate(length(min = "1"))]
+ value: String,
+
+ #[validate]
+ b: B,
+}
+
+#[derive(Debug, Validate)]
+struct B {
+ #[validate(length(min = "1"))]
+ value: String,
+}
+
+#[derive(Debug, Validate)]
+struct ParentWithOptionalChild {
+ #[validate]
+ child: Option<Child>,
+}
+
+#[derive(Debug, Validate)]
+struct ParentWithVectorOfChildren {
+ #[validate]
+ #[validate(length(min = "1"))]
+ child: Vec<Child>,
+}
+
+#[derive(Debug, Validate, Serialize)]
+struct Child {
+ #[validate(length(min = "1"))]
+ value: String,
+}
+
+#[test]
+fn is_fine_with_nested_validations() {
+ let root = Root {
+ value: "valid".to_string(),
+ a: &A {
+ value: "valid".to_string(),
+ b: B {
+ value: "valid".to_string(),
+ }
+ }
+ };
+
+ assert!(root.validate().is_ok());
+}
+
+#[test]
+fn failed_validation_points_to_original_field_names() {
+ let root = Root {
+ value: String::new(),
+ a: &A {
+ value: String::new(),
+ b: B {
+ value: String::new(),
+ }
+ }
+ };
+
+ let res = root.validate();
+ assert!(res.is_err());
+ let errs = res.unwrap_err().errors();
+ assert_eq!(errs.len(), 2);
+ assert!(errs.contains_key("value"));
+ if let ValidationErrorsKind::Field(ref errs) = errs["value"] {
+ assert_eq!(errs.len(), 1);
+ assert_eq!(errs[0].code, "length");
+ } else {
+ panic!("Expected field validation errors");
+ }
+ assert!(errs.contains_key("a"));
+ if let ValidationErrorsKind::Struct(ref errs) = errs["a"] {
+ unwrap_map(errs, |errs| {
+ assert_eq!(errs.len(), 2);
+ assert!(errs.contains_key("value"));
+ if let ValidationErrorsKind::Field(ref errs) = errs["value"] {
+ assert_eq!(errs.len(), 1);
+ assert_eq!(errs[0].code, "length");
+ } else {
+ panic!("Expected field validation errors");
+ }
+ assert!(errs.contains_key("b"));
+ if let ValidationErrorsKind::Struct(ref errs) = errs["b"] {
+ unwrap_map(errs, |errs| {
+ assert_eq!(errs.len(), 1);
+ assert!(errs.contains_key("value"));
+ if let ValidationErrorsKind::Field(ref errs) = errs["value"] {
+ assert_eq!(errs.len(), 1);
+ assert_eq!(errs[0].code, "length");
+ } else {
+ panic!("Expected field validation errors");
+ }
+ });
+ } else {
+ panic!("Expected struct validation errors");
+ }
+ });
+ } else {
+ panic!("Expected struct validation errors");
+ }
+}
+
+#[test]
+fn test_can_validate_option_fields_without_lifetime() {
+ let instance = ParentWithOptionalChild {
+ child: Some(Child {
+ value: String::new(),
+ })
+ };
+
+ let res = instance.validate();
+ assert!(res.is_err());
+ let errs = res.unwrap_err().errors();
+ assert_eq!(errs.len(), 1);
+ assert!(errs.contains_key("child"));
+ if let ValidationErrorsKind::Struct(ref errs) = errs["child"] {
+ unwrap_map(errs, |errs| {
+ assert_eq!(errs.len(), 1);
+ assert!(errs.contains_key("value"));
+ if let ValidationErrorsKind::Field(ref errs) = errs["value"] {
+ assert_eq!(errs.len(), 1);
+ assert_eq!(errs[0].code, "length");
+ } else {
+ panic!("Expected field validation errors");
+ }
+ });
+ } else {
+ panic!("Expected struct validation errors");
+ }
+}
+
+#[test]
+fn test_can_validate_option_fields_with_lifetime() {
+ #[derive(Debug, Validate)]
+ struct ParentWithLifetimeAndOptionalChild<'a> {
+ #[validate]
+ child: Option<&'a Child>,
+ }
+
+ let child = Child {
+ value: String::new(),
+ };
+
+ let instance = ParentWithLifetimeAndOptionalChild {
+ child: Some(&child)
+ };
+
+ let res = instance.validate();
+ assert!(res.is_err());
+ let errs = res.unwrap_err().errors();
+ assert_eq!(errs.len(), 1);
+ assert!(errs.contains_key("child"));
+ if let ValidationErrorsKind::Struct(ref errs) = errs["child"] {
+ unwrap_map(errs, |errs| {
+ assert_eq!(errs.len(), 1);
+ assert!(errs.contains_key("value"));
+ if let ValidationErrorsKind::Field(ref errs) = errs["value"] {
+ assert_eq!(errs.len(), 1);
+ assert_eq!(errs[0].code, "length");
+ } else {
+ panic!("Expected field validation errors");
+ }
+ });
+ } else {
+ panic!("Expected struct validation errors");
+ }
+}
+
+#[test]
+fn test_works_with_none_values() {
+ let instance = ParentWithOptionalChild {
+ child: None,
+ };
+
+ let res = instance.validate();
+ assert!(res.is_ok());
+}
+
+#[test]
+fn test_can_validate_vector_fields() {
+ let instance = ParentWithVectorOfChildren {
+ child: vec![
+ Child {
+ value: "valid".to_string(),
+ },
+ Child {
+ value: String::new(),
+ },
+ Child {
+ value: "valid".to_string(),
+ },
+ Child {
+ value: String::new(),
+ }
+ ],
+ };
+
+ let res = instance.validate();
+ assert!(res.is_err());
+ let errs = res.unwrap_err().errors();
+ assert_eq!(errs.len(), 1);
+ assert!(errs.contains_key("child"));
+ if let ValidationErrorsKind::List(ref errs) = errs["child"] {
+ assert!(errs.contains_key(&1));
+ unwrap_map(&errs[&1], |errs| {
+ assert_eq!(errs.len(), 1);
+ assert!(errs.contains_key("value"));
+ if let ValidationErrorsKind::Field(ref errs) = errs["value"] {
+ assert_eq!(errs.len(), 1);
+ assert_eq!(errs[0].code, "length");
+ } else {
+ panic!("Expected field validation errors");
+ }
+ });
+ assert!(errs.contains_key(&3));
+ unwrap_map(&errs[&3], |errs| {
+ assert_eq!(errs.len(), 1);
+ assert!(errs.contains_key("value"));
+ if let ValidationErrorsKind::Field(ref errs) = errs["value"] {
+ assert_eq!(errs.len(), 1);
+ assert_eq!(errs[0].code, "length");
+ } else {
+ panic!("Expected field validation errors");
+ }
+ });
+ } else {
+ panic!("Expected list validation errors");
+ }
+}
+
+#[test]
+fn test_field_validations_take_priority_over_nested_validations() {
+ let instance = ParentWithVectorOfChildren {
+ child: Vec::new(),
+ };
+
+ let res = instance.validate();
+ assert!(res.is_err());
+ let errs = res.unwrap_err().errors();
+ assert_eq!(errs.len(), 1);
+ assert!(errs.contains_key("child"));
+ if let ValidationErrorsKind::Field(ref errs) = errs["child"] {
+ assert_eq!(errs.len(), 1);
+ assert_eq!(errs[0].code, "length");
+ } else {
+ panic!("Expected field validation errors");
+ }
+}
+
+#[test]
+#[should_panic(expected = "Attempt to replace non-empty ValidationErrors entry")]
+#[allow(unused)]
+fn test_field_validation_errors_replaced_with_nested_validations_fails() {
+
+ #[derive(Debug)]
+ struct ParentWithOverridingStructValidations {
+ child: Vec<Child>,
+ }
+
+ impl Validate for ParentWithOverridingStructValidations {
+ // Evaluating structs after fields validations have discovered errors should fail because
+ // field validations are expected to take priority over nested struct validations
+ #[allow(unused_mut)]
+ fn validate(&self) -> Result<(), ValidationErrors> {
+ // First validate the length of the vector:
+ let mut errors = ValidationErrors::new();
+ if !validate_length(Validator::Length { min: Some(2u64), max: None, equal: None }, &self.child) {
+ let mut err = ValidationError::new("length");
+ err.add_param(Cow::from("min"), &2u64);
+ err.add_param(Cow::from("value"), &&self.child);
+ errors.add("child", err);
+ }
+
+ // Then validate the nested vector of structs without checking for existing field errors:
+ let mut result = if errors.is_empty() { Ok(()) } else { Err(errors) };
+ {
+ let results: Vec<_> = self.child.iter().map(|child| {
+ let mut result = Ok(());
+ result = ValidationErrors::merge(result, "child", child.validate());
+ result
+ }).collect();
+ result = ValidationErrors::merge_all(result, "child", results);
+ }
+ result
+ }
+ }
+
+ let instance = ParentWithOverridingStructValidations {
+ child: vec![
+ Child {
+ value: String::new()
+ }]
+ };
+ instance.validate();
+}
+
+#[test]
+#[should_panic(expected = "Attempt to add field validation to a non-Field ValidationErrorsKind instance")]
+#[allow(unused)]
+fn test_field_validations_evaluated_after_nested_validations_fails() {
+ #[derive(Debug)]
+ struct ParentWithStructValidationsFirst {
+ child: Vec<Child>,
+ }
+
+ impl Validate for ParentWithStructValidationsFirst {
+ // Evaluating fields after their nested structs should fail because field
+ // validations are expected to take priority over nested struct validations
+ #[allow(unused_mut)]
+ fn validate(&self) -> Result<(), ValidationErrors> {
+ // First validate the nested vector of structs:
+ let mut result = Ok(());
+ if !ValidationErrors::has_error(&result, "child") {
+ let results: Vec<_> = self.child.iter().map(|child| {
+ let mut result = Ok(());
+ result = ValidationErrors::merge(result, "child", child.validate());
+ result
+ }).collect();
+ result = ValidationErrors::merge_all(result, "child", results);
+ }
+
+ // Then validate the length of the vector itself:
+ if !validate_length(Validator::Length { min: Some(2u64), max: None, equal: None }, &self.child) {
+ let mut err = ValidationError::new("length");
+ err.add_param(Cow::from("min"), &2u64);
+ err.add_param(Cow::from("value"), &&self.child);
+ result = result.and_then(|_| Err(ValidationErrors::new())).map_err(|mut errors| {
+ errors.add("child", err);
+ errors
+ });
+ }
+ result
+ }
+ }
+
+ let instance = ParentWithStructValidationsFirst {
+ child: vec![
+ Child {
+ value: String::new()
+ }]
+ };
+ let res = instance.validate();
+}
+
+fn unwrap_map<F>(errors: &Box<ValidationErrors>, f: F)
+ where F: FnOnce(HashMap<&'static str, ValidationErrorsKind>)
+{
+ let errors = *errors.clone();
+ f(errors.errors());
+} \ No newline at end of file
diff --git a/validator_derive/tests/phone.rs b/validator_derive/tests/phone.rs
index ad8f3cd..3131bad 100644
--- a/validator_derive/tests/phone.rs
+++ b/validator_derive/tests/phone.rs
@@ -35,7 +35,7 @@ fn bad_phone_fails_validation() {
};
let res = s.validate();
assert!(res.is_err());
- let errs = res.unwrap_err().inner();
+ let errs = res.unwrap_err().field_errors();
assert!(errs.contains_key("val"));
assert_eq!(errs["val"].len(), 1);
assert_eq!(errs["val"][0].code, "phone");
@@ -54,7 +54,7 @@ fn can_specify_code_for_phone() {
};
let res = s.validate();
assert!(res.is_err());
- let errs = res.unwrap_err().inner();
+ let errs = res.unwrap_err().field_errors();
assert!(errs.contains_key("val"));
assert_eq!(errs["val"].len(), 1);
assert_eq!(errs["val"][0].code, "oops");
@@ -74,7 +74,7 @@ fn can_specify_message_for_phone() {
};
let res = s.validate();
assert!(res.is_err());
- let errs = res.unwrap_err().inner();
+ let errs = res.unwrap_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 2ecd678..084e530 100644
--- a/validator_derive/tests/range.rs
+++ b/validator_derive/tests/range.rs
@@ -32,7 +32,7 @@ fn value_out_of_range_fails_validation() {
};
let res = s.validate();
assert!(res.is_err());
- let errs = res.unwrap_err().inner();
+ let errs = res.unwrap_err().field_errors();
assert!(errs.contains_key("val"));
assert_eq!(errs["val"].len(), 1);
assert_eq!(errs["val"][0].code, "range");
@@ -50,7 +50,7 @@ fn can_specify_code_for_range() {
};
let res = s.validate();
assert!(res.is_err());
- let errs = res.unwrap_err().inner();
+ let errs = res.unwrap_err().field_errors();
assert!(errs.contains_key("val"));
assert_eq!(errs["val"].len(), 1);
assert_eq!(errs["val"][0].code, "oops");
@@ -71,7 +71,7 @@ fn can_specify_message_for_range() {
};
let res = s.validate();
assert!(res.is_err());
- let errs = res.unwrap_err().inner();
+ let errs = res.unwrap_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 58f8f69..b54df03 100644
--- a/validator_derive/tests/regex.rs
+++ b/validator_derive/tests/regex.rs
@@ -40,7 +40,7 @@ fn bad_value_for_regex_fails_validation() {
};
let res = s.validate();
assert!(res.is_err());
- let errs = res.unwrap_err().inner();
+ let errs = res.unwrap_err().field_errors();
assert!(errs.contains_key("val"));
assert_eq!(errs["val"].len(), 1);
assert_eq!(errs["val"][0].code, "regex");
@@ -59,7 +59,7 @@ fn can_specify_code_for_regex() {
};
let res = s.validate();
assert!(res.is_err());
- let errs = res.unwrap_err().inner();
+ let errs = res.unwrap_err().field_errors();
assert!(errs.contains_key("val"));
assert_eq!(errs["val"].len(), 1);
assert_eq!(errs["val"][0].code, "oops");
@@ -77,7 +77,7 @@ fn can_specify_message_for_regex() {
};
let res = s.validate();
assert!(res.is_err());
- let errs = res.unwrap_err().inner();
+ let errs = res.unwrap_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/schema.rs b/validator_derive/tests/schema.rs
index 6b3ae4f..32684fa 100644
--- a/validator_derive/tests/schema.rs
+++ b/validator_derive/tests/schema.rs
@@ -41,7 +41,7 @@ fn can_fail_schema_fn_validation() {
};
let res = s.validate();
assert!(res.is_err());
- let errs = res.unwrap_err().inner();
+ let errs = res.unwrap_err().field_errors();
assert!(errs.contains_key("__all__"));
assert_eq!(errs["__all__"].len(), 1);
assert_eq!(errs["__all__"][0].code, "meh");
@@ -63,7 +63,7 @@ fn can_specify_message_for_schema_fn() {
};
let res = s.validate();
assert!(res.is_err());
- let errs = res.unwrap_err().inner();
+ let errs = res.unwrap_err().field_errors();
assert!(errs.contains_key("__all__"));
assert_eq!(errs["__all__"].len(), 1);
assert_eq!(errs["__all__"][0].clone().message.unwrap(), "oops");
@@ -89,7 +89,7 @@ fn can_choose_to_run_schema_validation_even_after_field_errors() {
let res = s.validate();
assert!(res.is_err());
- let errs = res.unwrap_err().inner();
+ let errs = res.unwrap_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 1182086..5a3b791 100644
--- a/validator_derive/tests/url.rs
+++ b/validator_derive/tests/url.rs
@@ -33,7 +33,7 @@ fn bad_url_fails_validation() {
};
let res = s.validate();
assert!(res.is_err());
- let errs = res.unwrap_err().inner();
+ let errs = res.unwrap_err().field_errors();
assert!(errs.contains_key("val"));
assert_eq!(errs["val"].len(), 1);
assert_eq!(errs["val"][0].code, "url");
@@ -51,7 +51,7 @@ fn can_specify_code_for_url() {
};
let res = s.validate();
assert!(res.is_err());
- let errs = res.unwrap_err().inner();
+ let errs = res.unwrap_err().field_errors();
assert!(errs.contains_key("val"));
assert_eq!(errs["val"].len(), 1);
assert_eq!(errs["val"][0].code, "oops");
@@ -70,7 +70,7 @@ fn can_specify_message_for_url() {
};
let res = s.validate();
assert!(res.is_err());
- let errs = res.unwrap_err().inner();
+ let errs = res.unwrap_err().field_errors();
assert!(errs.contains_key("val"));
assert_eq!(errs["val"].len(), 1);
assert_eq!(errs["val"][0].clone().message.unwrap(), "oops");