user_email.rs 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. use crate::errors::UserErrorCode;
  2. use validator::validate_email;
  3. #[derive(Debug)]
  4. pub struct UserEmail(pub String);
  5. impl UserEmail {
  6. pub fn parse(s: String) -> Result<UserEmail, UserErrorCode> {
  7. if s.trim().is_empty() {
  8. return Err(UserErrorCode::EmailIsEmpty);
  9. }
  10. if validate_email(&s) {
  11. Ok(Self(s))
  12. } else {
  13. Err(UserErrorCode::EmailFormatInvalid)
  14. }
  15. }
  16. }
  17. impl AsRef<str> for UserEmail {
  18. fn as_ref(&self) -> &str {
  19. &self.0
  20. }
  21. }
  22. #[cfg(test)]
  23. mod tests {
  24. use super::*;
  25. use fake::{faker::internet::en::SafeEmail, Fake};
  26. use rand::prelude::StdRng;
  27. use rand_core::SeedableRng;
  28. #[test]
  29. fn empty_string_is_rejected() {
  30. let email = "".to_string();
  31. assert!(UserEmail::parse(email).is_err());
  32. }
  33. #[test]
  34. fn email_missing_at_symbol_is_rejected() {
  35. let email = "helloworld.com".to_string();
  36. assert!(UserEmail::parse(email).is_err());
  37. }
  38. #[test]
  39. fn email_missing_subject_is_rejected() {
  40. let email = "@domain.com".to_string();
  41. assert!(UserEmail::parse(email).is_err());
  42. }
  43. #[derive(Debug, Clone)]
  44. struct ValidEmailFixture(pub String);
  45. impl quickcheck::Arbitrary for ValidEmailFixture {
  46. fn arbitrary(g: &mut quickcheck::Gen) -> Self {
  47. let mut rand_slice: [u8; 32] = [0; 32];
  48. #[allow(clippy::needless_range_loop)]
  49. for i in 0..32 {
  50. rand_slice[i] = u8::arbitrary(g);
  51. }
  52. let mut seed = StdRng::from_seed(rand_slice);
  53. let email = SafeEmail().fake_with_rng(&mut seed);
  54. Self(email)
  55. }
  56. }
  57. #[quickcheck_macros::quickcheck]
  58. fn valid_emails_are_parsed_successfully(valid_email: ValidEmailFixture) -> bool {
  59. UserEmail::parse(valid_email.0).is_ok()
  60. }
  61. }