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.
This commit is contained in:
Michael James Gratton 2018-05-09 17:34:56 +10:00
parent a2a95686b4
commit bfe665d1a0
8 changed files with 248 additions and 62 deletions

View file

@ -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) {

View file

@ -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--

View file

@ -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.

View file

@ -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.

3
test/data/meson.build Normal file
View file

@ -0,0 +1,3 @@
geary_test_engine_resources = gnome.compile_resources('org.gnome.GearyTest',
files('org.gnome.GearyTest.gresource.xml'),
)

View file

@ -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>

View file

@ -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";

View file

@ -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 = [