Skip to content

Commit fd243fa

Browse files
committed
maildir: add mailbox creation tests
Signed-off-by: Manos Pitsidianakis <[email protected]>
1 parent 36a63e8 commit fd243fa

File tree

1 file changed

+316
-3
lines changed

1 file changed

+316
-3
lines changed

melib/src/maildir/tests.rs

Lines changed: 316 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,19 @@
2020
//
2121
// SPDX-License-Identifier: EUPL-1.2 OR GPL-3.0-or-later
2222

23-
use std::path::{Path, PathBuf};
23+
use std::{
24+
path::{Path, PathBuf},
25+
sync::Arc,
26+
};
2427

2528
use regex::Regex;
29+
use tempfile::TempDir;
2630

2731
use crate::{
28-
backends::FlagOp,
32+
backends::prelude::*,
2933
email::Flag,
3034
error::Result,
31-
maildir::{move_to_cur, Configuration, MaildirPathTrait},
35+
maildir::{move_to_cur, Configuration, MaildirMailbox, MaildirPathTrait, MaildirType},
3236
};
3337

3438
fn set_flags(config: &Configuration, path: &Path, flag_ops: &[FlagOp]) -> Result<PathBuf> {
@@ -232,3 +236,312 @@ fn test_maildir_place_in_dir_regexp() {
232236
"place_in_dir() should add missing `:2,` substring"
233237
);
234238
}
239+
240+
fn new_maildir_backend(
241+
temp_dir: &TempDir,
242+
acc_name: &str,
243+
event_consumer: BackendEventConsumer,
244+
with_root_mailbox: bool,
245+
) -> Result<(PathBuf, AccountSettings, Box<MaildirType>)> {
246+
let root_mailbox = temp_dir.path().join("INBOX");
247+
{
248+
std::fs::create_dir(&root_mailbox).expect("Could not create root mailbox directory.");
249+
if with_root_mailbox {
250+
for d in &["cur", "new", "tmp"] {
251+
std::fs::create_dir(root_mailbox.join(d))
252+
.expect("Could not create root mailbox directory contents.");
253+
}
254+
}
255+
}
256+
let subscribed_mailboxes = if with_root_mailbox {
257+
vec!["INBOX".into()]
258+
} else {
259+
vec![]
260+
};
261+
let mailboxes = if with_root_mailbox {
262+
vec![(
263+
"INBOX".into(),
264+
crate::conf::MailboxConf {
265+
extra: indexmap::indexmap! {
266+
"path".into() => root_mailbox.display().to_string(),
267+
},
268+
..Default::default()
269+
},
270+
)]
271+
.into_iter()
272+
.collect()
273+
} else {
274+
indexmap::indexmap! {}
275+
};
276+
let extra = if with_root_mailbox {
277+
indexmap::indexmap! {
278+
"root_mailbox".into() => root_mailbox.display().to_string(),
279+
}
280+
} else {
281+
indexmap::indexmap! {}
282+
};
283+
284+
let account_conf = AccountSettings {
285+
name: acc_name.to_string(),
286+
root_mailbox: root_mailbox.display().to_string(),
287+
format: "maildir".to_string(),
288+
identity: "user@localhost".to_string(),
289+
extra_identities: vec![],
290+
read_only: false,
291+
display_name: None,
292+
order: Default::default(),
293+
subscribed_mailboxes,
294+
mailboxes,
295+
manual_refresh: true,
296+
extra,
297+
};
298+
299+
let maildir = MaildirType::new(&account_conf, Default::default(), event_consumer)?;
300+
Ok((root_mailbox, account_conf, maildir))
301+
}
302+
303+
#[test]
304+
fn test_maildir_mailbox_paths() {
305+
let temp_dir = TempDir::new().unwrap();
306+
let backend_event_queue = Arc::new(std::sync::Mutex::new(
307+
std::collections::VecDeque::with_capacity(16),
308+
));
309+
310+
let backend_event_consumer = {
311+
let backend_event_queue = Arc::clone(&backend_event_queue);
312+
313+
BackendEventConsumer::new(Arc::new(move |ah, be| {
314+
backend_event_queue.lock().unwrap().push_back((ah, be));
315+
}))
316+
};
317+
318+
// Perform tests on a maildir backend where the root mailbox, is not a valid
319+
// maildir mailbox (e.g. has no cur,new,tmp sub directories.
320+
{
321+
let (root_mailbox, _settings, maildir) =
322+
new_maildir_backend(&temp_dir, "maildir", backend_event_consumer.clone(), false)
323+
.unwrap();
324+
assert!(!maildir.config.is_root_a_mailbox);
325+
// Assert that giving a file system path to MaildirBox::new is valid
326+
let new_mailbox = MaildirMailbox::new(
327+
root_mailbox.join("Archive").display().to_string(),
328+
"Archive".into(),
329+
None,
330+
vec![],
331+
true,
332+
&maildir.config,
333+
)
334+
.unwrap();
335+
assert_eq!(new_mailbox.name, "Archive");
336+
assert_eq!(&new_mailbox.path, &Path::new("Archive"));
337+
assert_eq!(&new_mailbox.fs_path, &root_mailbox.join("Archive"));
338+
// Assert that giving a mailbox path to MaildirBox::new is valid
339+
let new_mailbox = MaildirMailbox::new(
340+
"INBOX/Archive".into(),
341+
"Archive".into(),
342+
None,
343+
vec![],
344+
true,
345+
&maildir.config,
346+
)
347+
.unwrap();
348+
assert_eq!(new_mailbox.name, "Archive");
349+
assert_eq!(&new_mailbox.path, &Path::new("Archive"));
350+
assert_eq!(&new_mailbox.fs_path, &root_mailbox.join("Archive"));
351+
let mut backend = maildir as Box<dyn MailBackend>;
352+
let ref_mailboxes = smol::block_on(backend.mailboxes().unwrap()).unwrap();
353+
// Assert that backend has no mailboxes at all");
354+
assert!(
355+
ref_mailboxes.is_empty(),
356+
"ref_mailboxes were not empty: {:?}",
357+
ref_mailboxes
358+
);
359+
let (new_hash, ref_mailboxes) =
360+
smol::block_on(backend.create_mailbox("Archive".into()).unwrap()).unwrap();
361+
assert_eq!(ref_mailboxes[&new_hash].name(), "Archive");
362+
assert_eq!(ref_mailboxes[&new_hash].path(), "Archive");
363+
assert_eq!(
364+
ref_mailboxes[&new_hash]
365+
.as_any()
366+
.downcast_ref::<MaildirMailbox>()
367+
.unwrap()
368+
.fs_path(),
369+
&root_mailbox.join("Archive")
370+
);
371+
// Assert that even if we accidentally give a file system path to a maildir
372+
// backend's create_mailbox() method, it still does the correct thing.
373+
let (new_hash, ref_mailboxes) = smol::block_on(
374+
backend
375+
.create_mailbox(root_mailbox.join("Archive2").display().to_string())
376+
.unwrap(),
377+
)
378+
.unwrap();
379+
assert_eq!(ref_mailboxes[&new_hash].name(), "Archive2");
380+
assert_eq!(ref_mailboxes[&new_hash].path(), "Archive2");
381+
assert_eq!(
382+
ref_mailboxes[&new_hash]
383+
.as_any()
384+
.downcast_ref::<MaildirMailbox>()
385+
.unwrap()
386+
.fs_path(),
387+
&root_mailbox.join("Archive2")
388+
);
389+
let ref_mailboxes = smol::block_on(backend.mailboxes().unwrap()).unwrap();
390+
// Assert that backend has all the created mailboxes so far
391+
assert_eq!(
392+
ref_mailboxes.len(),
393+
2,
394+
"mailboxes() return value content not what expected: {:?}",
395+
ref_mailboxes
396+
);
397+
// Assert that giving an absolute path returns an error
398+
assert_eq!(
399+
&smol::block_on(backend.create_mailbox("/Archive3".to_string()).unwrap())
400+
.unwrap_err()
401+
.to_string(),
402+
"Path given (`/Archive3`) is absolute. Please provide a path relative to the \
403+
account's root mailbox."
404+
);
405+
// Assert that attempting to create a mailbox outside of the root mailbox
406+
// returns an error
407+
assert_eq!(
408+
&smol::block_on(
409+
backend
410+
.create_mailbox(temp_dir.path().join("Archive3").display().to_string())
411+
.unwrap()
412+
)
413+
.unwrap_err()
414+
.to_string(),
415+
&format!(
416+
"Path given, `{}`, is not included in the root mailbox path `{}`. A maildir \
417+
backend cannot contain mailboxes outside of its root path.",
418+
temp_dir.path().join("Archive3").display(),
419+
root_mailbox.display(),
420+
)
421+
);
422+
423+
std::fs::remove_dir_all(root_mailbox).unwrap();
424+
}
425+
426+
// Perform same tests on a maildir backend where the root mailbox is a valid
427+
// maildir mailbox (e.g. has cur,new,tmp sub directories.
428+
{
429+
let (root_mailbox, _settings, maildir) =
430+
new_maildir_backend(&temp_dir, "maildir", backend_event_consumer, true).unwrap();
431+
assert!(maildir.config.is_root_a_mailbox);
432+
// Assert that giving a file system path to MaildirBox::new is valid
433+
let new_mailbox = MaildirMailbox::new(
434+
root_mailbox.join("Archive").display().to_string(),
435+
"Archive".into(),
436+
None,
437+
vec![],
438+
true,
439+
&maildir.config,
440+
)
441+
.unwrap();
442+
assert_eq!(new_mailbox.name, "Archive");
443+
assert_eq!(&new_mailbox.path, &Path::new("INBOX/Archive"));
444+
assert_eq!(&new_mailbox.fs_path, &root_mailbox.join("Archive"));
445+
// Assert that giving a mailbox path to MaildirBox::new is valid
446+
let new_mailbox = MaildirMailbox::new(
447+
"INBOX/Archive".into(),
448+
"Archive".into(),
449+
None,
450+
vec![],
451+
true,
452+
&maildir.config,
453+
)
454+
.unwrap();
455+
assert_eq!(new_mailbox.name, "Archive");
456+
assert_eq!(&new_mailbox.path, &Path::new("INBOX/Archive"));
457+
assert_eq!(&new_mailbox.fs_path, &root_mailbox.join("Archive"));
458+
let mut backend = maildir as Box<dyn MailBackend>;
459+
let ref_mailboxes = smol::block_on(backend.mailboxes().unwrap()).unwrap();
460+
// Assert that backend has only INBOX as a mailbox
461+
assert_eq!(
462+
ref_mailboxes.len(),
463+
1,
464+
"ref_mailboxes is not just INBOX: {:?}",
465+
ref_mailboxes
466+
);
467+
// Assert that creating a mailbox without the root mailbox as a prefix does the
468+
// correct thing.
469+
let (new_hash, ref_mailboxes) =
470+
smol::block_on(backend.create_mailbox("Archive".into()).unwrap()).unwrap();
471+
assert_eq!(ref_mailboxes[&new_hash].name(), "Archive");
472+
assert_eq!(ref_mailboxes[&new_hash].path(), "INBOX/Archive");
473+
assert_eq!(
474+
ref_mailboxes[&new_hash]
475+
.as_any()
476+
.downcast_ref::<MaildirMailbox>()
477+
.unwrap()
478+
.fs_path(),
479+
&root_mailbox.join("Archive")
480+
);
481+
// Assert that creating a mailbox with the root mailbox as a prefix does the
482+
// correct thing.
483+
let (new_hash, ref_mailboxes) =
484+
smol::block_on(backend.create_mailbox("INBOX/Archive2".into()).unwrap()).unwrap();
485+
assert_eq!(ref_mailboxes[&new_hash].name(), "Archive2");
486+
assert_eq!(ref_mailboxes[&new_hash].path(), "INBOX/Archive2");
487+
assert_eq!(
488+
ref_mailboxes[&new_hash]
489+
.as_any()
490+
.downcast_ref::<MaildirMailbox>()
491+
.unwrap()
492+
.fs_path(),
493+
&root_mailbox.join("Archive2")
494+
);
495+
// Assert that even if we accidentally give a file system path to a maildir
496+
// backend's create_mailbox() method, it still does the correct thing.
497+
let (new_hash, ref_mailboxes) = smol::block_on(
498+
backend
499+
.create_mailbox(root_mailbox.join("Archive3").display().to_string())
500+
.unwrap(),
501+
)
502+
.unwrap();
503+
assert_eq!(ref_mailboxes[&new_hash].name(), "Archive3");
504+
assert_eq!(ref_mailboxes[&new_hash].path(), "INBOX/Archive3");
505+
assert_eq!(
506+
ref_mailboxes[&new_hash]
507+
.as_any()
508+
.downcast_ref::<MaildirMailbox>()
509+
.unwrap()
510+
.fs_path(),
511+
&root_mailbox.join("Archive3")
512+
);
513+
let ref_mailboxes = smol::block_on(backend.mailboxes().unwrap()).unwrap();
514+
// Assert that backend has all the created mailboxes so far
515+
assert_eq!(
516+
ref_mailboxes.len(),
517+
4,
518+
"mailboxes() return value content not what expected: {:?}",
519+
ref_mailboxes
520+
);
521+
// Assert that giving an absolute path returns an error
522+
assert_eq!(
523+
&smol::block_on(backend.create_mailbox("/Archive4".to_string()).unwrap())
524+
.unwrap_err()
525+
.to_string(),
526+
"Path given (`/Archive4`) is absolute. Please provide a path relative to the \
527+
account's root mailbox."
528+
);
529+
// Assert that attempting to create a mailbox outside of the root mailbox
530+
// returns an error
531+
assert_eq!(
532+
&smol::block_on(
533+
backend
534+
.create_mailbox(temp_dir.path().join("Archive4").display().to_string())
535+
.unwrap()
536+
)
537+
.unwrap_err()
538+
.to_string(),
539+
&format!(
540+
"Path given, `{}`, is not included in the root mailbox path `{}`. A maildir \
541+
backend cannot contain mailboxes outside of its root path.",
542+
temp_dir.path().join("Archive4").display(),
543+
root_mailbox.display(),
544+
)
545+
);
546+
}
547+
}

0 commit comments

Comments
 (0)