/src/validators/regex.rs

https://github.com/ChrisBuchholz/accord · Rust · 111 lines · 84 code · 9 blank · 18 comment · 2 complexity · 751ecd7778f36fc7839da90bcb1e1fe5 MD5 · raw file

  1. use regex::RegexBuilder;
  2. /// Enforce that a string must match a given regex
  3. /// Flags is a string containing all the flags that affect the regex.
  4. /// i = ignore case
  5. /// m = multiline
  6. /// s = dot matches new line
  7. /// U = swaps greedy modifiers (a* is lazy, a*? is greedy)
  8. /// u = disable unicode support
  9. /// x = ignore whitespace
  10. /// Note that this doesn't test the length of the match; meaning
  11. /// r"a..." will match "a12345678" as a match is present.
  12. /// To force the value to match the regex exactly, use ^ and $
  13. /// e.g: r"^a...$" will not match "a12345678"
  14. pub fn regex(regex: &'static str, flags: &'static str) -> Box<Fn(&String) -> ::ValidatorResult> {
  15. let regex = RegexBuilder::new(regex)
  16. .case_insensitive(flags.contains("i"))
  17. .multi_line(flags.contains("m"))
  18. .dot_matches_new_line(flags.contains("s"))
  19. .swap_greed(flags.contains("U"))
  20. .unicode(!flags.contains("u"))
  21. .ignore_whitespace(flags.contains("x"))
  22. .build()
  23. .expect("Invalid regex in validator!");
  24. Box::new(move |s: &String| {
  25. if regex.is_match(s) {
  26. Ok(())
  27. } else {
  28. Err(::Invalid {
  29. msg: "Must match regex '/%1/%2'.".to_string(),
  30. // TODO: sucks to clone this, it could probably be a &'static str
  31. args: vec![regex.as_str().to_owned(), flags.to_owned()],
  32. human_readable: format!("Must match regex '/{}/{}'", regex.as_str().clone(), flags)
  33. })
  34. }
  35. })
  36. }
  37. /// Convenience function for validating email addresses
  38. pub fn email() -> Box<Fn(&String) -> ::ValidatorResult> {
  39. regex(r"^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$", "i")
  40. }
  41. /// Convenience function for validating URLs.
  42. pub fn url() -> Box<Fn(&String) -> ::ValidatorResult> {
  43. regex(r"^(https?://)?([A-Z]+\.)+[A-Z]{2,}(/[A-Z%0-9_]*)*?(/[A-Z%0-9_]*\.[A-Z%0-9_]*)?([#?][A-Z%0-9=&]*){0,2}$", "i")
  44. }
  45. #[cfg(test)]
  46. mod tests
  47. {
  48. use super::*;
  49. // regex
  50. #[test]
  51. pub fn regex_valid() {
  52. assert!(regex(r"^a...$", "")(&"a123".to_owned()).is_ok());
  53. assert!(regex(r"^a...$", "")(&"abcd".to_owned()).is_ok());
  54. assert!(regex(r"^a...$", "")(&"a!?£".to_owned()).is_ok());
  55. }
  56. #[test]
  57. pub fn regex_invalid() {
  58. assert!(regex(r"^a...$", "")(&"a".to_owned()).is_err());
  59. assert!(regex(r"^a...$", "")(&"abc".to_owned()).is_err());
  60. assert!(regex(r"^a...$", "")(&"a123457".to_owned()).is_err());
  61. assert!(regex(r"^a...$", "")(&"b".to_owned()).is_err());
  62. assert!(regex(r"^a...$", "")(&"baaa".to_owned()).is_err());
  63. }
  64. // email
  65. #[test]
  66. pub fn email_valid() {
  67. assert!(email()(&"asdf@asdf.com".to_owned()).is_ok());
  68. assert!(email()(&"amazing.email.address@super.amazing.site.tk".to_owned()).is_ok());
  69. assert!(email()(&"prick@legal.google".to_owned()).is_ok());
  70. }
  71. #[test]
  72. pub fn email_invalid() {
  73. assert!(email()(&"you tried.".to_owned()).is_err());
  74. assert!(email()(&"so close @super.amazing.site.tk".to_owned()).is_err());
  75. assert!(email()(&"prick@legal.g".to_owned()).is_err());
  76. assert!(email()(&"prick@important legal documents!.google".to_owned()).is_err());
  77. }
  78. // url
  79. #[test]
  80. pub fn url_valid() {
  81. assert!(url()(&"http://github.com".to_owned()).is_ok());
  82. assert!(url()(&"https://github.com".to_owned()).is_ok());
  83. assert!(url()(&"www.github.com".to_owned()).is_ok());
  84. assert!(url()(&"github.com".to_owned()).is_ok());
  85. assert!(url()(&"sub.domains.github.fr".to_owned()).is_ok());
  86. assert!(url()(&"neet.cool".to_owned()).is_ok());
  87. assert!(url()(&"github.com/org/repo".to_owned()).is_ok());
  88. assert!(url()(&"github.com/org/repo/logo.jpeg".to_owned()).is_ok());
  89. assert!(url()(&"github.com/org/repo/README#Usage".to_owned()).is_ok());
  90. assert!(url()(&"github.com/org/repo?folder=src&sort=desc".to_owned()).is_ok());
  91. }
  92. #[test]
  93. pub fn url_invalid() {
  94. assert!(url()(&"ftp://super.amazing.site".to_owned()).is_err());
  95. assert!(url()(&"http/super.amazing.site".to_owned()).is_err());
  96. assert!(url()(&"my awesome site!!.com".to_owned()).is_err());
  97. assert!(url()(&"nonon.o".to_owned()).is_err());
  98. assert!(url()(&"github.com/invalid file".to_owned()).is_err());
  99. assert!(url()(&"github.com/file? bad query params".to_owned()).is_err());
  100. assert!(url()(&"github.com/file# bad jump thing".to_owned()).is_err());
  101. }
  102. }