blob: 61f04c6a1297afcf196312fe545bf2abb822b108 [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
13from email.Parser import Parser
14from email.Generator import Generator, DecodedGenerator
15from email.Message import Message
16from email.Text import Text
17from email.Image import Image
18from email.MIMEBase import MIMEBase
19from email.MessageRFC822 import MessageRFC822
20from email import Utils
21from email import Errors
22from email import Encoders
23from email import Iterators
24
25import test.regrtest
26
27NL = '\n'
28EMPTYSTRING = ''
29
30
31
32def openfile(filename):
33 path = os.path.join(os.path.dirname(test.regrtest.__file__),
34 'data', filename)
35 return open(path)
36
37
38
39# Base test class
40class TestEmailBase(unittest.TestCase):
41 def _msgobj(self, filename):
42 fp = openfile(filename)
43 try:
44 msgobj = email.message_from_file(fp)
45 finally:
46 fp.close()
47 return msgobj
48
49
50
51# Test various aspects of the Message class's API
52class TestMessageAPI(TestEmailBase):
53 def test_get_charsets(self):
54 eq = self.assertEqual
55
56 msgobj = self._msgobj('msg_08.txt')
57 charsets = msgobj.get_charsets()
58 eq(charsets, ['us-ascii', 'iso-8859-1', 'iso-8859-2', 'koi8-r'])
59
60 msgobj = self._msgobj('msg_09.txt')
61 charsets = msgobj.get_charsets('dingbat')
62 eq(charsets, ['us-ascii', 'iso-8859-1', 'dingbat', 'koi8-r'])
63
64 msgobj = self._msgobj('msg_12.txt')
65 charsets = msgobj.get_charsets()
66 eq(charsets, ['us-ascii', 'iso-8859-1', 'iso-8859-2', 'iso-8859-3',
67 'us-ascii', 'koi8-r'])
68
69 def test_get_filename(self):
70 eq = self.assertEqual
71
72 msgobj = self._msgobj('msg_04.txt')
73 filenames = [p.get_filename() for p in msgobj.get_payload()]
74 eq(filenames, ['msg.txt', 'msg.txt'])
75
76 msgobj = self._msgobj('msg_07.txt')
77 subpart = msgobj.get_payload(1)
78 eq(subpart.get_filename(), 'dingusfish.gif')
79
80 def test_get_boundary(self):
81 eq = self.assertEqual
82 msgobj = self._msgobj('msg_07.txt')
83 # No quotes!
84 eq(msgobj.get_boundary(), 'BOUNDARY')
85
86 def test_set_boundary(self):
87 eq = self.assertEqual
88 # This one has no existing boundary parameter, but the Content-Type:
89 # header appears fifth.
90 msgobj = self._msgobj('msg_01.txt')
91 msgobj.set_boundary('BOUNDARY')
92 header, value = msgobj.items()[4]
93 eq(header.lower(), 'content-type')
94 eq(value, 'text/plain; charset=us-ascii; boundary="BOUNDARY"')
95 # This one has a Content-Type: header, with a boundary, stuck in the
96 # middle of its headers. Make sure the order is preserved; it should
97 # be fifth.
98 msgobj = self._msgobj('msg_04.txt')
99 msgobj.set_boundary('BOUNDARY')
100 header, value = msgobj.items()[4]
101 eq(header.lower(), 'content-type')
102 eq(value, 'multipart/mixed; boundary="BOUNDARY"')
103 # And this one has no Content-Type: header at all.
104 msgobj = self._msgobj('msg_03.txt')
105 self.assertRaises(Errors.HeaderParseError,
106 msgobj.set_boundary, 'BOUNDARY')
107
108 def test_get_decoded_payload(self):
109 eq = self.assertEqual
110 msgobj = self._msgobj('msg_10.txt')
111 # The outer message is a multipart
112 eq(msgobj.get_payload(decode=1), None)
113 # Subpart 1 is 7bit encoded
114 eq(msgobj.get_payload(0).get_payload(decode=1),
115 'This is a 7bit encoded message.\n')
116 # Subpart 2 is quopri
117 eq(msgobj.get_payload(1).get_payload(decode=1),
118 '\xa1This is a Quoted Printable encoded message!\n')
119 # Subpart 3 is base64
120 eq(msgobj.get_payload(2).get_payload(decode=1),
121 'This is a Base64 encoded message.')
122 # Subpart 4 has no Content-Transfer-Encoding: header.
123 eq(msgobj.get_payload(3).get_payload(decode=1),
124 'This has no Content-Transfer-Encoding: header.\n')
125
126 def test_decoded_generator(self):
127 eq = self.assertEqual
128 msgobj = self._msgobj('msg_07.txt')
129 s = StringIO()
130 g = DecodedGenerator(s)
131 g(msgobj)
132 eq(s.getvalue(), '''\
133MIME-Version: 1.0
134From: Barry <barry@digicool.com>
135To: Dingus Lovers <cravindogs@cravindogs.com>
136Subject: Here is your dingus fish
137Date: Fri, 20 Apr 2001 19:35:02 -0400
138Content-Type: multipart/mixed; boundary="BOUNDARY"
139
140Hi there,
141
142This is the dingus fish.
143
144[Non-text (image/gif) part of message omitted, filename dingusfish.gif]
145''')
146
147 def test__contains__(self):
148 msg = Message()
149 msg['From'] = 'Me'
150 msg['to'] = 'You'
151 # Check for case insensitivity
152 self.failUnless('from' in msg)
153 self.failUnless('From' in msg)
154 self.failUnless('FROM' in msg)
155 self.failUnless('to' in msg)
156 self.failUnless('To' in msg)
157 self.failUnless('TO' in msg)
158
159 def test_as_string(self):
160 eq = self.assertEqual
161 msgobj = self._msgobj('msg_01.txt')
162 fp = openfile('msg_01.txt')
163 try:
164 text = fp.read()
165 finally:
166 fp.close()
167 eq(text, msgobj.as_string())
168 fullrepr = str(msgobj)
169 lines = fullrepr.split('\n')
170 self.failUnless(lines[0].startswith('From '))
171 eq(text, NL.join(lines[1:]))
172
173 def test_bad_param(self):
174 msg = email.message_from_string("""\
175From: foo
176Content-Type: blarg; baz; boo
177
178""")
179 self.assertEqual(msg.get_param('baz'), '')
180
181 def test_missing_filename(self):
182 msg = email.message_from_string("""\
183From: foo
184
185""")
186 self.assertEqual(msg.get_filename(), None)
187
188 def test_bogus_filename(self):
189 msg = email.message_from_string("""\
190From: foo
191Content-Disposition: blarg; filename
192
193""")
194 self.assertEqual(msg.get_filename(), '')
195
196 def test_missing_boundary(self):
197 msg = email.message_from_string("""\
198From: foo
199
200""")
201 self.assertEqual(msg.get_boundary(), None)
202
203
204
205# Test the email.Encoders module
206class TestEncoders(unittest.TestCase):
207 def test_encode_noop(self):
208 eq = self.assertEqual
209 msg = Text('hello world', _encoder=Encoders.encode_noop)
210 eq(msg.get_payload(), 'hello world\n')
211 eq(msg['content-transfer-encoding'], None)
212
213 def test_encode_7bit(self):
214 eq = self.assertEqual
215 msg = Text('hello world', _encoder=Encoders.encode_7or8bit)
216 eq(msg.get_payload(), 'hello world\n')
217 eq(msg['content-transfer-encoding'], '7bit')
218 msg = Text('hello \x7f world', _encoder=Encoders.encode_7or8bit)
219 eq(msg.get_payload(), 'hello \x7f world\n')
220 eq(msg['content-transfer-encoding'], '7bit')
221
222 def test_encode_8bit(self):
223 eq = self.assertEqual
224 msg = Text('hello \x80 world', _encoder=Encoders.encode_7or8bit)
225 eq(msg.get_payload(), 'hello \x80 world\n')
226 eq(msg['content-transfer-encoding'], '8bit')
227
228 def test_encode_base64(self):
229 eq = self.assertEqual
230 msg = Text('hello world', _encoder=Encoders.encode_base64)
231 eq(msg.get_payload(), 'aGVsbG8gd29ybGQK\n')
232 eq(msg['content-transfer-encoding'], 'base64')
233
234 def test_encode_quoted_printable(self):
235 eq = self.assertEqual
236 msg = Text('hello world', _encoder=Encoders.encode_quopri)
237 eq(msg.get_payload(), 'hello=20world\n')
238 eq(msg['content-transfer-encoding'], 'quoted-printable')
239
240
241
242class TestLongHeaders(unittest.TestCase):
243 def test_header_splitter(self):
244 msg = Text('')
245 # It'd be great if we could use add_header() here, but that doesn't
246 # guarantee an order of the parameters.
247 msg['X-Foobar-Spoink-Defrobnit'] = (
248 'wasnipoop; giraffes="very-long-necked-animals"; '
249 'spooge="yummy"; hippos="gargantuan"; marshmallows="gooey"')
250 sfp = StringIO()
251 g = Generator(sfp)
252 g(msg)
253 self.assertEqual(sfp.getvalue(), '''\
254Content-Type: text/plain; charset="us-ascii"
255MIME-Version: 1.0
256Content-Transfer-Encoding: 7bit
257X-Foobar-Spoink-Defrobnit: wasnipoop; giraffes="very-long-necked-animals";
258 spooge="yummy"; hippos="gargantuan"; marshmallows="gooey"
259
260''')
261
262
263
264class TestFromMangling(unittest.TestCase):
265 def setUp(self):
266 self.msg = Message()
267 self.msg['From'] = 'aaa@bbb.org'
268 self.msg.add_payload("""\
269From the desk of A.A.A.:
270Blah blah blah
271""")
272
273 def test_mangled_from(self):
274 s = StringIO()
275 g = Generator(s, mangle_from_=1)
276 g(self.msg)
277 self.assertEqual(s.getvalue(), """\
278From: aaa@bbb.org
279
280>From the desk of A.A.A.:
281Blah blah blah
282""")
283
284 def test_dont_mangle_from(self):
285 s = StringIO()
286 g = Generator(s, mangle_from_=0)
287 g(self.msg)
288 self.assertEqual(s.getvalue(), """\
289From: aaa@bbb.org
290
291From the desk of A.A.A.:
292Blah blah blah
293""")
294
295
296
297# Test the basic Image class
298class TestImage(unittest.TestCase):
299 def setUp(self):
300 fp = openfile('PyBanner048.gif')
301 try:
302 self._imgdata = fp.read()
303 finally:
304 fp.close()
305 self._im = Image(self._imgdata)
306
307 def test_guess_minor_type(self):
308 self.assertEqual(self._im.get_type(), 'image/gif')
309
310 def test_encoding(self):
311 payload = self._im.get_payload()
312 self.assertEqual(base64.decodestring(payload), self._imgdata)
313
314 def checkSetMinor(self):
315 im = Image(self._imgdata, 'fish')
316 self.assertEqual(im.get_type(), 'image/fish')
317
318 def test_custom_encoder(self):
319 eq = self.assertEqual
320 def encoder(msg):
321 orig = msg.get_payload()
322 msg.set_payload(0)
323 msg['Content-Transfer-Encoding'] = 'broken64'
324 im = Image(self._imgdata, _encoder=encoder)
325 eq(im.get_payload(), 0)
326 eq(im['content-transfer-encoding'], 'broken64')
327
328 def test_add_header(self):
329 eq = self.assertEqual
330 unless = self.failUnless
331 self._im.add_header('Content-Disposition', 'attachment',
332 filename='dingusfish.gif')
333 eq(self._im['content-disposition'],
334 'attachment; filename="dingusfish.gif"')
335 eq(self._im.get_params(header='content-disposition'),
336 ['filename="dingusfish.gif"'])
337 eq(self._im.get_param('filename', header='content-disposition'),
338 'dingusfish.gif')
339 missing = []
340 unless(self._im.get_param('attachment', missing,
341 header='content-disposition') is missing)
342 # Try some missing stuff
343 unless(self._im.get_param('foobar', missing) is missing)
344 unless(self._im.get_param('attachment', missing,
345 header='foobar') is missing)
346
347
348
349# Test the basic Text class
350class TestText(unittest.TestCase):
351 def setUp(self):
352 self._msg = Text('hello there')
353
354 def test_types(self):
355 eq = self.assertEqual
356 unless = self.failUnless
357 eq(self._msg.get_type(), 'text/plain')
358 eq(self._msg.get_param('charset'), 'us-ascii')
359 missing = []
360 unless(self._msg.get_param('foobar', missing) is missing)
361 unless(self._msg.get_param('charset', missing, header='foobar')
362 is missing)
363
364 def test_payload(self):
365 self.assertEqual(self._msg.get_payload(), 'hello there\n')
366 self.failUnless(not self._msg.is_multipart())
367
368
369
370class TestMultipartMixed(unittest.TestCase):
371 def setUp(self):
372 fp = openfile('PyBanner048.gif')
373 try:
374 data = fp.read()
375 finally:
376 fp.close()
377
378 container = MIMEBase('multipart', 'mixed', boundary='BOUNDARY')
379 image = Image(data, name='dingusfish.gif')
380 image.add_header('content-disposition', 'attachment',
381 filename='dingusfish.gif')
382 intro = Text('''\
383Hi there,
384
385This is the dingus fish.
386''')
387 container.add_payload(intro)
388 container.add_payload(image)
389 container['From'] = 'Barry <barry@digicool.com>'
390 container['To'] = 'Dingus Lovers <cravindogs@cravindogs.com>'
391 container['Subject'] = 'Here is your dingus fish'
392
393 now = 987809702.54848599
394 timetuple = time.localtime(now)
395 if timetuple[-1] == 0:
396 tzsecs = time.timezone
397 else:
398 tzsecs = time.altzone
399 if tzsecs > 0:
400 sign = '-'
401 else:
402 sign = '+'
403 tzoffset = ' %s%04d' % (sign, tzsecs / 36)
404 container['Date'] = time.strftime(
405 '%a, %d %b %Y %H:%M:%S',
406 time.localtime(now)) + tzoffset
407 self._msg = container
408 self._im = image
409 self._txt = intro
410
411 def test_hierarchy(self):
412 # convenience
413 eq = self.assertEqual
414 unless = self.failUnless
415 raises = self.assertRaises
416 # tests
417 m = self._msg
418 unless(m.is_multipart())
419 eq(m.get_type(), 'multipart/mixed')
420 eq(len(m.get_payload()), 2)
421 raises(IndexError, m.get_payload, 2)
422 m0 = m.get_payload(0)
423 m1 = m.get_payload(1)
424 unless(m0 is self._txt)
425 unless(m1 is self._im)
426 eq(m.get_payload(), [m0, m1])
427 unless(not m0.is_multipart())
428 unless(not m1.is_multipart())
429
430
431
432class TestNonConformant(TestEmailBase):
433 def test_parse_missing_minor_type(self):
434 eq = self.assertEqual
435 msg = self._msgobj('msg_14.txt')
436 eq(msg.get_type(), 'text')
437 eq(msg.get_main_type(), 'text')
438 self.failUnless(msg.get_subtype() is None)
439
440 def test_bogus_boundary(self):
441 fp = openfile('msg_15.txt')
442 try:
443 data = fp.read()
444 finally:
445 fp.close()
446 p = Parser()
447 # Note, under a future non-strict parsing mode, this would parse the
448 # message into the intended message tree.
449 self.assertRaises(Errors.BoundaryError, p.parsestr, data)
450
451
452
453class TestRFC2047(unittest.TestCase):
454 def test_iso_8859_1(self):
455 eq = self.assertEqual
456 s = '=?iso-8859-1?q?this=20is=20some=20text?='
457 eq(Utils.decode(s), 'this is some text')
458 s = '=?ISO-8859-1?Q?Keld_J=F8rn_Simonsen?='
459 eq(Utils.decode(s), u'Keld_J\xf8rn_Simonsen')
460 s = '=?ISO-8859-1?B?SWYgeW91IGNhbiByZWFkIHRoaXMgeW8=?=' \
461 '=?ISO-8859-2?B?dSB1bmRlcnN0YW5kIHRoZSBleGFtcGxlLg==?='
462 eq(Utils.decode(s), 'If you can read this you understand the example.')
463 s = '=?iso-8859-8?b?7eXs+SDv4SDp7Oj08A==?='
464 eq(Utils.decode(s),
465 u'\u05dd\u05d5\u05dc\u05e9 \u05df\u05d1 \u05d9\u05dc\u05d8\u05e4\u05e0')
466 s = '=?iso-8859-1?q?this=20is?= =?iso-8859-1?q?some=20text?='
467 eq(Utils.decode(s), u'this is some text')
468
469 def test_encode_header(self):
470 eq = self.assertEqual
471 s = 'this is some text'
472 eq(Utils.encode(s), '=?iso-8859-1?q?this=20is=20some=20text?=')
473 s = 'Keld_J\xf8rn_Simonsen'
474 eq(Utils.encode(s), '=?iso-8859-1?q?Keld_J=F8rn_Simonsen?=')
475 s1 = 'If you can read this yo'
476 s2 = 'u understand the example.'
477 eq(Utils.encode(s1, encoding='b'),
478 '=?iso-8859-1?b?SWYgeW91IGNhbiByZWFkIHRoaXMgeW8=?=')
479 eq(Utils.encode(s2, charset='iso-8859-2', encoding='b'),
480 '=?iso-8859-2?b?dSB1bmRlcnN0YW5kIHRoZSBleGFtcGxlLg==?=')
481
482
483
484class TestMessageRFC822(unittest.TestCase):
485 def setUp(self):
486 fp = openfile('msg_11.txt')
487 self._text = fp.read()
488 fp.close()
489
490 def test_type_error(self):
491 self.assertRaises(TypeError, MessageRFC822, 'a plain string')
492
493 def test_valid_argument(self):
494 eq = self.assertEqual
495 subject = 'A sub-message'
496 m = Message()
497 m['Subject'] = subject
498 r = MessageRFC822(m)
499 eq(r.get_type(), 'message/rfc822')
500 self.failUnless(r.get_payload() is m)
501 eq(r.get_payload()['subject'], subject)
502
503 def test_generate(self):
504 # First craft the message to be encapsulated
505 m = Message()
506 m['Subject'] = 'An enclosed message'
507 m.add_payload('Here is the body of the message.\n')
508 r = MessageRFC822(m)
509 r['Subject'] = 'The enclosing message'
510 s = StringIO()
511 g = Generator(s)
512 g(r)
513 self.assertEqual(s.getvalue(), self._text)
514
515
516
517class TestIdempotent(unittest.TestCase):
518 def _msgobj(self, filename):
519 fp = openfile(filename)
520 try:
521 data = fp.read()
522 finally:
523 fp.close()
524 msgobj = email.message_from_string(data)
525 return msgobj, data
526
527 def _idempotent(self, msg, text):
528 eq = self.assertEquals
529 s = StringIO()
530 g = Generator(s, maxheaderlen=0)
531 g(msg)
532 eq(text, s.getvalue())
533
534 def test_parse_text_message(self):
535 eq = self.assertEquals
536 msg, text = self._msgobj('msg_01.txt')
537 eq(msg.get_type(), 'text/plain')
538 eq(msg.get_main_type(), 'text')
539 eq(msg.get_subtype(), 'plain')
540 eq(msg.get_params(), ['charset=us-ascii'])
541 eq(msg.get_param('charset'), 'us-ascii')
542 eq(msg.preamble, None)
543 eq(msg.epilogue, None)
544 self._idempotent(msg, text)
545
546 def test_parse_untyped_message(self):
547 eq = self.assertEquals
548 msg, text = self._msgobj('msg_03.txt')
549 eq(msg.get_type(), None)
550 eq(msg.get_params(), None)
551 eq(msg.get_param('charset'), None)
552 self._idempotent(msg, text)
553
554 def test_simple_multipart(self):
555 msg, text = self._msgobj('msg_04.txt')
556 self._idempotent(msg, text)
557
558 def test_MIME_digest(self):
559 msg, text = self._msgobj('msg_02.txt')
560 self._idempotent(msg, text)
561
562 def test_mixed_with_image(self):
563 msg, text = self._msgobj('msg_06.txt')
564 self._idempotent(msg, text)
565
566 def test_multipart_report(self):
567 msg, text = self._msgobj('msg_05.txt')
568 self._idempotent(msg, text)
569
570 def test_content_type(self):
571 eq = self.assertEquals
572 # Get a message object and reset the seek pointer for other tests
573 msg, text = self._msgobj('msg_05.txt')
574 eq(msg.get_type(), 'multipart/report')
575 # Test the Content-Type: parameters
576 params = {}
577 for p in msg.get_params():
578 pk, pv = p.split('=', 1)
579 params[pk] = pv
580 eq(params['report-type'], 'delivery-status')
581 eq(params['boundary'], '"D1690A7AC1.996856090/mail.example.com"')
582 eq(msg.preamble, 'This is a MIME-encapsulated message.\n\n')
583 eq(msg.epilogue, '\n\n')
584 eq(len(msg.get_payload()), 3)
585 # Make sure the subparts are what we expect
586 msg1 = msg.get_payload(0)
587 eq(msg1.get_type(), 'text/plain')
588 eq(msg1.get_payload(), 'Yadda yadda yadda\n')
589 msg2 = msg.get_payload(1)
590 eq(msg2.get_type(), None)
591 eq(msg2.get_payload(), 'Yadda yadda yadda\n')
592 msg3 = msg.get_payload(2)
593 eq(msg3.get_type(), 'message/rfc822')
594 self.failUnless(isinstance(msg3, Message))
595 msg4 = msg3.get_payload()
596 self.failUnless(isinstance(msg4, Message))
597 eq(msg4.get_payload(), 'Yadda yadda yadda\n')
598
599 def test_parser(self):
600 eq = self.assertEquals
601 msg, text = self._msgobj('msg_06.txt')
602 # Check some of the outer headers
603 eq(msg.get_type(), 'message/rfc822')
604 # Make sure there's exactly one thing in the payload and that's a
605 # sub-Message object of type text/plain
606 msg1 = msg.get_payload()
607 self.failUnless(isinstance(msg1, Message))
608 eq(msg1.get_type(), 'text/plain')
609 self.failUnless(isinstance(msg1.get_payload(), StringType))
610 eq(msg1.get_payload(), '\n')
611
612
613
614class TestMiscellaneous(unittest.TestCase):
615 def test_message_from_string(self):
616 fp = openfile('msg_01.txt')
617 try:
618 text = fp.read()
619 finally:
620 fp.close()
621 msg = email.message_from_string(text)
622 s = StringIO()
623 # Don't wrap/continue long headers since we're trying to test
624 # idempotency.
625 g = Generator(s, maxheaderlen=0)
626 g(msg)
627 self.assertEqual(text, s.getvalue())
628
629 def test_message_from_file(self):
630 fp = openfile('msg_01.txt')
631 try:
632 text = fp.read()
633 fp.seek(0)
634 msg = email.message_from_file(fp)
635 s = StringIO()
636 # Don't wrap/continue long headers since we're trying to test
637 # idempotency.
638 g = Generator(s, maxheaderlen=0)
639 g(msg)
640 self.assertEqual(text, s.getvalue())
641 finally:
642 fp.close()
643
644 def test_message_from_string_with_class(self):
645 unless = self.failUnless
646 fp = openfile('msg_01.txt')
647 try:
648 text = fp.read()
649 finally:
650 fp.close()
651 # Create a subclass
652 class MyMessage(Message):
653 pass
654
655 msg = email.message_from_string(text, MyMessage)
656 unless(isinstance(msg, MyMessage))
657 # Try something more complicated
658 fp = openfile('msg_02.txt')
659 try:
660 text = fp.read()
661 finally:
662 fp.close()
663 msg = email.message_from_string(text, MyMessage)
664 for subpart in msg.walk():
665 unless(isinstance(subpart, MyMessage))
666
667
668 def test_message_from_file_with_class(self):
669 unless = self.failUnless
670 # Create a subclass
671 class MyMessage(Message):
672 pass
673
674 fp = openfile('msg_01.txt')
675 try:
676 msg = email.message_from_file(fp, MyMessage)
677 finally:
678 fp.close()
679 unless(isinstance(msg, MyMessage))
680 # Try something more complicated
681 fp = openfile('msg_02.txt')
682 try:
683 msg = email.message_from_file(fp, MyMessage)
684 finally:
685 fp.close()
686 for subpart in msg.walk():
687 unless(isinstance(subpart, MyMessage))
688
689
690
691class TestIterators(TestEmailBase):
692 def test_body_line_iterator(self):
693 eq = self.assertEqual
694 # First a simple non-multipart message
695 msg = self._msgobj('msg_01.txt')
696 it = Iterators.body_line_iterator(msg)
697 lines = []
698 for line in it:
699 lines.append(line)
700 eq(len(lines), 6)
701 eq(EMPTYSTRING.join(lines), msg.get_payload())
702 # Now a more complicated multipart
703 msg = self._msgobj('msg_02.txt')
704 it = Iterators.body_line_iterator(msg)
705 lines = []
706 for line in it:
707 lines.append(line)
708 eq(len(lines), 43)
709 eq(EMPTYSTRING.join(lines), """\
710Send Ppp mailing list submissions to
711 ppp@zzz.org
712
713To subscribe or unsubscribe via the World Wide Web, visit
714 http://www.zzz.org/mailman/listinfo/ppp
715or, via email, send a message with subject or body 'help' to
716 ppp-request@zzz.org
717
718You can reach the person managing the list at
719 ppp-admin@zzz.org
720
721When replying, please edit your Subject line so it is more specific
722than "Re: Contents of Ppp digest..."
723
724Today's Topics:
725
726 1. testing #1 (Barry A. Warsaw)
727 2. testing #2 (Barry A. Warsaw)
728 3. testing #3 (Barry A. Warsaw)
729 4. testing #4 (Barry A. Warsaw)
730 5. testing #5 (Barry A. Warsaw)
731
732hello
733
734
735hello
736
737
738hello
739
740
741hello
742
743
744hello
745
746
747
748_______________________________________________
749Ppp mailing list
750Ppp@zzz.org
751http://www.zzz.org/mailman/listinfo/ppp
752
753""")
754
755 def test_typed_subpart_iterator(self):
756 eq = self.assertEqual
757 msg = self._msgobj('msg_04.txt')
758 it = Iterators.typed_subpart_iterator(msg, 'text')
759 lines = []
760 subparts = 0
761 for subpart in it:
762 subparts += 1
763 lines.append(subpart.get_payload())
764 eq(subparts, 2)
765 eq(EMPTYSTRING.join(lines), """\
766a simple kind of mirror
767to reflect upon our own
768a simple kind of mirror
769to reflect upon our own
770""")
771
772
773
774def suite():
775 suite = unittest.TestSuite()
776 suite.addTest(unittest.makeSuite(TestMessageAPI))
777 suite.addTest(unittest.makeSuite(TestEncoders))
778 suite.addTest(unittest.makeSuite(TestLongHeaders))
779 suite.addTest(unittest.makeSuite(TestFromMangling))
780 suite.addTest(unittest.makeSuite(TestImage))
781 suite.addTest(unittest.makeSuite(TestText))
782 suite.addTest(unittest.makeSuite(TestMultipartMixed))
783 suite.addTest(unittest.makeSuite(TestNonConformant))
784 suite.addTest(unittest.makeSuite(TestRFC2047))
785 suite.addTest(unittest.makeSuite(TestMessageRFC822))
786 suite.addTest(unittest.makeSuite(TestIdempotent))
787 suite.addTest(unittest.makeSuite(TestMiscellaneous))
788 suite.addTest(unittest.makeSuite(TestIterators))
789 return suite
790
791
792
793if __name__ == '__main__':
794 unittest.main(defaultTest='suite')
795else:
796 from test_support import run_suite
797 run_suite(suite())