use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq)]
pub struct GroupContacts {
pub emails: Vec<String>,
}
impl GroupContacts {
pub fn new<I, S>(emails: I) -> Self
where
I: IntoIterator<Item = S>,
S: Into<String>,
{
let mut v: Vec<String> = emails
.into_iter()
.map(|e| e.into().trim().to_lowercase())
.filter(|e| !e.is_empty())
.collect();
v.sort();
v.dedup();
Self { emails: v }
}
pub fn is_empty(&self) -> bool {
self.emails.is_empty()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new_trims_lowercases_sorts_dedups_and_drops_blanks() {
let c = GroupContacts::new([
" Ops@Example.com ",
"it@example.com",
"OPS@example.com",
" ",
"",
]);
assert_eq!(c.emails, vec!["it@example.com", "ops@example.com"]);
}
#[test]
fn round_trips_through_json() {
let c = GroupContacts::new(["sec@example.com"]);
let json = serde_json::to_string(&c).unwrap();
assert_eq!(json, r#"{"emails":["sec@example.com"]}"#);
let back: GroupContacts = serde_json::from_str(&json).unwrap();
assert_eq!(back, c);
}
#[test]
fn empty_round_trips() {
let c = GroupContacts::default();
assert_eq!(serde_json::to_string(&c).unwrap(), r#"{"emails":[]}"#);
assert!(c.is_empty());
}
#[test]
fn accepts_unknown_fields_for_forward_compat() {
let json = r#"{"emails":["a@b.com"],"display_name":"IT","set_by":"alice"}"#;
let c: GroupContacts = serde_json::from_str(json).unwrap();
assert_eq!(c.emails, vec!["a@b.com"]);
}
}