[geary/wip/726281-text-attachment-crlf: 6/13] Move attachment related code from ImapDB.Folder to Attachment.
- From: Michael Gratton <mjog src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [geary/wip/726281-text-attachment-crlf: 6/13] Move attachment related code from ImapDB.Folder to Attachment.
- Date: Fri, 18 May 2018 23:27:32 +0000 (UTC)
commit 15d8789685fc118e3307a8b9a84be8e663f62b86
Author: Michael James Gratton <mike vee net>
Date: Sat Apr 28 20:56:09 2018 +1000
Move attachment related code from ImapDB.Folder to Attachment.
src/engine/imap-db/imap-db-account.vala | 6 +-
src/engine/imap-db/imap-db-attachment.vala | 219 +++++++++++++++++++
src/engine/imap-db/imap-db-database.vala | 10 +-
src/engine/imap-db/imap-db-folder.vala | 250 ++--------------------
test/CMakeLists.txt | 1 +
test/engine/imap-db/imap-db-attachment-test.vala | 89 ++++++++
test/meson.build | 1 +
test/test-engine.vala | 1 +
8 files changed, 337 insertions(+), 240 deletions(-)
---
diff --git a/src/engine/imap-db/imap-db-account.vala b/src/engine/imap-db/imap-db-account.vala
index b142dab..41b86da 100644
--- a/src/engine/imap-db/imap-db-account.vala
+++ b/src/engine/imap-db/imap-db-account.vala
@@ -728,7 +728,7 @@ private class Geary.ImapDB.Account : BaseObject {
// Ignore any messages that don't have the required fields.
if (partial_ok || row.fields.fulfills(requested_fields)) {
Geary.Email email = row.to_email(new Geary.ImapDB.EmailIdentifier(id, null));
- Geary.ImapDB.Folder.do_add_attachments(
+ Attachment.do_add_attachments(
cx, this.db.attachments_path, email, id, cancellable
);
@@ -1393,7 +1393,7 @@ private class Geary.ImapDB.Account : BaseObject {
email_id.to_string(), row.fields, required_fields);
email = row.to_email(email_id);
- Geary.ImapDB.Folder.do_add_attachments(
+ Attachment.do_add_attachments(
cx, this.db.attachments_path, email, email_id.message_id, cancellable
);
@@ -1556,7 +1556,7 @@ private class Geary.ImapDB.Account : BaseObject {
MessageRow row = Geary.ImapDB.Folder.do_fetch_message_row(
cx, message_id, search_fields, out db_fields, cancellable);
Geary.Email email = row.to_email(new Geary.ImapDB.EmailIdentifier(message_id, null));
- Geary.ImapDB.Folder.do_add_attachments(
+ Attachment.do_add_attachments(
cx, this.db.attachments_path, email, message_id, cancellable
);
diff --git a/src/engine/imap-db/imap-db-attachment.vala b/src/engine/imap-db/imap-db-attachment.vala
index c7752d1..19f5b0d 100644
--- a/src/engine/imap-db/imap-db-attachment.vala
+++ b/src/engine/imap-db/imap-db-attachment.vala
@@ -40,4 +40,223 @@ private class Geary.ImapDB.Attachment : Geary.Attachment {
.get_child(filename ?? NULL_FILE_NAME);
}
+ internal static void do_save_attachments(Db.Connection cx,
+ GLib.File attachments_path,
+ int64 message_id,
+ Gee.List<GMime.Part>? attachments,
+ Cancellable? cancellable)
+ throws Error {
+ // nothing to do if no attachments
+ if (attachments == null || attachments.size == 0)
+ return;
+
+ foreach (GMime.Part attachment in attachments) {
+ GMime.ContentType? content_type = attachment.get_content_type();
+ string mime_type = (content_type != null)
+ ? content_type.to_string()
+ : Mime.ContentType.DEFAULT_CONTENT_TYPE;
+ string? disposition = attachment.get_disposition();
+ string? content_id = attachment.get_content_id();
+ string? description = attachment.get_content_description();
+ string? filename = RFC822.Utils.get_clean_attachment_filename(attachment);
+
+ // Convert the attachment content into a usable ByteArray.
+ GMime.DataWrapper? attachment_data = attachment.get_content_object();
+ ByteArray byte_array = new ByteArray();
+ GMime.StreamMem stream = new GMime.StreamMem.with_byte_array(byte_array);
+ stream.set_owner(false);
+ if (attachment_data != null)
+ attachment_data.write_to_stream(stream); // data is null if it's 0 bytes
+ uint filesize = byte_array.len;
+
+ // convert into DispositionType enum, which is stored as int
+ // (legacy code stored UNSPECIFIED as NULL, which is zero, which is ATTACHMENT, so preserve
+ // this behavior)
+ Mime.DispositionType disposition_type = Mime.DispositionType.deserialize(disposition,
+ null);
+ if (disposition_type == Mime.DispositionType.UNSPECIFIED)
+ disposition_type = Mime.DispositionType.ATTACHMENT;
+
+ // Insert it into the database.
+ Db.Statement stmt = cx.prepare("""
+ INSERT INTO MessageAttachmentTable (message_id, filename, mime_type, filesize, disposition,
content_id, description)
+ VALUES (?, ?, ?, ?, ?, ?, ?)
+ """);
+ stmt.bind_rowid(0, message_id);
+ stmt.bind_string(1, filename);
+ stmt.bind_string(2, mime_type);
+ stmt.bind_uint(3, filesize);
+ stmt.bind_int(4, disposition_type);
+ stmt.bind_string(5, content_id);
+ stmt.bind_string(6, description);
+
+ int64 attachment_id = stmt.exec_insert(cancellable);
+ File saved_file = ImapDB.Attachment.generate_file(
+ attachments_path, message_id, attachment_id, filename
+ );
+
+ // On the off-chance this is marked for deletion, unmark it
+ try {
+ stmt = cx.prepare("""
+ DELETE FROM DeleteAttachmentFileTable
+ WHERE filename = ?
+ """);
+ stmt.bind_string(0, saved_file.get_path());
+
+ stmt.exec(cancellable);
+ } catch (Error err) {
+ debug("Unable to delete from DeleteAttachmentFileTable: %s", err.message);
+
+ // not a deal-breaker, fall through
+ }
+
+ debug("Saving attachment to %s", saved_file.get_path());
+
+ try {
+ // create directory, but don't throw exception if already exists
+ try {
+ saved_file.get_parent().make_directory_with_parents(cancellable);
+ } catch (IOError ioe) {
+ // fall through if already exists
+ if (!(ioe is IOError.EXISTS))
+ throw ioe;
+ }
+
+ // REPLACE_DESTINATION doesn't seem to work as advertised all the time ... just
+ // play it safe here
+ if (saved_file.query_exists(cancellable))
+ saved_file.delete(cancellable);
+
+ // Create the file where the attachment will be saved and get the output stream.
+ FileOutputStream saved_stream = saved_file.create(FileCreateFlags.REPLACE_DESTINATION,
+ cancellable);
+
+ // Save the data to disk and flush it.
+ size_t written;
+ if (filesize != 0)
+ saved_stream.write_all(byte_array.data[0:filesize], out written, cancellable);
+
+ saved_stream.flush(cancellable);
+ } catch (Error error) {
+ // An error occurred while saving the attachment, so lets remove the attachment from
+ // the database and delete the file (in case it's partially written)
+ debug("Failed to save attachment %s: %s", saved_file.get_path(), error.message);
+
+ try {
+ saved_file.delete();
+ } catch (Error delete_error) {
+ debug("Error attempting to delete partial attachment %s: %s", saved_file.get_path(),
+ delete_error.message);
+ }
+
+ try {
+ Db.Statement remove_stmt = cx.prepare(
+ "DELETE FROM MessageAttachmentTable WHERE id=?");
+ remove_stmt.bind_rowid(0, attachment_id);
+
+ remove_stmt.exec();
+ } catch (Error remove_error) {
+ debug("Error attempting to remove added attachment row for %s: %s",
+ saved_file.get_path(), remove_error.message);
+ }
+
+ throw error;
+ }
+ }
+ }
+
+ internal static void do_delete_attachments(Db.Connection cx,
+ GLib.File attachments_path,
+ int64 message_id)
+ throws Error {
+ Gee.List<Geary.Attachment>? attachments = do_list_attachments(
+ cx, attachments_path, message_id, null
+ );
+ if (attachments == null || attachments.size == 0)
+ return;
+
+ // delete all files
+ foreach (Geary.Attachment attachment in attachments) {
+ try {
+ attachment.file.delete(null);
+ } catch (Error err) {
+ debug("Unable to delete file %s: %s", attachment.file.get_path(), err.message);
+ }
+ }
+
+ // remove all from attachment table
+ Db.Statement stmt = new Db.Statement(cx, """
+ DELETE FROM MessageAttachmentTable WHERE message_id = ?
+ """);
+ stmt.bind_rowid(0, message_id);
+
+ stmt.exec();
+ }
+
+ internal static Geary.Email do_add_attachments(Db.Connection cx,
+ GLib.File attachments_path,
+ Geary.Email email,
+ int64 message_id,
+ Cancellable? cancellable = null)
+ throws Error {
+ // Add attachments if available
+ if (email.fields.fulfills(ImapDB.Attachment.REQUIRED_FIELDS)) {
+ Gee.List<Geary.Attachment>? attachments = do_list_attachments(
+ cx, attachments_path, message_id, cancellable
+ );
+ if (attachments != null)
+ email.add_attachments(attachments);
+ }
+
+ return email;
+ }
+
+ private static Gee.List<Geary.Attachment>?
+ do_list_attachments(Db.Connection cx,
+ GLib.File attachments_path,
+ int64 message_id,
+ Cancellable? cancellable)
+ throws Error {
+ Db.Statement stmt = cx.prepare("""
+ SELECT id, filename, mime_type, filesize, disposition, content_id, description
+ FROM MessageAttachmentTable
+ WHERE message_id = ?
+ ORDER BY id
+ """);
+ stmt.bind_rowid(0, message_id);
+
+ Db.Result results = stmt.exec(cancellable);
+ if (results.finished)
+ return null;
+
+ Gee.List<Geary.Attachment> list = new Gee.ArrayList<Geary.Attachment>();
+ do {
+ string? content_filename = results.string_at(1);
+ if (content_filename == ImapDB.Attachment.NULL_FILE_NAME) {
+ // Prior to 0.12, Geary would store the untranslated
+ // string "none" as the filename when none was
+ // specified by the MIME content disposition. Check
+ // for that and clean it up.
+ content_filename = null;
+ }
+ Mime.ContentDisposition disposition = new Mime.ContentDisposition.simple(
+ Mime.DispositionType.from_int(results.int_at(4)));
+ list.add(
+ new ImapDB.Attachment(
+ message_id,
+ results.rowid_at(0),
+ Mime.ContentType.deserialize(results.nonnull_string_at(2)),
+ results.string_at(5),
+ results.string_at(6),
+ disposition,
+ content_filename,
+ attachments_path,
+ results.int64_at(3)
+ )
+ );
+ } while (results.next(cancellable));
+
+ return list;
+ }
+
}
diff --git a/src/engine/imap-db/imap-db-database.vala b/src/engine/imap-db/imap-db-database.vala
index bced663..8028865 100644
--- a/src/engine/imap-db/imap-db-database.vala
+++ b/src/engine/imap-db/imap-db-database.vala
@@ -336,11 +336,11 @@ private class Geary.ImapDB.Database : Geary.Db.VersionedDatabase {
Mime.DispositionType target_disposition = Mime.DispositionType.UNSPECIFIED;
if (message.get_sub_messages().is_empty)
target_disposition = Mime.DispositionType.INLINE;
- Geary.ImapDB.Folder.do_save_attachments_db(
+ Attachment.do_save_attachments(
cx,
+ this.attachments_path,
id,
message.get_attachments(target_disposition),
- this.attachments_path,
null
);
} catch (Error e) {
@@ -500,7 +500,7 @@ private class Geary.ImapDB.Database : Geary.Db.VersionedDatabase {
message.get_attachments();
try {
- Geary.ImapDB.Folder.do_delete_attachments(
+ Attachment.do_delete_attachments(
cx, this.attachments_path, message_id
);
} catch (Error err) {
@@ -511,11 +511,11 @@ private class Geary.ImapDB.Database : Geary.Db.VersionedDatabase {
// rebuild all
try {
- Geary.ImapDB.Folder.do_save_attachments_db(
+ Attachment.do_save_attachments(
cx,
+ this.attachments_path,
message_id,
msg_attachments,
- this.attachments_path,
null
);
} catch (Error err) {
diff --git a/src/engine/imap-db/imap-db-folder.vala b/src/engine/imap-db/imap-db-folder.vala
index f7aa264..0bb5085 100644
--- a/src/engine/imap-db/imap-db-folder.vala
+++ b/src/engine/imap-db/imap-db-folder.vala
@@ -1452,8 +1452,15 @@ private class Geary.ImapDB.Folder : BaseObject, Geary.ReferenceSemantics {
// write out attachments, if any
// TODO: Because this involves saving files, it potentially means holding up access to the
// database while they're being written; may want to do this outside of transaction.
- if (email.fields.fulfills(Attachment.REQUIRED_FIELDS))
- do_save_attachments(cx, message_id, email.get_message().get_attachments(), cancellable);
+ if (email.fields.fulfills(Attachment.REQUIRED_FIELDS)) {
+ Attachment.do_save_attachments(
+ cx,
+ this.attachments_path,
+ message_id,
+ email.get_message().get_attachments(),
+ cancellable
+ );
+ }
do_add_email_to_search_table(cx, message_id, email, cancellable);
@@ -1597,29 +1604,11 @@ private class Geary.ImapDB.Folder : BaseObject, Geary.ReferenceSemantics {
Geary.Email email = row.to_email(location.email_id);
- return do_add_attachments(
+ return Attachment.do_add_attachments(
cx, this.attachments_path, email, location.message_id, cancellable
);
}
- internal static Geary.Email do_add_attachments(Db.Connection cx,
- GLib.File attachments_path,
- Geary.Email email,
- int64 message_id,
- Cancellable? cancellable = null)
- throws Error {
- // Add attachments if available
- if (email.fields.fulfills(ImapDB.Attachment.REQUIRED_FIELDS)) {
- Gee.List<Geary.Attachment>? attachments = do_list_attachments(
- cx, attachments_path, message_id, cancellable
- );
- if (attachments != null)
- email.add_attachments(attachments);
- }
-
- return email;
- }
-
private static string fields_to_columns(Geary.Email.Field fields) {
// always pull the rowid and fields of the message
StringBuilder builder = new StringBuilder("id, fields");
@@ -2045,13 +2034,18 @@ private class Geary.ImapDB.Folder : BaseObject, Geary.ReferenceSemantics {
// Update attachments if not already in the database
if (!fetched_fields.fulfills(Attachment.REQUIRED_FIELDS)
&& combined_email.fields.fulfills(Attachment.REQUIRED_FIELDS)) {
- do_save_attachments(cx, location.message_id, combined_email.get_message().get_attachments(),
- cancellable);
+ Attachment.do_save_attachments(
+ cx,
+ this.attachments_path,
+ location.message_id,
+ combined_email.get_message().get_attachments(),
+ cancellable
+ );
}
// Must add attachments to the email object after they're saved to
// the database.
- do_add_attachments(
+ Attachment.do_add_attachments(
cx,
this.attachments_path,
combined_email,
@@ -2078,214 +2072,6 @@ private class Geary.ImapDB.Folder : BaseObject, Geary.ReferenceSemantics {
unread_count_change += new_unread_count;
}
- private static Gee.List<Geary.Attachment>?
- do_list_attachments(Db.Connection cx,
- GLib.File attachments_path,
- int64 message_id,
- Cancellable? cancellable)
- throws Error {
- Db.Statement stmt = cx.prepare("""
- SELECT id, filename, mime_type, filesize, disposition, content_id, description
- FROM MessageAttachmentTable
- WHERE message_id = ?
- ORDER BY id
- """);
- stmt.bind_rowid(0, message_id);
-
- Db.Result results = stmt.exec(cancellable);
- if (results.finished)
- return null;
-
- Gee.List<Geary.Attachment> list = new Gee.ArrayList<Geary.Attachment>();
- do {
- string? content_filename = results.string_at(1);
- if (content_filename == ImapDB.Attachment.NULL_FILE_NAME) {
- // Prior to 0.12, Geary would store the untranslated
- // string "none" as the filename when none was
- // specified by the MIME content disposition. Check
- // for that and clean it up.
- content_filename = null;
- }
- Mime.ContentDisposition disposition = new Mime.ContentDisposition.simple(
- Mime.DispositionType.from_int(results.int_at(4)));
- list.add(
- new ImapDB.Attachment(
- message_id,
- results.rowid_at(0),
- Mime.ContentType.deserialize(results.nonnull_string_at(2)),
- results.string_at(5),
- results.string_at(6),
- disposition,
- content_filename,
- attachments_path,
- results.int64_at(3)
- )
- );
- } while (results.next(cancellable));
-
- return list;
- }
-
- private void do_save_attachments(Db.Connection cx, int64 message_id,
- Gee.List<GMime.Part>? attachments, Cancellable? cancellable) throws Error {
- do_save_attachments_db(
- cx, message_id, attachments, this.attachments_path, cancellable
- );
- }
-
- public static void do_save_attachments_db(Db.Connection cx,
- int64 message_id,
- Gee.List<GMime.Part>? attachments,
- GLib.File attachments_path,
- Cancellable? cancellable)
- throws Error {
- // nothing to do if no attachments
- if (attachments == null || attachments.size == 0)
- return;
-
- foreach (GMime.Part attachment in attachments) {
- GMime.ContentType? content_type = attachment.get_content_type();
- string mime_type = (content_type != null)
- ? content_type.to_string()
- : Mime.ContentType.DEFAULT_CONTENT_TYPE;
- string? disposition = attachment.get_disposition();
- string? content_id = attachment.get_content_id();
- string? description = attachment.get_content_description();
- string? filename = RFC822.Utils.get_clean_attachment_filename(attachment);
-
- // Convert the attachment content into a usable ByteArray.
- GMime.DataWrapper? attachment_data = attachment.get_content_object();
- ByteArray byte_array = new ByteArray();
- GMime.StreamMem stream = new GMime.StreamMem.with_byte_array(byte_array);
- stream.set_owner(false);
- if (attachment_data != null)
- attachment_data.write_to_stream(stream); // data is null if it's 0 bytes
- uint filesize = byte_array.len;
-
- // convert into DispositionType enum, which is stored as int
- // (legacy code stored UNSPECIFIED as NULL, which is zero, which is ATTACHMENT, so preserve
- // this behavior)
- Mime.DispositionType disposition_type = Mime.DispositionType.deserialize(disposition,
- null);
- if (disposition_type == Mime.DispositionType.UNSPECIFIED)
- disposition_type = Mime.DispositionType.ATTACHMENT;
-
- // Insert it into the database.
- Db.Statement stmt = cx.prepare("""
- INSERT INTO MessageAttachmentTable (message_id, filename, mime_type, filesize, disposition,
content_id, description)
- VALUES (?, ?, ?, ?, ?, ?, ?)
- """);
- stmt.bind_rowid(0, message_id);
- stmt.bind_string(1, filename);
- stmt.bind_string(2, mime_type);
- stmt.bind_uint(3, filesize);
- stmt.bind_int(4, disposition_type);
- stmt.bind_string(5, content_id);
- stmt.bind_string(6, description);
-
- int64 attachment_id = stmt.exec_insert(cancellable);
- File saved_file = ImapDB.Attachment.generate_file(
- attachments_path, message_id, attachment_id, filename
- );
-
- // On the off-chance this is marked for deletion, unmark it
- try {
- stmt = cx.prepare("""
- DELETE FROM DeleteAttachmentFileTable
- WHERE filename = ?
- """);
- stmt.bind_string(0, saved_file.get_path());
-
- stmt.exec(cancellable);
- } catch (Error err) {
- debug("Unable to delete from DeleteAttachmentFileTable: %s", err.message);
-
- // not a deal-breaker, fall through
- }
-
- debug("Saving attachment to %s", saved_file.get_path());
-
- try {
- // create directory, but don't throw exception if already exists
- try {
- saved_file.get_parent().make_directory_with_parents(cancellable);
- } catch (IOError ioe) {
- // fall through if already exists
- if (!(ioe is IOError.EXISTS))
- throw ioe;
- }
-
- // REPLACE_DESTINATION doesn't seem to work as advertised all the time ... just
- // play it safe here
- if (saved_file.query_exists(cancellable))
- saved_file.delete(cancellable);
-
- // Create the file where the attachment will be saved and get the output stream.
- FileOutputStream saved_stream = saved_file.create(FileCreateFlags.REPLACE_DESTINATION,
- cancellable);
-
- // Save the data to disk and flush it.
- size_t written;
- if (filesize != 0)
- saved_stream.write_all(byte_array.data[0:filesize], out written, cancellable);
-
- saved_stream.flush(cancellable);
- } catch (Error error) {
- // An error occurred while saving the attachment, so lets remove the attachment from
- // the database and delete the file (in case it's partially written)
- debug("Failed to save attachment %s: %s", saved_file.get_path(), error.message);
-
- try {
- saved_file.delete();
- } catch (Error delete_error) {
- debug("Error attempting to delete partial attachment %s: %s", saved_file.get_path(),
- delete_error.message);
- }
-
- try {
- Db.Statement remove_stmt = cx.prepare(
- "DELETE FROM MessageAttachmentTable WHERE id=?");
- remove_stmt.bind_rowid(0, attachment_id);
-
- remove_stmt.exec();
- } catch (Error remove_error) {
- debug("Error attempting to remove added attachment row for %s: %s",
- saved_file.get_path(), remove_error.message);
- }
-
- throw error;
- }
- }
- }
-
- public static void do_delete_attachments(Db.Connection cx,
- GLib.File attachments_path,
- int64 message_id)
- throws Error {
- Gee.List<Geary.Attachment>? attachments = do_list_attachments(
- cx, attachments_path, message_id, null
- );
- if (attachments == null || attachments.size == 0)
- return;
-
- // delete all files
- foreach (Geary.Attachment attachment in attachments) {
- try {
- attachment.file.delete(null);
- } catch (Error err) {
- debug("Unable to delete file %s: %s", attachment.file.get_path(), err.message);
- }
- }
-
- // remove all from attachment table
- Db.Statement stmt = new Db.Statement(cx, """
- DELETE FROM MessageAttachmentTable WHERE message_id = ?
- """);
- stmt.bind_rowid(0, message_id);
-
- stmt.exec();
- }
-
/**
* Adds a value to the unread count. If this makes the unread count negative, it will be
* set to zero.
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index cd96c03..2841073 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -31,6 +31,7 @@ set(TEST_ENGINE_SRC
engine/imap/command/imap-create-command-test.vala
engine/imap/response/imap-namespace-response-test.vala
engine/imap/transport/imap-deserializer-test.vala
+ engine/imap-db/imap-db-attachment-test.vala
engine/imap-db/imap-db-database-test.vala
engine/imap-engine/account-processor-test.vala
engine/mime-content-type-test.vala
diff --git a/test/engine/imap-db/imap-db-attachment-test.vala
b/test/engine/imap-db/imap-db-attachment-test.vala
new file mode 100644
index 0000000..7600f75
--- /dev/null
+++ b/test/engine/imap-db/imap-db-attachment-test.vala
@@ -0,0 +1,89 @@
+/*
+ * Copyright 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.ImapDB.AttachmentTest : TestCase {
+
+
+ private Geary.Db.Database? db;
+
+ public AttachmentTest() {
+ base("Geary.ImapDB.FolderTest");
+ add_test("save_minimal_attachment", save_minimal_attachment);
+ }
+
+ public override void set_up() throws Error {
+ this.db = new Geary.Db.Database.transient();
+ this.db.open.begin(
+ Geary.Db.DatabaseFlags.NONE, null, null,
+ (obj, res) => { async_complete(res); }
+ );
+ this.db.open.end(async_result());
+ this.db.exec("""
+CREATE TABLE MessageTable (
+ id INTEGER PRIMARY KEY
+);
+""");
+ this.db.exec("INSERT INTO MessageTable VALUES (1);");
+
+ this.db.exec("""
+CREATE TABLE MessageAttachmentTable (
+ id INTEGER PRIMARY KEY,
+ message_id INTEGER REFERENCES MessageTable ON DELETE CASCADE,
+ filename TEXT,
+ mime_type TEXT,
+ filesize INTEGER,
+ disposition INTEGER,
+ content_id TEXT DEFAULT NULL,
+ description TEXT DEFAULT NULL
+);
+""");
+
+ }
+
+ public override void tear_down() throws Error {
+ this.db.close();
+ this.db = null;
+ }
+
+ public void save_minimal_attachment() throws Error {
+ GLib.File tmp_dir = GLib.File.new_for_path(
+ GLib.DirUtils.make_tmp("geary-impadb-foldertest-XXXXXX")
+ );
+
+ GMime.DataWrapper body = new GMime.DataWrapper.with_stream(
+ new GMime.StreamMem.with_buffer(TEXT_ATTACHMENT.data),
+ GMime.ContentEncoding.DEFAULT
+ );
+ GMime.Part attachment = new GMime.Part.with_type("text", "plain");
+ attachment.set_content_object(body);
+ attachment.encode(GMime.EncodingConstraint.7BIT);
+
+ Gee.List<GMime.Part> attachments = new Gee.LinkedList<GMime.Part>();
+ attachments.add(attachment);
+
+ Geary.ImapDB.Attachment.do_save_attachments(
+ this.db.get_master_connection(),
+ tmp_dir,
+ 1,
+ attachments,
+ null
+ );
+
+ Geary.Db.Result result = this.db.query(
+ "SELECT * FROM MessageAttachmentTable;"
+ );
+ assert_false(result.finished, "Row not inserted");
+ assert_int(1, result.int_for("message_id"), "Message id");
+ assert_false(result.next(), "Multiple rows inserted");
+
+ Geary.Files.recursive_delete_async.begin(tmp_dir);
+ }
+
+
+ private const string TEXT_ATTACHMENT = "This is an attachment.\n";
+
+}
diff --git a/test/meson.build b/test/meson.build
index f2e5f44..6749136 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -27,6 +27,7 @@ geary_test_engine_sources = [
'engine/imap/command/imap-create-command-test.vala',
'engine/imap/response/imap-namespace-response-test.vala',
'engine/imap/transport/imap-deserializer-test.vala',
+ 'engine/imap-db/imap-db-attachment-test.vala',
'engine/imap-db/imap-db-database-test.vala',
'engine/imap-engine/account-processor-test.vala',
'engine/mime-content-type-test.vala',
diff --git a/test/test-engine.vala b/test/test-engine.vala
index 071f781..89bf5d1 100644
--- a/test/test-engine.vala
+++ b/test/test-engine.vala
@@ -36,6 +36,7 @@ int main(string[] args) {
engine.add_suite(new Geary.Imap.DeserializerTest().get_suite());
engine.add_suite(new Geary.Imap.CreateCommandTest().get_suite());
engine.add_suite(new Geary.Imap.NamespaceResponseTest().get_suite());
+ engine.add_suite(new Geary.ImapDB.AttachmentTest().get_suite());
engine.add_suite(new Geary.ImapDB.DatabaseTest().get_suite());
engine.add_suite(new Geary.ImapEngine.AccountProcessorTest().get_suite());
engine.add_suite(new Geary.Inet.Test().get_suite());
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]