/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
6614.1.1 by Vincent Ladeuil
Fix assert_ being deprecated by using assertTrue.
1
# Copyright (C) 2007, 2009, 2011, 2014, 2016 Canonical Ltd
2625.6.1 by Adeodato Simó
New EmailMessage class, façade around email.Message and MIMEMultipart.
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
2625.6.1 by Adeodato Simó
New EmailMessage class, façade around email.Message and MIMEMultipart.
16
6592.1.1 by Vincent Ladeuil
Fix minor incompatible change in email python 2.7.6 module.
17
import sys
7078.11.1 by Jelmer Vernooij
Fix email tests on Python 3.
18
from email.header import decode_header
2625.6.1 by Adeodato Simó
New EmailMessage class, façade around email.Message and MIMEMultipart.
19
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
20
from .. import __version__ as _breezy_version
21
from ..email_message import EmailMessage
22
from ..errors import BzrBadParameterNotUnicode
23
from ..smtp_connection import SMTPConnection
24
from .. import tests
2625.6.1 by Adeodato Simó
New EmailMessage class, façade around email.Message and MIMEMultipart.
25
26
EMPTY_MESSAGE = '''\
27
From: from@from.com
28
Subject: subject
29
To: to@to.com
30
User-Agent: Bazaar (%s)
31
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
32
''' % _breezy_version
2625.6.1 by Adeodato Simó
New EmailMessage class, façade around email.Message and MIMEMultipart.
33
34
_SIMPLE_MESSAGE = '''\
35
MIME-Version: 1.0
36
Content-Type: text/plain; charset="%%s"
37
Content-Transfer-Encoding: %%s
38
From: from@from.com
39
Subject: subject
40
To: to@to.com
41
User-Agent: Bazaar (%s)
42
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
43
%%s''' % _breezy_version
2625.6.1 by Adeodato Simó
New EmailMessage class, façade around email.Message and MIMEMultipart.
44
45
SIMPLE_MESSAGE_ASCII = _SIMPLE_MESSAGE % ('us-ascii', '7bit', 'body')
46
SIMPLE_MESSAGE_UTF8 = _SIMPLE_MESSAGE % ('utf-8', 'base64', 'YsOzZHk=\n')
2639.1.2 by John Arbash Meinel
Some cleanups for the EmailMessage class.
47
SIMPLE_MESSAGE_8BIT = _SIMPLE_MESSAGE % ('8-bit', 'base64', 'YvRkeQ==\n')
2625.6.1 by Adeodato Simó
New EmailMessage class, façade around email.Message and MIMEMultipart.
48
49
50
BOUNDARY = '=====123456=='
51
52
_MULTIPART_HEAD = '''\
53
Content-Type: multipart/mixed; boundary="%(boundary)s"
54
MIME-Version: 1.0
55
From: from@from.com
56
Subject: subject
57
To: to@to.com
58
User-Agent: Bazaar (%(version)s)
59
60
--%(boundary)s
61
MIME-Version: 1.0
62
Content-Type: text/plain; charset="us-ascii"
63
Content-Transfer-Encoding: 7bit
64
Content-Disposition: inline
65
66
body
7143.15.2 by Jelmer Vernooij
Run autopep8.
67
''' % {'version': _breezy_version, 'boundary': BOUNDARY}
2625.6.1 by Adeodato Simó
New EmailMessage class, façade around email.Message and MIMEMultipart.
68
6592.1.1 by Vincent Ladeuil
Fix minor incompatible change in email python 2.7.6 module.
69
7479.2.1 by Jelmer Vernooij
Drop python2 support.
70
def simple_multipart_message():
71
    msg = _MULTIPART_HEAD + '--%s--\n' % BOUNDARY
6592.1.1 by Vincent Ladeuil
Fix minor incompatible change in email python 2.7.6 module.
72
    return msg
