From 809f664319ed36c69012647c92d563698fa5399e Mon Sep 17 00:00:00 2001 From: Michael Gratton Date: Sun, 9 Jun 2019 21:56:25 +1000 Subject: [PATCH] ContactStoreImpl unit tests --- .../common/common-contact-store-impl.vala | 30 ++-- .../common-contact-store-impl-test.vala | 153 ++++++++++++++++++ test/meson.build | 1 + test/test-engine.vala | 4 + 4 files changed, 173 insertions(+), 15 deletions(-) create mode 100644 test/engine/common/common-contact-store-impl-test.vala diff --git a/src/engine/common/common-contact-store-impl.vala b/src/engine/common/common-contact-store-impl.vala index 0ddde6d0..48f4ad4c 100644 --- a/src/engine/common/common-contact-store-impl.vala +++ b/src/engine/common/common-contact-store-impl.vala @@ -19,30 +19,30 @@ internal class Geary.ContactStoreImpl : BaseObject, Geary.ContactStore { // Internal and static since it is used by ImapDB.Database during // upgrades internal static void do_update_contact(Db.Connection cx, - Contact contact, + Contact updated, GLib.Cancellable? cancellable) throws GLib.Error { Contact? existing = do_fetch_contact( - cx, contact.email, cancellable + cx, updated.email, cancellable ); - if (contact == null) { + if (existing == null) { // Not found, so just insert it Db.Statement stmt = cx.prepare( "INSERT INTO ContactTable(normalized_email, email, real_name, flags, highest_importance) " + "VALUES(?, ?, ?, ?, ?)"); - stmt.bind_string(0, contact.normalized_email); - stmt.bind_string(1, contact.email); - stmt.bind_string(2, contact.real_name); - stmt.bind_string(3, contact.flags.serialize()); - stmt.bind_int(4, contact.highest_importance); + stmt.bind_string(0, updated.normalized_email); + stmt.bind_string(1, updated.email); + stmt.bind_string(2, updated.real_name); + stmt.bind_string(3, updated.flags.serialize()); + stmt.bind_int(4, updated.highest_importance); stmt.exec(cancellable); } else { // Update existing contact // Merge two flags sets together - contact.flags.add_all(existing.flags); + updated.flags.add_all(existing.flags); // update remaining fields, careful not to overwrite // non-null real_name with null (but using latest @@ -53,16 +53,16 @@ internal class Geary.ContactStoreImpl : BaseObject, Geary.ContactStore { Db.Statement stmt = cx.prepare( "UPDATE ContactTable SET real_name=?, flags=?, highest_importance=? WHERE email=?"); stmt.bind_string( - 0, !String.is_empty(contact.real_name) ? contact.real_name : existing.real_name + 0, !String.is_empty(updated.real_name) ? updated.real_name : existing.real_name ); stmt.bind_string( - 1, contact.flags.serialize() + 1, updated.flags.serialize() ); stmt.bind_int( - 2, int.max(contact.highest_importance, existing.highest_importance) + 2, int.max(updated.highest_importance, existing.highest_importance) ); stmt.bind_string( - 3, contact.email + 3, updated.email ); stmt.exec(cancellable); @@ -105,14 +105,14 @@ internal class Geary.ContactStoreImpl : BaseObject, Geary.ContactStore { } /** Returns the contact matching the given email address, if any */ - public async Contact? get_by_rfc822(Geary.RFC822.MailboxAddress address, + public async Contact? get_by_rfc822(Geary.RFC822.MailboxAddress mailbox, GLib.Cancellable? cancellable) throws GLib.Error { Contact? contact = null; yield this.backing.exec_transaction_async( Db.TransactionType.RO, (cx, cancellable) => { - contact = do_fetch_contact(cx, address.mailbox, cancellable); + contact = do_fetch_contact(cx, mailbox.address, cancellable); return Db.TransactionOutcome.COMMIT; }, cancellable); diff --git a/test/engine/common/common-contact-store-impl-test.vala b/test/engine/common/common-contact-store-impl-test.vala new file mode 100644 index 00000000..e57d3e3f --- /dev/null +++ b/test/engine/common/common-contact-store-impl-test.vala @@ -0,0 +1,153 @@ +/* + * Copyright 2019 Michael Gratton + * + * 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.ContactStoreImplTest : TestCase { + + + private GLib.File? tmp_dir = null; + private ImapDB.Database? db = null; + private ContactStoreImpl? test_article = null; + + + public ContactStoreImplTest() { + base("Geary.ContactStoreImplTest"); + add_test("get_by_rfc822", get_by_rfc822); + add_test("update_new_contact", update_new_contact); + add_test("update_existing_contact", update_existing_contact); + } + + public override void set_up() throws GLib.Error { + this.tmp_dir = GLib.File.new_for_path( + GLib.DirUtils.make_tmp("geary-contact-harvester-test-XXXXXX") + ); + GLib.File db_file = this.tmp_dir.get_child("geary.db"); + GLib.File attachments_dir = this.tmp_dir.get_child("attachments"); + + this.db = new ImapDB.Database( + db_file, + GLib.File.new_for_path(_SOURCE_ROOT_DIR).get_child("sql"), + attachments_dir, + new Geary.SimpleProgressMonitor(Geary.ProgressType.DB_UPGRADE), + new Geary.SimpleProgressMonitor(Geary.ProgressType.DB_VACUUM) + ); + this.db.open.begin( + Geary.Db.DatabaseFlags.CREATE_FILE, null, + (obj, ret) => { async_complete(ret); } + ); + this.db.open.end(async_result()); + + this.db.exec(""" +INSERT INTO ContactTable ( + id, + normalized_email, + real_name, + email, + highest_importance +) VALUES ( + 1, + 'test@example.com', + 'Test', + 'Test@example.com', + 50 +); +"""); + + this.test_article = new ContactStoreImpl(this.db); + } + + public override void tear_down() throws GLib.Error { + this.test_article = null; + + this.db.close(); + this.db = null; + + delete_file(this.tmp_dir); + this.tmp_dir = null; + } + + public void get_by_rfc822() throws GLib.Error { + test_article.get_by_rfc822.begin( + new RFC822.MailboxAddress(null, "Test@example.com"), + null, + (obj, ret) => { async_complete(ret); } + ); + Contact? existing = test_article.get_by_rfc822.end(async_result()); + assert_non_null(existing, "Existing contact"); + assert_string("Test@example.com", existing.email, "Existing email"); + assert_string("test@example.com", existing.normalized_email, "Existing normalized_email"); + assert_string("Test", existing.real_name, "Existing real_name"); + assert_int(50, existing.highest_importance, "Existing highest_importance"); + assert_false(existing.flags.always_load_remote_images(), "Existing flags"); + + test_article.get_by_rfc822.begin( + new RFC822.MailboxAddress(null, "test@example.com"), + null, + (obj, ret) => { async_complete(ret); } + ); + Contact? missing = test_article.get_by_rfc822.end(async_result()); + assert_null(missing, "Missing contact"); + } + + public void update_new_contact() throws GLib.Error { + Contact not_persisted = new Contact( + "New@example.com", + "New", + 0, + "new@example.com" + ); + not_persisted.flags.add(Contact.Flags.ALWAYS_LOAD_REMOTE_IMAGES); + test_article.update_contacts.begin( + Collection.single(not_persisted), + null, + (obj, ret) => { async_complete(ret); } + ); + test_article.update_contacts.end(async_result()); + + test_article.get_by_rfc822.begin( + new RFC822.MailboxAddress(null, "New@example.com"), + null, + (obj, ret) => { async_complete(ret); } + ); + Contact? persisted = test_article.get_by_rfc822.end(async_result()); + assert_non_null(persisted, "persisted"); + assert_string("New@example.com", persisted.email, "Persisted email"); + assert_string("new@example.com", persisted.normalized_email, "Persisted normalized_email"); + assert_string("New", persisted.real_name, "Persisted real_name"); + assert_int(0, persisted.highest_importance, "Persisted highest_importance"); + assert_true(persisted.flags.always_load_remote_images(), "Persisted real_name"); + } + + public void update_existing_contact() throws GLib.Error { + Contact not_updated = new Contact( + "Test@example.com", + "Updated", + 100, + "new@example.com" + ); + not_updated.flags.add(Contact.Flags.ALWAYS_LOAD_REMOTE_IMAGES); + test_article.update_contacts.begin( + Collection.single(not_updated), + null, + (obj, ret) => { async_complete(ret); } + ); + test_article.update_contacts.end(async_result()); + test_article.get_by_rfc822.begin( + new RFC822.MailboxAddress(null, "Test@example.com"), + null, + (obj, ret) => { async_complete(ret); } + ); + Contact? updated = test_article.get_by_rfc822.end(async_result()); + assert_non_null(updated, "updated"); + assert_string("Test@example.com", updated.email, "Updated email"); + assert_string("test@example.com", updated.normalized_email, "Updated normalized_email"); + assert_string("Updated", updated.real_name, "Updated real_name"); + assert_int(100, updated.highest_importance, "Updated highest_importance"); + assert_true(updated.flags.always_load_remote_images(), "Updated real_name"); + } + +} diff --git a/test/meson.build b/test/meson.build index 327504b7..a3e78998 100644 --- a/test/meson.build +++ b/test/meson.build @@ -28,6 +28,7 @@ geary_test_engine_sources = [ 'engine/app/app-conversation-test.vala', 'engine/app/app-conversation-monitor-test.vala', 'engine/app/app-conversation-set-test.vala', + 'engine/common/common-contact-store-impl-test.vala', 'engine/db/db-database-test.vala', 'engine/db/db-versioned-database-test.vala', 'engine/imap/command/imap-create-command-test.vala', diff --git a/test/test-engine.vala b/test/test-engine.vala index 8a575708..3c725cdd 100644 --- a/test/test-engine.vala +++ b/test/test-engine.vala @@ -53,6 +53,10 @@ int main(string[] args) { engine.add_suite(new Geary.ImapDB.EmailIdentifierTest().get_suite()); engine.add_suite(new Geary.ImapDB.FolderTest().get_suite()); engine.add_suite(new Geary.ImapEngine.AccountProcessorTest().get_suite()); + + // Depends on ImapDb.Database working correctly + engine.add_suite(new Geary.ContactStoreImplTest().get_suite()); + engine.add_suite(new Geary.Inet.Test().get_suite()); engine.add_suite(new Geary.JS.Test().get_suite()); engine.add_suite(new Geary.Mime.ContentTypeTest().get_suite());