[geary/wip/726281-text-attachment-crlf: 9/13] Add unit tests for Geary.RFC822.Message body content, fix a few issues.



commit bfe665d1a0ed809acd904a60a8814da3aa07d0ad
Author: Michael James Gratton <mike vee net>
Date:   Wed May 9 17:34:56 2018 +1000

    Add unit tests for Geary.RFC822.Message body content, fix a few issues.
    
    * src/engine/rfc822/rfc822-message.vala (Message): Fix has_plain_body(),
      handle the case where displayed MIME entities (as opposed to attached
      ones) with no Content-Type default to US-ASCII, per the RFC.
    
    * test/engine/rfc822-message-test.vala (MessageTest): Add tests for
      testing and accessing body content as both plain text and HTML. Use
      GResources for accessing test message bodies rather than extremely long
      const strings.

 src/engine/rfc822/rfc822-message.vala       |   32 +++--
 test/data/basic-multipart-alternative.eml   |   36 +++++
 test/data/basic-text-html.eml               |   18 +++
 test/data/basic-text-plain.eml              |   17 +++
 test/data/meson.build                       |    3 +
 test/data/org.gnome.GearyTest.gresource.xml |    8 +
 test/engine/rfc822-message-test.vala        |  190 ++++++++++++++++++++-------
 test/meson.build                            |    6 +-
 8 files changed, 248 insertions(+), 62 deletions(-)
