/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
7078.11.1 by Jelmer Vernooij
Fix email tests on Python 3.
23
from ..sixish import PY3, text_type
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
24
from ..smtp_connection import SMTPConnection
25
from .. import tests
2625.6.1 by Adeodato Simó
New EmailMessage class, façade around email.Message and MIMEMultipart.
26
27
EMPTY_MESSAGE = '''\
28
From: from@from.com
29
Subject: subject
30
To: to@to.com
31
User-Agent: Bazaar (%s)
32
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
33
''' % _breezy_version
2625.6.1 by Adeodato Simó
New EmailMessage class, façade around email.Message and MIMEMultipart.
34
35
_SIMPLE_MESSAGE = '''\
36
MIME-Version: 1.0
37
Content-Type: text/plain; charset="%%s"
38
Content-Transfer-Encoding: %%s
39
From: from@from.com
40
Subject: subject
41
To: to@to.com
42
User-Agent: Bazaar (%s)
43
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
44
%%s''' % _breezy_version
2625.6.1 by Adeodato Simó
New EmailMessage class, façade around email.Message and MIMEMultipart.
45
46
SIMPLE_MESSAGE_ASCII = _SIMPLE_MESSAGE % ('us-ascii', '7bit', 'body')
47
SIMPLE_MESSAGE_UTF8 = _SIMPLE_MESSAGE % ('utf-8', 'base64', 'YsOzZHk=\n')
2639.1.2 by John Arbash Meinel
Some cleanups for the EmailMessage class.
48
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.
49
50
51
BOUNDARY = '=====123456=='
52
53
_MULTIPART_HEAD = '''\
54
Content-Type: multipart/mixed; boundary="%(boundary)s"
55
MIME-Version: 1.0
56
From: from@from.com
57
Subject: subject
58
To: to@to.com
59
User-Agent: Bazaar (%(version)s)
60
61
--%(boundary)s
62
MIME-Version: 1.0
63
Content-Type: text/plain; charset="us-ascii"
64
Content-Transfer-Encoding: 7bit
65
Content-Disposition: inline
66
67
body
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
68
''' %  { 'version': _breezy_version, 'boundary': BOUNDARY }
2625.6.1 by Adeodato Simó
New EmailMessage class, façade around email.Message and MIMEMultipart.
69
6592.1.1 by Vincent Ladeuil
Fix minor incompatible change in email python 2.7.6 module.
70
71
def final_newline_or_not(msg):
72
    if sys.version_info >= (2, 7, 6):
73
        # Some internals of python's email module changed in an (minor)
74
        # incompatible way: a final newline is appended in 2.7.6...
75
       msg += '\n'
76
    return msg
77
78
79
def simple_multipart_message():
80
    msg = _MULTIPART_HEAD + '--%s--' % BOUNDARY
81
    return final_newline_or_not(msg)
82
83
84
def complex_multipart_message(typ):
85
    msg = _MULTIPART_HEAD + '''\
2625.6.1 by Adeodato Simó
New EmailMessage class, façade around email.Message and MIMEMultipart.
86
--%(boundary)s
87
MIME-Version: 1.0
88
Content-Type: text/%%s; charset="us-ascii"; name="lines.txt"
89
Content-Transfer-Encoding: 7bit
90
Content-Disposition: inline
91
92
a
93
b
94
c
95
d
96
e
97
98
--%(boundary)s--''' %  { 'boundary': BOUNDARY }
6592.1.1 by Vincent Ladeuil
Fix minor incompatible change in email python 2.7.6 module.
99
    msg = final_newline_or_not(msg)
100
    return msg % (typ,)
101
102
103
class TestEmailMessage(tests.TestCase):
2625.6.1 by Adeodato Simó
New EmailMessage class, façade around email.Message and MIMEMultipart.
104
105
    def test_empty_message(self):
106
        msg = EmailMessage('from@from.com', 'to@to.com', 'subject')
6809.1.1 by Martin
Apply 2to3 ws_comma fixer
107
        self.assertEqualDiff(EMPTY_MESSAGE, msg.as_string())
2625.6.1 by Adeodato Simó
New EmailMessage class, façade around email.Message and MIMEMultipart.
108
109
    def test_simple_message(self):
