#![allow(clippy::unwrap_used, clippy::expect_used)]
use super::*;
#[test]
fn sequence_set_valid_single_number() {
assert!(SequenceSet::new("1").is_ok());
assert!(SequenceSet::new("42").is_ok());
assert!(SequenceSet::new("4294967295").is_ok()); }
#[test]
fn sequence_set_valid_range() {
assert!(SequenceSet::new("1:100").is_ok());
assert!(SequenceSet::new("1:*").is_ok());
assert!(SequenceSet::new("*:1").is_ok());
}
#[test]
fn sequence_set_valid_comma_separated() {
assert!(SequenceSet::new("1,3:5,*").is_ok());
assert!(SequenceSet::new("1,2,3").is_ok());
assert!(SequenceSet::new("1:5,10:20").is_ok());
}
#[test]
fn sequence_set_valid_dollar_sign() {
assert!(SequenceSet::new("$").is_ok());
assert!(SequenceSet::new("1,$").is_ok());
}
#[test]
fn sequence_set_valid_star() {
assert!(SequenceSet::new("*").is_ok());
assert!(SequenceSet::new("1:*").is_ok());
}
#[test]
fn sequence_set_rejects_empty() {
assert!(SequenceSet::new("").is_err());
}
#[test]
fn sequence_set_rejects_zero() {
assert!(SequenceSet::new("0").is_err());
}
#[test]
fn sequence_set_rejects_leading_zero() {
assert!(SequenceSet::new("01").is_err());
}
#[test]
fn sequence_set_rejects_overflow() {
assert!(SequenceSet::new("4294967296").is_err()); }
#[test]
fn sequence_set_rejects_non_digit() {
assert!(SequenceSet::new("abc").is_err());
assert!(SequenceSet::new("1 2").is_err());
}
#[test]
fn sequence_set_rejects_trailing_comma() {
assert!(SequenceSet::new("1,").is_err());
}
#[test]
fn sequence_set_rejects_double_colon() {
assert!(SequenceSet::new("1::2").is_err());
}
#[test]
fn sequence_set_rejects_triple_colon() {
assert!(SequenceSet::new("1:2:3").is_err());
}
#[test]
fn known_sequence_set_valid() {
assert!(SequenceSet::new_known("1").is_ok());
assert!(SequenceSet::new_known("1:100").is_ok());
assert!(SequenceSet::new_known("1,2,3").is_ok());
assert!(SequenceSet::new_known("1:5,10:20").is_ok());
assert!(SequenceSet::new_known("4294967295").is_ok()); }
#[test]
fn known_sequence_set_rejects_star() {
assert!(SequenceSet::new_known("*").is_err());
assert!(SequenceSet::new_known("1:*").is_err());
}
#[test]
fn known_sequence_set_rejects_dollar() {
assert!(SequenceSet::new_known("$").is_err());
assert!(SequenceSet::new_known("1,$").is_err());
}
#[test]
fn known_sequence_set_rejects_empty() {
assert!(SequenceSet::new_known("").is_err());
}
#[test]
fn known_sequence_set_rejects_zero() {
assert!(SequenceSet::new_known("0").is_err());
}
#[test]
fn known_sequence_set_rejects_leading_zero() {
assert!(SequenceSet::new_known("01").is_err());
}
#[test]
fn known_sequence_set_rejects_overflow() {
assert!(SequenceSet::new_known("4294967296").is_err());
}
#[test]
fn known_sequence_set_rejects_trailing_comma() {
assert!(SequenceSet::new_known("1,").is_err());
}
#[test]
fn known_sequence_set_rejects_double_colon() {
assert!(SequenceSet::new_known("1::2").is_err());
}
#[test]
fn sequence_set_display() {
let ss = SequenceSet::new("1:*").unwrap();
assert_eq!(ss.to_string(), "1:*");
}
#[test]
fn sequence_set_as_ref() {
let ss = SequenceSet::new("1,2,3").unwrap();
let r: &str = ss.as_ref();
assert_eq!(r, "1,2,3");
}
#[test]
fn sequence_set_as_str() {
let ss = SequenceSet::new("1:100").unwrap();
assert_eq!(ss.as_str(), "1:100");
}
#[test]
fn sequence_set_try_from_string() {
let ss: Result<SequenceSet, _> = "1:*".to_string().try_into();
assert!(ss.is_ok());
}
#[test]
fn sequence_set_try_from_str() {
let ss: Result<SequenceSet, _> = SequenceSet::try_from("1:*");
assert!(ss.is_ok());
}
#[test]
fn sequence_set_try_from_invalid() {
let ss: Result<SequenceSet, _> = String::new().try_into();
assert!(ss.is_err());
}
#[test]
fn atom_valid() {
assert!(ImapAtom::new("PLAIN").is_ok());
assert!(ImapAtom::new("a").is_ok());
assert!(ImapAtom::new("AUTH=PLAIN").is_ok());
}
#[test]
fn atom_rejects_empty() {
assert!(ImapAtom::new("").is_err());
}
#[test]
fn atom_rejects_specials() {
assert!(ImapAtom::new("(").is_err());
assert!(ImapAtom::new(")").is_err());
assert!(ImapAtom::new("{").is_err());
assert!(ImapAtom::new(" ").is_err());
assert!(ImapAtom::new("%").is_err());
assert!(ImapAtom::new("*").is_err());
assert!(ImapAtom::new("\"").is_err());
assert!(ImapAtom::new("\\").is_err());
assert!(ImapAtom::new("]").is_err());
}
#[test]
fn atom_rejects_ctl() {
assert!(ImapAtom::new("\x00").is_err());
assert!(ImapAtom::new("\x1F").is_err());
assert!(ImapAtom::new("\x7F").is_err());
}
#[test]
fn atom_rejects_non_ascii() {
assert!(ImapAtom::new("\u{00e9}").is_err()); }
#[test]
fn atom_rejects_crlf() {
assert!(ImapAtom::new("A\r\nB").is_err());
}
#[test]
fn atom_display() {
let a = ImapAtom::new("PLAIN").unwrap();
assert_eq!(a.to_string(), "PLAIN");
}
#[test]
fn atom_as_ref() {
let a = ImapAtom::new("XOAUTH2").unwrap();
let r: &str = a.as_ref();
assert_eq!(r, "XOAUTH2");
}
#[test]
fn atom_try_from_string() {
let a: Result<ImapAtom, _> = "PLAIN".to_string().try_into();
assert!(a.is_ok());
}
#[test]
fn atom_try_from_str() {
let a: Result<ImapAtom, _> = ImapAtom::try_from("PLAIN");
assert!(a.is_ok());
}
#[test]
fn atom_try_from_invalid() {
let a: Result<ImapAtom, _> = String::new().try_into();
assert!(a.is_err());
}
#[test]
fn mailbox_name_valid() {
assert!(MailboxName::new("INBOX").is_ok());
assert!(MailboxName::new("My Drafts").is_ok()); assert!(MailboxName::new("日本語").is_ok()); assert!(MailboxName::new("Archive/2024").is_ok());
}
#[test]
fn mailbox_name_allows_empty() {
assert!(MailboxName::new("").is_ok());
}
#[test]
fn mailbox_name_rejects_cr() {
assert!(MailboxName::new("INBOX\r").is_err());
}
#[test]
fn mailbox_name_rejects_lf() {
assert!(MailboxName::new("INBOX\n").is_err());
}
#[test]
fn mailbox_name_rejects_crlf() {
assert!(MailboxName::new("INBOX\r\nDELETE").is_err());
}
#[test]
fn mailbox_name_rejects_nul() {
assert!(MailboxName::new("IN\0BOX").is_err());
}
#[test]
fn mailbox_name_display() {
let m = MailboxName::new("INBOX").unwrap();
assert_eq!(m.to_string(), "INBOX");
}
#[test]
fn mailbox_name_as_ref() {
let m = MailboxName::new("Sent").unwrap();
let r: &str = m.as_ref();
assert_eq!(r, "Sent");
}
#[test]
fn mailbox_name_as_str() {
let m = MailboxName::new("Archive").unwrap();
assert_eq!(m.as_str(), "Archive");
}
#[test]
fn mailbox_name_try_from_string() {
let m: Result<MailboxName, _> = "INBOX".to_string().try_into();
assert!(m.is_ok());
}
#[test]
fn mailbox_name_try_from_invalid() {
let m: Result<MailboxName, _> = "INBOX\r\n".to_string().try_into();
assert!(m.is_err());
}
#[test]
fn object_id_valid() {
assert!(ObjectId::new("abc123").is_ok());
assert!(ObjectId::new("A-B_C").is_ok());
assert!(ObjectId::new("x").is_ok());
assert!(ObjectId::new("a".repeat(255)).is_ok());
}
#[test]
fn object_id_rejects_empty() {
assert!(ObjectId::new("").is_err());
}
#[test]
fn object_id_rejects_too_long() {
assert!(ObjectId::new("a".repeat(256)).is_err());
}
#[test]
fn object_id_rejects_special_chars() {
assert!(ObjectId::new("abc!def").is_err());
assert!(ObjectId::new("abc def").is_err());
assert!(ObjectId::new("abc.def").is_err());
}
#[test]
fn object_id_rejects_non_ascii() {
assert!(ObjectId::new("abc\u{00e9}").is_err());
}
#[test]
fn object_id_display() {
let oid = ObjectId::new("M6d99ac3275826039").unwrap();
assert_eq!(oid.to_string(), "M6d99ac3275826039");
}
#[test]
fn object_id_as_ref() {
let oid = ObjectId::new("abc123").unwrap();
let r: &str = oid.as_ref();
assert_eq!(r, "abc123");
}
#[test]
fn object_id_as_str() {
let oid = ObjectId::new("abc123").unwrap();
assert_eq!(oid.as_str(), "abc123");
}
#[test]
fn object_id_try_from_string() {
let oid: Result<ObjectId, _> = "abc123".to_string().try_into();
assert!(oid.is_ok());
}
#[test]
fn object_id_try_from_str() {
let oid: Result<ObjectId, _> = ObjectId::try_from("abc123");
assert!(oid.is_ok());
}
#[test]
fn object_id_try_from_invalid() {
let oid: Result<ObjectId, _> = String::new().try_into();
assert!(oid.is_err());
}
use crate::types::UidRange;
fn intervals(set: &ParsedUidSet) -> &[(u32, u32)] {
&set.0
}
#[test]
fn parsed_uid_set_single_uid() {
let ss = SequenceSet::new("5").unwrap();
let set = ParsedUidSet::new(&ss).unwrap();
assert_eq!(intervals(&set), &[(5, 5)]);
}
#[test]
fn parsed_uid_set_range() {
let ss = SequenceSet::new("5:10").unwrap();
let set = ParsedUidSet::new(&ss).unwrap();
assert_eq!(intervals(&set), &[(5, 10)]);
}
#[test]
fn parsed_uid_set_multiple_disjoint() {
let ss = SequenceSet::new("1:5,10:20").unwrap();
let set = ParsedUidSet::new(&ss).unwrap();
assert_eq!(intervals(&set), &[(1, 5), (10, 20)]);
}
#[test]
fn parsed_uid_set_overlapping_merged() {
let ss = SequenceSet::new("1:10,5:15").unwrap();
let set = ParsedUidSet::new(&ss).unwrap();
assert_eq!(intervals(&set), &[(1, 15)]);
}
#[test]
fn parsed_uid_set_adjacent_merged() {
let ss = SequenceSet::new("1:5,6:10").unwrap();
let set = ParsedUidSet::new(&ss).unwrap();
assert_eq!(intervals(&set), &[(1, 10)]);
}
#[test]
fn parsed_uid_set_reversed_range() {
let ss = SequenceSet::new("10:5").unwrap();
let set = ParsedUidSet::new(&ss).unwrap();
assert_eq!(intervals(&set), &[(5, 10)]);
}
#[test]
fn parsed_uid_set_star_in_range() {
let ss = SequenceSet::new("5:*").unwrap();
let set = ParsedUidSet::new(&ss).unwrap();
assert_eq!(intervals(&set), &[(5, u32::MAX)]);
}
#[test]
fn parsed_uid_set_star_alone() {
let ss = SequenceSet::new("*").unwrap();
let set = ParsedUidSet::new(&ss).unwrap();
assert_eq!(intervals(&set), &[(u32::MAX, u32::MAX)]);
}
#[test]
fn parsed_uid_set_dollar_returns_none() {
let ss = SequenceSet::new("$").unwrap();
assert!(ParsedUidSet::new(&ss).is_none());
}
#[test]
fn parsed_uid_set_dollar_mixed_returns_none() {
let ss = SequenceSet::new("$,1:5").unwrap();
assert!(ParsedUidSet::new(&ss).is_none());
}
#[test]
fn parsed_uid_set_u32_max() {
let ss = SequenceSet::new("4294967295").unwrap();
let set = ParsedUidSet::new(&ss).unwrap();
assert_eq!(intervals(&set), &[(u32::MAX, u32::MAX)]);
}
#[test]
fn parsed_uid_set_complex_merge() {
let ss = SequenceSet::new("20:25,1:3,2:5,6:10").unwrap();
let set = ParsedUidSet::new(&ss).unwrap();
assert_eq!(intervals(&set), &[(1, 10), (20, 25)]);
}
#[test]
fn intersect_total_containment() {
let ss = SequenceSet::new("1:20").unwrap();
let set = ParsedUidSet::new(&ss).unwrap();
let vanished = vec![UidRange::range(5, 10)];
let (result, dropped) = set.intersect_uid_ranges(&vanished);
assert_eq!(result, vec![UidRange::range(5, 10)]);
assert_eq!(dropped, 0);
}
#[test]
fn intersect_total_exclusion() {
let ss = SequenceSet::new("1:5").unwrap();
let set = ParsedUidSet::new(&ss).unwrap();
let vanished = vec![UidRange::range(10, 20)];
let (result, dropped) = set.intersect_uid_ranges(&vanished);
assert!(result.is_empty());
assert_eq!(dropped, 11); }
#[test]
fn intersect_partial_overlap() {
let ss = SequenceSet::new("5:15").unwrap();
let set = ParsedUidSet::new(&ss).unwrap();
let vanished = vec![UidRange::range(1, 10)];
let (result, dropped) = set.intersect_uid_ranges(&vanished);
assert_eq!(result, vec![UidRange::range(5, 10)]);
assert_eq!(dropped, 4); }
#[test]
fn intersect_spanning_gap() {
let ss = SequenceSet::new("1:5,15:20").unwrap();
let set = ParsedUidSet::new(&ss).unwrap();
let vanished = vec![UidRange::range(3, 18)];
let (result, dropped) = set.intersect_uid_ranges(&vanished);
assert_eq!(result, vec![UidRange::range(3, 5), UidRange::range(15, 18)]);
assert_eq!(dropped, 9); }
#[test]
fn intersect_single_uid_match() {
let ss = SequenceSet::new("1:10").unwrap();
let set = ParsedUidSet::new(&ss).unwrap();
let vanished = vec![UidRange::single(5)];
let (result, dropped) = set.intersect_uid_ranges(&vanished);
assert_eq!(result, vec![UidRange::single(5)]);
assert_eq!(dropped, 0);
}
#[test]
fn intersect_single_uid_miss() {
let ss = SequenceSet::new("1:5").unwrap();
let set = ParsedUidSet::new(&ss).unwrap();
let vanished = vec![UidRange::single(10)];
let (result, dropped) = set.intersect_uid_ranges(&vanished);
assert!(result.is_empty());
assert_eq!(dropped, 1);
}
#[test]
fn intersect_empty_input() {
let ss = SequenceSet::new("1:100").unwrap();
let set = ParsedUidSet::new(&ss).unwrap();
let (result, dropped) = set.intersect_uid_ranges(&[]);
assert!(result.is_empty());
assert_eq!(dropped, 0);
}
#[test]
fn intersect_reversed_uid_range() {
let ss = SequenceSet::new("1:10").unwrap();
let set = ParsedUidSet::new(&ss).unwrap();
let vanished = vec![UidRange::range(8, 3)]; let (result, dropped) = set.intersect_uid_ranges(&vanished);
assert_eq!(result, vec![UidRange::range(3, 8)]);
assert_eq!(dropped, 0);
}
#[test]
fn intersect_vanished_entirely_in_gap() {
let ss = SequenceSet::new("1:5,20:25").unwrap();
let set = ParsedUidSet::new(&ss).unwrap();
let vanished = vec![UidRange::range(10, 15)];
let (result, dropped) = set.intersect_uid_ranges(&vanished);
assert!(result.is_empty());
assert_eq!(dropped, 6);
}
#[test]
fn intersect_multiple_vanished_ranges() {
let ss = SequenceSet::new("1:10,20:30").unwrap();
let set = ParsedUidSet::new(&ss).unwrap();
let vanished = vec![
UidRange::range(5, 8), UidRange::range(12, 18), UidRange::range(25, 35), ];
let (result, dropped) = set.intersect_uid_ranges(&vanished);
assert_eq!(result, vec![UidRange::range(5, 8), UidRange::range(25, 30)]);
assert_eq!(dropped, 7 + 5); }
#[test]
fn intersect_single_uid_overlap_produces_single() {
let ss = SequenceSet::new("5:10").unwrap();
let set = ParsedUidSet::new(&ss).unwrap();
let vanished = vec![UidRange::range(1, 5)];
let (result, dropped) = set.intersect_uid_ranges(&vanished);
assert_eq!(result, vec![UidRange::single(5)]);
assert_eq!(dropped, 4); }