---
diff --git a/src/engine/rfc822/rfc822-message.vala b/src/engine/rfc822/rfc822-message.vala
index b78078c..a0e0709 100644
--- a/src/engine/rfc822/rfc822-message.vala
+++ b/src/engine/rfc822/rfc822-message.vala
@@ -471,7 +471,7 @@ public class Geary.RFC822.Message : BaseObject {
      * Determines if the message has one or plain text display parts.
      */
     public bool has_plain_body() {
-        return has_body_parts(message.get_mime_part(), "text");
+        return has_body_parts(message.get_mime_part(), "plain");
     }
 
     /**
@@ -486,10 +486,16 @@ public class Geary.RFC822.Message : BaseObject {
      */
     private bool has_body_parts(GMime.Object node, string text_subtype) {
         bool has_part = false;
-        Mime.ContentType? this_content_type = null;
-        if (node.get_content_type() != null)
-            this_content_type =
-                new Mime.ContentType.from_gmime(node.get_content_type());
+
+        // RFC 2045 Section 5.2 allows us to assume
+        // text/plain US-ASCII if no content type is
+        // otherwise specified.
+        Mime.ContentType this_content_type = Mime.ContentType.DISPLAY_DEFAULT;
+        if (node.get_content_type() != null) {
+            this_content_type = new Mime.ContentType.from_gmime(
+                node.get_content_type()
+            );
+        }
 
         GMime.Multipart? multipart = node as GMime.Multipart;
         if (multipart != null) {
@@ -508,8 +514,7 @@ public class Geary.RFC822.Message : BaseObject {
 
                 if (disposition == null ||
                     disposition.disposition_type != Mime.DispositionType.ATTACHMENT) {
-                    if (this_content_type != null &&
-                        this_content_type.has_media_type("text") &&
+                    if (this_content_type.has_media_type("text") &&
                         this_content_type.has_media_subtype(text_subtype)) {
                         has_part = true;
                     }
@@ -537,10 +542,15 @@ public class Geary.RFC822.Message : BaseObject {
      */
     private bool construct_body_from_mime_parts(GMime.Object node, Mime.MultipartSubtype container_subtype,
         string text_subtype, bool to_html, InlinePartReplacer? replacer, ref string? body) throws 
RFC822Error {
-        Mime.ContentType? this_content_type = null;
-        if (node.get_content_type() != null)
-            this_content_type = new Mime.ContentType.from_gmime(node.get_content_type());
-        
+        // RFC 2045 Section 5.2 allows us to assume text/plain
+        // US-ASCII if no content type is otherwise specified.
+        Mime.ContentType this_content_type = Mime.ContentType.DISPLAY_DEFAULT;
+        if (node.get_content_type() != null) {
+            this_content_type = new Mime.ContentType.from_gmime(
+                node.get_content_type()
+            );
+        }
+
         // If this is a multipart, call ourselves recursively on the children
         GMime.Multipart? multipart = node as GMime.Multipart;
         if (multipart != null) {
diff --git a/test/data/basic-multipart-alternative.eml b/test/data/basic-multipart-alternative.eml
new file mode 100644
index 0000000..cb453fb
--- /dev/null
+++ b/test/data/basic-multipart-alternative.eml
@@ -0,0 +1,36 @@
+From: Alice <alice example net>
+Sender: Bob <bob example net>
+To: Charlie <charlie example net>
+CC: Dave <dave example net>
+BCC: Eve <eve example net>
+Reply-To: \"Alice: Personal Account\" <alice example org>
+Subject: Re: Basic text/html message
+Date: Fri, 21 Nov 1997 10:01:10 -0600
+MIME-Version: 1.0
+Content-Type: multipart/alternative; boundary="=-NJextDaQ1tE2ZGhW9Wm0"
+Message-ID: <3456 example net>
+In-Reply-To: <1234@local.machine.example>
+References: <1234@local.machine.example>
+X-Mailer: Geary Test Suite 1.0
+
+--=-NJextDaQ1tE2ZGhW9Wm0
+Content-Type: text/plain; charset=UTF-8; format=flowed
+Content-Transfer-Encoding: quoted-printable
+
+This is the first line.
+
+This is the second line.
+
+=
+
+--=-NJextDaQ1tE2ZGhW9Wm0
+Content-Type: text/html; charset=UTF-8
+Content-Transfer-Encoding: quoted-printable
+
+<P>This is the first line.
+
+<P>This is the second line.
+
+=
+
+--=-NJextDaQ1tE2ZGhW9Wm0--
diff --git a/test/data/basic-text-html.eml b/test/data/basic-text-html.eml
new file mode 100644
index 0000000..0c3f4a6
--- /dev/null
+++ b/test/data/basic-text-html.eml
@@ -0,0 +1,18 @@
+From: Alice <alice example net>
+Sender: Bob <bob example net>
+To: Charlie <charlie example net>
+CC: Dave <dave example net>
+BCC: Eve <eve example net>
+Reply-To: \"Alice: Personal Account\" <alice example org>
+Subject: Re: Basic text/html message
+Date: Fri, 21 Nov 1997 10:01:10 -0600
+Content-Type: text/html; charset=UTF-8
+Message-ID: <3456 example net>
+In-Reply-To: <1234@local.machine.example>
+References: <1234@local.machine.example>
+X-Mailer: Geary Test Suite 1.0
+
+<P>This is the first line.
+
+<P>This is the second line.
+
diff --git a/test/data/basic-text-plain.eml b/test/data/basic-text-plain.eml
new file mode 100644
index 0000000..517d15e
--- /dev/null
+++ b/test/data/basic-text-plain.eml
@@ -0,0 +1,17 @@
+From: Alice <alice example net>
+Sender: Bob <bob example net>
+To: Charlie <charlie example net>
+CC: Dave <dave example net>
+BCC: Eve <eve example net>
+Reply-To: "Alice: Personal Account" <alice example org>
+Subject: Re: Basic text/plain message
+Date: Fri, 21 Nov 1997 10:01:10 -0600
+Message-ID: <3456 example net>
+In-Reply-To: <1234@local.machine.example>
+References: <1234@local.machine.example>
+X-Mailer: Geary Test Suite 1.0
+
+This is the first line.
+
+This is the second line.
+
diff --git a/test/data/meson.build b/test/data/meson.build
new file mode 100644
index 0000000..a4cda4d
--- /dev/null
+++ b/test/data/meson.build
@@ -0,0 +1,3 @@
+geary_test_engine_resources = gnome.compile_resources('org.gnome.GearyTest',
+  files('org.gnome.GearyTest.gresource.xml'),
+)
diff --git a/test/data/org.gnome.GearyTest.gresource.xml b/test/data/org.gnome.GearyTest.gresource.xml
new file mode 100644
index 0000000..3473b55
--- /dev/null
+++ b/test/data/org.gnome.GearyTest.gresource.xml
@@ -0,0 +1,8 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<gresources>
+  <gresource prefix="/org/gnome/GearyTest">
+    <file>basic-text-plain.eml</file>
+    <file>basic-text-html.eml</file>
+    <file>basic-multipart-alternative.eml</file>
+  </gresource>
+</gresources>
diff --git a/test/engine/rfc822-message-test.vala b/test/engine/rfc822-message-test.vala
index aaca0c8..75affed 100644
--- a/test/engine/rfc822-message-test.vala
+++ b/test/engine/rfc822-message-test.vala
@@ -7,29 +7,57 @@
 
 class Geary.RFC822.MessageTest : TestCase {
 
+    private const string RESOURCE_URI = "resource:///org/gnome/GearyTest";
+
+    private const string BASIC_TEXT_PLAIN = "basic-text-plain.eml";
+    private const string BASIC_TEXT_HTML = "basic-text-html.eml";
+    private const string BASIC_MULTIPART_ALTERNATIVE =
+        "basic-multipart-alternative.eml";
+
+    private const string HTML_CONVERSION_TEMPLATE =
+        "<div class=\"plaintext\" style=\"white-space: pre-wrap;\">%s</div>";
+
+    private const string BASIC_PLAIN_BODY = """This is the first line.
+
+This is the second line.
+
+""";
+
+    private const string BASIC_HTML_BODY = """<P>This is the first line.
+
+<P>This is the second line.
+
+""";
+
     public MessageTest() {
         base("Geary.RFC822.MessageTest");
         add_test("basic_message_from_buffer", basic_message_from_buffer);
         add_test("encoded_recipient", encoded_recipient);
         add_test("duplicate_mailbox", duplicate_mailbox);
         add_test("duplicate_message_id", duplicate_message_id);
+        add_test("text_plain_as_plain", text_plain_as_plain);
+        add_test("text_plain_as_html", text_plain_as_html);
+        add_test("text_html_as_html", text_html_as_html);
+        add_test("text_html_as_plain", text_html_as_plain);
+        add_test("multipart_alternative_as_plain",
+                 multipart_alternative_as_plain);
+        add_test("multipart_alternative_as_converted_html",
+                 multipart_alternative_as_converted_html);
+        add_test("multipart_alternative_as_html",
+                 multipart_alternative_as_html);
         add_test("get_preview", get_preview);
     }
 
     public void basic_message_from_buffer() throws Error {
-        Message? basic = null;
-        try {
-            basic = string_to_message(BASIC_MESSAGE);
-        } catch (Error err) {
-            assert_no_error(err);
-        }
-        assert_data(basic.subject, "Re: Saying Hello");
-        assert_addresses(basic.from, "Mary Smith <mary example net>");
-        assert_address(basic.sender, "Mary Smith Sender <mary example net>");
-        assert_addresses(basic.reply_to, "\"Mary Smith: Personal Account\" <smith@home.example>");
-        assert_addresses(basic.to, "John Doe <jdoe@machine.example>");
-        assert_addresses(basic.cc, "John Doe CC <jdoe@machine.example>");
-        assert_addresses(basic.bcc, "John Doe BCC <jdoe@machine.example>");
+        Message basic = resource_to_message(BASIC_TEXT_PLAIN);
+
+        assert_data(basic.subject, "Re: Basic text/plain message");
+        assert_addresses(basic.from, "Alice <alice example net>");
+        assert_address(basic.sender, "Bob <bob example net>");
+        assert_addresses(basic.reply_to, "\"Alice: Personal Account\" <alice example org>");
+        assert_addresses(basic.to, "Charlie <charlie example net>");
+        assert_addresses(basic.cc, "Dave <dave example net>");
+        assert_addresses(basic.bcc, "Eve <eve example net>");
         //assert_data(basic.message_id, "<3456 example net>");
         assert_message_id_list(basic.in_reply_to, "<1234@local.machine.example>");
         assert_message_id_list(basic.references, "<1234@local.machine.example>");
@@ -38,24 +66,14 @@ class Geary.RFC822.MessageTest : TestCase {
     }
 
     public void encoded_recipient() throws Error {
-        Message? enc = null;
-        try {
-            enc = string_to_message(ENCODED_TO);
-        } catch (Error err) {
-            assert_no_error(err);
-        }
+        Message enc = string_to_message(ENCODED_TO);
 
         // Courtesy Mailsploit https://www.mailsploit.com
         assert(enc.to[0].name == "potus whitehouse gov <test>");
     }
 
     public void duplicate_mailbox() throws Error {
-        Message? dup = null;
-        try {
-            dup = string_to_message(DUPLICATE_TO);
-        } catch (Error err) {
-            assert_no_error(err);
-        }
+        Message dup = string_to_message(DUPLICATE_TO);
 
         assert(dup.to.size == 2);
         assert_addresses(
@@ -64,12 +82,7 @@ class Geary.RFC822.MessageTest : TestCase {
     }
 
     public void duplicate_message_id() throws Error {
-        Message? dup = null;
-        try {
-            dup = string_to_message(DUPLICATE_REFERENCES);
-        } catch (Error err) {
-            assert_no_error(err);
-        }
+        Message dup = string_to_message(DUPLICATE_REFERENCES);
 
         assert(dup.references.list.size == 2);
         assert_message_id_list(
@@ -77,13 +90,84 @@ class Geary.RFC822.MessageTest : TestCase {
         );
     }
 
+    public void text_plain_as_plain() throws Error {
+        Message test = resource_to_message(BASIC_TEXT_PLAIN);
+
+        assert_true(test.has_plain_body(), "Expected plain body");
+        assert_false(test.has_html_body(), "Expected non-html body");
+        assert_string(BASIC_PLAIN_BODY, test.get_plain_body(false, null));
+    }
+
+    public void text_plain_as_html() throws Error {
+        Message test = resource_to_message(BASIC_TEXT_PLAIN);
+
+        assert_true(test.has_plain_body(), "Expected plain body");
+        assert_false(test.has_html_body(), "Expected non-html body");
+        assert_string(
+            HTML_CONVERSION_TEMPLATE.printf(BASIC_PLAIN_BODY),
+            test.get_plain_body(true, null)
+        );
+    }
+
+    public void text_html_as_html() throws Error {
+        Message test = resource_to_message(BASIC_TEXT_HTML);
+
+        assert_true(test.has_html_body(), "Expected html body");
+        assert_false(test.has_plain_body(), "Expected non-plain body");
+        assert_string(BASIC_HTML_BODY, test.get_html_body(null));
+    }
+
+    public void text_html_as_plain() throws Error {
+        Message test = resource_to_message(BASIC_TEXT_HTML);
+
+        assert_true(test.has_html_body(), "Expected html body");
+        assert_false(test.has_plain_body(), "Expected non-plain body");
+        assert_string(BASIC_HTML_BODY, test.get_html_body(null));
+    }
+
+    public void multipart_alternative_as_plain() throws Error {
+        Message test = resource_to_message(BASIC_MULTIPART_ALTERNATIVE);
+
+        assert_true(test.has_plain_body(), "Expected plain body");
+        assert_true(test.has_html_body(), "Expected html body");
+        assert_string(BASIC_PLAIN_BODY, test.get_plain_body(false, null));
+    }
+
+    public void multipart_alternative_as_converted_html() throws Error {
+        Message test = resource_to_message(BASIC_MULTIPART_ALTERNATIVE);
+
+        assert_true(test.has_plain_body(), "Expected plain body");
+        assert_true(test.has_html_body(), "Expected html body");
+        assert_string(
+            HTML_CONVERSION_TEMPLATE.printf(BASIC_PLAIN_BODY),
+            test.get_plain_body(true, null)
+        );
+    }
+
+    public void multipart_alternative_as_html() throws Error {
+        Message test = resource_to_message(BASIC_MULTIPART_ALTERNATIVE);
+
+        assert_true(test.has_plain_body(), "Expected plain body");
+        assert_true(test.has_html_body(), "Expected html body");
+        assert_string(BASIC_HTML_BODY, test.get_html_body(null));
+    }
+
     public void get_preview() throws Error {
-        try {
-            Message multipart_signed = string_to_message(MULTIPART_SIGNED_MESSAGE_TEXT);
-            assert(multipart_signed.get_preview() == MULTIPART_SIGNED_MESSAGE_PREVIEW);
-        } catch (Error err) {
-            assert_no_error(err);
-        }
+        Message multipart_signed = string_to_message(MULTIPART_SIGNED_MESSAGE_TEXT);
+
+        assert(multipart_signed.get_preview() == MULTIPART_SIGNED_MESSAGE_PREVIEW);
+    }
+
+    private Message resource_to_message(string path) throws Error {
+        GLib.File resource =
+            GLib.File.new_for_uri(RESOURCE_URI).resolve_relative_path(path);
+
+        uint8[] contents;
+        resource.load_contents(null, out contents, null);
+
+        return new Message.from_buffer(
+            new Geary.Memory.ByteBuffer(contents, contents.length)
+        );
     }
 
     private Message string_to_message(string message_text) throws Error {
@@ -92,28 +176,34 @@ class Geary.RFC822.MessageTest : TestCase {
         );
     }
 
-    private void assert_data(Geary.MessageData.AbstractMessageData? data, string expected) {
-        assert(data != null);
-        assert(data.to_string() == expected);
+    private void assert_data(Geary.MessageData.AbstractMessageData? actual,
+                             string expected)
+        throws Error {
+        assert_non_null(actual, expected);
+        assert_string(expected, actual.to_string());
     }
 
-    private void assert_address(Geary.RFC822.MailboxAddress? address, string expected) {
-        assert(address != null);
-        assert(address.to_rfc822_string() == expected);
+    private void assert_address(Geary.RFC822.MailboxAddress? address,
+                                string expected)
+        throws Error {
+        assert_non_null(address, expected);
+        assert_string(expected, address.to_rfc822_string());
     }
 
-    private void assert_addresses(Geary.RFC822.MailboxAddresses? addresses, string expected) {
-        assert(addresses != null);
-        assert(addresses.to_rfc822_string() == expected);
+    private void assert_addresses(Geary.RFC822.MailboxAddresses? addresses,
+                                  string expected)
+        throws Error {
+        assert_non_null(addresses, expected);
+        assert_string(expected, addresses.to_rfc822_string());
     }
 
-    private void assert_message_id_list(Geary.RFC822.MessageIDList? ids, string expected) {
-        assert(ids != null);
+    private void assert_message_id_list(Geary.RFC822.MessageIDList? ids,
+                                        string expected)
+        throws Error {
+        assert_non_null(ids, expected);
         assert(ids.to_rfc822_string() == expected);
     }
 
-    private static string BASIC_MESSAGE = "From: Mary Smith <mary example net>\r\nSender: Mary Smith Sender 
<mary example net>\r\nTo: John Doe <jdoe@machine.example>\r\nCC: John Doe CC <jdoe@machine.example>\r\nBCC: 
John Doe BCC <jdoe@machine.example>\r\nReply-To: \"Mary Smith: Personal Account\" 
<smith@home.example>\r\nSubject: Re: Saying Hello\r\nDate: Fri, 21 Nov 1997 10:01:10 -0600\r\nMessage-ID: 
<3456 example net>\r\nIn-Reply-To: <1234@local.machine.example>\r\nReferences: 
<1234@local.machine.example>\r\nX-Mailer: Geary Test Suite 1.0\r\n\r\nThis is a reply to your hello.\r\n\r\n";
-
     // Courtesy Mailsploit https://www.mailsploit.com
     private static string ENCODED_TO = "From: Mary Smith <mary example net>\r\nTo: 
=?utf-8?b?cG90dXNAd2hpdGVob3VzZS5nb3YiIDx0ZXN0Pg==?= <jdoe@machine.example>\r\nSubject: Re: Saying 
Hello\r\nDate: Fri, 21 Nov 1997 10:01:10 -0600\r\n\r\nThis is a reply to your hello.\r\n\r\n";
 
diff --git a/test/meson.build b/test/meson.build
index 6749136..aeeeeda 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -1,3 +1,5 @@
+subdir('data')
+
 geary_test_lib_sources = [
   'mock-object.vala',
   'test-case.vala',
@@ -41,7 +43,9 @@ geary_test_engine_sources = [
   'engine/util-inet-test.vala',
   'engine/util-js-test.vala',
   'engine/util-string-test.vala',
-  'engine/util-timeout-manager-test.vala'
+  'engine/util-timeout-manager-test.vala',
+
+  geary_test_engine_resources
 ]
 
 geary_test_client_sources = [


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]