• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1"""Test the parser and generator are inverses.
2
3Note that this is only strictly true if we are parsing RFC valid messages and
4producing RFC valid messages.
5"""
6
7import io
8import unittest
9from email import policy, message_from_bytes
10from email.message import EmailMessage
11from email.generator import BytesGenerator
12from test.test_email import TestEmailBase, parameterize
13
14# This is like textwrap.dedent for bytes, except that it uses \r\n for the line
15# separators on the rebuilt string.
16def dedent(bstr):
17    lines = bstr.splitlines()
18    if not lines[0].strip():
19        raise ValueError("First line must contain text")
20    stripamt = len(lines[0]) - len(lines[0].lstrip())
21    return b'\r\n'.join(
22        [x[stripamt:] if len(x)>=stripamt else b''
23            for x in lines])
24
25
26@parameterize
27class TestInversion(TestEmailBase):
28
29    policy = policy.default
30    message = EmailMessage
31
32    def msg_as_input(self, msg):
33        m = message_from_bytes(msg, policy=policy.SMTP)
34        b = io.BytesIO()
35        g = BytesGenerator(b)
36        g.flatten(m)
37        self.assertEqual(b.getvalue(), msg)
38
39    # XXX: spaces are not preserved correctly here yet in the general case.
40    msg_params = {
41        'header_with_one_space_body': (dedent(b"""\
42            From: abc@xyz.com
43            X-Status:\x20
44            Subject: test
45
46            foo
47            """),),
48
49        'header_with_invalid_date': (dedent(b"""\
50            Date: Tue, 06 Jun 2017 27:39:33 +0600
51            From: abc@xyz.com
52            Subject: timezones
53
54            How do they work even?
55            """),),
56
57            }
58
59    payload_params = {
60        'plain_text': dict(payload='This is a test\n'*20),
61        'base64_text': dict(payload=(('xy a'*40+'\n')*5), cte='base64'),
62        'qp_text': dict(payload=(('xy a'*40+'\n')*5), cte='quoted-printable'),
63        }
64
65    def payload_as_body(self, payload, **kw):
66        msg = self._make_message()
67        msg['From'] = 'foo'
68        msg['To'] = 'bar'
69        msg['Subject'] = 'payload round trip test'
70        msg.set_content(payload, **kw)
71        b = bytes(msg)
72        msg2 = message_from_bytes(b, policy=self.policy)
73        self.assertEqual(bytes(msg2), b)
74        self.assertEqual(msg2.get_content(), payload)
75
76
77if __name__ == '__main__':
78    unittest.main()
79