use crate::mail::Mail;
use regex::bytes::Regex;
use std::collections::HashSet;
#[derive(Default)]
pub struct MailAssertion {
sender: Option<Vec<u8>>,
recipients: Option<RecipientAssertion>,
body: Option<BodyAssertion>,
}
enum RecipientAssertion {
Exact(HashSet<Vec<u8>>),
Contains(HashSet<Vec<u8>>),
}
enum BodyAssertion {
Exact(Vec<u8>),
Regex(Regex),
}
impl MailAssertion {
pub fn new() -> Self {
Default::default()
}
pub fn sender_is<V: AsRef<[u8]>>(mut self, user: V) -> Self {
self.sender = Some(user.as_ref().to_vec());
self
}
pub fn recipients_are<I, S>(mut self, users: I) -> Self
where
I: IntoIterator<Item = S>,
S: AsRef<[u8]>,
{
self.recipients = Some(RecipientAssertion::Exact(Self::convert_recipients(users)));
self
}
pub fn recipients_contain<I, S>(mut self, users: I) -> Self
where
I: IntoIterator<Item = S>,
S: AsRef<[u8]>,
{
self.recipients = Some(RecipientAssertion::Contains(Self::convert_recipients(
users,
)));
self
}
fn convert_recipients<I, S>(users: I) -> HashSet<Vec<u8>>
where
I: IntoIterator<Item = S>,
S: AsRef<[u8]>,
{
users.into_iter().map(|r| r.as_ref().to_vec()).collect()
}
pub fn body_is<V: AsRef<[u8]>>(mut self, text: V) -> Self {
self.body = Some(BodyAssertion::Exact(text.as_ref().to_vec()));
self
}
pub fn body_matches(mut self, regex: Regex) -> Self {
self.body = Some(BodyAssertion::Regex(regex));
self
}
pub(crate) fn assert(&self, mails: &[Mail]) -> bool {
mails.iter().any(|mail| {
self.sender.as_ref().is_none_or(|s| &mail.sender == s)
&& self.recipients.as_ref().is_none_or(|rec| match rec {
RecipientAssertion::Exact(expected) => &mail.recipients == expected,
RecipientAssertion::Contains(needle) => mail.recipients.is_superset(needle),
})
&& self.body.as_ref().is_none_or(|body| match body {
BodyAssertion::Exact(expected) => &mail.body == expected,
BodyAssertion::Regex(re) => re.is_match(&mail.body),
})
})
}
}