"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "test/test_multipart.py" between
roundup-1.6.1.tar.gz and roundup-2.0.0.tar.gz

About: Roundup is an highly customisable issue-tracking system with command-line, web and e-mail interfaces (written in Python).

test_multipart.py  (roundup-1.6.1):test_multipart.py  (roundup-2.0.0)
skipping to change at line 18 skipping to change at line 18
# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING # DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING
# OUT OF THE USE OF THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE # OUT OF THE USE OF THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE. # POSSIBILITY OF SUCH DAMAGE.
# #
# BIZAR SOFTWARE PTY LTD SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, # BIZAR SOFTWARE PTY LTD SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" # FOR A PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS"
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
import email
import unittest import unittest
from cStringIO import StringIO from roundup.anypy.strings import StringIO
from roundup.mailgw import Message from roundup.mailgw import RoundupMessage
def gen_message(spec):
"""Create a basic MIME message according to 'spec'.
Each line of a spec has one content-type, which is optionally indented.
The indentation signifies how deep in the MIME hierarchy the
content-type is.
"""
def getIndent(line):
"""Get the current line's indentation, using four-space indents."""
count = 0
for char in line:
if char != ' ':
break
count += 1
return count // 4
class ExampleMessage(Message):
# A note on message/rfc822: The content of such an attachment is an # A note on message/rfc822: The content of such an attachment is an
# email with at least one header line. RFC2046 tells us: """ A # email with at least one header line. RFC2046 tells us: """ A
# media type of "message/rfc822" indicates that the body contains an # media type of "message/rfc822" indicates that the body contains an
# encapsulated message, with the syntax of an RFC 822 message. # encapsulated message, with the syntax of an RFC 822 message.
# However, unlike top-level RFC 822 messages, the restriction that # However, unlike top-level RFC 822 messages, the restriction that
# each "message/rfc822" body must include a "From", "Date", and at # each "message/rfc822" body must include a "From", "Date", and at
# least one destination header is removed and replaced with the # least one destination header is removed and replaced with the
# requirement that at least one of "From", "Subject", or "Date" must # requirement that at least one of "From", "Subject", or "Date" must
# be present.""" # be present."""
# This means we have to add a newline after the mime-header before # This means we have to add a newline after the mime-header before
skipping to change at line 45 skipping to change at line 63
# part of the email header. # part of the email header.
table = {'multipart/signed': ' boundary="boundary-%(indent)s";\n', table = {'multipart/signed': ' boundary="boundary-%(indent)s";\n',
'multipart/mixed': ' boundary="boundary-%(indent)s";\n', 'multipart/mixed': ' boundary="boundary-%(indent)s";\n',
'multipart/alternative': ' boundary="boundary-%(indent)s";\n', 'multipart/alternative': ' boundary="boundary-%(indent)s";\n',
'text/plain': ' name="foo.txt"\nfoo\n', 'text/plain': ' name="foo.txt"\nfoo\n',
'text/html': ' name="bar.html"\n<html><body>bar &gt;</body></htm l>\n', 'text/html': ' name="bar.html"\n<html><body>bar &gt;</body></htm l>\n',
'application/pgp-signature': ' name="foo.gpg"\nfoo\n', 'application/pgp-signature': ' name="foo.gpg"\nfoo\n',
'application/pdf': ' name="foo.pdf"\nfoo\n', 'application/pdf': ' name="foo.pdf"\nfoo\n',
'message/rfc822': '\nSubject: foo\n\nfoo\n'} 'message/rfc822': '\nSubject: foo\n\nfoo\n'}
def __init__(self, spec): parts = []
"""Create a basic MIME message according to 'spec'. for line in spec.splitlines():
content_type = line.strip()
Each line of a spec has one content-type, which is optionally indented. if not content_type:
The indentation signifies how deep in the MIME hierarchy the continue
content-type is.
indent = getIndent(line)
""" if indent:
parts = [] parts.append('\n--boundary-%s\n' % indent)
for line in spec.splitlines(): parts.append('Content-type: %s;\n' % content_type)
content_type = line.strip() parts.append(table[content_type] % {'indent': indent + 1})
if not content_type:
continue
indent = self.getIndent(line)
if indent:
parts.append('\n--boundary-%s\n' % indent)
parts.append('Content-type: %s;\n' % content_type)
parts.append(self.table[content_type] % {'indent': indent + 1})
Message.__init__(self, StringIO(''.join(parts))) for i in range(indent, 0, -1):
parts.append('\n--boundary-%s--\n' % i)
def getIndent(self, line): return email.message_from_file(StringIO(''.join(parts)), RoundupMessage)
"""Get the current line's indentation, using four-space indents."""
count = 0
for char in line:
if char != ' ':
break
count += 1
return count / 4
class MultipartTestCase(unittest.TestCase): class MultipartTestCase(unittest.TestCase):
def setUp(self): def setUp(self):
self.fp = StringIO() self.fp = StringIO()
w = self.fp.write w = self.fp.write
w('Content-Type: multipart/mixed; boundary="foo"\r\n\r\n') w('Content-Type: multipart/mixed; boundary="foo"\r\n\r\n')
w('This is a multipart message. Ignore this bit.\r\n') w('This is a multipart message. Ignore this bit.\r\n')
w('\r\n--foo\r\n') w('\r\n--foo\r\n')
w('Content-Type: text/plain\r\n\r\n') w('Content-Type: text/plain\r\n\r\n')
skipping to change at line 113 skipping to change at line 117
w('<b>Hello, world!</b>\r\n') w('<b>Hello, world!</b>\r\n')
w('\r\n--bar--\r\n') w('\r\n--bar--\r\n')
w('\r\n--foo\r\n') w('\r\n--foo\r\n')
w('Content-Type: text/plain\r\n\r\n') w('Content-Type: text/plain\r\n\r\n')
w('Last bit\n') w('Last bit\n')
w('\r\n--foo--\r\n') w('\r\n--foo--\r\n')
self.fp.seek(0) self.fp.seek(0)
def testMultipart(self): def testMultipart(self):
m = Message(self.fp) m = email.message_from_file(self.fp, RoundupMessage)
self.assert_(m is not None) self.assertTrue(m is not None)
# skip the first bit it = iter(m.get_payload())
p = m.getpart()
self.assert_(p is not None)
self.assertEqual(p.fp.read(),
'This is a multipart message. Ignore this bit.\r\n')
# first text/plain # first text/plain
p = m.getpart() p = next(it, None)
self.assert_(p is not None) self.assertTrue(p is not None)
self.assertEqual(p.gettype(), 'text/plain') self.assertEqual(p.get_content_type(), 'text/plain')
self.assertEqual(p.fp.read(), self.assertEqual(p.get_payload(),
'Hello, world!\r\n\r\nBlah blah\r\nfoo\r\n-foo\r\n') 'Hello, world!\r\n\r\nBlah blah\r\nfoo\r\n-foo\r\n')
# sub-multipart # sub-multipart
p = m.getpart() p = next(it, None)
self.assert_(p is not None) self.assertTrue(p is not None)
self.assertEqual(p.gettype(), 'multipart/alternative') self.assertEqual(p.get_content_type(), 'multipart/alternative')
# sub-multipart text/plain # sub-multipart text/plain
q = p.getpart() qit = iter(p.get_payload())
self.assert_(q is not None) q = next(qit, None)
q = p.getpart() self.assertTrue(q is not None)
self.assert_(q is not None) self.assertEqual(q.get_content_type(), 'text/plain')
self.assertEqual(q.gettype(), 'text/plain') self.assertEqual(q.get_payload(), 'Hello, world!\r\n\r\nBlah blah\r\n')
self.assertEqual(q.fp.read(), 'Hello, world!\r\n\r\nBlah blah\r\n')
# sub-multipart text/html # sub-multipart text/html
q = p.getpart() q = next(qit, None)
self.assert_(q is not None) self.assertTrue(q is not None)
self.assertEqual(q.gettype(), 'text/html') self.assertEqual(q.get_content_type(), 'text/html')
self.assertEqual(q.fp.read(), '<b>Hello, world!</b>\r\n') self.assertEqual(q.get_payload(), '<b>Hello, world!</b>\r\n')
# sub-multipart end # sub-multipart end
q = p.getpart() q = next(qit, None)
self.assert_(q is None) self.assertTrue(q is None)
# final text/plain # final text/plain
p = m.getpart() p = next(it, None)
self.assert_(p is not None) self.assertTrue(p is not None)
self.assertEqual(p.gettype(), 'text/plain') self.assertEqual(p.get_content_type(), 'text/plain')
self.assertEqual(p.fp.read(), self.assertEqual(p.get_payload(),
'Last bit\n') 'Last bit\n')
# end # end
p = m.getpart() p = next(it, None)
self.assert_(p is None) self.assertTrue(p is None)
def TestExtraction(self, spec, expected, convert_html_with=False): def TestExtraction(self, spec, expected, convert_html_with=False):
if convert_html_with: if convert_html_with:
from roundup.dehtml import dehtml from roundup.dehtml import dehtml
html2text=dehtml(convert_html_with).html2text html2text=dehtml(convert_html_with).html2text
else: else:
html2text=None html2text=None
self.assertEqual(ExampleMessage(spec).extract_content( self.assertEqual(gen_message(spec).extract_content(
html2text=html2text), expected) html2text=html2text), expected)
def testTextPlain(self): def testTextPlain(self):
self.TestExtraction('text/plain', ('foo\n', [], False)) self.TestExtraction('text/plain', ('foo\n', [], False))
def testAttachedTextPlain(self): def testAttachedTextPlain(self):
self.TestExtraction(""" self.TestExtraction("""
multipart/mixed multipart/mixed
text/plain text/plain
text/plain""", text/plain""",
('foo\n', ('foo\n',
[('foo.txt', 'text/plain', 'foo\n')], False)) [('foo.txt', 'text/plain', 'foo\n')], False))
def testMultipartMixed(self): def testMultipartMixed(self):
self.TestExtraction(""" self.TestExtraction("""
multipart/mixed multipart/mixed
text/plain text/plain
application/pdf""", application/pdf""",
('foo\n', ('foo\n',
[('foo.pdf', 'application/pdf', 'foo\n')], False)) [('foo.pdf', 'application/pdf', b'foo\n')], False))
def testMultipartMixedHtml(self): def testMultipartMixedHtml(self):
# test with html conversion enabled # test with html conversion enabled
self.TestExtraction(""" self.TestExtraction("""
multipart/mixed multipart/mixed
text/html text/html
application/pdf""", application/pdf""",
('bar >\n', ('bar >\n',
[('bar.html', 'text/html', [('bar.html', 'text/html',
'<html><body>bar &gt;</body></html>\n'), '<html><body>bar &gt;</body></html>\n'),
('foo.pdf', 'application/pdf', 'foo\n')], False), ('foo.pdf', 'application/pdf', b'foo\n')], False),
convert_html_with='dehtml') convert_html_with='dehtml')
# test with html conversion disabled # test with html conversion disabled
self.TestExtraction(""" self.TestExtraction("""
multipart/mixed multipart/mixed
text/html text/html
application/pdf""", application/pdf""",
(None, (None,
[('bar.html', 'text/html', [('bar.html', 'text/html',
'<html><body>bar &gt;</body></html>\n'), '<html><body>bar &gt;</body></html>\n'),
('foo.pdf', 'application/pdf', 'foo\n')], False), ('foo.pdf', 'application/pdf', b'foo\n')], False),
convert_html_with=False) convert_html_with=False)
def testMultipartAlternative(self): def testMultipartAlternative(self):
self.TestExtraction(""" self.TestExtraction("""
multipart/alternative multipart/alternative
text/plain text/plain
application/pdf application/pdf
""", ('foo\n', [('foo.pdf', 'application/pdf', 'foo\n')], False)) """, ('foo\n', [('foo.pdf', 'application/pdf', b'foo\n')], False))
def testMultipartAlternativeHtml(self): def testMultipartAlternativeHtml(self):
self.TestExtraction(""" self.TestExtraction("""
multipart/alternative multipart/alternative
text/html text/html
application/pdf""", application/pdf""",
('bar >\n', ('bar >\n',
[('bar.html', 'text/html', [('bar.html', 'text/html',
'<html><body>bar &gt;</body></html>\n'), '<html><body>bar &gt;</body></html>\n'),
('foo.pdf', 'application/pdf', 'foo\n')], False), ('foo.pdf', 'application/pdf', b'foo\n')], False),
convert_html_with='dehtml') convert_html_with='dehtml')
self.TestExtraction(""" self.TestExtraction("""
multipart/alternative multipart/alternative
text/html text/html
application/pdf""", application/pdf""",
(None, (None,
[('bar.html', 'text/html', [('bar.html', 'text/html',
'<html><body>bar &gt;</body></html>\n'), '<html><body>bar &gt;</body></html>\n'),
('foo.pdf', 'application/pdf', 'foo\n')], False), ('foo.pdf', 'application/pdf', b'foo\n')], False),
convert_html_with=False) convert_html_with=False)
def testMultipartAlternativeHtmlText(self): def testMultipartAlternativeHtmlText(self):
# text should take priority over html when html is first # text should take priority over html when html is first
self.TestExtraction(""" self.TestExtraction("""
multipart/alternative multipart/alternative
text/html text/html
text/plain text/plain
application/pdf""", application/pdf""",
('foo\n', ('foo\n',
[('bar.html', 'text/html', [('bar.html', 'text/html',
'<html><body>bar &gt;</body></html>\n'), '<html><body>bar &gt;</body></html>\n'),
('foo.pdf', 'application/pdf', 'foo\n')], False), ('foo.pdf', 'application/pdf', b'foo\n')], False),
convert_html_with='dehtml') convert_html_with='dehtml')
# text should take priority over html when text is first # text should take priority over html when text is first
self.TestExtraction(""" self.TestExtraction("""
multipart/alternative multipart/alternative
text/plain text/plain
text/html text/html
application/pdf""", application/pdf""",
('foo\n', ('foo\n',
[('bar.html', 'text/html', [('bar.html', 'text/html',
'<html><body>bar &gt;</body></html>\n'), '<html><body>bar &gt;</body></html>\n'),
('foo.pdf', 'application/pdf', 'foo\n')], False), ('foo.pdf', 'application/pdf', b'foo\n')], False),
convert_html_with='dehtml') convert_html_with='dehtml')
# text should take priority over html when text is second and # text should take priority over html when text is second and
# html is disabled # html is disabled
self.TestExtraction(""" self.TestExtraction("""
multipart/alternative multipart/alternative
text/html text/html
text/plain text/plain
application/pdf""", application/pdf""",
('foo\n', ('foo\n',
[('bar.html', 'text/html', [('bar.html', 'text/html',
'<html><body>bar &gt;</body></html>\n'), '<html><body>bar &gt;</body></html>\n'),
('foo.pdf', 'application/pdf', 'foo\n')], False), ('foo.pdf', 'application/pdf', b'foo\n')], False),
convert_html_with=False) convert_html_with=False)
# text should take priority over html when text is first and # text should take priority over html when text is first and
# html is disabled # html is disabled
self.TestExtraction(""" self.TestExtraction("""
multipart/alternative multipart/alternative
text/plain text/plain
text/html text/html
application/pdf""", application/pdf""",
('foo\n', ('foo\n',
[('bar.html', 'text/html', [('bar.html', 'text/html',
'<html><body>bar &gt;</body></html>\n'), '<html><body>bar &gt;</body></html>\n'),
('foo.pdf', 'application/pdf', 'foo\n')], False), ('foo.pdf', 'application/pdf', b'foo\n')], False),
convert_html_with=False) convert_html_with=False)
def testDeepMultipartAlternative(self): def testDeepMultipartAlternative(self):
self.TestExtraction(""" self.TestExtraction("""
multipart/mixed multipart/mixed
multipart/alternative multipart/alternative
text/plain text/plain
application/pdf application/pdf
""", ('foo\n', [('foo.pdf', 'application/pdf', 'foo\n')], False)) """, ('foo\n', [('foo.pdf', 'application/pdf', b'foo\n')], False))
def testSignedText(self): def testSignedText(self):
self.TestExtraction(""" self.TestExtraction("""
multipart/signed multipart/signed
text/plain text/plain
application/pgp-signature""", ('foo\n', [], False)) application/pgp-signature""", ('foo\n', [], False))
def testSignedAttachments(self): def testSignedAttachments(self):
self.TestExtraction(""" self.TestExtraction("""
multipart/signed multipart/signed
multipart/mixed multipart/mixed
text/plain text/plain
application/pdf application/pdf
application/pgp-signature""", application/pgp-signature""",
('foo\n', ('foo\n',
[('foo.pdf', 'application/pdf', 'foo\n')], False)) [('foo.pdf', 'application/pdf', b'foo\n')], False))
def testAttachedSignature(self): def testAttachedSignature(self):
self.TestExtraction(""" self.TestExtraction("""
multipart/mixed multipart/mixed
text/plain text/plain
application/pgp-signature""", application/pgp-signature""",
('foo\n', ('foo\n',
[('foo.gpg', 'application/pgp-signature', 'foo\n')], False)) [('foo.gpg', 'application/pgp-signature', b'foo\n')], False))
def testMessageRfc822(self): def testMessageRfc822(self):
self.TestExtraction(""" self.TestExtraction("""
multipart/mixed multipart/mixed
message/rfc822""", message/rfc822""",
(None, (None,
[('foo.eml', 'message/rfc822', 'Subject: foo\n\nfoo\n')], Fal se)) [('foo.eml', 'message/rfc822', 'Subject: foo\n\nfoo\n')], Fal se))
# vim: set filetype=python ts=4 sw=4 et si # vim: set filetype=python ts=4 sw=4 et si
 End of changes. 30 change blocks. 
77 lines changed or deleted 76 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)