73
74
75
def complex_multipart_message(typ):
76
    msg = _MULTIPART_HEAD + '''\
2625.6.1 by Adeodato Simó
New EmailMessage class, façade around email.Message and MIMEMultipart.
77
--%(boundary)s
78
MIME-Version: 1.0
79
Content-Type: text/%%s; charset="us-ascii"; name="lines.txt"
80
Content-Transfer-Encoding: 7bit
81
Content-Disposition: inline
82
83
a
84
b
85
c
86
d
87
e
88
7479.2.1 by Jelmer Vernooij
Drop python2 support.
89
--%(boundary)s--
90
''' % {'boundary': BOUNDARY}
6592.1.1 by Vincent Ladeuil
Fix minor incompatible change in email python 2.7.6 module.
91
    return msg % (typ,)
92
93
94
class TestEmailMessage(tests.TestCase):
2625.6.1 by Adeodato Simó
New EmailMessage class, façade around email.Message and MIMEMultipart.
95
96
    def test_empty_message(self):
97
        msg = EmailMessage('from@from.com', 'to@to.com', 'subject')
6809.1.1 by Martin
Apply 2to3 ws_comma fixer
98
        self.assertEqualDiff(EMPTY_MESSAGE, msg.as_string())
2625.6.1 by Adeodato Simó
New EmailMessage class, façade around email.Message and MIMEMultipart.
99
100
    def test_simple_message(self):
101
        pairs = {
7058.4.2 by Jelmer Vernooij
Fix boundaries handling.
102
            b'body': SIMPLE_MESSAGE_ASCII,
2625.6.1 by Adeodato Simó
New EmailMessage class, façade around email.Message and MIMEMultipart.
103
            u'b\xf3dy': SIMPLE_MESSAGE_UTF8,
7058.4.2 by Jelmer Vernooij
Fix boundaries handling.
104
            b'b\xc3\xb3dy': SIMPLE_MESSAGE_UTF8,
105
            b'b\xf4dy': SIMPLE_MESSAGE_8BIT,
2625.6.1 by Adeodato Simó
New EmailMessage class, façade around email.Message and MIMEMultipart.
106
        }
107
        for body, expected in pairs.items():
108
            msg = EmailMessage('from@from.com', 'to@to.com', 'subject', body)
109
            self.assertEqualDiff(expected, msg.as_string())
110
6592.1.1 by Vincent Ladeuil
Fix minor incompatible change in email python 2.7.6 module.
111
    def test_multipart_message_simple(self):
2625.6.1 by Adeodato Simó
New EmailMessage class, façade around email.Message and MIMEMultipart.
112
        msg = EmailMessage('from@from.com', 'to@to.com', 'subject')
113
        msg.add_inline_attachment('body')
6592.1.1 by Vincent Ladeuil
Fix minor incompatible change in email python 2.7.6 module.
114
        self.assertEqualDiff(simple_multipart_message(),
115
                             msg.as_string(BOUNDARY))
116
117
    def test_multipart_message_complex(self):
2625.6.1 by Adeodato Simó
New EmailMessage class, façade around email.Message and MIMEMultipart.
118
        msg = EmailMessage('from@from.com', 'to@to.com', 'subject', 'body')
119
        msg.add_inline_attachment(u'a\nb\nc\nd\ne\n', 'lines.txt', 'x-subtype')
6592.1.1 by Vincent Ladeuil
Fix minor incompatible change in email python 2.7.6 module.
120
        self.assertEqualDiff(complex_multipart_message('x-subtype'),
121
                             msg.as_string(BOUNDARY))
2625.6.1 by Adeodato Simó
New EmailMessage class, façade around email.Message and MIMEMultipart.
122
123
    def test_headers_accept_unicode_and_utf8(self):
7143.15.2 by Jelmer Vernooij
Run autopep8.
124
        for user in [u'Pepe P\xe9rez <pperez@ejemplo.com>',
125
                     'Pepe P\xc3\xa9red <pperez@ejemplo.com>']:
126
            msg = EmailMessage(user, user, user)  # no exception raised