110
        pairs = {
7058.4.2 by Jelmer Vernooij
Fix boundaries handling.
111
            b'body': SIMPLE_MESSAGE_ASCII,
2625.6.1 by Adeodato Simó
New EmailMessage class, façade around email.Message and MIMEMultipart.
112
            u'b\xf3dy': SIMPLE_MESSAGE_UTF8,
7058.4.2 by Jelmer Vernooij
Fix boundaries handling.
113
            b'b\xc3\xb3dy': SIMPLE_MESSAGE_UTF8,
114
            b'b\xf4dy': SIMPLE_MESSAGE_8BIT,
2625.6.1 by Adeodato Simó
New EmailMessage class, façade around email.Message and MIMEMultipart.
115
        }
116
        for body, expected in pairs.items():
117
            msg = EmailMessage('from@from.com', 'to@to.com', 'subject', body)
118
            self.assertEqualDiff(expected, msg.as_string())
119
6592.1.1 by Vincent Ladeuil
Fix minor incompatible change in email python 2.7.6 module.
120
    def test_multipart_message_simple(self):
2625.6.1 by Adeodato Simó
New EmailMessage class, façade around email.Message and MIMEMultipart.
121
        msg = EmailMessage('from@from.com', 'to@to.com', 'subject')
122
        msg.add_inline_attachment('body')
6592.1.1 by Vincent Ladeuil
Fix minor incompatible change in email python 2.7.6 module.
123
        self.assertEqualDiff(simple_multipart_message(),
124
                             msg.as_string(BOUNDARY))
125
126
127
    def test_multipart_message_complex(self):
2625.6.1 by Adeodato Simó
New EmailMessage class, façade around email.Message and MIMEMultipart.
128
        msg = EmailMessage('from@from.com', 'to@to.com', 'subject', 'body')
129
        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.
130
        self.assertEqualDiff(complex_multipart_message('x-subtype'),
131
                             msg.as_string(BOUNDARY))
2625.6.1 by Adeodato Simó
New EmailMessage class, façade around email.Message and MIMEMultipart.
132
133
    def test_headers_accept_unicode_and_utf8(self):
2625.6.3 by Adeodato Simó
Changes after review by John.
134
        for user in [ u'Pepe P\xe9rez <pperez@ejemplo.com>',
2625.6.1 by Adeodato Simó
New EmailMessage class, façade around email.Message and MIMEMultipart.
135
                'Pepe P\xc3\xa9red <pperez@ejemplo.com>' ]:
2625.6.3 by Adeodato Simó
Changes after review by John.
136
            msg = EmailMessage(user, user, user) # no exception raised
2625.6.1 by Adeodato Simó
New EmailMessage class, façade around email.Message and MIMEMultipart.
137
138
            for header in ['From', 'To', 'Subject']:
139
                value = msg[header]
7078.11.1 by Jelmer Vernooij
Fix email tests on Python 3.
140
                value.encode('ascii') # no UnicodeDecodeError
2625.6.1 by Adeodato Simó
New EmailMessage class, façade around email.Message and MIMEMultipart.
141
142
    def test_headers_reject_8bit(self):
143
        for i in range(3): # from_address, to_address, subject
7078.11.1 by Jelmer Vernooij
Fix email tests on Python 3.
144
            x = [ b'"J. Random Developer" <jrandom@example.com>' ] * 3
145
            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.
146
            self.assertRaises(BzrBadParameterNotUnicode, EmailMessage, *x)
147
148
    def test_multiple_destinations(self):
149
        to_addresses = [ 'to1@to.com', 'to2@to.com', 'to3@to.com' ]
150
        msg = EmailMessage('from@from.com', to_addresses, 'subject')
151
        self.assertContainsRe(msg.as_string(), 'To: ' +
152
                ', '.join(to_addresses)) # re.M can't be passed, so no ^$
153
154
    def test_retrieving_headers(self):
155
        msg = EmailMessage('from@from.com', 'to@to.com', 'subject')
156
        for header, value in [('From', 'from@from.com'), ('To', 'to@to.com'),
157
                ('Subject', 'subject')]:
158
            self.assertEqual(value, msg.get(header))
159
            self.assertEqual(value, msg[header])
160
        self.assertEqual(None, msg.get('Does-Not-Exist'))
161
        self.assertEqual(None, msg['Does-Not-Exist'])
162
        self.assertEqual('None', msg.get('Does-Not-Exist', 'None'))
163
164
    def test_setting_headers(self):
165
        msg = EmailMessage('from@from.com', 'to@to.com', 'subject')
166
        msg['To'] = 'to2@to.com'
167
        msg['Cc'] = 'cc@cc.com'
168
        self.assertEqual('to2@to.com', msg['To'])
169
        self.assertEqual('cc@cc.com', msg['Cc'])
