Files
ElyOffice/crates/ely-mail-engine/tests/vault.rs
T
雷电芽衣 1c225f6812 C12.5: mail accounts, add and remove
ElyMail's window lists accounts and adds Gmail, Microsoft, iCloud
(app-specific password), IMAP and POP3 ones; a check logs in to both
servers and reports each. Accounts live in the store as JSON with a
case-insensitive unique address; secrets go to the keychain. Removal
names the cache it deletes, takes the secret first and puts it back
when local removal fails. Originals are set aside until commit and
restored after a crash. Requests are numbered so late results stay
with their own dialog. The account list is keyboard-navigable.
2026-10-19 20:17:19 -04:00

88 lines
2.5 KiB
Rust

use std::{
collections::HashMap,
sync::{Arc, Mutex},
};
use ely_mail_engine::{Backend, Error, Kept, Vault};
#[derive(Clone, Default)]
struct Fake {
saved: Arc<Mutex<HashMap<String, String>>>,
refuse: Option<&'static str>,
}
impl Backend for Fake {
fn get(&self, name: &str) -> Result<Option<String>, String> {
match self.refuse {
Some(reason) => Err(reason.into()),
None => Ok(self.saved.lock().unwrap().get(name).cloned()),
}
}
fn set(&self, name: &str, secret: &str) -> Result<(), String> {
match self.refuse {
Some(reason) => Err(reason.into()),
None => {
self.saved
.lock()
.unwrap()
.insert(name.into(), secret.into());
Ok(())
}
}
}
fn delete(&self, name: &str) -> Result<(), String> {
match self.refuse {
Some(reason) => Err(reason.into()),
None => {
self.saved.lock().unwrap().remove(name);
Ok(())
}
}
}
}
#[test]
fn secrets_go_to_the_system_store() {
let fake = Fake::default();
let vault = Vault::new(Box::new(fake.clone()));
assert_eq!(vault.get("a").unwrap(), None);
assert_eq!(vault.put("a", "rt-1"), Kept::System);
assert_eq!(fake.saved.lock().unwrap()["a"], "rt-1");
assert_eq!(vault.get("a").unwrap().as_deref(), Some("rt-1"));
vault.remove("a").unwrap();
assert!(fake.saved.lock().unwrap().is_empty());
}
#[test]
fn a_refused_store_keeps_the_secret_for_this_session() {
let vault = Vault::new(Box::new(Fake {
refuse: Some("locked"),
..Fake::default()
}));
assert_eq!(vault.put("a", "pw"), Kept::Session("locked".into()));
assert_eq!(vault.get("a").unwrap().as_deref(), Some("pw"));
let err = vault.get("b").err().unwrap();
assert!(matches!(err, Error::Vault(text) if text.contains("locked")));
let err = vault.remove("a").err().unwrap();
assert!(matches!(err, Error::Vault(_)));
assert_eq!(
vault.get("a").unwrap().as_deref(),
Some("pw"),
"a failed remove keeps the session copy"
);
}
#[test]
fn a_new_secret_replaces_the_session_copy() {
let fake = Fake {
refuse: Some("locked"),
..Fake::default()
};
let vault = Vault::new(Box::new(fake));
vault.put("a", "old");
assert_eq!(vault.put("a", "new"), Kept::Session("locked".into()));
assert_eq!(vault.get("a").unwrap().as_deref(), Some("new"));
}