2625.6.1 by Adeodato Simó
New EmailMessage class, façade around email.Message and MIMEMultipart.
127
128
            for header in ['From', 'To', 'Subject']:
129
                value = msg[header]
7143.15.2 by Jelmer Vernooij
Run autopep8.
130
                value.encode('ascii')  # no UnicodeDecodeError
2625.6.1 by Adeodato Simó
New EmailMessage class, façade around email.Message and MIMEMultipart.
131
132
    def test_headers_reject_8bit(self):
7143.15.2 by Jelmer Vernooij
Run autopep8.
133
        for i in range(3):  # from_address, to_address, subject
134
            x = [b'"J. Random Developer" <jrandom@example.com>'] * 3
7078.11.1 by Jelmer Vernooij
Fix email tests on Python 3.
135
            x[i] = b'Pepe P\xe9rez <pperez@ejemplo.com>'
2625.6.1 by Adeodato Simó
New EmailMessage class, façade around email.Message and MIMEMultipart.
136
            self.assertRaises(BzrBadParameterNotUnicode, EmailMessage, *x)
137
138
    def test_multiple_destinations(self):
7143.15.2 by Jelmer Vernooij
Run autopep8.
139
        to_addresses = ['to1@to.com', 'to2@to.com', 'to3@to.com']
2625.6.1 by Adeodato Simó
New EmailMessage class, façade around email.Message and MIMEMultipart.
140
        msg = EmailMessage('from@from.com', to_addresses, 'subject')
7143.15.13 by Jelmer Vernooij
Fix more syntax errors.
141
        self.assertContainsRe(msg.as_string(), 'To: '
7143.15.2 by Jelmer Vernooij
Run autopep8.
142
                              + ', '.join(to_addresses))  # re.M can't be passed, so no ^$
2625.6.1 by Adeodato Simó
New EmailMessage class, façade around email.Message and MIMEMultipart.
143
144
    def test_retrieving_headers(self):
145
        msg = EmailMessage('from@from.com', 'to@to.com', 'subject')
146
        for header, value in [('From', 'from@from.com'), ('To', 'to@to.com'),
7143.15.2 by Jelmer Vernooij
Run autopep8.
147
                              ('Subject', 'subject')]:
2625.6.1 by Adeodato Simó
New EmailMessage class, façade around email.Message and MIMEMultipart.
148
            self.assertEqual(value, msg.get(header))
149
            self.assertEqual(value, msg[header])
150
        self.assertEqual(None, msg.get('Does-Not-Exist'))
151
        self.assertEqual(None, msg['Does-Not-Exist'])
152
        self.assertEqual('None', msg.get('Does-Not-Exist', 'None'))
153
154
    def test_setting_headers(self):
155
        msg = EmailMessage('from@from.com', 'to@to.com', 'subject')
156
        msg['To'] = 'to2@to.com'
157
        msg['Cc'] = 'cc@cc.com'
158
        self.assertEqual('to2@to.com', msg['To'])
159
        self.assertEqual('cc@cc.com', msg['Cc'])
160
161
    def test_address_to_encoded_header(self):
162
        def decode(s):
163
            """Convert a RFC2047-encoded string to a unicode string."""
7479.2.1 by Jelmer Vernooij
Drop python2 support.
164
            return ''.join([chunk.decode(encoding or 'ascii')
165
                            for chunk, encoding in decode_header(s)])
2625.6.1 by Adeodato Simó
New EmailMessage class, façade around email.Message and MIMEMultipart.
166
167
        address = 'jrandom@example.com'
168
        encoded = EmailMessage.address_to_encoded_header(address)
169
        self.assertEqual(address, encoded)
170
171
        address = 'J Random Developer <jrandom@example.com>'
172
        encoded = EmailMessage.address_to_encoded_header(address)
173
        self.assertEqual(address, encoded)
174
175
        address = '"J. Random Developer" <jrandom@example.com>'
176
        encoded = EmailMessage.address_to_encoded_header(address)