170
171
    def test_address_to_encoded_header(self):
172
        def decode(s):
173
            """Convert a RFC2047-encoded string to a unicode string."""
7078.11.1 by Jelmer Vernooij
Fix email tests on Python 3.
174
            if PY3:
175
                return ''.join([chunk.decode(encoding or 'ascii')
176
                                for chunk, encoding in decode_header(s)])
177
            else:
178
                # Cope with python2 stripping whitespace.
179
                # https://bugs.python.org/issue1467619
180
                return ' '.join([chunk.decode(encoding or 'ascii')
181
                                 for chunk, encoding in decode_header(s)])
2625.6.1 by Adeodato Simó
New EmailMessage class, façade around email.Message and MIMEMultipart.
182
183
        address = 'jrandom@example.com'
184
        encoded = EmailMessage.address_to_encoded_header(address)
185
        self.assertEqual(address, encoded)
186
187
        address = 'J Random Developer <jrandom@example.com>'
188
        encoded = EmailMessage.address_to_encoded_header(address)
189
        self.assertEqual(address, encoded)
190
191
        address = '"J. Random Developer" <jrandom@example.com>'
192
        encoded = EmailMessage.address_to_encoded_header(address)
193
        self.assertEqual(address, encoded)
194
195
        address = u'Pepe P\xe9rez <pperez@ejemplo.com>' # unicode ok
196
        encoded = EmailMessage.address_to_encoded_header(address)
6614.1.1 by Vincent Ladeuil
Fix assert_ being deprecated by using assertTrue.
197
        self.assertTrue('pperez@ejemplo.com' in encoded) # addr must be unencoded
6614.1.3 by Vincent Ladeuil
Fix assertEquals being deprecated by using assertEqual.
198
        self.assertEqual(address, decode(encoded))
2625.6.1 by Adeodato Simó
New EmailMessage class, façade around email.Message and MIMEMultipart.
199
7078.11.1 by Jelmer Vernooij
Fix email tests on Python 3.
200
        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.
201
        self.assertRaises(BzrBadParameterNotUnicode,
202
                EmailMessage.address_to_encoded_header, address)
203
204
    def test_string_with_encoding(self):
205
        pairs = {
7045.5.4 by Jelmer Vernooij
Fix a few more tests.
206
                u'Pepe':        (b'Pepe', 'ascii'),
7058.4.2 by Jelmer Vernooij
Fix boundaries handling.
207
                u'P\xe9rez':    (b'P\xc3\xa9rez', 'utf-8'),
208
                b'P\xc3\xa9rez': (b'P\xc3\xa9rez', 'utf-8'),
209
                b'P\xe8rez':     (b'P\xe8rez', '8-bit'),
2625.6.1 by Adeodato Simó
New EmailMessage class, façade around email.Message and MIMEMultipart.
210
        }
2625.6.3 by Adeodato Simó
Changes after review by John.
211
        for string_, pair in pairs.items():
212
            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.
213
214
215
class TestSend(tests.TestCase):
216
217
    def setUp(self):
218
        super(TestSend, self).setUp()
219
        self.messages = []
220
221
        def send_as_append(_self, msg):
222
            self.messages.append(msg.as_string(BOUNDARY))
223
224
        self.overrideAttr(SMTPConnection, 'send_email', send_as_append)
225
226
227
228
    def send_email(self, attachment=None, attachment_filename=None,
229
                   attachment_mime_subtype='plain'):
230
        class FakeConfig:
231
            def get(self, option):
232
                return None
233
234
        EmailMessage.send(FakeConfig(), 'from@from.com', 'to@to.com',
235
                          'subject', 'body',
236
                          attachment=attachment,
237
                          attachment_filename=attachment_filename,
238
                          attachment_mime_subtype=attachment_mime_subtype)
239
240
    def assertMessage(self, expected):
241
        self.assertLength(1, self.messages)
242
        self.assertEqualDiff(expected, self.messages[0])
243
244
    def test_send_plain(self):
245
        self.send_email(u'a\nb\nc\nd\ne\n', 'lines.txt')
246
        self.assertMessage(complex_multipart_message('plain'))
247
248
    def test_send_patch(self):
249
        self.send_email(u'a\nb\nc\nd\ne\n', 'lines.txt', 'x-patch')
250
        self.assertMessage(complex_multipart_message('x-patch'))
251
252
    def test_send_simple(self):
253
          self.send_email()
254
          self.assertMessage(SIMPLE_MESSAGE_ASCII)
255