diff --git a/django_mailbox/runtests.py b/django_mailbox/runtests.py index 628054a..62094fd 100644 --- a/django_mailbox/runtests.py +++ b/django_mailbox/runtests.py @@ -27,7 +27,11 @@ def runtests(*test_args): test_args = ['django_mailbox'] parent = dirname(abspath(__file__)) sys.path.insert(0, parent) - runner = DjangoTestSuiteRunner(verbosity=1, interactive=True) + runner = DjangoTestSuiteRunner( + verbosity=1, + interactive=False, + failfast=False + ) failures = runner.run_tests(test_args) sys.exit(failures) diff --git a/django_mailbox/tests/__init__.py b/django_mailbox/tests/__init__.py index 5cc7dc7..42d5abe 100644 --- a/django_mailbox/tests/__init__.py +++ b/django_mailbox/tests/__init__.py @@ -1,309 +1,3 @@ -import email -import os.path - -from django.test import TestCase -import six - -from django_mailbox import models -from django_mailbox.models import Mailbox, Message - - -class TestMailbox(TestCase): - def test_protocol_info(self): - mailbox = Mailbox() - mailbox.uri = 'alpha://test.com' - - expected_protocol = 'alpha' - actual_protocol = mailbox._protocol_info.scheme - - self.assertEqual( - expected_protocol, - actual_protocol, - ) - - -class EmailMessageTestCase(TestCase): - def setUp(self): - self._ALLOWED_MIMETYPES = models.ALLOWED_MIMETYPES - self._STRIP_UNALLOWED_MIMETYPES = models.STRIP_UNALLOWED_MIMETYPES - self._TEXT_STORED_MIMETYPES = models.TEXT_STORED_MIMETYPES - - self.mailbox = Mailbox.objects.create() - super(EmailMessageTestCase, self).setUp() - - def _get_email_object(self, name): - with open(os.path.join(os.path.dirname(__file__), name), 'r') as f: - return email.message_from_string( - f.read() - ) - - def _headers_identical(self, left, right): - """ Check if headers are identical. - - This is particularly tricky because Python 2.6, Python 2.7 and Python 3 - each handle this slightly differently. This should mash away all - of the differences, though. - - """ - left = left.replace('\n\t', ' ').replace('\n ', ' ') - right = right.replace('\n\t', ' ').replace('\n ', ' ') - if right != left: - return False - return True - - def compare_email_objects(self, left, right): - # Compare headers - for key, value in left.items(): - if not right[key]: - raise AssertionError("Extra header '%s'" % key) - if not self._headers_identical(right[key], value): - raise AssertionError( - "Header '%s' unequal:\n%s\n%s" % ( - key, - repr(value), - repr(right[key]), - ) - ) - for key, value in right.items(): - if not left[key]: - raise AssertionError("Extra header '%s'" % key) - if not self._headers_identical(left[key], value): - raise AssertionError( - "Header '%s' unequal:\n%s\n%s" % ( - key, - repr(value), - repr(right[key]), - ) - ) - if left.is_multipart() != right.is_multipart(): - self._raise_mismatched(left, right) - if left.is_multipart(): - left_payloads = left.get_payload() - right_payloads = right.get_payload() - if len(left_payloads) != len(right_payloads): - self._raise_mismatched(left, right) - for n in range(len(left_payloads)): - self.compare_email_objects( - left_payloads[n], - right_payloads[n] - ) - else: - if left.get_payload() is None or right.get_payload() is None: - if left.get_payload() is None: - if right.get_payload is not None: - self._raise_mismatched(left, right) - if right.get_payload() is None: - if left.get_payload is not None: - self._raise_mismatched(left, right) - elif left.get_payload().strip() != right.get_payload().strip(): - self._raise_mismatched(left, right) - - def _raise_mismatched(self, left, right): - raise AssertionError( - "Message payloads do not match:\n%s\n%s" % ( - left.as_string(), - right.as_string() - ) - ) - - def assertEqual(self, left, right): - if not isinstance(left, email.message.Message): - return super(EmailMessageTestCase, self).assertEqual(left, right) - return self.compare_email_objects(left, right) - - def tearDown(self): - for message in Message.objects.all(): - message.delete() - models.ALLOWED_MIMETYPES = self._ALLOWED_MIMETYPES - models.STRIP_UNALLOWED_MIMETYPES = self._STRIP_UNALLOWED_MIMETYPES - models.TEXT_STORED_MIMETYPES = self._TEXT_STORED_MIMETYPES - - self.mailbox.delete() - super(EmailMessageTestCase, self).tearDown() - - -class TestProcessEmail(EmailMessageTestCase): - def test_message_without_attachments(self): - message = self._get_email_object('generic_message.eml') - - mailbox = Mailbox.objects.create() - msg = mailbox.process_incoming_message(message) - - self.assertEqual( - msg.mailbox, - mailbox - ) - self.assertEqual(msg.subject, 'Message Without Attachment') - self.assertEqual( - msg.message_id, - ( - '' - ) - ) - self.assertEqual( - msg.from_header, - 'Adam Coddington ', - ) - self.assertEqual( - msg.to_header, - 'Adam Coddington ', - ) - - def test_message_with_attachments(self): - message = self._get_email_object('message_with_attachment.eml') - - mailbox = Mailbox.objects.create() - msg = mailbox.process_incoming_message(message) - - expected_count = 1 - actual_count = msg.attachments.count() - - self.assertEqual( - expected_count, - actual_count, - ) - - attachment = msg.attachments.all()[0] - self.assertEqual( - attachment.get_filename(), - 'heart.png', - ) - - def test_message_get_text_body(self): - message = self._get_email_object('multipart_text.eml') - - mailbox = Mailbox.objects.create() - msg = mailbox.process_incoming_message(message) - - expected_results = 'Hello there!' - actual_results = msg.get_text_body().strip() - - self.assertEqual( - expected_results, - actual_results, - ) - - -class TestGetMessage(EmailMessageTestCase): - def test_get_text_body_properly_recomposes_line_continuations(self): - message = Message() - email_object = self._get_email_object( - 'message_with_long_text_lines.eml' - ) - - message.get_email_object = lambda: email_object - - actual_text = message.get_text_body() - expected_text = ( - 'The one of us with a bike pump is far ahead, ' - 'but a man stopped to help us and gave us his pump.' - ) - - self.assertEqual( - actual_text, - expected_text - ) - - -class TestMessageFlattening(EmailMessageTestCase): - def test_quopri_message_is_properly_rehydrated(self): - incoming_email_object = self._get_email_object( - 'message_with_many_multiparts.eml', - ) - # Note: this is identical to the above, but it appears that - # while reading-in an e-mail message, we do alter it slightly - expected_email_object = self._get_email_object( - 'message_with_many_multiparts.eml', - ) - models.TEXT_STORED_MIMETYPES = ['text/plain'] - - msg = self.mailbox.process_incoming_message(incoming_email_object) - - actual_email_object = msg.get_email_object() - - self.assertEqual( - actual_email_object, - expected_email_object, - ) - - def test_base64_message_is_properly_rehydrated(self): - incoming_email_object = self._get_email_object( - 'message_with_attachment.eml', - ) - # Note: this is identical to the above, but it appears that - # while reading-in an e-mail message, we do alter it slightly - expected_email_object = self._get_email_object( - 'message_with_attachment.eml', - ) - - msg = self.mailbox.process_incoming_message(incoming_email_object) - - actual_email_object = msg.get_email_object() - - self.assertEqual( - actual_email_object, - expected_email_object, - ) - - def test_message_handles_rehydration_problems(self): - incoming_email_object = self._get_email_object( - 'message_with_defective_attachment_association.eml', - ) - expected_email_object = self._get_email_object( - 'message_with_defective_attachment_association_result.eml', - ) - # Note: this is identical to the above, but it appears that - # while reading-in an e-mail message, we do alter it slightly - message = Message() - message.body = incoming_email_object.as_string() - - msg = self.mailbox.process_incoming_message(incoming_email_object) - - actual_email_object = msg.get_email_object() - - self.assertEqual( - actual_email_object, - expected_email_object, - ) - - def test_message_content_type_stripping(self): - incoming_email_object = self._get_email_object( - 'message_with_many_multiparts.eml', - ) - expected_email_object = self._get_email_object( - 'message_with_many_multiparts_stripped_html.eml', - ) - models.STRIP_UNALLOWED_MIMETYPES = True - models.ALLOWED_MIMETYPES = ['text/plain'] - - msg = self.mailbox.process_incoming_message(incoming_email_object) - - actual_email_object = msg.get_email_object() - - self.assertEqual( - actual_email_object, - expected_email_object, - ) - - -class TestMessageGetEmailObject(TestCase): - def test_get_body_properly_handles_unicode_body(self): - with open( - os.path.join( - os.path.dirname(__file__), - 'generic_message.eml' - ) - ) as f: - unicode_body = six.u(f.read()) - - message = Message() - message.body = unicode_body - - expected_body = unicode_body - actual_body = message.get_email_object().as_string() - - self.assertEqual( - expected_body, - actual_body - ) +from .test_mailbox import * +from .test_message_flattening import * +from .test_process_email import * diff --git a/django_mailbox/tests/base.py b/django_mailbox/tests/base.py new file mode 100644 index 0000000..73d449d --- /dev/null +++ b/django_mailbox/tests/base.py @@ -0,0 +1,107 @@ +import email +import os.path + +from django.test import TestCase + +from django_mailbox import models +from django_mailbox.models import Mailbox, Message + + +class EmailMessageTestCase(TestCase): + def setUp(self): + self._ALLOWED_MIMETYPES = models.ALLOWED_MIMETYPES + self._STRIP_UNALLOWED_MIMETYPES = models.STRIP_UNALLOWED_MIMETYPES + self._TEXT_STORED_MIMETYPES = models.TEXT_STORED_MIMETYPES + + self.mailbox = Mailbox.objects.create() + super(EmailMessageTestCase, self).setUp() + + def _get_email_object(self, name): + with open(os.path.join(os.path.dirname(__file__), name), 'r') as f: + return email.message_from_string( + f.read() + ) + + def _headers_identical(self, left, right): + """ Check if headers are identical. + + This is particularly tricky because Python 2.6, Python 2.7 and Python 3 + each handle this slightly differently. This should mash away all + of the differences, though. + + """ + left = left.replace('\n\t', ' ').replace('\n ', ' ') + right = right.replace('\n\t', ' ').replace('\n ', ' ') + if right != left: + return False + return True + + def compare_email_objects(self, left, right): + # Compare headers + for key, value in left.items(): + if not right[key]: + raise AssertionError("Extra header '%s'" % key) + if not self._headers_identical(right[key], value): + raise AssertionError( + "Header '%s' unequal:\n%s\n%s" % ( + key, + repr(value), + repr(right[key]), + ) + ) + for key, value in right.items(): + if not left[key]: + raise AssertionError("Extra header '%s'" % key) + if not self._headers_identical(left[key], value): + raise AssertionError( + "Header '%s' unequal:\n%s\n%s" % ( + key, + repr(value), + repr(right[key]), + ) + ) + if left.is_multipart() != right.is_multipart(): + self._raise_mismatched(left, right) + if left.is_multipart(): + left_payloads = left.get_payload() + right_payloads = right.get_payload() + if len(left_payloads) != len(right_payloads): + self._raise_mismatched(left, right) + for n in range(len(left_payloads)): + self.compare_email_objects( + left_payloads[n], + right_payloads[n] + ) + else: + if left.get_payload() is None or right.get_payload() is None: + if left.get_payload() is None: + if right.get_payload is not None: + self._raise_mismatched(left, right) + if right.get_payload() is None: + if left.get_payload is not None: + self._raise_mismatched(left, right) + elif left.get_payload().strip() != right.get_payload().strip(): + self._raise_mismatched(left, right) + + def _raise_mismatched(self, left, right): + raise AssertionError( + "Message payloads do not match:\n%s\n%s" % ( + left.as_string(), + right.as_string() + ) + ) + + def assertEqual(self, left, right): + if not isinstance(left, email.message.Message): + return super(EmailMessageTestCase, self).assertEqual(left, right) + return self.compare_email_objects(left, right) + + def tearDown(self): + for message in Message.objects.all(): + message.delete() + models.ALLOWED_MIMETYPES = self._ALLOWED_MIMETYPES + models.STRIP_UNALLOWED_MIMETYPES = self._STRIP_UNALLOWED_MIMETYPES + models.TEXT_STORED_MIMETYPES = self._TEXT_STORED_MIMETYPES + + self.mailbox.delete() + super(EmailMessageTestCase, self).tearDown() diff --git a/django_mailbox/tests/message_with_image_jpg_mimetype.eml b/django_mailbox/tests/message_with_image_jpg_mimetype.eml index 061190e..01fb081 100644 --- a/django_mailbox/tests/message_with_image_jpg_mimetype.eml +++ b/django_mailbox/tests/message_with_image_jpg_mimetype.eml @@ -1,5 +1,3 @@ -From - Sat Aug 3 13:25:07 2013 - Delivered-To: person3@example.com Received: by 10.76.18.165 with SMTP id x5csp92235oad; Thu, 31 Jan 2013 10:00:48 -0800 (PST) diff --git a/django_mailbox/tests/message_with_utf16_char.eml b/django_mailbox/tests/message_with_utf16_char.eml index dd88a30..7869100 100644 --- a/django_mailbox/tests/message_with_utf16_char.eml +++ b/django_mailbox/tests/message_with_utf16_char.eml @@ -1,5 +1,3 @@ -From - Sat Aug 3 13:25:07 2013 - Delivered-To: user1@example.com Received: by 10.76.18.165 with SMTP id x5csp6205oad; Sat, 5 Jan 2013 17:59:14 -0800 (PST) diff --git a/django_mailbox/tests/test_mailbox.py b/django_mailbox/tests/test_mailbox.py new file mode 100644 index 0000000..d06fc77 --- /dev/null +++ b/django_mailbox/tests/test_mailbox.py @@ -0,0 +1,20 @@ +from django.test import TestCase + +from django_mailbox.models import Mailbox + + +__all__ = ['TestMailbox'] + + +class TestMailbox(TestCase): + def test_protocol_info(self): + mailbox = Mailbox() + mailbox.uri = 'alpha://test.com' + + expected_protocol = 'alpha' + actual_protocol = mailbox._protocol_info.scheme + + self.assertEqual( + expected_protocol, + actual_protocol, + ) diff --git a/django_mailbox/tests/test_message_flattening.py b/django_mailbox/tests/test_message_flattening.py new file mode 100644 index 0000000..9574701 --- /dev/null +++ b/django_mailbox/tests/test_message_flattening.py @@ -0,0 +1,87 @@ +from django_mailbox import models +from django_mailbox.models import Message +from django_mailbox.tests.base import EmailMessageTestCase + + +__all__ = ['TestMessageFlattening'] + + +class TestMessageFlattening(EmailMessageTestCase): + def test_quopri_message_is_properly_rehydrated(self): + incoming_email_object = self._get_email_object( + 'message_with_many_multiparts.eml', + ) + # Note: this is identical to the above, but it appears that + # while reading-in an e-mail message, we do alter it slightly + expected_email_object = self._get_email_object( + 'message_with_many_multiparts.eml', + ) + models.TEXT_STORED_MIMETYPES = ['text/plain'] + + msg = self.mailbox.process_incoming_message(incoming_email_object) + + actual_email_object = msg.get_email_object() + + self.assertEqual( + actual_email_object, + expected_email_object, + ) + + def test_base64_message_is_properly_rehydrated(self): + incoming_email_object = self._get_email_object( + 'message_with_attachment.eml', + ) + # Note: this is identical to the above, but it appears that + # while reading-in an e-mail message, we do alter it slightly + expected_email_object = self._get_email_object( + 'message_with_attachment.eml', + ) + + msg = self.mailbox.process_incoming_message(incoming_email_object) + + actual_email_object = msg.get_email_object() + + self.assertEqual( + actual_email_object, + expected_email_object, + ) + + def test_message_handles_rehydration_problems(self): + incoming_email_object = self._get_email_object( + 'message_with_defective_attachment_association.eml', + ) + expected_email_object = self._get_email_object( + 'message_with_defective_attachment_association_result.eml', + ) + # Note: this is identical to the above, but it appears that + # while reading-in an e-mail message, we do alter it slightly + message = Message() + message.body = incoming_email_object.as_string() + + msg = self.mailbox.process_incoming_message(incoming_email_object) + + actual_email_object = msg.get_email_object() + + self.assertEqual( + actual_email_object, + expected_email_object, + ) + + def test_message_content_type_stripping(self): + incoming_email_object = self._get_email_object( + 'message_with_many_multiparts.eml', + ) + expected_email_object = self._get_email_object( + 'message_with_many_multiparts_stripped_html.eml', + ) + models.STRIP_UNALLOWED_MIMETYPES = True + models.ALLOWED_MIMETYPES = ['text/plain'] + + msg = self.mailbox.process_incoming_message(incoming_email_object) + + actual_email_object = msg.get_email_object() + + self.assertEqual( + actual_email_object, + expected_email_object, + ) diff --git a/django_mailbox/tests/test_process_email.py b/django_mailbox/tests/test_process_email.py new file mode 100644 index 0000000..bf92dc8 --- /dev/null +++ b/django_mailbox/tests/test_process_email.py @@ -0,0 +1,111 @@ +import os.path + +import six + +from django_mailbox.models import Mailbox, Message +from django_mailbox.tests.base import EmailMessageTestCase + + +__all__ = ['TestProcessEmail'] + + +class TestProcessEmail(EmailMessageTestCase): + def test_message_without_attachments(self): + message = self._get_email_object('generic_message.eml') + + mailbox = Mailbox.objects.create() + msg = mailbox.process_incoming_message(message) + + self.assertEqual( + msg.mailbox, + mailbox + ) + self.assertEqual(msg.subject, 'Message Without Attachment') + self.assertEqual( + msg.message_id, + ( + '' + ) + ) + self.assertEqual( + msg.from_header, + 'Adam Coddington ', + ) + self.assertEqual( + msg.to_header, + 'Adam Coddington ', + ) + + def test_message_with_attachments(self): + message = self._get_email_object('message_with_attachment.eml') + + mailbox = Mailbox.objects.create() + msg = mailbox.process_incoming_message(message) + + expected_count = 1 + actual_count = msg.attachments.count() + + self.assertEqual( + expected_count, + actual_count, + ) + + attachment = msg.attachments.all()[0] + self.assertEqual( + attachment.get_filename(), + 'heart.png', + ) + + def test_message_get_text_body(self): + message = self._get_email_object('multipart_text.eml') + + mailbox = Mailbox.objects.create() + msg = mailbox.process_incoming_message(message) + + expected_results = 'Hello there!' + actual_results = msg.get_text_body().strip() + + self.assertEqual( + expected_results, + actual_results, + ) + + def test_get_text_body_properly_recomposes_line_continuations(self): + message = Message() + email_object = self._get_email_object( + 'message_with_long_text_lines.eml' + ) + + message.get_email_object = lambda: email_object + + actual_text = message.get_text_body() + expected_text = ( + 'The one of us with a bike pump is far ahead, ' + 'but a man stopped to help us and gave us his pump.' + ) + + self.assertEqual( + actual_text, + expected_text + ) + + def test_get_body_properly_handles_unicode_body(self): + with open( + os.path.join( + os.path.dirname(__file__), + 'generic_message.eml' + ) + ) as f: + unicode_body = six.u(f.read()) + + message = Message() + message.body = unicode_body + + expected_body = unicode_body + actual_body = message.get_email_object().as_string() + + self.assertEqual( + expected_body, + actual_body + )