diff options
| author | Vincent Prouillet | 2019-10-14 19:53:18 +0200 |
|---|---|---|
| committer | GitHub | 2019-10-14 19:53:18 +0200 |
| commit | 5c509da6e41726e5a80d52c10f70e582b28d145f (patch) | |
| tree | ed2962ef987c124d9f44cb14c2dacdc7aaf97797 /validator_derive | |
| parent | 9554ba1116e2cbdf4ea565616c627792c1d03fa9 (diff) | |
| parent | ac3810f68d2dd86c17a57593959506bd1b99cab5 (diff) | |
| download | validator-5c509da6e41726e5a80d52c10f70e582b28d145f.tar.bz2 | |
Merge pull request #79 from mocsy/master
Add utf-8 non-control characters validator
Diffstat (limited to 'validator_derive')
| -rw-r--r-- | validator_derive/Cargo.toml | 1 | ||||
| -rw-r--r-- | validator_derive/src/lib.rs | 9 | ||||
| -rw-r--r-- | validator_derive/src/quoting.rs | 24 | ||||
| -rw-r--r-- | validator_derive/src/validation.rs | 4 | ||||
| -rw-r--r-- | validator_derive/tests/non_control.rs | 75 |
5 files changed, 110 insertions, 3 deletions
diff --git a/validator_derive/Cargo.toml b/validator_derive/Cargo.toml index e8e50aa..5c515de 100644 --- a/validator_derive/Cargo.toml +++ b/validator_derive/Cargo.toml @@ -14,6 +14,7 @@ proc-macro = true [features] phone = ["validator/phone"] card = ["validator/card"] +unic = ["validator/unic"] [dependencies] syn = { version = "0.15", features = ["extra-traits"] } diff --git a/validator_derive/src/lib.rs b/validator_derive/src/lib.rs index f3796b4..d8bbb3e 100644 --- a/validator_derive/src/lib.rs +++ b/validator_derive/src/lib.rs @@ -266,7 +266,7 @@ fn find_validators_for_field( for meta_item in meta_items { match *meta_item { syn::NestedMeta::Meta(ref item) => match *item { - // email, url, phone + // email, url, phone, credit_card, non_control_character syn::Meta::Word(ref name) => match name.to_string().as_ref() { "email" => { assert_string_type("email", field_type); @@ -286,6 +286,11 @@ fn find_validators_for_field( assert_string_type("credit_card", field_type); validators.push(FieldValidation::new(Validator::CreditCard)); } + #[cfg(feature = "unic")] + "non_control_character" => { + assert_string_type("non_control_character", field_type); + validators.push(FieldValidation::new(Validator::NonControlCharacter)); + } _ => panic!("Unexpected validator: {}", name), }, // custom, contains, must_match, regex @@ -341,7 +346,7 @@ fn find_validators_for_field( &meta_items, )); } - "email" | "url" | "phone" | "credit_card" => { + "email" | "url" | "phone" | "credit_card" | "non_control_character" => { validators.push(extract_argless_validation( ident.to_string(), rust_ident.clone(), diff --git a/validator_derive/src/quoting.rs b/validator_derive/src/quoting.rs index b94962c..6bfef0c 100644 --- a/validator_derive/src/quoting.rs +++ b/validator_derive/src/quoting.rs @@ -258,6 +258,26 @@ pub fn quote_phone_validation( field_quoter.wrap_if_option(quoted) } +#[cfg(feature = "unic")] +pub fn quote_non_control_character_validation( + field_quoter: &FieldQuoter, + validation: &FieldValidation, +) -> proc_macro2::TokenStream { + let field_name = &field_quoter.name; + let validator_param = field_quoter.quote_validator_param(); + + let quoted_error = quote_error(&validation); + let quoted = quote!( + if !::validator::validate_non_control_character(#validator_param) { + #quoted_error + err.add_param(::std::borrow::Cow::from("value"), &#validator_param); + errors.add(#field_name, err); + } + ); + + field_quoter.wrap_if_option(quoted) +} + pub fn quote_url_validation( field_quoter: &FieldQuoter, validation: &FieldValidation, @@ -440,6 +460,10 @@ pub fn quote_field_validation( #[cfg(feature = "phone")] Validator::Phone => validations.push(quote_phone_validation(&field_quoter, validation)), Validator::Nested => nested_validations.push(quote_nested_validation(&field_quoter)), + #[cfg(feature = "unic")] + Validator::NonControlCharacter => { + validations.push(quote_non_control_character_validation(&field_quoter, validation)) + } } } diff --git a/validator_derive/src/validation.rs b/validator_derive/src/validation.rs index 5f42d7b..be8afee 100644 --- a/validator_derive/src/validation.rs +++ b/validator_derive/src/validation.rs @@ -146,7 +146,7 @@ pub fn extract_range_validation( } } -/// Extract url/email/phone field validation with a code or a message +/// Extract url/email/phone/non_control_character field validation with a code or a message pub fn extract_argless_validation( validator_name: String, field: String, @@ -178,6 +178,8 @@ pub fn extract_argless_validation( "credit_card" => Validator::CreditCard, #[cfg(feature = "phone")] "phone" => Validator::Phone, + #[cfg(feature = "unic")] + "non_control_character" => Validator::NonControlCharacter, _ => Validator::Url, }; diff --git a/validator_derive/tests/non_control.rs b/validator_derive/tests/non_control.rs new file mode 100644 index 0000000..37fb153 --- /dev/null +++ b/validator_derive/tests/non_control.rs @@ -0,0 +1,75 @@ +#[macro_use] +extern crate validator_derive; +extern crate validator; + +use validator::Validate; + +#[cfg(feature = "unic")] +#[test] +fn can_validate_utf8_ok() { + #[derive(Debug, Validate)] + struct TestStruct { + #[validate(non_control_character)] + val: String, + } + + let s = TestStruct { val: "하늘".to_string() }; + + assert!(s.validate().is_ok()); +} + +#[cfg(feature = "unic")] +#[test] +fn utf8_with_control_fails_validation() { + #[derive(Debug, Validate)] + struct TestStruct { + #[validate(non_control_character)] + val: String, + } + + let s = TestStruct { val: "\u{009F}하늘".to_string() }; + let res = s.validate(); + assert!(res.is_err()); + 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, "non_control_character"); +} + +#[cfg(feature = "unic")] +#[test] +fn can_specify_code_for_non_control_character() { + #[derive(Debug, Validate)] + struct TestStruct { + #[validate(non_control_character(code = "oops"))] + val: String, + } + let s = TestStruct { val: "\u{009F}하늘".to_string() }; + let res = s.validate(); + assert!(res.is_err()); + 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"); + assert_eq!(errs["val"][0].params["value"], "\u{9F}하늘"); +} + +#[cfg(feature = "unic")] +#[test] +fn can_specify_message_for_non_control_character() { + #[derive(Debug, Validate)] + struct TestStruct { + #[validate(non_control_character(message = "oops"))] + val: String, + } + let s = TestStruct { val: "\u{009F}하늘".to_string() }; + let res = s.validate(); + assert!(res.is_err()); + 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"); +} |