177
        self.assertEqual(address, encoded)
178
7143.15.2 by Jelmer Vernooij
Run autopep8.
179
        address = u'Pepe P\xe9rez <pperez@ejemplo.com>'  # unicode ok
2625.6.1 by Adeodato Simó
New EmailMessage class, façade around email.Message and MIMEMultipart.
180
        encoded = EmailMessage.address_to_encoded_header(address)
7143.15.2 by Jelmer Vernooij
Run autopep8.
181
        # addr must be unencoded
182
        self.assertTrue('pperez@ejemplo.com' in encoded)
6614.1.3 by Vincent Ladeuil
Fix assertEquals being deprecated by using assertEqual.
183
        self.assertEqual(address, decode(encoded))
2625.6.1 by Adeodato Simó
New EmailMessage class, façade around email.Message and MIMEMultipart.
184
7143.15.2 by Jelmer Vernooij
Run autopep8.
185
        address = b'Pepe P\xe9rez <pperez@ejemplo.com>'  # ISO-8859-1 not ok
2625.6.1 by Adeodato Simó
New EmailMessage class, façade around email.Message and MIMEMultipart.
186
        self.assertRaises(BzrBadParameterNotUnicode,
7143.15.2 by Jelmer Vernooij
Run autopep8.
187
                          EmailMessage.address_to_encoded_header, address)
2625.6.1 by Adeodato Simó
New EmailMessage class, façade around email.Message and MIMEMultipart.
188
189
    def test_string_with_encoding(self):
190
        pairs = {
7143.15.2 by Jelmer Vernooij
Run autopep8.
191
            u'Pepe': (b'Pepe', 'ascii'),
192
            u'P\xe9rez': (b'P\xc3\xa9rez', 'utf-8'),
193
            b'P\xc3\xa9rez': (b'P\xc3\xa9rez', 'utf-8'),
194
            b'P\xe8rez': (b'P\xe8rez', '8-bit'),
2625.6.1 by Adeodato Simó
New EmailMessage class, façade around email.Message and MIMEMultipart.
195
        }
2625.6.3 by Adeodato Simó
Changes after review by John.
196
        for string_, pair in pairs.items():
197
            self.assertEqual(pair, EmailMessage.string_with_encoding(string_))
6592.1.1 by Vincent Ladeuil
Fix minor incompatible change in email python 2.7.6 module.
198
199
200
class TestSend(tests.TestCase):
201
202
    def setUp(self):
203
        super(TestSend, self).setUp()
204
        self.messages = []
205
206
        def send_as_append(_self, msg):
207
            self.messages.append(msg.as_string(BOUNDARY))
208
209
        self.overrideAttr(SMTPConnection, 'send_email', send_as_append)
210
211
    def send_email(self, attachment=None, attachment_filename=None,
212
                   attachment_mime_subtype='plain'):
213
        class FakeConfig:
214
            def get(self, option):
215
                return None
216
217
        EmailMessage.send(FakeConfig(), 'from@from.com', 'to@to.com',
218
                          'subject', 'body',
219
                          attachment=attachment,
220
                          attachment_filename=attachment_filename,
221
                          attachment_mime_subtype=attachment_mime_subtype)
222
223
    def assertMessage(self, expected):
224
        self.assertLength(1, self.messages)
225
        self.assertEqualDiff(expected, self.messages[0])
226
227
    def test_send_plain(self):
228
        self.send_email(u'a\nb\nc\nd\ne\n', 'lines.txt')
229
        self.assertMessage(complex_multipart_message('plain'))
230
231
    def test_send_patch(self):
232
        self.send_email(u'a\nb\nc\nd\ne\n', 'lines.txt', 'x-patch')
233
        self.assertMessage(complex_multipart_message('x-patch'))
234
235
    def test_send_simple(self):
7143.15.2 by Jelmer Vernooij
Run autopep8.
236
        self.send_email()
237
        self.assertMessage(SIMPLE_MESSAGE_ASCII)