user_email.rs 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. use crate::errors::ErrorCode;
  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, ErrorCode> {
  7. if s.trim().is_empty() {
  8. return Err(ErrorCode::EmailIsEmpty);
  9. }
  10. if validate_email(&s) {
  11. Ok(Self(s))
  12. } else {
  13. Err(ErrorCode::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 claim::assert_err;
  26. use fake::{faker::internet::en::SafeEmail, Fake};
  27. use rand::prelude::StdRng;
  28. use rand_core::SeedableRng;
  29. #[test]
  30. fn empty_string_is_rejected() {
  31. let email = "".to_string();
  32. assert_err!(UserEmail::parse(email));
  33. }
  34. #[test]
  35. fn email_missing_at_symbol_is_rejected() {
  36. let email = "helloworld.com".to_string();
  37. assert_err!(UserEmail::parse(email));
  38. }
  39. #[test]
  40. fn email_missing_subject_is_rejected() {
  41. let email = "@domain.com".to_string();
  42. assert_err!(UserEmail::parse(email));
  43. }
  44. #[derive(Debug, Clone)]
  45. struct ValidEmailFixture(pub String);
  46. impl quickcheck::Arbitrary for ValidEmailFixture {
  47. fn arbitrary(g: &mut quickcheck::Gen) -> Self {
  48. let mut rand_slice: [u8; 32] = [0; 32];
  49. #[allow(clippy::needless_range_loop)]
  50. for i in 0..32 {
  51. rand_slice[i] = u8::arbitrary(g);
  52. }
  53. let mut seed = StdRng::from_seed(rand_slice);
  54. let email = SafeEmail().fake_with_rng(&mut seed);
  55. Self(email)
  56. }
  57. }
  58. #[quickcheck_macros::quickcheck]
  59. fn valid_emails_are_parsed_successfully(valid_email: ValidEmailFixture) -> bool {
  60. UserEmail::parse(valid_email.0).is_ok()
  61. }
  62. }