blob: d397c091ac564998ab9937102d89e0bf58bd397e [file] [log] [blame]
Barry Warsaw41075852001-09-23 03:18:13 +00001# Copyright (C) 2001 Python Software Foundation
2# email package unit tests
3
4import os
5import time
6import unittest
7import base64
8from cStringIO import StringIO
9from types import StringType
10
11import email
12
Barry Warsawbf7a59d2001-10-11 15:44:50 +000013from email.Parser import Parser, HeaderParser
Barry Warsaw41075852001-09-23 03:18:13 +000014from email.Generator import Generator, DecodedGenerator
15from email.Message import Message
Barry Warsawfee435a2001-10-09 19:23:57 +000016from email.MIMEAudio import MIMEAudio
Barry Warsaw65279d02001-09-26 05:47:08 +000017from email.MIMEText import MIMEText
18from email.MIMEImage import MIMEImage
Barry Warsaw41075852001-09-23 03:18:13 +000019from email.MIMEBase import MIMEBase
Barry Warsaw65279d02001-09-26 05:47:08 +000020from email.MIMEMessage import MIMEMessage
Barry Warsaw41075852001-09-23 03:18:13 +000021from email import Utils
22from email import Errors
23from email import Encoders
24from email import Iterators
25
Barry Warsawfee435a2001-10-09 19:23:57 +000026import test_email
27from test_support import findfile
Barry Warsaw41075852001-09-23 03:18:13 +000028
Barry Warsaw1f0fa922001-10-19 04:08:59 +000029
Barry Warsaw41075852001-09-23 03:18:13 +000030NL = '\n'
31EMPTYSTRING = ''
Barry Warsaw07227d12001-10-17 20:52:26 +000032SPACE = ' '
Barry Warsaw41075852001-09-23 03:18:13 +000033
34
Barry Warsaw08a534d2001-10-04 17:58:50 +000035
Barry Warsaw41075852001-09-23 03:18:13 +000036def openfile(filename):
Barry Warsawfee435a2001-10-09 19:23:57 +000037 path = os.path.join(os.path.dirname(test_email.__file__), 'data', filename)
Barry Warsaw41075852001-09-23 03:18:13 +000038 return open(path)
39
40
Barry Warsaw08a534d2001-10-04 17:58:50 +000041
Barry Warsaw41075852001-09-23 03:18:13 +000042# Base test class
43class TestEmailBase(unittest.TestCase):
44 def _msgobj(self, filename):
45 fp = openfile(filename)
46 try:
Barry Warsaw65279d02001-09-26 05:47:08 +000047 msg = email.message_from_file(fp)
Barry Warsaw41075852001-09-23 03:18:13 +000048 finally:
49 fp.close()
Barry Warsaw65279d02001-09-26 05:47:08 +000050 return msg
Barry Warsaw41075852001-09-23 03:18:13 +000051
52
Barry Warsaw08a534d2001-10-04 17:58:50 +000053
Barry Warsaw41075852001-09-23 03:18:13 +000054# Test various aspects of the Message class's API
55class TestMessageAPI(TestEmailBase):
Barry Warsaw2f6a0b02001-10-09 15:49:35 +000056 def test_get_all(self):
57 eq = self.assertEqual
58 msg = self._msgobj('msg_20.txt')
59 eq(msg.get_all('cc'), ['ccc@zzz.org', 'ddd@zzz.org', 'eee@zzz.org'])
60 eq(msg.get_all('xx', 'n/a'), 'n/a')
61
Barry Warsaw41075852001-09-23 03:18:13 +000062 def test_get_charsets(self):
63 eq = self.assertEqual
Tim Peters527e64f2001-10-04 05:36:56 +000064
Barry Warsaw65279d02001-09-26 05:47:08 +000065 msg = self._msgobj('msg_08.txt')
66 charsets = msg.get_charsets()
67 eq(charsets, [None, 'us-ascii', 'iso-8859-1', 'iso-8859-2', 'koi8-r'])
Barry Warsaw41075852001-09-23 03:18:13 +000068
Barry Warsaw65279d02001-09-26 05:47:08 +000069 msg = self._msgobj('msg_09.txt')
70 charsets = msg.get_charsets('dingbat')
71 eq(charsets, ['dingbat', 'us-ascii', 'iso-8859-1', 'dingbat',
72 'koi8-r'])
Barry Warsaw41075852001-09-23 03:18:13 +000073
Barry Warsaw65279d02001-09-26 05:47:08 +000074 msg = self._msgobj('msg_12.txt')
75 charsets = msg.get_charsets()
76 eq(charsets, [None, 'us-ascii', 'iso-8859-1', None, 'iso-8859-2',
77 'iso-8859-3', 'us-ascii', 'koi8-r'])
Barry Warsaw41075852001-09-23 03:18:13 +000078
79 def test_get_filename(self):
80 eq = self.assertEqual
81
Barry Warsaw65279d02001-09-26 05:47:08 +000082 msg = self._msgobj('msg_04.txt')
83 filenames = [p.get_filename() for p in msg.get_payload()]
Barry Warsaw41075852001-09-23 03:18:13 +000084 eq(filenames, ['msg.txt', 'msg.txt'])
85
Barry Warsaw65279d02001-09-26 05:47:08 +000086 msg = self._msgobj('msg_07.txt')
87 subpart = msg.get_payload(1)
Barry Warsaw41075852001-09-23 03:18:13 +000088 eq(subpart.get_filename(), 'dingusfish.gif')
89
90 def test_get_boundary(self):
91 eq = self.assertEqual
Barry Warsaw65279d02001-09-26 05:47:08 +000092 msg = self._msgobj('msg_07.txt')
Barry Warsaw41075852001-09-23 03:18:13 +000093 # No quotes!
Barry Warsaw65279d02001-09-26 05:47:08 +000094 eq(msg.get_boundary(), 'BOUNDARY')
Barry Warsaw41075852001-09-23 03:18:13 +000095
96 def test_set_boundary(self):
97 eq = self.assertEqual
98 # This one has no existing boundary parameter, but the Content-Type:
99 # header appears fifth.
Barry Warsaw65279d02001-09-26 05:47:08 +0000100 msg = self._msgobj('msg_01.txt')
101 msg.set_boundary('BOUNDARY')
102 header, value = msg.items()[4]
Barry Warsaw41075852001-09-23 03:18:13 +0000103 eq(header.lower(), 'content-type')
104 eq(value, 'text/plain; charset=us-ascii; boundary="BOUNDARY"')
105 # This one has a Content-Type: header, with a boundary, stuck in the
106 # middle of its headers. Make sure the order is preserved; it should
107 # be fifth.
Barry Warsaw65279d02001-09-26 05:47:08 +0000108 msg = self._msgobj('msg_04.txt')
109 msg.set_boundary('BOUNDARY')
110 header, value = msg.items()[4]
Barry Warsaw41075852001-09-23 03:18:13 +0000111 eq(header.lower(), 'content-type')
112 eq(value, 'multipart/mixed; boundary="BOUNDARY"')
113 # And this one has no Content-Type: header at all.
Barry Warsaw65279d02001-09-26 05:47:08 +0000114 msg = self._msgobj('msg_03.txt')
Barry Warsaw41075852001-09-23 03:18:13 +0000115 self.assertRaises(Errors.HeaderParseError,
Barry Warsaw65279d02001-09-26 05:47:08 +0000116 msg.set_boundary, 'BOUNDARY')
Barry Warsaw41075852001-09-23 03:18:13 +0000117
118 def test_get_decoded_payload(self):
119 eq = self.assertEqual
Barry Warsaw65279d02001-09-26 05:47:08 +0000120 msg = self._msgobj('msg_10.txt')
Barry Warsaw41075852001-09-23 03:18:13 +0000121 # The outer message is a multipart
Barry Warsaw65279d02001-09-26 05:47:08 +0000122 eq(msg.get_payload(decode=1), None)
Barry Warsaw41075852001-09-23 03:18:13 +0000123 # Subpart 1 is 7bit encoded
Barry Warsaw65279d02001-09-26 05:47:08 +0000124 eq(msg.get_payload(0).get_payload(decode=1),
Barry Warsaw41075852001-09-23 03:18:13 +0000125 'This is a 7bit encoded message.\n')
126 # Subpart 2 is quopri
Barry Warsaw65279d02001-09-26 05:47:08 +0000127 eq(msg.get_payload(1).get_payload(decode=1),
Barry Warsaw41075852001-09-23 03:18:13 +0000128 '\xa1This is a Quoted Printable encoded message!\n')
129 # Subpart 3 is base64
Barry Warsaw65279d02001-09-26 05:47:08 +0000130 eq(msg.get_payload(2).get_payload(decode=1),
Barry Warsaw41075852001-09-23 03:18:13 +0000131 'This is a Base64 encoded message.')
132 # Subpart 4 has no Content-Transfer-Encoding: header.
Barry Warsaw65279d02001-09-26 05:47:08 +0000133 eq(msg.get_payload(3).get_payload(decode=1),
Barry Warsaw41075852001-09-23 03:18:13 +0000134 'This has no Content-Transfer-Encoding: header.\n')
135
136 def test_decoded_generator(self):
137 eq = self.assertEqual
Barry Warsaw65279d02001-09-26 05:47:08 +0000138 msg = self._msgobj('msg_07.txt')
139 fp = openfile('msg_17.txt')
140 try:
141 text = fp.read()
142 finally:
143 fp.close()
Barry Warsaw41075852001-09-23 03:18:13 +0000144 s = StringIO()
145 g = DecodedGenerator(s)
Barry Warsaw65279d02001-09-26 05:47:08 +0000146 g(msg)
147 eq(s.getvalue(), text)
Barry Warsaw41075852001-09-23 03:18:13 +0000148
149 def test__contains__(self):
150 msg = Message()
151 msg['From'] = 'Me'
152 msg['to'] = 'You'
153 # Check for case insensitivity
154 self.failUnless('from' in msg)
155 self.failUnless('From' in msg)
156 self.failUnless('FROM' in msg)
157 self.failUnless('to' in msg)
158 self.failUnless('To' in msg)
159 self.failUnless('TO' in msg)
160
161 def test_as_string(self):
162 eq = self.assertEqual
Barry Warsaw65279d02001-09-26 05:47:08 +0000163 msg = self._msgobj('msg_01.txt')
Barry Warsaw41075852001-09-23 03:18:13 +0000164 fp = openfile('msg_01.txt')
165 try:
166 text = fp.read()
167 finally:
168 fp.close()
Barry Warsaw65279d02001-09-26 05:47:08 +0000169 eq(text, msg.as_string())
170 fullrepr = str(msg)
Barry Warsaw41075852001-09-23 03:18:13 +0000171 lines = fullrepr.split('\n')
172 self.failUnless(lines[0].startswith('From '))
173 eq(text, NL.join(lines[1:]))
174
175 def test_bad_param(self):
Barry Warsaw65279d02001-09-26 05:47:08 +0000176 msg = email.message_from_string("Content-Type: blarg; baz; boo\n")
Barry Warsaw41075852001-09-23 03:18:13 +0000177 self.assertEqual(msg.get_param('baz'), '')
178
179 def test_missing_filename(self):
Barry Warsaw65279d02001-09-26 05:47:08 +0000180 msg = email.message_from_string("From: foo\n")
Barry Warsaw41075852001-09-23 03:18:13 +0000181 self.assertEqual(msg.get_filename(), None)
182
183 def test_bogus_filename(self):
Barry Warsaw65279d02001-09-26 05:47:08 +0000184 msg = email.message_from_string(
185 "Content-Disposition: blarg; filename\n")
Barry Warsaw41075852001-09-23 03:18:13 +0000186 self.assertEqual(msg.get_filename(), '')
Tim Peters527e64f2001-10-04 05:36:56 +0000187
Barry Warsaw41075852001-09-23 03:18:13 +0000188 def test_missing_boundary(self):
Barry Warsaw65279d02001-09-26 05:47:08 +0000189 msg = email.message_from_string("From: foo\n")
Barry Warsaw41075852001-09-23 03:18:13 +0000190 self.assertEqual(msg.get_boundary(), None)
191
Barry Warsaw65279d02001-09-26 05:47:08 +0000192 def test_get_params(self):
193 eq = self.assertEqual
194 msg = email.message_from_string(
195 'X-Header: foo=one; bar=two; baz=three\n')
196 eq(msg.get_params(header='x-header'),
197 [('foo', 'one'), ('bar', 'two'), ('baz', 'three')])
198 msg = email.message_from_string(
199 'X-Header: foo; bar=one; baz=two\n')
200 eq(msg.get_params(header='x-header'),
201 [('foo', ''), ('bar', 'one'), ('baz', 'two')])
202 eq(msg.get_params(), None)
203 msg = email.message_from_string(
204 'X-Header: foo; bar="one"; baz=two\n')
205 eq(msg.get_params(header='x-header'),
206 [('foo', ''), ('bar', 'one'), ('baz', 'two')])
207
208 def test_get_param(self):
209 eq = self.assertEqual
210 msg = email.message_from_string(
211 "X-Header: foo=one; bar=two; baz=three\n")
212 eq(msg.get_param('bar', header='x-header'), 'two')
213 eq(msg.get_param('quuz', header='x-header'), None)
214 eq(msg.get_param('quuz'), None)
215 msg = email.message_from_string(
216 'X-Header: foo; bar="one"; baz=two\n')
217 eq(msg.get_param('foo', header='x-header'), '')
218 eq(msg.get_param('bar', header='x-header'), 'one')
219 eq(msg.get_param('baz', header='x-header'), 'two')
220
Barry Warsaw2539cf52001-10-25 22:43:46 +0000221 def test_get_param_funky_continuation_lines(self):
222 msg = self._msgobj('msg_22.txt')
223 self.assertEqual(msg.get_payload(1).get_param('name'), 'wibble.JPG')
224
Barry Warsaw65279d02001-09-26 05:47:08 +0000225 def test_has_key(self):
226 msg = email.message_from_string('Header: exists')
227 self.failUnless(msg.has_key('header'))
228 self.failUnless(msg.has_key('Header'))
229 self.failUnless(msg.has_key('HEADER'))
230 self.failIf(msg.has_key('headeri'))
231
Barry Warsaw41075852001-09-23 03:18:13 +0000232
Barry Warsaw08a534d2001-10-04 17:58:50 +0000233
Barry Warsaw41075852001-09-23 03:18:13 +0000234# Test the email.Encoders module
235class TestEncoders(unittest.TestCase):
236 def test_encode_noop(self):
237 eq = self.assertEqual
Barry Warsaw65279d02001-09-26 05:47:08 +0000238 msg = MIMEText('hello world', _encoder=Encoders.encode_noop)
Barry Warsaw41075852001-09-23 03:18:13 +0000239 eq(msg.get_payload(), 'hello world\n')
240 eq(msg['content-transfer-encoding'], None)
241
242 def test_encode_7bit(self):
243 eq = self.assertEqual
Barry Warsaw65279d02001-09-26 05:47:08 +0000244 msg = MIMEText('hello world', _encoder=Encoders.encode_7or8bit)
Barry Warsaw41075852001-09-23 03:18:13 +0000245 eq(msg.get_payload(), 'hello world\n')
246 eq(msg['content-transfer-encoding'], '7bit')
Barry Warsaw65279d02001-09-26 05:47:08 +0000247 msg = MIMEText('hello \x7f world', _encoder=Encoders.encode_7or8bit)
Barry Warsaw41075852001-09-23 03:18:13 +0000248 eq(msg.get_payload(), 'hello \x7f world\n')
249 eq(msg['content-transfer-encoding'], '7bit')
250
251 def test_encode_8bit(self):
252 eq = self.assertEqual
Barry Warsaw65279d02001-09-26 05:47:08 +0000253 msg = MIMEText('hello \x80 world', _encoder=Encoders.encode_7or8bit)
Barry Warsaw41075852001-09-23 03:18:13 +0000254 eq(msg.get_payload(), 'hello \x80 world\n')
255 eq(msg['content-transfer-encoding'], '8bit')
256
257 def test_encode_base64(self):
258 eq = self.assertEqual
Barry Warsaw65279d02001-09-26 05:47:08 +0000259 msg = MIMEText('hello world', _encoder=Encoders.encode_base64)
Barry Warsaw41075852001-09-23 03:18:13 +0000260 eq(msg.get_payload(), 'aGVsbG8gd29ybGQK\n')
261 eq(msg['content-transfer-encoding'], 'base64')
262
263 def test_encode_quoted_printable(self):
264 eq = self.assertEqual
Barry Warsaw65279d02001-09-26 05:47:08 +0000265 msg = MIMEText('hello world', _encoder=Encoders.encode_quopri)
Barry Warsaw41075852001-09-23 03:18:13 +0000266 eq(msg.get_payload(), 'hello=20world\n')
267 eq(msg['content-transfer-encoding'], 'quoted-printable')
268
269
Barry Warsaw08a534d2001-10-04 17:58:50 +0000270
271# Test long header wrapping
Barry Warsaw41075852001-09-23 03:18:13 +0000272class TestLongHeaders(unittest.TestCase):
273 def test_header_splitter(self):
Barry Warsaw65279d02001-09-26 05:47:08 +0000274 msg = MIMEText('')
Barry Warsaw41075852001-09-23 03:18:13 +0000275 # It'd be great if we could use add_header() here, but that doesn't
276 # guarantee an order of the parameters.
277 msg['X-Foobar-Spoink-Defrobnit'] = (
278 'wasnipoop; giraffes="very-long-necked-animals"; '
279 'spooge="yummy"; hippos="gargantuan"; marshmallows="gooey"')
280 sfp = StringIO()
281 g = Generator(sfp)
282 g(msg)
Barry Warsaw08a534d2001-10-04 17:58:50 +0000283 self.assertEqual(sfp.getvalue(), openfile('msg_18.txt').read())
Barry Warsaw41075852001-09-23 03:18:13 +0000284
Barry Warsaw07227d12001-10-17 20:52:26 +0000285 def test_no_semis_header_splitter(self):
286 msg = Message()
287 msg['From'] = 'test@dom.ain'
288 refparts = []
289 for i in range(10):
290 refparts.append('<%d@dom.ain>' % i)
291 msg['References'] = SPACE.join(refparts)
292 msg.set_payload('Test')
293 sfp = StringIO()
294 g = Generator(sfp)
295 g(msg)
296 self.assertEqual(sfp.getvalue(), """\
297From: test@dom.ain
298References: <0@dom.ain> <1@dom.ain> <2@dom.ain> <3@dom.ain> <4@dom.ain>
Tim Peterse0c446b2001-10-18 21:57:37 +0000299\t<5@dom.ain> <6@dom.ain> <7@dom.ain> <8@dom.ain> <9@dom.ain>
Barry Warsaw07227d12001-10-17 20:52:26 +0000300
301Test""")
302
303 def test_no_split_long_header(self):
304 msg = Message()
305 msg['From'] = 'test@dom.ain'
306 refparts = []
307 msg['References'] = 'x' * 80
308 msg.set_payload('Test')
309 sfp = StringIO()
310 g = Generator(sfp)
311 g(msg)
312 self.assertEqual(sfp.getvalue(), """\
313From: test@dom.ain
314References: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
315
316Test""")
317
Barry Warsaw41075852001-09-23 03:18:13 +0000318
Barry Warsaw08a534d2001-10-04 17:58:50 +0000319
320# Test mangling of "From " lines in the body of a message
Barry Warsaw41075852001-09-23 03:18:13 +0000321class TestFromMangling(unittest.TestCase):
322 def setUp(self):
323 self.msg = Message()
324 self.msg['From'] = 'aaa@bbb.org'
325 self.msg.add_payload("""\
326From the desk of A.A.A.:
327Blah blah blah
328""")
329
330 def test_mangled_from(self):
331 s = StringIO()
332 g = Generator(s, mangle_from_=1)
333 g(self.msg)
334 self.assertEqual(s.getvalue(), """\
335From: aaa@bbb.org
336
337>From the desk of A.A.A.:
338Blah blah blah
339""")
340
341 def test_dont_mangle_from(self):
342 s = StringIO()
343 g = Generator(s, mangle_from_=0)
344 g(self.msg)
345 self.assertEqual(s.getvalue(), """\
346From: aaa@bbb.org
347
348From the desk of A.A.A.:
349Blah blah blah
350""")
351
352
Barry Warsaw08a534d2001-10-04 17:58:50 +0000353
Barry Warsawfee435a2001-10-09 19:23:57 +0000354# Test the basic MIMEAudio class
355class TestMIMEAudio(unittest.TestCase):
356 def setUp(self):
357 # In Python, audiotest.au lives in Lib/test not Lib/test/data
358 fp = open(findfile('audiotest.au'))
359 try:
360 self._audiodata = fp.read()
361 finally:
362 fp.close()
363 self._au = MIMEAudio(self._audiodata)
364
365 def test_guess_minor_type(self):
366 self.assertEqual(self._au.get_type(), 'audio/basic')
367
368 def test_encoding(self):
369 payload = self._au.get_payload()
370 self.assertEqual(base64.decodestring(payload), self._audiodata)
371
372 def checkSetMinor(self):
373 au = MIMEAudio(self._audiodata, 'fish')
374 self.assertEqual(im.get_type(), 'audio/fish')
375
376 def test_custom_encoder(self):
377 eq = self.assertEqual
378 def encoder(msg):
379 orig = msg.get_payload()
380 msg.set_payload(0)
381 msg['Content-Transfer-Encoding'] = 'broken64'
382 au = MIMEAudio(self._audiodata, _encoder=encoder)
383 eq(au.get_payload(), 0)
384 eq(au['content-transfer-encoding'], 'broken64')
385
386 def test_add_header(self):
387 eq = self.assertEqual
388 unless = self.failUnless
389 self._au.add_header('Content-Disposition', 'attachment',
390 filename='audiotest.au')
391 eq(self._au['content-disposition'],
392 'attachment; filename="audiotest.au"')
393 eq(self._au.get_params(header='content-disposition'),
394 [('attachment', ''), ('filename', 'audiotest.au')])
395 eq(self._au.get_param('filename', header='content-disposition'),
396 'audiotest.au')
397 missing = []
398 eq(self._au.get_param('attachment', header='content-disposition'), '')
399 unless(self._au.get_param('foo', failobj=missing,
400 header='content-disposition') is missing)
401 # Try some missing stuff
402 unless(self._au.get_param('foobar', missing) is missing)
403 unless(self._au.get_param('attachment', missing,
404 header='foobar') is missing)
405
406
407
Barry Warsaw65279d02001-09-26 05:47:08 +0000408# Test the basic MIMEImage class
409class TestMIMEImage(unittest.TestCase):
Barry Warsaw41075852001-09-23 03:18:13 +0000410 def setUp(self):
411 fp = openfile('PyBanner048.gif')
412 try:
413 self._imgdata = fp.read()
414 finally:
415 fp.close()
Barry Warsaw65279d02001-09-26 05:47:08 +0000416 self._im = MIMEImage(self._imgdata)
Barry Warsaw41075852001-09-23 03:18:13 +0000417
418 def test_guess_minor_type(self):
419 self.assertEqual(self._im.get_type(), 'image/gif')
420
421 def test_encoding(self):
422 payload = self._im.get_payload()
423 self.assertEqual(base64.decodestring(payload), self._imgdata)
424
425 def checkSetMinor(self):
Barry Warsaw65279d02001-09-26 05:47:08 +0000426 im = MIMEImage(self._imgdata, 'fish')
Barry Warsaw41075852001-09-23 03:18:13 +0000427 self.assertEqual(im.get_type(), 'image/fish')
428
429 def test_custom_encoder(self):
430 eq = self.assertEqual
431 def encoder(msg):
432 orig = msg.get_payload()
433 msg.set_payload(0)
434 msg['Content-Transfer-Encoding'] = 'broken64'
Barry Warsaw65279d02001-09-26 05:47:08 +0000435 im = MIMEImage(self._imgdata, _encoder=encoder)
Barry Warsaw41075852001-09-23 03:18:13 +0000436 eq(im.get_payload(), 0)
437 eq(im['content-transfer-encoding'], 'broken64')
438
439 def test_add_header(self):
440 eq = self.assertEqual
441 unless = self.failUnless
442 self._im.add_header('Content-Disposition', 'attachment',
443 filename='dingusfish.gif')
444 eq(self._im['content-disposition'],
445 'attachment; filename="dingusfish.gif"')
446 eq(self._im.get_params(header='content-disposition'),
Barry Warsaw65279d02001-09-26 05:47:08 +0000447 [('attachment', ''), ('filename', 'dingusfish.gif')])
Barry Warsaw41075852001-09-23 03:18:13 +0000448 eq(self._im.get_param('filename', header='content-disposition'),
449 'dingusfish.gif')
450 missing = []
Barry Warsaw65279d02001-09-26 05:47:08 +0000451 eq(self._im.get_param('attachment', header='content-disposition'), '')
452 unless(self._im.get_param('foo', failobj=missing,
Barry Warsaw41075852001-09-23 03:18:13 +0000453 header='content-disposition') is missing)
454 # Try some missing stuff
455 unless(self._im.get_param('foobar', missing) is missing)
456 unless(self._im.get_param('attachment', missing,
457 header='foobar') is missing)
458
459
Barry Warsaw08a534d2001-10-04 17:58:50 +0000460
Barry Warsaw65279d02001-09-26 05:47:08 +0000461# Test the basic MIMEText class
462class TestMIMEText(unittest.TestCase):
Barry Warsaw41075852001-09-23 03:18:13 +0000463 def setUp(self):
Barry Warsaw65279d02001-09-26 05:47:08 +0000464 self._msg = MIMEText('hello there')
Barry Warsaw41075852001-09-23 03:18:13 +0000465
466 def test_types(self):
467 eq = self.assertEqual
468 unless = self.failUnless
469 eq(self._msg.get_type(), 'text/plain')
470 eq(self._msg.get_param('charset'), 'us-ascii')
471 missing = []
472 unless(self._msg.get_param('foobar', missing) is missing)
473 unless(self._msg.get_param('charset', missing, header='foobar')
474 is missing)
475
476 def test_payload(self):
477 self.assertEqual(self._msg.get_payload(), 'hello there\n')
478 self.failUnless(not self._msg.is_multipart())
479
480
Barry Warsaw08a534d2001-10-04 17:58:50 +0000481
482# Test a more complicated multipart/mixed type message
Barry Warsaw41075852001-09-23 03:18:13 +0000483class TestMultipartMixed(unittest.TestCase):
484 def setUp(self):
485 fp = openfile('PyBanner048.gif')
486 try:
487 data = fp.read()
488 finally:
489 fp.close()
490
491 container = MIMEBase('multipart', 'mixed', boundary='BOUNDARY')
Barry Warsaw65279d02001-09-26 05:47:08 +0000492 image = MIMEImage(data, name='dingusfish.gif')
Barry Warsaw41075852001-09-23 03:18:13 +0000493 image.add_header('content-disposition', 'attachment',
494 filename='dingusfish.gif')
Barry Warsaw65279d02001-09-26 05:47:08 +0000495 intro = MIMEText('''\
Barry Warsaw41075852001-09-23 03:18:13 +0000496Hi there,
497
498This is the dingus fish.
499''')
500 container.add_payload(intro)
501 container.add_payload(image)
502 container['From'] = 'Barry <barry@digicool.com>'
503 container['To'] = 'Dingus Lovers <cravindogs@cravindogs.com>'
504 container['Subject'] = 'Here is your dingus fish'
Tim Peters527e64f2001-10-04 05:36:56 +0000505
Barry Warsaw41075852001-09-23 03:18:13 +0000506 now = 987809702.54848599
507 timetuple = time.localtime(now)
508 if timetuple[-1] == 0:
509 tzsecs = time.timezone
510 else:
511 tzsecs = time.altzone
512 if tzsecs > 0:
513 sign = '-'
514 else:
515 sign = '+'
516 tzoffset = ' %s%04d' % (sign, tzsecs / 36)
517 container['Date'] = time.strftime(
518 '%a, %d %b %Y %H:%M:%S',
519 time.localtime(now)) + tzoffset
520 self._msg = container
521 self._im = image
522 self._txt = intro
523
524 def test_hierarchy(self):
525 # convenience
526 eq = self.assertEqual
527 unless = self.failUnless
528 raises = self.assertRaises
529 # tests
530 m = self._msg
531 unless(m.is_multipart())
532 eq(m.get_type(), 'multipart/mixed')
533 eq(len(m.get_payload()), 2)
534 raises(IndexError, m.get_payload, 2)
535 m0 = m.get_payload(0)
536 m1 = m.get_payload(1)
537 unless(m0 is self._txt)
538 unless(m1 is self._im)
539 eq(m.get_payload(), [m0, m1])
540 unless(not m0.is_multipart())
541 unless(not m1.is_multipart())
542
543
Barry Warsaw08a534d2001-10-04 17:58:50 +0000544
545# Test some badly formatted messages
Barry Warsaw41075852001-09-23 03:18:13 +0000546class TestNonConformant(TestEmailBase):
547 def test_parse_missing_minor_type(self):
548 eq = self.assertEqual
549 msg = self._msgobj('msg_14.txt')
550 eq(msg.get_type(), 'text')
551 eq(msg.get_main_type(), 'text')
552 self.failUnless(msg.get_subtype() is None)
553
554 def test_bogus_boundary(self):
555 fp = openfile('msg_15.txt')
556 try:
557 data = fp.read()
558 finally:
559 fp.close()
560 p = Parser()
561 # Note, under a future non-strict parsing mode, this would parse the
562 # message into the intended message tree.
563 self.assertRaises(Errors.BoundaryError, p.parsestr, data)
564
565
Barry Warsaw08a534d2001-10-04 17:58:50 +0000566
567# Test RFC 2047 header encoding and decoding
Barry Warsaw41075852001-09-23 03:18:13 +0000568class TestRFC2047(unittest.TestCase):
569 def test_iso_8859_1(self):
570 eq = self.assertEqual
571 s = '=?iso-8859-1?q?this=20is=20some=20text?='
572 eq(Utils.decode(s), 'this is some text')
573 s = '=?ISO-8859-1?Q?Keld_J=F8rn_Simonsen?='
574 eq(Utils.decode(s), u'Keld_J\xf8rn_Simonsen')
575 s = '=?ISO-8859-1?B?SWYgeW91IGNhbiByZWFkIHRoaXMgeW8=?=' \
576 '=?ISO-8859-2?B?dSB1bmRlcnN0YW5kIHRoZSBleGFtcGxlLg==?='
577 eq(Utils.decode(s), 'If you can read this you understand the example.')
578 s = '=?iso-8859-8?b?7eXs+SDv4SDp7Oj08A==?='
579 eq(Utils.decode(s),
580 u'\u05dd\u05d5\u05dc\u05e9 \u05df\u05d1 \u05d9\u05dc\u05d8\u05e4\u05e0')
581 s = '=?iso-8859-1?q?this=20is?= =?iso-8859-1?q?some=20text?='
582 eq(Utils.decode(s), u'this is some text')
583
584 def test_encode_header(self):
585 eq = self.assertEqual
586 s = 'this is some text'
587 eq(Utils.encode(s), '=?iso-8859-1?q?this=20is=20some=20text?=')
588 s = 'Keld_J\xf8rn_Simonsen'
589 eq(Utils.encode(s), '=?iso-8859-1?q?Keld_J=F8rn_Simonsen?=')
590 s1 = 'If you can read this yo'
591 s2 = 'u understand the example.'
592 eq(Utils.encode(s1, encoding='b'),
593 '=?iso-8859-1?b?SWYgeW91IGNhbiByZWFkIHRoaXMgeW8=?=')
594 eq(Utils.encode(s2, charset='iso-8859-2', encoding='b'),
595 '=?iso-8859-2?b?dSB1bmRlcnN0YW5kIHRoZSBleGFtcGxlLg==?=')
596
597
Barry Warsaw08a534d2001-10-04 17:58:50 +0000598
599# Test the MIMEMessage class
Barry Warsaw65279d02001-09-26 05:47:08 +0000600class TestMIMEMessage(TestEmailBase):
Barry Warsaw41075852001-09-23 03:18:13 +0000601 def setUp(self):
602 fp = openfile('msg_11.txt')
603 self._text = fp.read()
604 fp.close()
605
606 def test_type_error(self):
Barry Warsaw65279d02001-09-26 05:47:08 +0000607 self.assertRaises(TypeError, MIMEMessage, 'a plain string')
Barry Warsaw41075852001-09-23 03:18:13 +0000608
609 def test_valid_argument(self):
610 eq = self.assertEqual
611 subject = 'A sub-message'
612 m = Message()
613 m['Subject'] = subject
Barry Warsaw65279d02001-09-26 05:47:08 +0000614 r = MIMEMessage(m)
Barry Warsaw41075852001-09-23 03:18:13 +0000615 eq(r.get_type(), 'message/rfc822')
616 self.failUnless(r.get_payload() is m)
617 eq(r.get_payload()['subject'], subject)
618
619 def test_generate(self):
620 # First craft the message to be encapsulated
621 m = Message()
622 m['Subject'] = 'An enclosed message'
623 m.add_payload('Here is the body of the message.\n')
Barry Warsaw65279d02001-09-26 05:47:08 +0000624 r = MIMEMessage(m)
Barry Warsaw41075852001-09-23 03:18:13 +0000625 r['Subject'] = 'The enclosing message'
626 s = StringIO()
627 g = Generator(s)
628 g(r)
Barry Warsaw65279d02001-09-26 05:47:08 +0000629 self.assertEqual(s.getvalue(), """\
630Content-Type: message/rfc822
631MIME-Version: 1.0
632Subject: The enclosing message
633
634Subject: An enclosed message
635
636Here is the body of the message.
637""")
638
639 def test_parse_message_rfc822(self):
640 eq = self.assertEqual
641 msg = self._msgobj('msg_11.txt')
642 eq(msg.get_type(), 'message/rfc822')
643 eq(len(msg.get_payload()), 1)
644 submsg = msg.get_payload()
645 self.failUnless(isinstance(submsg, Message))
646 eq(submsg['subject'], 'An enclosed message')
647 eq(submsg.get_payload(), 'Here is the body of the message.\n')
648
649 def test_dsn(self):
650 eq = self.assertEqual
651 unless = self.failUnless
652 # msg 16 is a Delivery Status Notification, see RFC XXXX
653 msg = self._msgobj('msg_16.txt')
654 eq(msg.get_type(), 'multipart/report')
655 unless(msg.is_multipart())
656 eq(len(msg.get_payload()), 3)
657 # Subpart 1 is a text/plain, human readable section
658 subpart = msg.get_payload(0)
659 eq(subpart.get_type(), 'text/plain')
660 eq(subpart.get_payload(), """\
661This report relates to a message you sent with the following header fields:
662
663 Message-id: <002001c144a6$8752e060$56104586@oxy.edu>
664 Date: Sun, 23 Sep 2001 20:10:55 -0700
665 From: "Ian T. Henry" <henryi@oxy.edu>
666 To: SoCal Raves <scr@socal-raves.org>
667 Subject: [scr] yeah for Ians!!
668
669Your message cannot be delivered to the following recipients:
670
671 Recipient address: jangel1@cougar.noc.ucla.edu
672 Reason: recipient reached disk quota
673
674""")
675 # Subpart 2 contains the machine parsable DSN information. It
676 # consists of two blocks of headers, represented by two nested Message
677 # objects.
678 subpart = msg.get_payload(1)
679 eq(subpart.get_type(), 'message/delivery-status')
680 eq(len(subpart.get_payload()), 2)
681 # message/delivery-status should treat each block as a bunch of
682 # headers, i.e. a bunch of Message objects.
683 dsn1 = subpart.get_payload(0)
684 unless(isinstance(dsn1, Message))
685 eq(dsn1['original-envelope-id'], '0GK500B4HD0888@cougar.noc.ucla.edu')
686 eq(dsn1.get_param('dns', header='reporting-mta'), '')
687 # Try a missing one <wink>
688 eq(dsn1.get_param('nsd', header='reporting-mta'), None)
689 dsn2 = subpart.get_payload(1)
690 unless(isinstance(dsn2, Message))
691 eq(dsn2['action'], 'failed')
692 eq(dsn2.get_params(header='original-recipient'),
693 [('rfc822', ''), ('jangel1@cougar.noc.ucla.edu', '')])
694 eq(dsn2.get_param('rfc822', header='final-recipient'), '')
695 # Subpart 3 is the original message
696 subpart = msg.get_payload(2)
697 eq(subpart.get_type(), 'message/rfc822')
698 subsubpart = subpart.get_payload()
699 unless(isinstance(subsubpart, Message))
700 eq(subsubpart.get_type(), 'text/plain')
701 eq(subsubpart['message-id'],
702 '<002001c144a6$8752e060$56104586@oxy.edu>')
Barry Warsaw41075852001-09-23 03:18:13 +0000703
Barry Warsaw1f0fa922001-10-19 04:08:59 +0000704 def test_epilogue(self):
705 fp = openfile('msg_21.txt')
706 try:
707 text = fp.read()
708 finally:
709 fp.close()
710 msg = Message()
711 msg['From'] = 'aperson@dom.ain'
712 msg['To'] = 'bperson@dom.ain'
713 msg['Subject'] = 'Test'
714 msg.preamble = 'MIME message\n'
715 msg.epilogue = 'End of MIME message\n'
716 msg1 = MIMEText('One')
717 msg2 = MIMEText('Two')
718 msg.add_header('Content-Type', 'multipart/mixed', boundary='BOUNDARY')
719 msg.add_payload(msg1)
720 msg.add_payload(msg2)
721 sfp = StringIO()
722 g = Generator(sfp)
723 g(msg)
724 self.assertEqual(sfp.getvalue(), text)
725
Barry Warsaw41075852001-09-23 03:18:13 +0000726
Barry Warsaw08a534d2001-10-04 17:58:50 +0000727
728# A general test of parser->model->generator idempotency. IOW, read a message
729# in, parse it into a message object tree, then without touching the tree,
730# regenerate the plain text. The original text and the transformed text
731# should be identical. Note: that we ignore the Unix-From since that may
732# contain a changed date.
Barry Warsaw41075852001-09-23 03:18:13 +0000733class TestIdempotent(unittest.TestCase):
734 def _msgobj(self, filename):
735 fp = openfile(filename)
736 try:
737 data = fp.read()
738 finally:
739 fp.close()
Barry Warsaw65279d02001-09-26 05:47:08 +0000740 msg = email.message_from_string(data)
741 return msg, data
Barry Warsaw41075852001-09-23 03:18:13 +0000742
743 def _idempotent(self, msg, text):
744 eq = self.assertEquals
745 s = StringIO()
746 g = Generator(s, maxheaderlen=0)
747 g(msg)
748 eq(text, s.getvalue())
749
750 def test_parse_text_message(self):
751 eq = self.assertEquals
752 msg, text = self._msgobj('msg_01.txt')
753 eq(msg.get_type(), 'text/plain')
754 eq(msg.get_main_type(), 'text')
755 eq(msg.get_subtype(), 'plain')
Barry Warsaw65279d02001-09-26 05:47:08 +0000756 eq(msg.get_params()[1], ('charset', 'us-ascii'))
Barry Warsaw41075852001-09-23 03:18:13 +0000757 eq(msg.get_param('charset'), 'us-ascii')
758 eq(msg.preamble, None)
759 eq(msg.epilogue, None)
760 self._idempotent(msg, text)
761
762 def test_parse_untyped_message(self):
763 eq = self.assertEquals
764 msg, text = self._msgobj('msg_03.txt')
765 eq(msg.get_type(), None)
766 eq(msg.get_params(), None)
767 eq(msg.get_param('charset'), None)
768 self._idempotent(msg, text)
769
770 def test_simple_multipart(self):
771 msg, text = self._msgobj('msg_04.txt')
772 self._idempotent(msg, text)
773
774 def test_MIME_digest(self):
775 msg, text = self._msgobj('msg_02.txt')
776 self._idempotent(msg, text)
777
778 def test_mixed_with_image(self):
779 msg, text = self._msgobj('msg_06.txt')
780 self._idempotent(msg, text)
Tim Peters527e64f2001-10-04 05:36:56 +0000781
Barry Warsaw41075852001-09-23 03:18:13 +0000782 def test_multipart_report(self):
783 msg, text = self._msgobj('msg_05.txt')
784 self._idempotent(msg, text)
Barry Warsaw65279d02001-09-26 05:47:08 +0000785
786 def test_dsn(self):
787 msg, text = self._msgobj('msg_16.txt')
788 self._idempotent(msg, text)
Tim Peters527e64f2001-10-04 05:36:56 +0000789
Barry Warsaw1f0fa922001-10-19 04:08:59 +0000790 def test_preamble_epilogue(self):
791 msg, text = self._msgobj('msg_21.txt')
792 self._idempotent(msg, text)
793
Barry Warsaw41075852001-09-23 03:18:13 +0000794 def test_content_type(self):
795 eq = self.assertEquals
796 # Get a message object and reset the seek pointer for other tests
797 msg, text = self._msgobj('msg_05.txt')
798 eq(msg.get_type(), 'multipart/report')
799 # Test the Content-Type: parameters
800 params = {}
Barry Warsaw65279d02001-09-26 05:47:08 +0000801 for pk, pv in msg.get_params():
Barry Warsaw41075852001-09-23 03:18:13 +0000802 params[pk] = pv
803 eq(params['report-type'], 'delivery-status')
Barry Warsaw65279d02001-09-26 05:47:08 +0000804 eq(params['boundary'], 'D1690A7AC1.996856090/mail.example.com')
Barry Warsaw41075852001-09-23 03:18:13 +0000805 eq(msg.preamble, 'This is a MIME-encapsulated message.\n\n')
806 eq(msg.epilogue, '\n\n')
807 eq(len(msg.get_payload()), 3)
808 # Make sure the subparts are what we expect
809 msg1 = msg.get_payload(0)
810 eq(msg1.get_type(), 'text/plain')
811 eq(msg1.get_payload(), 'Yadda yadda yadda\n')
812 msg2 = msg.get_payload(1)
813 eq(msg2.get_type(), None)
814 eq(msg2.get_payload(), 'Yadda yadda yadda\n')
815 msg3 = msg.get_payload(2)
816 eq(msg3.get_type(), 'message/rfc822')
817 self.failUnless(isinstance(msg3, Message))
818 msg4 = msg3.get_payload()
819 self.failUnless(isinstance(msg4, Message))
820 eq(msg4.get_payload(), 'Yadda yadda yadda\n')
821
822 def test_parser(self):
823 eq = self.assertEquals
824 msg, text = self._msgobj('msg_06.txt')
825 # Check some of the outer headers
826 eq(msg.get_type(), 'message/rfc822')
827 # Make sure there's exactly one thing in the payload and that's a
828 # sub-Message object of type text/plain
829 msg1 = msg.get_payload()
830 self.failUnless(isinstance(msg1, Message))
831 eq(msg1.get_type(), 'text/plain')
832 self.failUnless(isinstance(msg1.get_payload(), StringType))
833 eq(msg1.get_payload(), '\n')
Barry Warsaw41075852001-09-23 03:18:13 +0000834
Tim Peters527e64f2001-10-04 05:36:56 +0000835
Barry Warsaw08a534d2001-10-04 17:58:50 +0000836
837# Test various other bits of the package's functionality
Barry Warsaw41075852001-09-23 03:18:13 +0000838class TestMiscellaneous(unittest.TestCase):
839 def test_message_from_string(self):
840 fp = openfile('msg_01.txt')
841 try:
842 text = fp.read()
843 finally:
844 fp.close()
845 msg = email.message_from_string(text)
846 s = StringIO()
847 # Don't wrap/continue long headers since we're trying to test
848 # idempotency.
849 g = Generator(s, maxheaderlen=0)
850 g(msg)
851 self.assertEqual(text, s.getvalue())
852
853 def test_message_from_file(self):
854 fp = openfile('msg_01.txt')
855 try:
856 text = fp.read()
857 fp.seek(0)
858 msg = email.message_from_file(fp)
859 s = StringIO()
860 # Don't wrap/continue long headers since we're trying to test
861 # idempotency.
862 g = Generator(s, maxheaderlen=0)
863 g(msg)
864 self.assertEqual(text, s.getvalue())
865 finally:
866 fp.close()
867
868 def test_message_from_string_with_class(self):
869 unless = self.failUnless
870 fp = openfile('msg_01.txt')
871 try:
872 text = fp.read()
873 finally:
874 fp.close()
875 # Create a subclass
876 class MyMessage(Message):
877 pass
Tim Peters527e64f2001-10-04 05:36:56 +0000878
Barry Warsaw41075852001-09-23 03:18:13 +0000879 msg = email.message_from_string(text, MyMessage)
880 unless(isinstance(msg, MyMessage))
881 # Try something more complicated
882 fp = openfile('msg_02.txt')
883 try:
884 text = fp.read()
885 finally:
886 fp.close()
887 msg = email.message_from_string(text, MyMessage)
888 for subpart in msg.walk():
889 unless(isinstance(subpart, MyMessage))
890
Barry Warsaw41075852001-09-23 03:18:13 +0000891 def test_message_from_file_with_class(self):
892 unless = self.failUnless
893 # Create a subclass
894 class MyMessage(Message):
895 pass
Tim Peters527e64f2001-10-04 05:36:56 +0000896
Barry Warsaw41075852001-09-23 03:18:13 +0000897 fp = openfile('msg_01.txt')
898 try:
899 msg = email.message_from_file(fp, MyMessage)
900 finally:
901 fp.close()
902 unless(isinstance(msg, MyMessage))
903 # Try something more complicated
904 fp = openfile('msg_02.txt')
905 try:
906 msg = email.message_from_file(fp, MyMessage)
907 finally:
908 fp.close()
909 for subpart in msg.walk():
910 unless(isinstance(subpart, MyMessage))
911
Barry Warsawfee435a2001-10-09 19:23:57 +0000912 def test__all__(self):
913 module = __import__('email')
914 all = module.__all__
915 all.sort()
916 self.assertEqual(all, ['Encoders', 'Errors', 'Generator', 'Iterators',
917 'MIMEAudio', 'MIMEBase', 'MIMEImage',
918 'MIMEMessage', 'MIMEText', 'Message', 'Parser',
919 'Utils',
920 'message_from_file', 'message_from_string'])
921
Barry Warsaw41075852001-09-23 03:18:13 +0000922
Barry Warsaw08a534d2001-10-04 17:58:50 +0000923
924# Test the iterator/generators
Barry Warsaw41075852001-09-23 03:18:13 +0000925class TestIterators(TestEmailBase):
926 def test_body_line_iterator(self):
927 eq = self.assertEqual
928 # First a simple non-multipart message
929 msg = self._msgobj('msg_01.txt')
930 it = Iterators.body_line_iterator(msg)
Barry Warsawd1de6ea2001-10-04 18:18:37 +0000931 lines = list(it)
Barry Warsaw41075852001-09-23 03:18:13 +0000932 eq(len(lines), 6)
933 eq(EMPTYSTRING.join(lines), msg.get_payload())
934 # Now a more complicated multipart
935 msg = self._msgobj('msg_02.txt')
936 it = Iterators.body_line_iterator(msg)
Barry Warsawd1de6ea2001-10-04 18:18:37 +0000937 lines = list(it)
Barry Warsaw41075852001-09-23 03:18:13 +0000938 eq(len(lines), 43)
Barry Warsaw08a534d2001-10-04 17:58:50 +0000939 eq(EMPTYSTRING.join(lines), openfile('msg_19.txt').read())
Barry Warsaw41075852001-09-23 03:18:13 +0000940
941 def test_typed_subpart_iterator(self):
942 eq = self.assertEqual
943 msg = self._msgobj('msg_04.txt')
944 it = Iterators.typed_subpart_iterator(msg, 'text')
Barry Warsawd1de6ea2001-10-04 18:18:37 +0000945 lines = [subpart.get_payload() for subpart in it]
946 eq(len(lines), 2)
Barry Warsaw41075852001-09-23 03:18:13 +0000947 eq(EMPTYSTRING.join(lines), """\
948a simple kind of mirror
949to reflect upon our own
950a simple kind of mirror
951to reflect upon our own
952""")
953
Barry Warsawcdc632c2001-10-15 04:39:02 +0000954 def test_typed_subpart_iterator_default_type(self):
955 eq = self.assertEqual
956 msg = self._msgobj('msg_03.txt')
957 it = Iterators.typed_subpart_iterator(msg, 'text', 'plain')
958 lines = []
959 subparts = 0
960 for subpart in it:
961 subparts += 1
962 lines.append(subpart.get_payload())
963 eq(subparts, 1)
964 eq(EMPTYSTRING.join(lines), """\
965
966Hi,
967
968Do you like this message?
969
970-Me
971""")
Barry Warsaw41075852001-09-23 03:18:13 +0000972
Barry Warsaw08a534d2001-10-04 17:58:50 +0000973
Barry Warsawbf7a59d2001-10-11 15:44:50 +0000974class TestParsers(unittest.TestCase):
975 def test_header_parser(self):
976 eq = self.assertEqual
977 # Parse only the headers of a complex multipart MIME document
978 p = HeaderParser()
979 fp = openfile('msg_02.txt')
980 msg = p.parse(fp)
981 eq(msg['from'], 'ppp-request@zzz.org')
982 eq(msg['to'], 'ppp@zzz.org')
983 eq(msg.get_type(), 'multipart/mixed')
984 eq(msg.is_multipart(), 0)
985 self.failUnless(isinstance(msg.get_payload(), StringType))
986
987
988
Barry Warsaw41075852001-09-23 03:18:13 +0000989def suite():
990 suite = unittest.TestSuite()
991 suite.addTest(unittest.makeSuite(TestMessageAPI))
992 suite.addTest(unittest.makeSuite(TestEncoders))
993 suite.addTest(unittest.makeSuite(TestLongHeaders))
994 suite.addTest(unittest.makeSuite(TestFromMangling))
Barry Warsawfee435a2001-10-09 19:23:57 +0000995 suite.addTest(unittest.makeSuite(TestMIMEAudio))
Barry Warsaw65279d02001-09-26 05:47:08 +0000996 suite.addTest(unittest.makeSuite(TestMIMEImage))
997 suite.addTest(unittest.makeSuite(TestMIMEText))
Barry Warsaw41075852001-09-23 03:18:13 +0000998 suite.addTest(unittest.makeSuite(TestMultipartMixed))
999 suite.addTest(unittest.makeSuite(TestNonConformant))
1000 suite.addTest(unittest.makeSuite(TestRFC2047))
Barry Warsaw65279d02001-09-26 05:47:08 +00001001 suite.addTest(unittest.makeSuite(TestMIMEMessage))
Barry Warsaw41075852001-09-23 03:18:13 +00001002 suite.addTest(unittest.makeSuite(TestIdempotent))
1003 suite.addTest(unittest.makeSuite(TestMiscellaneous))
1004 suite.addTest(unittest.makeSuite(TestIterators))
Barry Warsawbf7a59d2001-10-11 15:44:50 +00001005 suite.addTest(unittest.makeSuite(TestParsers))
Barry Warsaw41075852001-09-23 03:18:13 +00001006 return suite
1007
1008
Barry Warsaw08a534d2001-10-04 17:58:50 +00001009
Barry Warsaw41075852001-09-23 03:18:13 +00001010if __name__ == '__main__':
1011 unittest.main(defaultTest='suite')
1012else:
1013 from test_support import run_suite
1014 run_suite(suite())