geary/test/engine/app/app-conversation-test.vala
Michael Gratton 9619d18eda Ensure conversations that have no email in the base folder are dropped
If a least one email in a conversation that is in the base folder but
also in another is removed from the base folder, the conversation may
not be removed from the monitor despite possibly not having any email
in the base folder, since the email may not have been completely removed
from the conversation.

This was particulary being seen with GMail accounts where even single
message conversations were not disappering when trashed because the
converation's email was still in All Mail.

This fix does a few things: Avoids hitting the database when checking
a conversation still has email in the base folder, when it does check
only ensures that email are in the base folder, not *any* folder, and
updates ConversationSet::remove_all_emails_by_identifier to do this
check iternally, clean up its API and implementation and avoids having
to use out args calling it.
2019-02-16 16:26:10 +11:00

296 lines
9.9 KiB
Vala

/*
* Copyright 2017-2018 Michael Gratton <mike@vee.net>
*
* This software is licensed under the GNU Lesser General Public License
* (version 2.1 or later). See the COPYING file in this distribution.
*/
class Geary.App.ConversationTest : TestCase {
Conversation? test = null;
Folder? base_folder = null;
FolderRoot? folder_root = null;
public ConversationTest() {
base("Geary.App.ConversationTest");
add_test("add_basic", add_basic);
add_test("add_duplicate", add_duplicate);
add_test("add_multipath", add_multipath);
add_test("remove_basic", remove_basic);
add_test("remove_nonexistent", remove_nonexistent);
add_test("get_emails", get_emails);
add_test("get_emails_by_location", get_emails_by_location);
add_test("get_emails_blacklist", get_emails_blacklist);
add_test("get_emails_marked_for_deletion", get_emails_marked_for_deletion);
add_test("count_email_in_folder", count_email_in_folder);
}
public override void set_up() {
this.folder_root = new FolderRoot(false);
this.base_folder = new MockFolder(
null,
null,
this.folder_root.get_child("test"),
SpecialFolderType.NONE,
null
);
this.test = new Conversation(this.base_folder);
}
public override void tear_down() {
this.test = null;
this.folder_root = null;
this.base_folder = null;
}
public void add_basic() throws Error {
Geary.Email e1 = setup_email(1);
Geary.Email e2 = setup_email(2);
uint appended = 0;
this.test.appended.connect(() => {
appended++;
});
assert(this.test.add(e1, singleton(this.base_folder.path)) == true);
assert(this.test.is_in_base_folder(e1.id) == true);
assert(this.test.get_folder_count(e1.id) == 1);
assert(appended == 1);
assert(this.test.get_count() == 1);
assert(this.test.add(e2, singleton(this.base_folder.path)) == true);
assert(this.test.is_in_base_folder(e2.id) == true);
assert(this.test.get_folder_count(e2.id) == 1);
assert(appended == 2);
assert(this.test.get_count() == 2);
}
public void add_duplicate() throws Error {
Geary.Email e1 = setup_email(1);
uint appended = 0;
this.test.appended.connect(() => {
appended++;
});
assert(this.test.add(e1, singleton(this.base_folder.path)) == true);
assert(appended == 1);
assert(this.test.get_count() == 1);
assert(this.test.add(e1, singleton(this.base_folder.path)) == false);
assert(appended == 1);
assert(this.test.get_count() == 1);
}
public void add_multipath() throws Error {
Geary.Email e1 = setup_email(1);
this.test.add(e1, singleton(this.base_folder.path));
Geary.Email e2 = setup_email(2);
this.test.add(e2, singleton(this.base_folder.path));
FolderPath other_path = this.folder_root.get_child("other");
Gee.LinkedList<FolderPath> other_paths = new Gee.LinkedList<FolderPath>();
other_paths.add(other_path);
assert(this.test.add(e1, other_paths) == false);
assert(this.test.is_in_base_folder(e1.id) == true);
assert(this.test.get_folder_count(e1.id) == 2);
assert(this.test.is_in_base_folder(e2.id) == true);
assert(this.test.get_folder_count(e2.id) == 1);
this.test.remove_path(e1.id, other_path);
assert(this.test.is_in_base_folder(e1.id) == true);
assert(this.test.get_folder_count(e1.id) == 1);
}
public void remove_basic() throws Error {
Geary.Email e1 = setup_email(1);
this.test.add(e1, singleton(this.base_folder.path));
Geary.Email e2 = setup_email(2);
this.test.add(e2, singleton(this.base_folder.path));
uint trimmed = 0;
this.test.trimmed.connect(() => {
trimmed++;
});
Gee.Set<RFC822.MessageID>? removed = this.test.remove(e1);
assert(removed != null);
assert(removed.size == 1);
assert(removed.contains(e1.message_id));
assert(trimmed == 1);
assert(this.test.get_count() == 1);
removed = this.test.remove(e2);
assert(removed != null);
assert(removed.size == 1);
assert(removed.contains(e2.message_id));
assert(trimmed == 2);
assert(this.test.get_count() == 0);
}
public void remove_nonexistent() throws Error {
Geary.Email e1 = setup_email(1);
Geary.Email e2 = setup_email(2);
uint trimmed = 0;
this.test.trimmed.connect(() => {
trimmed++;
});
assert(this.test.remove(e2) == null);
assert(trimmed == 0);
assert(this.test.get_count() == 0);
this.test.add(e1, singleton(this.base_folder.path));
assert(this.test.remove(e2) == null);
assert(trimmed == 0);
assert(this.test.get_count() == 1);
}
public void get_emails() throws GLib.Error {
Geary.Email e1 = setup_email(1);
this.test.add(e1, singleton(this.base_folder.path));
FolderPath other_path = this.folder_root.get_child("other");
Geary.Email e2 = setup_email(2);
this.test.add(e2, singleton(other_path));
assert_int(
2, this.test.get_emails(Conversation.Ordering.NONE).size
);
}
public void get_emails_by_location() throws GLib.Error {
Geary.Email e1 = setup_email(1);
this.test.add(e1, singleton(this.base_folder.path));
FolderPath other_path = this.folder_root.get_child("other");
Geary.Email e2 = setup_email(2);
this.test.add(e2, singleton(other_path));
assert_int(
1, this.test.get_emails(Conversation.Ordering.NONE,
Conversation.Location.IN_FOLDER).size,
"Unexpected in-folder size"
);
assert_equal(
e1,
traverse(this.test.get_emails(Conversation.Ordering.NONE,
Conversation.Location.IN_FOLDER))
.first(),
"Unexpected in-folder element"
);
assert_int(
1, this.test.get_emails(Conversation.Ordering.NONE,
Conversation.Location.OUT_OF_FOLDER).size,
"Unexpected out-of-folder size"
);
assert_equal(
e2,
traverse(this.test.get_emails(Conversation.Ordering.NONE,
Conversation.Location.OUT_OF_FOLDER))
.first(),
"Unexpected out-of-folder element"
);
}
public void get_emails_blacklist() throws GLib.Error {
Geary.Email e1 = setup_email(1);
this.test.add(e1, singleton(this.base_folder.path));
FolderPath other_path = this.folder_root.get_child("other");
Geary.Email e2 = setup_email(2);
this.test.add(e2, singleton(other_path));
Gee.Collection<FolderPath> blacklist = new Gee.ArrayList<FolderPath>();
blacklist.add(other_path);
assert_int(
1, this.test.get_emails(Conversation.Ordering.NONE,
Conversation.Location.ANYWHERE,
blacklist
).size,
"Unexpected other blacklist size"
);
assert_equal(
e1,
traverse(this.test.get_emails(Conversation.Ordering.NONE,
Conversation.Location.ANYWHERE,
blacklist)
).first(),
"Unexpected other blacklist element"
);
blacklist.clear();
blacklist.add(this.base_folder.path);
assert_int(
1, this.test.get_emails(Conversation.Ordering.NONE,
Conversation.Location.ANYWHERE,
blacklist
).size,
"Unexpected other blacklist size"
);
assert_equal(
e2,
traverse(this.test.get_emails(Conversation.Ordering.NONE,
Conversation.Location.ANYWHERE,
blacklist)
).first(),
"Unexpected other blacklist element"
);
}
public void get_emails_marked_for_deletion() throws GLib.Error {
Geary.Email e1 = setup_email(1);
e1.set_flags(new Geary.EmailFlags.with(Geary.EmailFlags.DELETED));
this.test.add(e1, singleton(this.base_folder.path));
assert_int(
0, this.test.get_emails(Conversation.Ordering.NONE,
Conversation.Location.ANYWHERE
).size,
"Message marked for deletion still present in conversation"
);
}
public void count_email_in_folder() throws GLib.Error {
Geary.Email e1 = setup_email(1);
this.test.add(e1, singleton(this.base_folder.path));
assert_uint(
1, this.test.get_count_in_folder(this.base_folder.path),
"In-folder count"
);
assert_uint(
0,
this.test.get_count_in_folder(this.folder_root.get_child("other")),
"Out-folder count"
);
}
private Gee.Collection<E> singleton<E>(E element) {
Gee.LinkedList<E> collection = new Gee.LinkedList<E>();
collection.add(element);
return collection;
}
private Email setup_email(int id) {
Email email = new Email(new MockEmailIdentifer(id));
DateTime now = new DateTime.now_local();
Geary.RFC822.MessageID mid = new Geary.RFC822.MessageID(
"test%d@localhost".printf(id)
);
email.set_full_references(mid, null, null);
email.set_email_properties(new MockEmailProperties(now));
email.set_send_date(new Geary.RFC822.Date.from_date_time(now));
return email;
}
}