use validator::Validate; #[derive(Debug, Validate)] pub struct SubscriberEmail { #[validate(email)] email: String, } impl SubscriberEmail { pub fn parse(email: String) -> Result { let subscriber_email = SubscriberEmail { email }; if subscriber_email.validate().is_err() { anyhow::bail!("{} is not a valid email.", subscriber_email.email); } Ok(subscriber_email) } } impl AsRef for SubscriberEmail { fn as_ref(&self) -> &str { self.email.as_str() } } #[cfg(test)] mod tests { use super::SubscriberEmail; use claims::assert_err; use fake::Fake; use fake::faker::internet::en::SafeEmail; use fake::rand::SeedableRng; use fake::rand::rngs::StdRng; #[derive(Clone, Debug)] struct ValidEmailFixture(pub String); impl quickcheck::Arbitrary for ValidEmailFixture { fn arbitrary(g: &mut quickcheck::Gen) -> Self { let mut rng = StdRng::seed_from_u64(u64::arbitrary(g)); let email = SafeEmail().fake_with_rng(&mut rng); Self(email) } } #[test] fn empty_string_is_rejected() { let email = "".to_string(); assert_err!(SubscriberEmail::parse(email)); } #[test] fn email_missing_at_symbol_is_rejected() { let email = "alphonse.paixoutlook.com".to_string(); assert_err!(SubscriberEmail::parse(email)); } #[test] fn email_missing_subject_is_rejected() { let email = "@outlook.com".to_string(); assert_err!(SubscriberEmail::parse(email)); } #[quickcheck_macros::quickcheck] fn valid_emails_are_parsed_successfully(valid_email: ValidEmailFixture) -> bool { SubscriberEmail::parse(valid_email.0).is_ok() } }