#![allow(clippy::unwrap_used, clippy::expect_used)]
use super::*;
use crate::types::validated::MailboxName;
#[test]
fn special_use_from_attribute() {
let info = MailboxInfo {
name: MailboxName::new("MyArchive").unwrap(),
delimiter: Some('/'),
attributes: vec![MailboxAttribute::Archive],
..Default::default()
};
assert_eq!(info.special_use(), Some(SpecialUse::Archive));
}
#[test]
fn special_use_name_fallback() {
let info = MailboxInfo {
name: MailboxName::new("Spam").unwrap(),
delimiter: Some('/'),
attributes: vec![],
..Default::default()
};
assert_eq!(info.special_use(), Some(SpecialUse::Junk));
}
#[test]
fn special_use_case_insensitive() {
let info = MailboxInfo {
name: MailboxName::new("SENT").unwrap(),
delimiter: Some('/'),
attributes: vec![],
..Default::default()
};
assert_eq!(info.special_use(), Some(SpecialUse::Sent));
}
#[test]
fn special_use_nested_name() {
let info = MailboxInfo {
name: MailboxName::new("INBOX/Trash").unwrap(),
delimiter: Some('/'),
attributes: vec![],
..Default::default()
};
assert_eq!(info.special_use(), Some(SpecialUse::Trash));
}
#[test]
fn special_use_attribute_overrides_name() {
let info = MailboxInfo {
name: MailboxName::new("Trash").unwrap(),
delimiter: Some('/'),
attributes: vec![MailboxAttribute::Sent],
..Default::default()
};
assert_eq!(info.special_use(), Some(SpecialUse::Sent));
}
#[test]
fn special_use_dot_delimiter() {
let info = MailboxInfo {
name: MailboxName::new("INBOX.Trash").unwrap(),
delimiter: Some('.'),
attributes: vec![],
..Default::default()
};
assert_eq!(info.special_use(), Some(SpecialUse::Trash));
}
#[test]
fn special_use_no_delimiter() {
let info = MailboxInfo {
name: MailboxName::new("Sent").unwrap(),
delimiter: None,
attributes: vec![],
..Default::default()
};
assert_eq!(info.special_use(), Some(SpecialUse::Sent));
}
#[test]
fn special_use_unknown() {
let info = MailboxInfo {
name: MailboxName::new("Work").unwrap(),
delimiter: Some('/'),
attributes: vec![],
..Default::default()
};
assert_eq!(info.special_use(), None);
}
#[test]
fn special_use_from_drafts_attribute() {
let info = MailboxInfo {
name: MailboxName::new("MyDrafts").unwrap(),
delimiter: Some('/'),
attributes: vec![MailboxAttribute::Drafts],
..Default::default()
};
assert_eq!(info.special_use(), Some(SpecialUse::Drafts));
}
#[test]
fn special_use_from_junk_attribute() {
let info = MailboxInfo {
name: MailboxName::new("SpamFolder").unwrap(),
delimiter: Some('/'),
attributes: vec![MailboxAttribute::Junk],
..Default::default()
};
assert_eq!(info.special_use(), Some(SpecialUse::Junk));
}
#[test]
fn special_use_from_trash_attribute() {
let info = MailboxInfo {
name: MailboxName::new("Bin").unwrap(),
delimiter: Some('/'),
attributes: vec![MailboxAttribute::Trash],
..Default::default()
};
assert_eq!(info.special_use(), Some(SpecialUse::Trash));
}
#[test]
fn special_use_from_flagged_attribute() {
let info = MailboxInfo {
name: MailboxName::new("Stars").unwrap(),
delimiter: Some('/'),
attributes: vec![MailboxAttribute::Flagged],
..Default::default()
};
assert_eq!(info.special_use(), Some(SpecialUse::Flagged));
}
#[test]
fn special_use_from_important_attribute() {
let info = MailboxInfo {
name: MailboxName::new("Priority").unwrap(),
delimiter: Some('/'),
attributes: vec![MailboxAttribute::Important],
..Default::default()
};
assert_eq!(info.special_use(), Some(SpecialUse::Important));
}
#[test]
fn special_use_name_fallback_infers_important() {
let info = MailboxInfo {
name: MailboxName::new("Important").unwrap(),
delimiter: Some('/'),
attributes: vec![],
..Default::default()
};
assert_eq!(info.special_use(), Some(SpecialUse::Important));
}
#[test]
fn special_use_name_fallback_infers_all_mail() {
let info = MailboxInfo {
name: MailboxName::new("[Gmail]/All Mail").unwrap(),
delimiter: Some('/'),
attributes: vec![],
..Default::default()
};
assert_eq!(info.special_use(), Some(SpecialUse::All));
}
#[test]
fn special_use_name_fallback_infers_flagged_from_starred() {
let info = MailboxInfo {
name: MailboxName::new("Starred").unwrap(),
delimiter: Some('/'),
attributes: vec![],
..Default::default()
};
assert_eq!(info.special_use(), Some(SpecialUse::Flagged));
}
#[test]
fn special_use_name_fallback_returns_none_for_unknown_name() {
let info = MailboxInfo {
name: MailboxName::new("Projects/2024/reports").unwrap(),
delimiter: Some('/'),
attributes: vec![MailboxAttribute::HasNoChildren],
..Default::default()
};
assert_eq!(info.special_use(), None);
}
#[test]
fn status_item_mailboxid() {
let item = StatusItem::MailboxId("F2212ea87-6097-4256".into());
assert_eq!(item, StatusItem::MailboxId("F2212ea87-6097-4256".into()));
}
#[test]
fn as_imap_str_base_attributes() {
assert_eq!(MailboxAttribute::NoInferiors.as_imap_str(), "\\Noinferiors");
assert_eq!(MailboxAttribute::NoSelect.as_imap_str(), "\\Noselect");
assert_eq!(MailboxAttribute::NonExistent.as_imap_str(), "\\NonExistent");
assert_eq!(MailboxAttribute::HasChildren.as_imap_str(), "\\HasChildren");
assert_eq!(
MailboxAttribute::HasNoChildren.as_imap_str(),
"\\HasNoChildren"
);
assert_eq!(MailboxAttribute::Marked.as_imap_str(), "\\Marked");
assert_eq!(MailboxAttribute::Unmarked.as_imap_str(), "\\Unmarked");
assert_eq!(MailboxAttribute::Subscribed.as_imap_str(), "\\Subscribed");
assert_eq!(MailboxAttribute::Remote.as_imap_str(), "\\Remote");
}
#[test]
fn as_imap_str_special_use_attributes() {
assert_eq!(MailboxAttribute::All.as_imap_str(), "\\All");
assert_eq!(MailboxAttribute::Archive.as_imap_str(), "\\Archive");
assert_eq!(MailboxAttribute::Drafts.as_imap_str(), "\\Drafts");
assert_eq!(MailboxAttribute::Flagged.as_imap_str(), "\\Flagged");
assert_eq!(MailboxAttribute::Junk.as_imap_str(), "\\Junk");
assert_eq!(MailboxAttribute::Sent.as_imap_str(), "\\Sent");
assert_eq!(MailboxAttribute::Trash.as_imap_str(), "\\Trash");
assert_eq!(MailboxAttribute::Important.as_imap_str(), "\\Important");
}
#[test]
fn as_imap_str_non_standard_attributes() {
assert_eq!(MailboxAttribute::Memos.as_imap_str(), "\\Memos");
assert_eq!(MailboxAttribute::Scheduled.as_imap_str(), "\\Scheduled");
assert_eq!(MailboxAttribute::Snoozed.as_imap_str(), "\\Snoozed");
}
#[test]
fn as_imap_str_custom() {
let attr = MailboxAttribute::Custom("\\MyCustom".into());
assert_eq!(attr.as_imap_str(), "\\MyCustom");
}
#[test]
fn custom_attribute_equality_is_case_insensitive() {
assert_eq!(
MailboxAttribute::Custom("\\MyCustom".into()),
MailboxAttribute::Custom("\\mycustom".into()),
"Custom mailbox attributes must compare case-insensitively per RFC 3501 Section 7.2.2"
);
}
#[test]
fn custom_attribute_hash_is_case_insensitive() {
use std::collections::HashSet;
let mut set = HashSet::new();
set.insert(MailboxAttribute::Custom("\\MyCustom".into()));
set.insert(MailboxAttribute::Custom("\\mycustom".into()));
assert_eq!(
set.len(),
1,
"Case-insensitively equal Custom attributes must have the same Hash per RFC 3501 Section 7.2.2"
);
}
#[test]
fn custom_noselect_equals_noselect_variant() {
assert_eq!(
MailboxAttribute::Custom("\\Noselect".into()),
MailboxAttribute::NoSelect,
"Custom(\"\\\\Noselect\") must equal MailboxAttribute::NoSelect \
per RFC 3501 Section 7.2.2"
);
}
#[test]
fn custom_haschildren_equals_haschildren_variant() {
assert_eq!(
MailboxAttribute::Custom("\\HasChildren".into()),
MailboxAttribute::HasChildren,
"Custom(\"\\\\HasChildren\") must equal MailboxAttribute::HasChildren \
per RFC 3501 Section 7.2.2"
);
}
#[test]
fn custom_sent_equals_sent_variant() {
assert_eq!(
MailboxAttribute::Custom("\\Sent".into()),
MailboxAttribute::Sent,
"Custom(\"\\\\Sent\") must equal MailboxAttribute::Sent \
per RFC 6154 Section 2"
);
}
#[test]
fn custom_attribute_cross_representation_hash() {
use std::collections::HashSet;
let mut set = HashSet::new();
set.insert(MailboxAttribute::NoSelect);
set.insert(MailboxAttribute::Custom("\\Noselect".into()));
assert_eq!(
set.len(),
1,
"Custom(\"\\\\Noselect\") and NoSelect must hash the same \
per RFC 3501 Section 7.2.2"
);
}
#[test]
fn is_special_use_custom_noselect_is_not_special_use() {
assert!(
!MailboxAttribute::Custom("\\Noselect".into()).is_special_use(),
"Custom(\"\\\\Noselect\") must not be special-use — it is a base LIST attribute"
);
}
#[test]
fn is_special_use_custom_haschildren_is_not_special_use() {
assert!(
!MailboxAttribute::Custom("\\HasChildren".into()).is_special_use(),
"Custom(\"\\\\HasChildren\") must not be special-use — it is a base LIST attribute"
);
}
#[test]
fn is_special_use_custom_marked_is_not_special_use() {
assert!(
!MailboxAttribute::Custom("\\Marked".into()).is_special_use(),
"Custom(\"\\\\Marked\") must not be special-use — it is a base LIST attribute"
);
}
#[test]
fn is_special_use_custom_unknown_is_special_use() {
assert!(
MailboxAttribute::Custom("\\MyCustomFlag".into()).is_special_use(),
"Custom(\"\\\\MyCustomFlag\") should be special-use (potential use-attr-ext)"
);
}
#[test]
fn is_special_use_custom_missing_backslash_is_not_special_use() {
assert!(
!MailboxAttribute::Custom("MyCustomFlag".into()).is_special_use(),
"Custom(\"MyCustomFlag\") must not be special-use because use-attr-ext requires a leading backslash"
);
}
#[test]
fn is_special_use_custom_with_invalid_atom_char_is_not_special_use() {
assert!(
!MailboxAttribute::Custom("\\Bad Attr".into()).is_special_use(),
"Custom(\"\\\\Bad Attr\") must not be special-use because SP is not legal in IMAP atoms"
);
}
#[test]
fn is_special_use_known_special_use_variants() {
assert!(MailboxAttribute::All.is_special_use());
assert!(MailboxAttribute::Archive.is_special_use());
assert!(MailboxAttribute::Drafts.is_special_use());
assert!(MailboxAttribute::Flagged.is_special_use());
assert!(MailboxAttribute::Junk.is_special_use());
assert!(MailboxAttribute::Sent.is_special_use());
assert!(MailboxAttribute::Trash.is_special_use());
assert!(MailboxAttribute::Important.is_special_use());
}
#[test]
fn is_special_use_base_list_variants_are_not_special_use() {
assert!(!MailboxAttribute::NoInferiors.is_special_use());
assert!(!MailboxAttribute::NoSelect.is_special_use());
assert!(!MailboxAttribute::NonExistent.is_special_use());
assert!(!MailboxAttribute::HasChildren.is_special_use());
assert!(!MailboxAttribute::HasNoChildren.is_special_use());
assert!(!MailboxAttribute::Marked.is_special_use());
assert!(!MailboxAttribute::Unmarked.is_special_use());
assert!(!MailboxAttribute::Subscribed.is_special_use());
assert!(!MailboxAttribute::Remote.is_special_use());
}
#[test]
fn is_special_use_custom_base_attr_case_insensitive() {
assert!(
!MailboxAttribute::Custom("\\NOSELECT".into()).is_special_use(),
"Case-insensitive match: \\NOSELECT is \\Noselect"
);
assert!(
!MailboxAttribute::Custom("\\haschildren".into()).is_special_use(),
"Case-insensitive match: \\haschildren is \\HasChildren"
);
assert!(
!MailboxAttribute::Custom("\\NOINFERIORS".into()).is_special_use(),
"Case-insensitive match: \\NOINFERIORS is \\Noinferiors"
);
}
#[test]
fn spec_audit_l13_appendlimit_status_attribute() {
let input = b"* STATUS \"INBOX\" (MESSAGES 10 APPENDLIMIT 1048576)\r\n";
let (_, resp) = crate::codec::decode::parse_response(input).expect("should parse APPENDLIMIT");
match resp {
crate::types::response::Response::Untagged(inner) => match *inner {
crate::types::response::UntaggedResponse::MailboxStatus { ref items, .. } => {
let has_appendlimit = items
.iter()
.any(|item| matches!(item, StatusItem::AppendLimit(Some(1_048_576))));
assert!(
has_appendlimit,
"STATUS response should contain AppendLimit(Some(1048576)); got {items:?}"
);
}
other => panic!("expected MailboxStatus, got {other:?}"),
},
other => panic!("expected Untagged, got {other:?}"),
}
}
#[test]
fn mailbox_attr_from_str_known_variants() {
assert_eq!(
MailboxAttribute::from("\\Noselect"),
MailboxAttribute::NoSelect
);
assert_eq!(
MailboxAttribute::from("\\HasChildren"),
MailboxAttribute::HasChildren
);
assert_eq!(MailboxAttribute::from("\\Sent"), MailboxAttribute::Sent);
assert_eq!(MailboxAttribute::from("\\Drafts"), MailboxAttribute::Drafts);
assert_eq!(MailboxAttribute::from("\\Trash"), MailboxAttribute::Trash);
assert_eq!(MailboxAttribute::from("\\Junk"), MailboxAttribute::Junk);
assert_eq!(
MailboxAttribute::from("\\Archive"),
MailboxAttribute::Archive
);
assert_eq!(
MailboxAttribute::from("\\Important"),
MailboxAttribute::Important
);
assert_eq!(
MailboxAttribute::from("\\NonExistent"),
MailboxAttribute::NonExistent
);
}
#[test]
fn mailbox_attr_from_string_known_variant() {
assert_eq!(
MailboxAttribute::from("\\Sent".to_owned()),
MailboxAttribute::Sent
);
assert_eq!(
MailboxAttribute::from("\\Trash".to_owned()),
MailboxAttribute::Trash
);
}
#[test]
fn mailbox_attr_from_str_case_insensitive() {
assert_eq!(
MailboxAttribute::from("\\NOSELECT"),
MailboxAttribute::NoSelect
);
assert_eq!(
MailboxAttribute::from("\\noselect"),
MailboxAttribute::NoSelect
);
assert_eq!(
MailboxAttribute::from("\\HASCHILDREN"),
MailboxAttribute::HasChildren
);
assert_eq!(MailboxAttribute::from("\\sent"), MailboxAttribute::Sent);
}
#[test]
fn mailbox_attr_from_str_custom() {
assert_eq!(
MailboxAttribute::from("\\MyCustom"),
MailboxAttribute::Custom("\\MyCustom".to_owned())
);
}
#[test]
fn mailbox_attr_from_str_non_standard_google() {
assert_eq!(MailboxAttribute::from("\\Memos"), MailboxAttribute::Memos);
assert_eq!(
MailboxAttribute::from("\\Scheduled"),
MailboxAttribute::Scheduled
);
assert_eq!(
MailboxAttribute::from("\\Snoozed"),
MailboxAttribute::Snoozed
);
}