~ubuntu-branches/ubuntu/trusty/python3.4/trusty-proposed

« back to all changes in this revision

Viewing changes to Lib/test/test_email/test__header_value_parser.py

  • Committer: Package Import Robot
  • Author(s): Matthias Klose
  • Date: 2013-11-25 09:44:27 UTC
  • Revision ID: package-import@ubuntu.com-20131125094427-lzxj8ap5w01lmo7f
Tags: upstream-3.4~b1
Import upstream version 3.4~b1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
import string
 
2
import unittest
 
3
from email import _header_value_parser as parser
 
4
from email import errors
 
5
from email import policy
 
6
from test.test_email import TestEmailBase, parameterize
 
7
 
 
8
class TestTokens(TestEmailBase):
 
9
 
 
10
    # EWWhiteSpaceTerminal
 
11
 
 
12
    def test_EWWhiteSpaceTerminal(self):
 
13
        x = parser.EWWhiteSpaceTerminal(' \t', 'fws')
 
14
        self.assertEqual(x, ' \t')
 
15
        self.assertEqual(str(x), '')
 
16
        self.assertEqual(x.value, '')
 
17
        self.assertEqual(x.encoded, ' \t')
 
18
 
 
19
    # UnstructuredTokenList
 
20
 
 
21
    def test_undecodable_bytes_error_preserved(self):
 
22
        badstr = b"le pouf c\xaflebre".decode('ascii', 'surrogateescape')
 
23
        unst = parser.get_unstructured(badstr)
 
24
        self.assertDefectsEqual(unst.all_defects, [errors.UndecodableBytesDefect])
 
25
        parts = list(unst.parts)
 
26
        self.assertDefectsEqual(parts[0].all_defects, [])
 
27
        self.assertDefectsEqual(parts[1].all_defects, [])
 
28
        self.assertDefectsEqual(parts[2].all_defects, [errors.UndecodableBytesDefect])
 
29
 
 
30
 
 
31
class TestParserMixin:
 
32
 
 
33
    def _assert_results(self, tl, rest, string, value, defects, remainder,
 
34
                        comments=None):
 
35
        self.assertEqual(str(tl), string)
 
36
        self.assertEqual(tl.value, value)
 
37
        self.assertDefectsEqual(tl.all_defects, defects)
 
38
        self.assertEqual(rest, remainder)
 
39
        if comments is not None:
 
40
            self.assertEqual(tl.comments, comments)
 
41
 
 
42
    def _test_get_x(self, method, source, string, value, defects,
 
43
                          remainder, comments=None):
 
44
        tl, rest = method(source)
 
45
        self._assert_results(tl, rest, string, value, defects, remainder,
 
46
                             comments=None)
 
47
        return tl
 
48
 
 
49
    def _test_parse_x(self, method, input, string, value, defects,
 
50
                             comments=None):
 
51
        tl = method(input)
 
52
        self._assert_results(tl, '', string, value, defects, '', comments)
 
53
        return tl
 
54
 
 
55
 
 
56
class TestParser(TestParserMixin, TestEmailBase):
 
57
 
 
58
    # _wsp_splitter
 
59
 
 
60
    rfc_printable_ascii = bytes(range(33, 127)).decode('ascii')
 
61
    rfc_atext_chars = (string.ascii_letters + string.digits +
 
62
                        "!#$%&\'*+-/=?^_`{}|~")
 
63
    rfc_dtext_chars = rfc_printable_ascii.translate(str.maketrans('','',r'\[]'))
 
64
 
 
65
    def test__wsp_splitter_one_word(self):
 
66
        self.assertEqual(parser._wsp_splitter('foo', 1), ['foo'])
 
67
 
 
68
    def test__wsp_splitter_two_words(self):
 
69
        self.assertEqual(parser._wsp_splitter('foo def', 1),
 
70
                                               ['foo', ' ', 'def'])
 
71
 
 
72
    def test__wsp_splitter_ws_runs(self):
 
73
        self.assertEqual(parser._wsp_splitter('foo \t def jik', 1),
 
74
                                              ['foo', ' \t ', 'def jik'])
 
75
 
 
76
 
 
77
    # get_fws
 
78
 
 
79
    def test_get_fws_only(self):
 
80
        fws = self._test_get_x(parser.get_fws, ' \t  ', ' \t  ', ' ', [], '')
 
81
        self.assertEqual(fws.token_type, 'fws')
 
82
 
 
83
    def test_get_fws_space(self):
 
84
        self._test_get_x(parser.get_fws, ' foo', ' ', ' ', [], 'foo')
 
85
 
 
86
    def test_get_fws_ws_run(self):
 
87
        self._test_get_x(parser.get_fws, ' \t foo ', ' \t ', ' ', [], 'foo ')
 
88
 
 
89
    # get_encoded_word
 
90
 
 
91
    def test_get_encoded_word_missing_start_raises(self):
 
92
        with self.assertRaises(errors.HeaderParseError):
 
93
            parser.get_encoded_word('abc')
 
94
 
 
95
    def test_get_encoded_word_missing_end_raises(self):
 
96
        with self.assertRaises(errors.HeaderParseError):
 
97
            parser.get_encoded_word('=?abc')
 
98
 
 
99
    def test_get_encoded_word_missing_middle_raises(self):
 
100
        with self.assertRaises(errors.HeaderParseError):
 
101
            parser.get_encoded_word('=?abc?=')
 
102
 
 
103
    def test_get_encoded_word_valid_ew(self):
 
104
        self._test_get_x(parser.get_encoded_word,
 
105
                         '=?us-ascii?q?this_is_a_test?=  bird',
 
106
                         'this is a test',
 
107
                         'this is a test',
 
108
                         [],
 
109
                         '  bird')
 
110
 
 
111
    def test_get_encoded_word_internal_spaces(self):
 
112
        self._test_get_x(parser.get_encoded_word,
 
113
                         '=?us-ascii?q?this is a test?=  bird',
 
114
                         'this is a test',
 
115
                         'this is a test',
 
116
                         [errors.InvalidHeaderDefect],
 
117
                         '  bird')
 
118
 
 
119
    def test_get_encoded_word_gets_first(self):
 
120
        self._test_get_x(parser.get_encoded_word,
 
121
                         '=?us-ascii?q?first?=  =?utf-8?q?second?=',
 
122
                         'first',
 
123
                         'first',
 
124
                         [],
 
125
                         '  =?utf-8?q?second?=')
 
126
 
 
127
    def test_get_encoded_word_gets_first_even_if_no_space(self):
 
128
        self._test_get_x(parser.get_encoded_word,
 
129
                         '=?us-ascii?q?first?==?utf-8?q?second?=',
 
130
                         'first',
 
131
                         'first',
 
132
                         [],
 
133
                         '=?utf-8?q?second?=')
 
134
 
 
135
    def test_get_encoded_word_sets_extra_attributes(self):
 
136
        ew = self._test_get_x(parser.get_encoded_word,
 
137
                         '=?us-ascii*jive?q?first_second?=',
 
138
                         'first second',
 
139
                         'first second',
 
140
                         [],
 
141
                         '')
 
142
        self.assertEqual(ew.encoded, '=?us-ascii*jive?q?first_second?=')
 
143
        self.assertEqual(ew.charset, 'us-ascii')
 
144
        self.assertEqual(ew.lang, 'jive')
 
145
 
 
146
    def test_get_encoded_word_lang_default_is_blank(self):
 
147
        ew = self._test_get_x(parser.get_encoded_word,
 
148
                         '=?us-ascii?q?first_second?=',
 
149
                         'first second',
 
150
                         'first second',
 
151
                         [],
 
152
                         '')
 
153
        self.assertEqual(ew.encoded, '=?us-ascii?q?first_second?=')
 
154
        self.assertEqual(ew.charset, 'us-ascii')
 
155
        self.assertEqual(ew.lang, '')
 
156
 
 
157
    def test_get_encoded_word_non_printable_defect(self):
 
158
        self._test_get_x(parser.get_encoded_word,
 
159
                         '=?us-ascii?q?first\x02second?=',
 
160
                         'first\x02second',
 
161
                         'first\x02second',
 
162
                         [errors.NonPrintableDefect],
 
163
                         '')
 
164
 
 
165
    def test_get_encoded_word_leading_internal_space(self):
 
166
        self._test_get_x(parser.get_encoded_word,
 
167
                        '=?us-ascii?q?=20foo?=',
 
168
                        ' foo',
 
169
                        ' foo',
 
170
                        [],
 
171
                        '')
 
172
 
 
173
    def test_get_encoded_word_quopri_utf_escape_follows_cte(self):
 
174
        # Issue 18044
 
175
        self._test_get_x(parser.get_encoded_word,
 
176
                        '=?utf-8?q?=C3=89ric?=',
 
177
                        'Éric',
 
178
                        'Éric',
 
179
                        [],
 
180
                        '')
 
181
 
 
182
    # get_unstructured
 
183
 
 
184
    def _get_unst(self, value):
 
185
        token = parser.get_unstructured(value)
 
186
        return token, ''
 
187
 
 
188
    def test_get_unstructured_null(self):
 
189
        self._test_get_x(self._get_unst, '', '', '', [], '')
 
190
 
 
191
    def test_get_unstructured_one_word(self):
 
192
        self._test_get_x(self._get_unst, 'foo', 'foo', 'foo', [], '')
 
193
 
 
194
    def test_get_unstructured_normal_phrase(self):
 
195
        self._test_get_x(self._get_unst, 'foo bar bird',
 
196
                                         'foo bar bird',
 
197
                                         'foo bar bird',
 
198
                                         [],
 
199
                                         '')
 
200
 
 
201
    def test_get_unstructured_normal_phrase_with_whitespace(self):
 
202
        self._test_get_x(self._get_unst, 'foo \t bar      bird',
 
203
                                         'foo \t bar      bird',
 
204
                                         'foo bar bird',
 
205
                                         [],
 
206
                                         '')
 
207
 
 
208
    def test_get_unstructured_leading_whitespace(self):
 
209
        self._test_get_x(self._get_unst, '  foo bar',
 
210
                                         '  foo bar',
 
211
                                         ' foo bar',
 
212
                                         [],
 
213
                                         '')
 
214
 
 
215
    def test_get_unstructured_trailing_whitespace(self):
 
216
        self._test_get_x(self._get_unst, 'foo bar  ',
 
217
                                         'foo bar  ',
 
218
                                         'foo bar ',
 
219
                                         [],
 
220
                                         '')
 
221
 
 
222
    def test_get_unstructured_leading_and_trailing_whitespace(self):
 
223
        self._test_get_x(self._get_unst, '  foo bar  ',
 
224
                                         '  foo bar  ',
 
225
                                         ' foo bar ',
 
226
                                         [],
 
227
                                         '')
 
228
 
 
229
    def test_get_unstructured_one_valid_ew_no_ws(self):
 
230
        self._test_get_x(self._get_unst, '=?us-ascii?q?bar?=',
 
231
                                         'bar',
 
232
                                         'bar',
 
233
                                         [],
 
234
                                         '')
 
235
 
 
236
    def test_get_unstructured_one_ew_trailing_ws(self):
 
237
        self._test_get_x(self._get_unst, '=?us-ascii?q?bar?=  ',
 
238
                                         'bar  ',
 
239
                                         'bar ',
 
240
                                         [],
 
241
                                         '')
 
242
 
 
243
    def test_get_unstructured_one_valid_ew_trailing_text(self):
 
244
        self._test_get_x(self._get_unst, '=?us-ascii?q?bar?= bird',
 
245
                                         'bar bird',
 
246
                                         'bar bird',
 
247
                                         [],
 
248
                                         '')
 
249
 
 
250
    def test_get_unstructured_phrase_with_ew_in_middle_of_text(self):
 
251
        self._test_get_x(self._get_unst, 'foo =?us-ascii?q?bar?= bird',
 
252
                                         'foo bar bird',
 
253
                                         'foo bar bird',
 
254
                                         [],
 
255
                                         '')
 
256
 
 
257
    def test_get_unstructured_phrase_with_two_ew(self):
 
258
        self._test_get_x(self._get_unst,
 
259
            'foo =?us-ascii?q?bar?= =?us-ascii?q?bird?=',
 
260
            'foo barbird',
 
261
            'foo barbird',
 
262
            [],
 
263
            '')
 
264
 
 
265
    def test_get_unstructured_phrase_with_two_ew_trailing_ws(self):
 
266
        self._test_get_x(self._get_unst,
 
267
            'foo =?us-ascii?q?bar?= =?us-ascii?q?bird?=   ',
 
268
            'foo barbird   ',
 
269
            'foo barbird ',
 
270
            [],
 
271
            '')
 
272
 
 
273
    def test_get_unstructured_phrase_with_ew_with_leading_ws(self):
 
274
        self._test_get_x(self._get_unst,
 
275
            '  =?us-ascii?q?bar?=',
 
276
            '  bar',
 
277
            ' bar',
 
278
            [],
 
279
            '')
 
280
 
 
281
    def test_get_unstructured_phrase_with_two_ew_extra_ws(self):
 
282
        self._test_get_x(self._get_unst,
 
283
            'foo =?us-ascii?q?bar?= \t  =?us-ascii?q?bird?=',
 
284
            'foo barbird',
 
285
            'foo barbird',
 
286
            [],
 
287
            '')
 
288
 
 
289
    def test_get_unstructured_two_ew_extra_ws_trailing_text(self):
 
290
        self._test_get_x(self._get_unst,
 
291
            '=?us-ascii?q?test?=   =?us-ascii?q?foo?=  val',
 
292
            'testfoo  val',
 
293
            'testfoo val',
 
294
            [],
 
295
            '')
 
296
 
 
297
    def test_get_unstructured_ew_with_internal_ws(self):
 
298
        self._test_get_x(self._get_unst,
 
299
            '=?iso-8859-1?q?hello=20world?=',
 
300
            'hello world',
 
301
            'hello world',
 
302
            [],
 
303
            '')
 
304
 
 
305
    def test_get_unstructured_ew_with_internal_leading_ws(self):
 
306
        self._test_get_x(self._get_unst,
 
307
            '   =?us-ascii?q?=20test?=   =?us-ascii?q?=20foo?=  val',
 
308
            '    test foo  val',
 
309
            '  test foo val',
 
310
            [],
 
311
            '')
 
312
 
 
313
    def test_get_unstructured_invaild_ew(self):
 
314
        self._test_get_x(self._get_unst,
 
315
            '=?test val',
 
316
            '=?test val',
 
317
            '=?test val',
 
318
            [],
 
319
            '')
 
320
 
 
321
    def test_get_unstructured_undecodable_bytes(self):
 
322
        self._test_get_x(self._get_unst,
 
323
            b'test \xACfoo  val'.decode('ascii', 'surrogateescape'),
 
324
            'test \uDCACfoo  val',
 
325
            'test \uDCACfoo val',
 
326
            [errors.UndecodableBytesDefect],
 
327
            '')
 
328
 
 
329
    def test_get_unstructured_undecodable_bytes_in_EW(self):
 
330
        self._test_get_x(self._get_unst,
 
331
            (b'=?us-ascii?q?=20test?=   =?us-ascii?q?=20\xACfoo?='
 
332
                b'  val').decode('ascii', 'surrogateescape'),
 
333
            ' test \uDCACfoo  val',
 
334
            ' test \uDCACfoo val',
 
335
            [errors.UndecodableBytesDefect]*2,
 
336
            '')
 
337
 
 
338
    def test_get_unstructured_missing_base64_padding(self):
 
339
        self._test_get_x(self._get_unst,
 
340
            '=?utf-8?b?dmk?=',
 
341
            'vi',
 
342
            'vi',
 
343
            [errors.InvalidBase64PaddingDefect],
 
344
            '')
 
345
 
 
346
    def test_get_unstructured_invalid_base64_character(self):
 
347
        self._test_get_x(self._get_unst,
 
348
            '=?utf-8?b?dm\x01k===?=',
 
349
            'vi',
 
350
            'vi',
 
351
            [errors.InvalidBase64CharactersDefect],
 
352
            '')
 
353
 
 
354
    def test_get_unstructured_invalid_base64_character_and_bad_padding(self):
 
355
        self._test_get_x(self._get_unst,
 
356
            '=?utf-8?b?dm\x01k?=',
 
357
            'vi',
 
358
            'vi',
 
359
            [errors.InvalidBase64CharactersDefect,
 
360
             errors.InvalidBase64PaddingDefect],
 
361
            '')
 
362
 
 
363
    def test_get_unstructured_no_whitespace_between_ews(self):
 
364
        self._test_get_x(self._get_unst,
 
365
            '=?utf-8?q?foo?==?utf-8?q?bar?=',
 
366
            'foobar',
 
367
            'foobar',
 
368
            [errors.InvalidHeaderDefect],
 
369
            '')
 
370
 
 
371
    # get_qp_ctext
 
372
 
 
373
    def test_get_qp_ctext_only(self):
 
374
        ptext = self._test_get_x(parser.get_qp_ctext,
 
375
                                'foobar', 'foobar', ' ', [], '')
 
376
        self.assertEqual(ptext.token_type, 'ptext')
 
377
 
 
378
    def test_get_qp_ctext_all_printables(self):
 
379
        with_qp = self.rfc_printable_ascii.replace('\\', '\\\\')
 
380
        with_qp = with_qp.  replace('(', r'\(')
 
381
        with_qp = with_qp.replace(')', r'\)')
 
382
        ptext = self._test_get_x(parser.get_qp_ctext,
 
383
                                 with_qp, self.rfc_printable_ascii, ' ', [], '')
 
384
 
 
385
    def test_get_qp_ctext_two_words_gets_first(self):
 
386
        self._test_get_x(parser.get_qp_ctext,
 
387
                        'foo de', 'foo', ' ', [], ' de')
 
388
 
 
389
    def test_get_qp_ctext_following_wsp_preserved(self):
 
390
        self._test_get_x(parser.get_qp_ctext,
 
391
                        'foo \t\tde', 'foo', ' ', [], ' \t\tde')
 
392
 
 
393
    def test_get_qp_ctext_up_to_close_paren_only(self):
 
394
        self._test_get_x(parser.get_qp_ctext,
 
395
                        'foo)', 'foo', ' ', [], ')')
 
396
 
 
397
    def test_get_qp_ctext_wsp_before_close_paren_preserved(self):
 
398
        self._test_get_x(parser.get_qp_ctext,
 
399
                        'foo  )', 'foo', ' ', [], '  )')
 
400
 
 
401
    def test_get_qp_ctext_close_paren_mid_word(self):
 
402
        self._test_get_x(parser.get_qp_ctext,
 
403
                        'foo)bar', 'foo', ' ', [], ')bar')
 
404
 
 
405
    def test_get_qp_ctext_up_to_open_paren_only(self):
 
406
        self._test_get_x(parser.get_qp_ctext,
 
407
                        'foo(', 'foo', ' ', [], '(')
 
408
 
 
409
    def test_get_qp_ctext_wsp_before_open_paren_preserved(self):
 
410
        self._test_get_x(parser.get_qp_ctext,
 
411
                        'foo  (', 'foo', ' ', [], '  (')
 
412
 
 
413
    def test_get_qp_ctext_open_paren_mid_word(self):
 
414
        self._test_get_x(parser.get_qp_ctext,
 
415
                        'foo(bar', 'foo', ' ', [], '(bar')
 
416
 
 
417
    def test_get_qp_ctext_non_printables(self):
 
418
        ptext = self._test_get_x(parser.get_qp_ctext,
 
419
                                'foo\x00bar)', 'foo\x00bar', ' ',
 
420
                                [errors.NonPrintableDefect], ')')
 
421
        self.assertEqual(ptext.defects[0].non_printables[0], '\x00')
 
422
 
 
423
    # get_qcontent
 
424
 
 
425
    def test_get_qcontent_only(self):
 
426
        ptext = self._test_get_x(parser.get_qcontent,
 
427
                                'foobar', 'foobar', 'foobar', [], '')
 
428
        self.assertEqual(ptext.token_type, 'ptext')
 
429
 
 
430
    def test_get_qcontent_all_printables(self):
 
431
        with_qp = self.rfc_printable_ascii.replace('\\', '\\\\')
 
432
        with_qp = with_qp.  replace('"', r'\"')
 
433
        ptext = self._test_get_x(parser.get_qcontent, with_qp,
 
434
                                 self.rfc_printable_ascii,
 
435
                                 self.rfc_printable_ascii, [], '')
 
436
 
 
437
    def test_get_qcontent_two_words_gets_first(self):
 
438
        self._test_get_x(parser.get_qcontent,
 
439
                        'foo de', 'foo', 'foo', [], ' de')
 
440
 
 
441
    def test_get_qcontent_following_wsp_preserved(self):
 
442
        self._test_get_x(parser.get_qcontent,
 
443
                        'foo \t\tde', 'foo', 'foo', [], ' \t\tde')
 
444
 
 
445
    def test_get_qcontent_up_to_dquote_only(self):
 
446
        self._test_get_x(parser.get_qcontent,
 
447
                        'foo"', 'foo', 'foo', [], '"')
 
448
 
 
449
    def test_get_qcontent_wsp_before_close_paren_preserved(self):
 
450
        self._test_get_x(parser.get_qcontent,
 
451
                        'foo  "', 'foo', 'foo', [], '  "')
 
452
 
 
453
    def test_get_qcontent_close_paren_mid_word(self):
 
454
        self._test_get_x(parser.get_qcontent,
 
455
                        'foo"bar', 'foo', 'foo', [], '"bar')
 
456
 
 
457
    def test_get_qcontent_non_printables(self):
 
458
        ptext = self._test_get_x(parser.get_qcontent,
 
459
                                'foo\x00fg"', 'foo\x00fg', 'foo\x00fg',
 
460
                                [errors.NonPrintableDefect], '"')
 
461
        self.assertEqual(ptext.defects[0].non_printables[0], '\x00')
 
462
 
 
463
    # get_atext
 
464
 
 
465
    def test_get_atext_only(self):
 
466
        atext = self._test_get_x(parser.get_atext,
 
467
                                'foobar', 'foobar', 'foobar', [], '')
 
468
        self.assertEqual(atext.token_type, 'atext')
 
469
 
 
470
    def test_get_atext_all_atext(self):
 
471
        atext = self._test_get_x(parser.get_atext, self.rfc_atext_chars,
 
472
                                 self.rfc_atext_chars,
 
473
                                 self.rfc_atext_chars, [], '')
 
474
 
 
475
    def test_get_atext_two_words_gets_first(self):
 
476
        self._test_get_x(parser.get_atext,
 
477
                        'foo bar', 'foo', 'foo', [], ' bar')
 
478
 
 
479
    def test_get_atext_following_wsp_preserved(self):
 
480
        self._test_get_x(parser.get_atext,
 
481
                        'foo \t\tbar', 'foo', 'foo', [], ' \t\tbar')
 
482
 
 
483
    def test_get_atext_up_to_special(self):
 
484
        self._test_get_x(parser.get_atext,
 
485
                        'foo@bar', 'foo', 'foo', [], '@bar')
 
486
 
 
487
    def test_get_atext_non_printables(self):
 
488
        atext = self._test_get_x(parser.get_atext,
 
489
                                'foo\x00bar(', 'foo\x00bar', 'foo\x00bar',
 
490
                                [errors.NonPrintableDefect], '(')
 
491
        self.assertEqual(atext.defects[0].non_printables[0], '\x00')
 
492
 
 
493
    # get_bare_quoted_string
 
494
 
 
495
    def test_get_bare_quoted_string_only(self):
 
496
        bqs = self._test_get_x(parser.get_bare_quoted_string,
 
497
                               '"foo"', '"foo"', 'foo', [], '')
 
498
        self.assertEqual(bqs.token_type, 'bare-quoted-string')
 
499
 
 
500
    def test_get_bare_quoted_string_must_start_with_dquote(self):
 
501
        with self.assertRaises(errors.HeaderParseError):
 
502
            parser.get_bare_quoted_string('foo"')
 
503
        with self.assertRaises(errors.HeaderParseError):
 
504
            parser.get_bare_quoted_string('  "foo"')
 
505
 
 
506
    def test_get_bare_quoted_string_following_wsp_preserved(self):
 
507
        self._test_get_x(parser.get_bare_quoted_string,
 
508
             '"foo"\t bar', '"foo"', 'foo', [], '\t bar')
 
509
 
 
510
    def test_get_bare_quoted_string_multiple_words(self):
 
511
        self._test_get_x(parser.get_bare_quoted_string,
 
512
             '"foo bar moo"', '"foo bar moo"', 'foo bar moo', [], '')
 
513
 
 
514
    def test_get_bare_quoted_string_multiple_words_wsp_preserved(self):
 
515
        self._test_get_x(parser.get_bare_quoted_string,
 
516
             '" foo  moo\t"', '" foo  moo\t"', ' foo  moo\t', [], '')
 
517
 
 
518
    def test_get_bare_quoted_string_end_dquote_mid_word(self):
 
519
        self._test_get_x(parser.get_bare_quoted_string,
 
520
             '"foo"bar', '"foo"', 'foo', [], 'bar')
 
521
 
 
522
    def test_get_bare_quoted_string_quoted_dquote(self):
 
523
        self._test_get_x(parser.get_bare_quoted_string,
 
524
             r'"foo\"in"a', r'"foo\"in"', 'foo"in', [], 'a')
 
525
 
 
526
    def test_get_bare_quoted_string_non_printables(self):
 
527
        self._test_get_x(parser.get_bare_quoted_string,
 
528
             '"a\x01a"', '"a\x01a"', 'a\x01a',
 
529
             [errors.NonPrintableDefect], '')
 
530
 
 
531
    def test_get_bare_quoted_string_no_end_dquote(self):
 
532
        self._test_get_x(parser.get_bare_quoted_string,
 
533
             '"foo', '"foo"', 'foo',
 
534
             [errors.InvalidHeaderDefect], '')
 
535
        self._test_get_x(parser.get_bare_quoted_string,
 
536
             '"foo ', '"foo "', 'foo ',
 
537
             [errors.InvalidHeaderDefect], '')
 
538
 
 
539
    def test_get_bare_quoted_string_empty_quotes(self):
 
540
        self._test_get_x(parser.get_bare_quoted_string,
 
541
            '""', '""', '', [], '')
 
542
 
 
543
    # get_comment
 
544
 
 
545
    def test_get_comment_only(self):
 
546
        comment = self._test_get_x(parser.get_comment,
 
547
            '(comment)', '(comment)', ' ', [], '', ['comment'])
 
548
        self.assertEqual(comment.token_type, 'comment')
 
549
 
 
550
    def test_get_comment_must_start_with_paren(self):
 
551
        with self.assertRaises(errors.HeaderParseError):
 
552
            parser.get_comment('foo"')
 
553
        with self.assertRaises(errors.HeaderParseError):
 
554
            parser.get_comment('  (foo"')
 
555
 
 
556
    def test_get_comment_following_wsp_preserved(self):
 
557
        self._test_get_x(parser.get_comment,
 
558
            '(comment)  \t', '(comment)', ' ', [], '  \t', ['comment'])
 
559
 
 
560
    def test_get_comment_multiple_words(self):
 
561
        self._test_get_x(parser.get_comment,
 
562
            '(foo bar)  \t', '(foo bar)', ' ', [], '  \t', ['foo bar'])
 
563
 
 
564
    def test_get_comment_multiple_words_wsp_preserved(self):
 
565
        self._test_get_x(parser.get_comment,
 
566
            '( foo  bar\t )  \t', '( foo  bar\t )', ' ', [], '  \t',
 
567
                [' foo  bar\t '])
 
568
 
 
569
    def test_get_comment_end_paren_mid_word(self):
 
570
        self._test_get_x(parser.get_comment,
 
571
            '(foo)bar', '(foo)', ' ', [], 'bar', ['foo'])
 
572
 
 
573
    def test_get_comment_quoted_parens(self):
 
574
        self._test_get_x(parser.get_comment,
 
575
            '(foo\) \(\)bar)', '(foo\) \(\)bar)', ' ', [], '', ['foo) ()bar'])
 
576
 
 
577
    def test_get_comment_non_printable(self):
 
578
        self._test_get_x(parser.get_comment,
 
579
            '(foo\x7Fbar)', '(foo\x7Fbar)', ' ',
 
580
            [errors.NonPrintableDefect], '', ['foo\x7Fbar'])
 
581
 
 
582
    def test_get_comment_no_end_paren(self):
 
583
        self._test_get_x(parser.get_comment,
 
584
            '(foo bar', '(foo bar)', ' ',
 
585
            [errors.InvalidHeaderDefect], '', ['foo bar'])
 
586
        self._test_get_x(parser.get_comment,
 
587
            '(foo bar  ', '(foo bar  )', ' ',
 
588
            [errors.InvalidHeaderDefect], '', ['foo bar  '])
 
589
 
 
590
    def test_get_comment_nested_comment(self):
 
591
        comment = self._test_get_x(parser.get_comment,
 
592
            '(foo(bar))', '(foo(bar))', ' ', [], '', ['foo(bar)'])
 
593
        self.assertEqual(comment[1].content, 'bar')
 
594
 
 
595
    def test_get_comment_nested_comment_wsp(self):
 
596
        comment = self._test_get_x(parser.get_comment,
 
597
            '(foo ( bar ) )', '(foo ( bar ) )', ' ', [], '', ['foo ( bar ) '])
 
598
        self.assertEqual(comment[2].content, ' bar ')
 
599
 
 
600
    def test_get_comment_empty_comment(self):
 
601
        self._test_get_x(parser.get_comment,
 
602
            '()', '()', ' ', [], '', [''])
 
603
 
 
604
    def test_get_comment_multiple_nesting(self):
 
605
        comment = self._test_get_x(parser.get_comment,
 
606
            '(((((foo)))))', '(((((foo)))))', ' ', [], '', ['((((foo))))'])
 
607
        for i in range(4, 0, -1):
 
608
            self.assertEqual(comment[0].content, '('*(i-1)+'foo'+')'*(i-1))
 
609
            comment = comment[0]
 
610
        self.assertEqual(comment.content, 'foo')
 
611
 
 
612
    def test_get_comment_missing_end_of_nesting(self):
 
613
        self._test_get_x(parser.get_comment,
 
614
            '(((((foo)))', '(((((foo)))))', ' ',
 
615
            [errors.InvalidHeaderDefect]*2, '', ['((((foo))))'])
 
616
 
 
617
    def test_get_comment_qs_in_nested_comment(self):
 
618
        comment = self._test_get_x(parser.get_comment,
 
619
            '(foo (b\)))', '(foo (b\)))', ' ', [], '', ['foo (b\))'])
 
620
        self.assertEqual(comment[2].content, 'b)')
 
621
 
 
622
    # get_cfws
 
623
 
 
624
    def test_get_cfws_only_ws(self):
 
625
        cfws = self._test_get_x(parser.get_cfws,
 
626
            '  \t \t', '  \t \t', ' ', [], '', [])
 
627
        self.assertEqual(cfws.token_type, 'cfws')
 
628
 
 
629
    def test_get_cfws_only_comment(self):
 
630
        cfws = self._test_get_x(parser.get_cfws,
 
631
            '(foo)', '(foo)', ' ', [], '', ['foo'])
 
632
        self.assertEqual(cfws[0].content, 'foo')
 
633
 
 
634
    def test_get_cfws_only_mixed(self):
 
635
        cfws = self._test_get_x(parser.get_cfws,
 
636
            ' (foo )  ( bar) ', ' (foo )  ( bar) ', ' ', [], '',
 
637
                ['foo ', ' bar'])
 
638
        self.assertEqual(cfws[1].content, 'foo ')
 
639
        self.assertEqual(cfws[3].content, ' bar')
 
640
 
 
641
    def test_get_cfws_ends_at_non_leader(self):
 
642
        cfws = self._test_get_x(parser.get_cfws,
 
643
            '(foo) bar', '(foo) ', ' ', [], 'bar', ['foo'])
 
644
        self.assertEqual(cfws[0].content, 'foo')
 
645
 
 
646
    def test_get_cfws_ends_at_non_printable(self):
 
647
        cfws = self._test_get_x(parser.get_cfws,
 
648
            '(foo) \x07', '(foo) ', ' ', [], '\x07', ['foo'])
 
649
        self.assertEqual(cfws[0].content, 'foo')
 
650
 
 
651
    def test_get_cfws_non_printable_in_comment(self):
 
652
        cfws = self._test_get_x(parser.get_cfws,
 
653
            '(foo \x07) "test"', '(foo \x07) ', ' ',
 
654
            [errors.NonPrintableDefect], '"test"', ['foo \x07'])
 
655
        self.assertEqual(cfws[0].content, 'foo \x07')
 
656
 
 
657
    def test_get_cfws_header_ends_in_comment(self):
 
658
        cfws = self._test_get_x(parser.get_cfws,
 
659
            '  (foo ', '  (foo )', ' ',
 
660
            [errors.InvalidHeaderDefect], '', ['foo '])
 
661
        self.assertEqual(cfws[1].content, 'foo ')
 
662
 
 
663
    def test_get_cfws_multiple_nested_comments(self):
 
664
        cfws = self._test_get_x(parser.get_cfws,
 
665
            '(foo (bar)) ((a)(a))', '(foo (bar)) ((a)(a))', ' ', [],
 
666
                '', ['foo (bar)', '(a)(a)'])
 
667
        self.assertEqual(cfws[0].comments, ['foo (bar)'])
 
668
        self.assertEqual(cfws[2].comments, ['(a)(a)'])
 
669
 
 
670
    # get_quoted_string
 
671
 
 
672
    def test_get_quoted_string_only(self):
 
673
        qs = self._test_get_x(parser.get_quoted_string,
 
674
            '"bob"', '"bob"', 'bob', [], '')
 
675
        self.assertEqual(qs.token_type, 'quoted-string')
 
676
        self.assertEqual(qs.quoted_value, '"bob"')
 
677
        self.assertEqual(qs.content, 'bob')
 
678
 
 
679
    def test_get_quoted_string_with_wsp(self):
 
680
        qs = self._test_get_x(parser.get_quoted_string,
 
681
            '\t "bob"  ', '\t "bob"  ', ' bob ', [], '')
 
682
        self.assertEqual(qs.quoted_value, ' "bob" ')
 
683
        self.assertEqual(qs.content, 'bob')
 
684
 
 
685
    def test_get_quoted_string_with_comments_and_wsp(self):
 
686
        qs = self._test_get_x(parser.get_quoted_string,
 
687
            ' (foo) "bob"(bar)', ' (foo) "bob"(bar)', ' bob ', [], '')
 
688
        self.assertEqual(qs[0][1].content, 'foo')
 
689
        self.assertEqual(qs[2][0].content, 'bar')
 
690
        self.assertEqual(qs.content, 'bob')
 
691
        self.assertEqual(qs.quoted_value, ' "bob" ')
 
692
 
 
693
    def test_get_quoted_string_with_multiple_comments(self):
 
694
        qs = self._test_get_x(parser.get_quoted_string,
 
695
            ' (foo) (bar) "bob"(bird)', ' (foo) (bar) "bob"(bird)', ' bob ',
 
696
                [], '')
 
697
        self.assertEqual(qs[0].comments, ['foo', 'bar'])
 
698
        self.assertEqual(qs[2].comments, ['bird'])
 
699
        self.assertEqual(qs.content, 'bob')
 
700
        self.assertEqual(qs.quoted_value, ' "bob" ')
 
701
 
 
702
    def test_get_quoted_string_non_printable_in_comment(self):
 
703
        qs = self._test_get_x(parser.get_quoted_string,
 
704
            ' (\x0A) "bob"', ' (\x0A) "bob"', ' bob',
 
705
                [errors.NonPrintableDefect], '')
 
706
        self.assertEqual(qs[0].comments, ['\x0A'])
 
707
        self.assertEqual(qs.content, 'bob')
 
708
        self.assertEqual(qs.quoted_value, ' "bob"')
 
709
 
 
710
    def test_get_quoted_string_non_printable_in_qcontent(self):
 
711
        qs = self._test_get_x(parser.get_quoted_string,
 
712
            ' (a) "a\x0B"', ' (a) "a\x0B"', ' a\x0B',
 
713
                [errors.NonPrintableDefect], '')
 
714
        self.assertEqual(qs[0].comments, ['a'])
 
715
        self.assertEqual(qs.content, 'a\x0B')
 
716
        self.assertEqual(qs.quoted_value, ' "a\x0B"')
 
717
 
 
718
    def test_get_quoted_string_internal_ws(self):
 
719
        qs = self._test_get_x(parser.get_quoted_string,
 
720
            ' (a) "foo  bar "', ' (a) "foo  bar "', ' foo  bar ',
 
721
                [], '')
 
722
        self.assertEqual(qs[0].comments, ['a'])
 
723
        self.assertEqual(qs.content, 'foo  bar ')
 
724
        self.assertEqual(qs.quoted_value, ' "foo  bar "')
 
725
 
 
726
    def test_get_quoted_string_header_ends_in_comment(self):
 
727
        qs = self._test_get_x(parser.get_quoted_string,
 
728
            ' (a) "bob" (a', ' (a) "bob" (a)', ' bob ',
 
729
                [errors.InvalidHeaderDefect], '')
 
730
        self.assertEqual(qs[0].comments, ['a'])
 
731
        self.assertEqual(qs[2].comments, ['a'])
 
732
        self.assertEqual(qs.content, 'bob')
 
733
        self.assertEqual(qs.quoted_value, ' "bob" ')
 
734
 
 
735
    def test_get_quoted_string_header_ends_in_qcontent(self):
 
736
        qs = self._test_get_x(parser.get_quoted_string,
 
737
            ' (a) "bob', ' (a) "bob"', ' bob',
 
738
                [errors.InvalidHeaderDefect], '')
 
739
        self.assertEqual(qs[0].comments, ['a'])
 
740
        self.assertEqual(qs.content, 'bob')
 
741
        self.assertEqual(qs.quoted_value, ' "bob"')
 
742
 
 
743
    def test_get_quoted_string_no_quoted_string(self):
 
744
        with self.assertRaises(errors.HeaderParseError):
 
745
            parser.get_quoted_string(' (ab) xyz')
 
746
 
 
747
    def test_get_quoted_string_qs_ends_at_noncfws(self):
 
748
        qs = self._test_get_x(parser.get_quoted_string,
 
749
            '\t "bob" fee', '\t "bob" ', ' bob ', [], 'fee')
 
750
        self.assertEqual(qs.content, 'bob')
 
751
        self.assertEqual(qs.quoted_value, ' "bob" ')
 
752
 
 
753
    # get_atom
 
754
 
 
755
    def test_get_atom_only(self):
 
756
        atom = self._test_get_x(parser.get_atom,
 
757
            'bob', 'bob', 'bob', [], '')
 
758
        self.assertEqual(atom.token_type, 'atom')
 
759
 
 
760
    def test_get_atom_with_wsp(self):
 
761
        self._test_get_x(parser.get_atom,
 
762
            '\t bob  ', '\t bob  ', ' bob ', [], '')
 
763
 
 
764
    def test_get_atom_with_comments_and_wsp(self):
 
765
        atom = self._test_get_x(parser.get_atom,
 
766
            ' (foo) bob(bar)', ' (foo) bob(bar)', ' bob ', [], '')
 
767
        self.assertEqual(atom[0][1].content, 'foo')
 
768
        self.assertEqual(atom[2][0].content, 'bar')
 
769
 
 
770
    def test_get_atom_with_multiple_comments(self):
 
771
        atom = self._test_get_x(parser.get_atom,
 
772
            ' (foo) (bar) bob(bird)', ' (foo) (bar) bob(bird)', ' bob ',
 
773
                [], '')
 
774
        self.assertEqual(atom[0].comments, ['foo', 'bar'])
 
775
        self.assertEqual(atom[2].comments, ['bird'])
 
776
 
 
777
    def test_get_atom_non_printable_in_comment(self):
 
778
        atom = self._test_get_x(parser.get_atom,
 
779
            ' (\x0A) bob', ' (\x0A) bob', ' bob',
 
780
                [errors.NonPrintableDefect], '')
 
781
        self.assertEqual(atom[0].comments, ['\x0A'])
 
782
 
 
783
    def test_get_atom_non_printable_in_atext(self):
 
784
        atom = self._test_get_x(parser.get_atom,
 
785
            ' (a) a\x0B', ' (a) a\x0B', ' a\x0B',
 
786
                [errors.NonPrintableDefect], '')
 
787
        self.assertEqual(atom[0].comments, ['a'])
 
788
 
 
789
    def test_get_atom_header_ends_in_comment(self):
 
790
        atom = self._test_get_x(parser.get_atom,
 
791
            ' (a) bob (a', ' (a) bob (a)', ' bob ',
 
792
                [errors.InvalidHeaderDefect], '')
 
793
        self.assertEqual(atom[0].comments, ['a'])
 
794
        self.assertEqual(atom[2].comments, ['a'])
 
795
 
 
796
    def test_get_atom_no_atom(self):
 
797
        with self.assertRaises(errors.HeaderParseError):
 
798
            parser.get_atom(' (ab) ')
 
799
 
 
800
    def test_get_atom_no_atom_before_special(self):
 
801
        with self.assertRaises(errors.HeaderParseError):
 
802
            parser.get_atom(' (ab) @')
 
803
 
 
804
    def test_get_atom_atom_ends_at_special(self):
 
805
        atom = self._test_get_x(parser.get_atom,
 
806
            ' (foo) bob(bar)  @bang', ' (foo) bob(bar)  ', ' bob ', [], '@bang')
 
807
        self.assertEqual(atom[0].comments, ['foo'])
 
808
        self.assertEqual(atom[2].comments, ['bar'])
 
809
 
 
810
    def test_get_atom_atom_ends_at_noncfws(self):
 
811
        self._test_get_x(parser.get_atom,
 
812
            'bob  fred', 'bob  ', 'bob ', [], 'fred')
 
813
 
 
814
    def test_get_atom_rfc2047_atom(self):
 
815
        self._test_get_x(parser.get_atom,
 
816
            '=?utf-8?q?=20bob?=', ' bob', ' bob', [], '')
 
817
 
 
818
    # get_dot_atom_text
 
819
 
 
820
    def test_get_dot_atom_text(self):
 
821
        dot_atom_text = self._test_get_x(parser.get_dot_atom_text,
 
822
            'foo.bar.bang', 'foo.bar.bang', 'foo.bar.bang', [], '')
 
823
        self.assertEqual(dot_atom_text.token_type, 'dot-atom-text')
 
824
        self.assertEqual(len(dot_atom_text), 5)
 
825
 
 
826
    def test_get_dot_atom_text_lone_atom_is_valid(self):
 
827
        dot_atom_text = self._test_get_x(parser.get_dot_atom_text,
 
828
            'foo', 'foo', 'foo', [], '')
 
829
 
 
830
    def test_get_dot_atom_text_raises_on_leading_dot(self):
 
831
        with self.assertRaises(errors.HeaderParseError):
 
832
            parser.get_dot_atom_text('.foo.bar')
 
833
 
 
834
    def test_get_dot_atom_text_raises_on_trailing_dot(self):
 
835
        with self.assertRaises(errors.HeaderParseError):
 
836
            parser.get_dot_atom_text('foo.bar.')
 
837
 
 
838
    def test_get_dot_atom_text_raises_on_leading_non_atext(self):
 
839
        with self.assertRaises(errors.HeaderParseError):
 
840
            parser.get_dot_atom_text(' foo.bar')
 
841
        with self.assertRaises(errors.HeaderParseError):
 
842
            parser.get_dot_atom_text('@foo.bar')
 
843
        with self.assertRaises(errors.HeaderParseError):
 
844
            parser.get_dot_atom_text('"foo.bar"')
 
845
 
 
846
    def test_get_dot_atom_text_trailing_text_preserved(self):
 
847
        dot_atom_text = self._test_get_x(parser.get_dot_atom_text,
 
848
            'foo@bar', 'foo', 'foo', [], '@bar')
 
849
 
 
850
    def test_get_dot_atom_text_trailing_ws_preserved(self):
 
851
        dot_atom_text = self._test_get_x(parser.get_dot_atom_text,
 
852
            'foo .bar', 'foo', 'foo', [], ' .bar')
 
853
 
 
854
    # get_dot_atom
 
855
 
 
856
    def test_get_dot_atom_only(self):
 
857
        dot_atom = self._test_get_x(parser.get_dot_atom,
 
858
            'foo.bar.bing', 'foo.bar.bing', 'foo.bar.bing', [], '')
 
859
        self.assertEqual(dot_atom.token_type, 'dot-atom')
 
860
        self.assertEqual(len(dot_atom), 1)
 
861
 
 
862
    def test_get_dot_atom_with_wsp(self):
 
863
        self._test_get_x(parser.get_dot_atom,
 
864
            '\t  foo.bar.bing  ', '\t  foo.bar.bing  ', ' foo.bar.bing ', [], '')
 
865
 
 
866
    def test_get_dot_atom_with_comments_and_wsp(self):
 
867
        self._test_get_x(parser.get_dot_atom,
 
868
            ' (sing)  foo.bar.bing (here) ', ' (sing)  foo.bar.bing (here) ',
 
869
                ' foo.bar.bing ', [], '')
 
870
 
 
871
    def test_get_dot_atom_space_ends_dot_atom(self):
 
872
        self._test_get_x(parser.get_dot_atom,
 
873
            ' (sing)  foo.bar .bing (here) ', ' (sing)  foo.bar ',
 
874
                ' foo.bar ', [], '.bing (here) ')
 
875
 
 
876
    def test_get_dot_atom_no_atom_raises(self):
 
877
        with self.assertRaises(errors.HeaderParseError):
 
878
            parser.get_dot_atom(' (foo) ')
 
879
 
 
880
    def test_get_dot_atom_leading_dot_raises(self):
 
881
        with self.assertRaises(errors.HeaderParseError):
 
882
            parser.get_dot_atom(' (foo) .bar')
 
883
 
 
884
    def test_get_dot_atom_two_dots_raises(self):
 
885
        with self.assertRaises(errors.HeaderParseError):
 
886
            parser.get_dot_atom('bar..bang')
 
887
 
 
888
    def test_get_dot_atom_trailing_dot_raises(self):
 
889
        with self.assertRaises(errors.HeaderParseError):
 
890
            parser.get_dot_atom(' (foo) bar.bang. foo')
 
891
 
 
892
    def test_get_dot_atom_rfc2047_atom(self):
 
893
        self._test_get_x(parser.get_dot_atom,
 
894
            '=?utf-8?q?=20bob?=', ' bob', ' bob', [], '')
 
895
 
 
896
    # get_word (if this were black box we'd repeat all the qs/atom tests)
 
897
 
 
898
    def test_get_word_atom_yields_atom(self):
 
899
        word = self._test_get_x(parser.get_word,
 
900
            ' (foo) bar (bang) :ah', ' (foo) bar (bang) ', ' bar ', [], ':ah')
 
901
        self.assertEqual(word.token_type, 'atom')
 
902
        self.assertEqual(word[0].token_type, 'cfws')
 
903
 
 
904
    def test_get_word_qs_yields_qs(self):
 
905
        word = self._test_get_x(parser.get_word,
 
906
            '"bar " (bang) ah', '"bar " (bang) ', 'bar  ', [], 'ah')
 
907
        self.assertEqual(word.token_type, 'quoted-string')
 
908
        self.assertEqual(word[0].token_type, 'bare-quoted-string')
 
909
        self.assertEqual(word[0].value, 'bar ')
 
910
        self.assertEqual(word.content, 'bar ')
 
911
 
 
912
    def test_get_word_ends_at_dot(self):
 
913
        self._test_get_x(parser.get_word,
 
914
            'foo.', 'foo', 'foo', [], '.')
 
915
 
 
916
    # get_phrase
 
917
 
 
918
    def test_get_phrase_simple(self):
 
919
        phrase = self._test_get_x(parser.get_phrase,
 
920
            '"Fred A. Johnson" is his name, oh.',
 
921
            '"Fred A. Johnson" is his name',
 
922
            'Fred A. Johnson is his name',
 
923
            [],
 
924
            ', oh.')
 
925
        self.assertEqual(phrase.token_type, 'phrase')
 
926
 
 
927
    def test_get_phrase_complex(self):
 
928
        phrase = self._test_get_x(parser.get_phrase,
 
929
            ' (A) bird (in (my|your)) "hand  " is messy\t<>\t',
 
930
            ' (A) bird (in (my|your)) "hand  " is messy\t',
 
931
            ' bird hand   is messy ',
 
932
            [],
 
933
            '<>\t')
 
934
        self.assertEqual(phrase[0][0].comments, ['A'])
 
935
        self.assertEqual(phrase[0][2].comments, ['in (my|your)'])
 
936
 
 
937
    def test_get_phrase_obsolete(self):
 
938
        phrase = self._test_get_x(parser.get_phrase,
 
939
            'Fred A.(weird).O Johnson',
 
940
            'Fred A.(weird).O Johnson',
 
941
            'Fred A. .O Johnson',
 
942
            [errors.ObsoleteHeaderDefect]*3,
 
943
            '')
 
944
        self.assertEqual(len(phrase), 7)
 
945
        self.assertEqual(phrase[3].comments, ['weird'])
 
946
 
 
947
    def test_get_phrase_pharse_must_start_with_word(self):
 
948
        phrase = self._test_get_x(parser.get_phrase,
 
949
            '(even weirder).name',
 
950
            '(even weirder).name',
 
951
            ' .name',
 
952
            [errors.InvalidHeaderDefect] + [errors.ObsoleteHeaderDefect]*2,
 
953
            '')
 
954
        self.assertEqual(len(phrase), 3)
 
955
        self.assertEqual(phrase[0].comments, ['even weirder'])
 
956
 
 
957
    def test_get_phrase_ending_with_obsolete(self):
 
958
        phrase = self._test_get_x(parser.get_phrase,
 
959
            'simple phrase.(with trailing comment):boo',
 
960
            'simple phrase.(with trailing comment)',
 
961
            'simple phrase. ',
 
962
            [errors.ObsoleteHeaderDefect]*2,
 
963
            ':boo')
 
964
        self.assertEqual(len(phrase), 4)
 
965
        self.assertEqual(phrase[3].comments, ['with trailing comment'])
 
966
 
 
967
    def get_phrase_cfws_only_raises(self):
 
968
        with self.assertRaises(errors.HeaderParseError):
 
969
            parser.get_phrase(' (foo) ')
 
970
 
 
971
    # get_local_part
 
972
 
 
973
    def test_get_local_part_simple(self):
 
974
        local_part = self._test_get_x(parser.get_local_part,
 
975
            'dinsdale@python.org', 'dinsdale', 'dinsdale', [], '@python.org')
 
976
        self.assertEqual(local_part.token_type, 'local-part')
 
977
        self.assertEqual(local_part.local_part, 'dinsdale')
 
978
 
 
979
    def test_get_local_part_with_dot(self):
 
980
        local_part = self._test_get_x(parser.get_local_part,
 
981
            'Fred.A.Johnson@python.org',
 
982
            'Fred.A.Johnson',
 
983
            'Fred.A.Johnson',
 
984
            [],
 
985
            '@python.org')
 
986
        self.assertEqual(local_part.local_part, 'Fred.A.Johnson')
 
987
 
 
988
    def test_get_local_part_with_whitespace(self):
 
989
        local_part = self._test_get_x(parser.get_local_part,
 
990
            ' Fred.A.Johnson  @python.org',
 
991
            ' Fred.A.Johnson  ',
 
992
            ' Fred.A.Johnson ',
 
993
            [],
 
994
            '@python.org')
 
995
        self.assertEqual(local_part.local_part, 'Fred.A.Johnson')
 
996
 
 
997
    def test_get_local_part_with_cfws(self):
 
998
        local_part = self._test_get_x(parser.get_local_part,
 
999
            ' (foo) Fred.A.Johnson (bar (bird))  @python.org',
 
1000
            ' (foo) Fred.A.Johnson (bar (bird))  ',
 
1001
            ' Fred.A.Johnson ',
 
1002
            [],
 
1003
            '@python.org')
 
1004
        self.assertEqual(local_part.local_part, 'Fred.A.Johnson')
 
1005
        self.assertEqual(local_part[0][0].comments, ['foo'])
 
1006
        self.assertEqual(local_part[0][2].comments, ['bar (bird)'])
 
1007
 
 
1008
    def test_get_local_part_simple_quoted(self):
 
1009
        local_part = self._test_get_x(parser.get_local_part,
 
1010
            '"dinsdale"@python.org', '"dinsdale"', '"dinsdale"', [], '@python.org')
 
1011
        self.assertEqual(local_part.token_type, 'local-part')
 
1012
        self.assertEqual(local_part.local_part, 'dinsdale')
 
1013
 
 
1014
    def test_get_local_part_with_quoted_dot(self):
 
1015
        local_part = self._test_get_x(parser.get_local_part,
 
1016
            '"Fred.A.Johnson"@python.org',
 
1017
            '"Fred.A.Johnson"',
 
1018
            '"Fred.A.Johnson"',
 
1019
            [],
 
1020
            '@python.org')
 
1021
        self.assertEqual(local_part.local_part, 'Fred.A.Johnson')
 
1022
 
 
1023
    def test_get_local_part_quoted_with_whitespace(self):
 
1024
        local_part = self._test_get_x(parser.get_local_part,
 
1025
            ' "Fred A. Johnson"  @python.org',
 
1026
            ' "Fred A. Johnson"  ',
 
1027
            ' "Fred A. Johnson" ',
 
1028
            [],
 
1029
            '@python.org')
 
1030
        self.assertEqual(local_part.local_part, 'Fred A. Johnson')
 
1031
 
 
1032
    def test_get_local_part_quoted_with_cfws(self):
 
1033
        local_part = self._test_get_x(parser.get_local_part,
 
1034
            ' (foo) " Fred A. Johnson " (bar (bird))  @python.org',
 
1035
            ' (foo) " Fred A. Johnson " (bar (bird))  ',
 
1036
            ' " Fred A. Johnson " ',
 
1037
            [],
 
1038
            '@python.org')
 
1039
        self.assertEqual(local_part.local_part, ' Fred A. Johnson ')
 
1040
        self.assertEqual(local_part[0][0].comments, ['foo'])
 
1041
        self.assertEqual(local_part[0][2].comments, ['bar (bird)'])
 
1042
 
 
1043
 
 
1044
    def test_get_local_part_simple_obsolete(self):
 
1045
        local_part = self._test_get_x(parser.get_local_part,
 
1046
            'Fred. A.Johnson@python.org',
 
1047
            'Fred. A.Johnson',
 
1048
            'Fred. A.Johnson',
 
1049
            [errors.ObsoleteHeaderDefect],
 
1050
            '@python.org')
 
1051
        self.assertEqual(local_part.local_part, 'Fred.A.Johnson')
 
1052
 
 
1053
    def test_get_local_part_complex_obsolete_1(self):
 
1054
        local_part = self._test_get_x(parser.get_local_part,
 
1055
            ' (foo )Fred (bar).(bird) A.(sheep)Johnson."and  dogs "@python.org',
 
1056
            ' (foo )Fred (bar).(bird) A.(sheep)Johnson."and  dogs "',
 
1057
            ' Fred . A. Johnson.and  dogs ',
 
1058
            [errors.ObsoleteHeaderDefect],
 
1059
            '@python.org')
 
1060
        self.assertEqual(local_part.local_part, 'Fred.A.Johnson.and  dogs ')
 
1061
 
 
1062
    def test_get_local_part_complex_obsolete_invalid(self):
 
1063
        local_part = self._test_get_x(parser.get_local_part,
 
1064
            ' (foo )Fred (bar).(bird) A.(sheep)Johnson "and  dogs"@python.org',
 
1065
            ' (foo )Fred (bar).(bird) A.(sheep)Johnson "and  dogs"',
 
1066
            ' Fred . A. Johnson and  dogs',
 
1067
            [errors.InvalidHeaderDefect]*2,
 
1068
            '@python.org')
 
1069
        self.assertEqual(local_part.local_part, 'Fred.A.Johnson and  dogs')
 
1070
 
 
1071
    def test_get_local_part_no_part_raises(self):
 
1072
        with self.assertRaises(errors.HeaderParseError):
 
1073
            parser.get_local_part(' (foo) ')
 
1074
 
 
1075
    def test_get_local_part_special_instead_raises(self):
 
1076
        with self.assertRaises(errors.HeaderParseError):
 
1077
            parser.get_local_part(' (foo) @python.org')
 
1078
 
 
1079
    def test_get_local_part_trailing_dot(self):
 
1080
        local_part = self._test_get_x(parser.get_local_part,
 
1081
            ' borris.@python.org',
 
1082
            ' borris.',
 
1083
            ' borris.',
 
1084
            [errors.InvalidHeaderDefect]*2,
 
1085
            '@python.org')
 
1086
        self.assertEqual(local_part.local_part, 'borris.')
 
1087
 
 
1088
    def test_get_local_part_trailing_dot_with_ws(self):
 
1089
        local_part = self._test_get_x(parser.get_local_part,
 
1090
            ' borris. @python.org',
 
1091
            ' borris. ',
 
1092
            ' borris. ',
 
1093
            [errors.InvalidHeaderDefect]*2,
 
1094
            '@python.org')
 
1095
        self.assertEqual(local_part.local_part, 'borris.')
 
1096
 
 
1097
    def test_get_local_part_leading_dot(self):
 
1098
        local_part = self._test_get_x(parser.get_local_part,
 
1099
            '.borris@python.org',
 
1100
            '.borris',
 
1101
            '.borris',
 
1102
            [errors.InvalidHeaderDefect]*2,
 
1103
            '@python.org')
 
1104
        self.assertEqual(local_part.local_part, '.borris')
 
1105
 
 
1106
    def test_get_local_part_leading_dot_after_ws(self):
 
1107
        local_part = self._test_get_x(parser.get_local_part,
 
1108
            ' .borris@python.org',
 
1109
            ' .borris',
 
1110
            ' .borris',
 
1111
            [errors.InvalidHeaderDefect]*2,
 
1112
            '@python.org')
 
1113
        self.assertEqual(local_part.local_part, '.borris')
 
1114
 
 
1115
    def test_get_local_part_double_dot_raises(self):
 
1116
        local_part = self._test_get_x(parser.get_local_part,
 
1117
            ' borris.(foo).natasha@python.org',
 
1118
            ' borris.(foo).natasha',
 
1119
            ' borris. .natasha',
 
1120
            [errors.InvalidHeaderDefect]*2,
 
1121
            '@python.org')
 
1122
        self.assertEqual(local_part.local_part, 'borris..natasha')
 
1123
 
 
1124
    def test_get_local_part_quoted_strings_in_atom_list(self):
 
1125
        local_part = self._test_get_x(parser.get_local_part,
 
1126
            '""example" example"@example.com',
 
1127
            '""example" example"',
 
1128
            'example example',
 
1129
            [errors.InvalidHeaderDefect]*3,
 
1130
            '@example.com')
 
1131
        self.assertEqual(local_part.local_part, 'example example')
 
1132
 
 
1133
    def test_get_local_part_valid_and_invalid_qp_in_atom_list(self):
 
1134
        local_part = self._test_get_x(parser.get_local_part,
 
1135
            r'"\\"example\\" example"@example.com',
 
1136
            r'"\\"example\\" example"',
 
1137
            r'\example\\ example',
 
1138
            [errors.InvalidHeaderDefect]*5,
 
1139
            '@example.com')
 
1140
        self.assertEqual(local_part.local_part, r'\example\\ example')
 
1141
 
 
1142
    def test_get_local_part_unicode_defect(self):
 
1143
        # Currently this only happens when parsing unicode, not when parsing
 
1144
        # stuff that was originally binary.
 
1145
        local_part = self._test_get_x(parser.get_local_part,
 
1146
            'exámple@example.com',
 
1147
            'exámple',
 
1148
            'exámple',
 
1149
            [errors.NonASCIILocalPartDefect],
 
1150
            '@example.com')
 
1151
        self.assertEqual(local_part.local_part, 'exámple')
 
1152
 
 
1153
    # get_dtext
 
1154
 
 
1155
    def test_get_dtext_only(self):
 
1156
        dtext = self._test_get_x(parser.get_dtext,
 
1157
                                'foobar', 'foobar', 'foobar', [], '')
 
1158
        self.assertEqual(dtext.token_type, 'ptext')
 
1159
 
 
1160
    def test_get_dtext_all_dtext(self):
 
1161
        dtext = self._test_get_x(parser.get_dtext, self.rfc_dtext_chars,
 
1162
                                 self.rfc_dtext_chars,
 
1163
                                 self.rfc_dtext_chars, [], '')
 
1164
 
 
1165
    def test_get_dtext_two_words_gets_first(self):
 
1166
        self._test_get_x(parser.get_dtext,
 
1167
                        'foo bar', 'foo', 'foo', [], ' bar')
 
1168
 
 
1169
    def test_get_dtext_following_wsp_preserved(self):
 
1170
        self._test_get_x(parser.get_dtext,
 
1171
                        'foo \t\tbar', 'foo', 'foo', [], ' \t\tbar')
 
1172
 
 
1173
    def test_get_dtext_non_printables(self):
 
1174
        dtext = self._test_get_x(parser.get_dtext,
 
1175
                                'foo\x00bar]', 'foo\x00bar', 'foo\x00bar',
 
1176
                                [errors.NonPrintableDefect], ']')
 
1177
        self.assertEqual(dtext.defects[0].non_printables[0], '\x00')
 
1178
 
 
1179
    def test_get_dtext_with_qp(self):
 
1180
        ptext = self._test_get_x(parser.get_dtext,
 
1181
                                 r'foo\]\[\\bar\b\e\l\l',
 
1182
                                 r'foo][\barbell',
 
1183
                                 r'foo][\barbell',
 
1184
                                 [errors.ObsoleteHeaderDefect],
 
1185
                                 '')
 
1186
 
 
1187
    def test_get_dtext_up_to_close_bracket_only(self):
 
1188
        self._test_get_x(parser.get_dtext,
 
1189
                        'foo]', 'foo', 'foo', [], ']')
 
1190
 
 
1191
    def test_get_dtext_wsp_before_close_bracket_preserved(self):
 
1192
        self._test_get_x(parser.get_dtext,
 
1193
                        'foo  ]', 'foo', 'foo', [], '  ]')
 
1194
 
 
1195
    def test_get_dtext_close_bracket_mid_word(self):
 
1196
        self._test_get_x(parser.get_dtext,
 
1197
                        'foo]bar', 'foo', 'foo', [], ']bar')
 
1198
 
 
1199
    def test_get_dtext_up_to_open_bracket_only(self):
 
1200
        self._test_get_x(parser.get_dtext,
 
1201
                        'foo[', 'foo', 'foo', [], '[')
 
1202
 
 
1203
    def test_get_dtext_wsp_before_open_bracket_preserved(self):
 
1204
        self._test_get_x(parser.get_dtext,
 
1205
                        'foo  [', 'foo', 'foo', [], '  [')
 
1206
 
 
1207
    def test_get_dtext_open_bracket_mid_word(self):
 
1208
        self._test_get_x(parser.get_dtext,
 
1209
                        'foo[bar', 'foo', 'foo', [], '[bar')
 
1210
 
 
1211
    # get_domain_literal
 
1212
 
 
1213
    def test_get_domain_literal_only(self):
 
1214
        domain_literal = domain_literal = self._test_get_x(parser.get_domain_literal,
 
1215
                                '[127.0.0.1]',
 
1216
                                '[127.0.0.1]',
 
1217
                                '[127.0.0.1]',
 
1218
                                [],
 
1219
                                '')
 
1220
        self.assertEqual(domain_literal.token_type, 'domain-literal')
 
1221
        self.assertEqual(domain_literal.domain, '[127.0.0.1]')
 
1222
        self.assertEqual(domain_literal.ip, '127.0.0.1')
 
1223
 
 
1224
    def test_get_domain_literal_with_internal_ws(self):
 
1225
        domain_literal = self._test_get_x(parser.get_domain_literal,
 
1226
                                '[  127.0.0.1\t ]',
 
1227
                                '[  127.0.0.1\t ]',
 
1228
                                '[ 127.0.0.1 ]',
 
1229
                                [],
 
1230
                                '')
 
1231
        self.assertEqual(domain_literal.domain, '[127.0.0.1]')
 
1232
        self.assertEqual(domain_literal.ip, '127.0.0.1')
 
1233
 
 
1234
    def test_get_domain_literal_with_surrounding_cfws(self):
 
1235
        domain_literal = self._test_get_x(parser.get_domain_literal,
 
1236
                                '(foo)[  127.0.0.1] (bar)',
 
1237
                                '(foo)[  127.0.0.1] (bar)',
 
1238
                                ' [ 127.0.0.1] ',
 
1239
                                [],
 
1240
                                '')
 
1241
        self.assertEqual(domain_literal.domain, '[127.0.0.1]')
 
1242
        self.assertEqual(domain_literal.ip, '127.0.0.1')
 
1243
 
 
1244
    def test_get_domain_literal_no_start_char_raises(self):
 
1245
        with self.assertRaises(errors.HeaderParseError):
 
1246
            parser.get_domain_literal('(foo) ')
 
1247
 
 
1248
    def test_get_domain_literal_no_start_char_before_special_raises(self):
 
1249
        with self.assertRaises(errors.HeaderParseError):
 
1250
            parser.get_domain_literal('(foo) @')
 
1251
 
 
1252
    def test_get_domain_literal_bad_dtext_char_before_special_raises(self):
 
1253
        with self.assertRaises(errors.HeaderParseError):
 
1254
            parser.get_domain_literal('(foo) [abc[@')
 
1255
 
 
1256
    # get_domain
 
1257
 
 
1258
    def test_get_domain_regular_domain_only(self):
 
1259
        domain = self._test_get_x(parser.get_domain,
 
1260
                                  'example.com',
 
1261
                                  'example.com',
 
1262
                                  'example.com',
 
1263
                                  [],
 
1264
                                  '')
 
1265
        self.assertEqual(domain.token_type, 'domain')
 
1266
        self.assertEqual(domain.domain, 'example.com')
 
1267
 
 
1268
    def test_get_domain_domain_literal_only(self):
 
1269
        domain = self._test_get_x(parser.get_domain,
 
1270
                                  '[127.0.0.1]',
 
1271
                                  '[127.0.0.1]',
 
1272
                                  '[127.0.0.1]',
 
1273
                                  [],
 
1274
                                  '')
 
1275
        self.assertEqual(domain.token_type, 'domain')
 
1276
        self.assertEqual(domain.domain, '[127.0.0.1]')
 
1277
 
 
1278
    def test_get_domain_with_cfws(self):
 
1279
        domain = self._test_get_x(parser.get_domain,
 
1280
                                  '(foo) example.com(bar)\t',
 
1281
                                  '(foo) example.com(bar)\t',
 
1282
                                  ' example.com ',
 
1283
                                  [],
 
1284
                                  '')
 
1285
        self.assertEqual(domain.domain, 'example.com')
 
1286
 
 
1287
    def test_get_domain_domain_literal_with_cfws(self):
 
1288
        domain = self._test_get_x(parser.get_domain,
 
1289
                                  '(foo)[127.0.0.1]\t(bar)',
 
1290
                                  '(foo)[127.0.0.1]\t(bar)',
 
1291
                                  ' [127.0.0.1] ',
 
1292
                                  [],
 
1293
                                  '')
 
1294
        self.assertEqual(domain.domain, '[127.0.0.1]')
 
1295
 
 
1296
    def test_get_domain_domain_with_cfws_ends_at_special(self):
 
1297
        domain = self._test_get_x(parser.get_domain,
 
1298
                                  '(foo)example.com\t(bar), next',
 
1299
                                  '(foo)example.com\t(bar)',
 
1300
                                  ' example.com ',
 
1301
                                  [],
 
1302
                                  ', next')
 
1303
        self.assertEqual(domain.domain, 'example.com')
 
1304
 
 
1305
    def test_get_domain_domain_literal_with_cfws_ends_at_special(self):
 
1306
        domain = self._test_get_x(parser.get_domain,
 
1307
                                  '(foo)[127.0.0.1]\t(bar), next',
 
1308
                                  '(foo)[127.0.0.1]\t(bar)',
 
1309
                                  ' [127.0.0.1] ',
 
1310
                                  [],
 
1311
                                  ', next')
 
1312
        self.assertEqual(domain.domain, '[127.0.0.1]')
 
1313
 
 
1314
    def test_get_domain_obsolete(self):
 
1315
        domain = self._test_get_x(parser.get_domain,
 
1316
                                  '(foo) example . (bird)com(bar)\t',
 
1317
                                  '(foo) example . (bird)com(bar)\t',
 
1318
                                  ' example . com ',
 
1319
                                  [errors.ObsoleteHeaderDefect],
 
1320
                                  '')
 
1321
        self.assertEqual(domain.domain, 'example.com')
 
1322
 
 
1323
    def test_get_domain_no_non_cfws_raises(self):
 
1324
        with self.assertRaises(errors.HeaderParseError):
 
1325
            parser.get_domain("  (foo)\t")
 
1326
 
 
1327
    def test_get_domain_no_atom_raises(self):
 
1328
        with self.assertRaises(errors.HeaderParseError):
 
1329
            parser.get_domain("  (foo)\t, broken")
 
1330
 
 
1331
 
 
1332
    # get_addr_spec
 
1333
 
 
1334
    def test_get_addr_spec_normal(self):
 
1335
        addr_spec = self._test_get_x(parser.get_addr_spec,
 
1336
                                    'dinsdale@example.com',
 
1337
                                    'dinsdale@example.com',
 
1338
                                    'dinsdale@example.com',
 
1339
                                    [],
 
1340
                                    '')
 
1341
        self.assertEqual(addr_spec.token_type, 'addr-spec')
 
1342
        self.assertEqual(addr_spec.local_part, 'dinsdale')
 
1343
        self.assertEqual(addr_spec.domain, 'example.com')
 
1344
        self.assertEqual(addr_spec.addr_spec, 'dinsdale@example.com')
 
1345
 
 
1346
    def test_get_addr_spec_with_doamin_literal(self):
 
1347
        addr_spec = self._test_get_x(parser.get_addr_spec,
 
1348
                                    'dinsdale@[127.0.0.1]',
 
1349
                                    'dinsdale@[127.0.0.1]',
 
1350
                                    'dinsdale@[127.0.0.1]',
 
1351
                                    [],
 
1352
                                    '')
 
1353
        self.assertEqual(addr_spec.local_part, 'dinsdale')
 
1354
        self.assertEqual(addr_spec.domain, '[127.0.0.1]')
 
1355
        self.assertEqual(addr_spec.addr_spec, 'dinsdale@[127.0.0.1]')
 
1356
 
 
1357
    def test_get_addr_spec_with_cfws(self):
 
1358
        addr_spec = self._test_get_x(parser.get_addr_spec,
 
1359
                '(foo) dinsdale(bar)@ (bird) example.com (bog)',
 
1360
                '(foo) dinsdale(bar)@ (bird) example.com (bog)',
 
1361
                ' dinsdale@example.com ',
 
1362
                [],
 
1363
                '')
 
1364
        self.assertEqual(addr_spec.local_part, 'dinsdale')
 
1365
        self.assertEqual(addr_spec.domain, 'example.com')
 
1366
        self.assertEqual(addr_spec.addr_spec, 'dinsdale@example.com')
 
1367
 
 
1368
    def test_get_addr_spec_with_qouoted_string_and_cfws(self):
 
1369
        addr_spec = self._test_get_x(parser.get_addr_spec,
 
1370
                '(foo) "roy a bug"(bar)@ (bird) example.com (bog)',
 
1371
                '(foo) "roy a bug"(bar)@ (bird) example.com (bog)',
 
1372
                ' "roy a bug"@example.com ',
 
1373
                [],
 
1374
                '')
 
1375
        self.assertEqual(addr_spec.local_part, 'roy a bug')
 
1376
        self.assertEqual(addr_spec.domain, 'example.com')
 
1377
        self.assertEqual(addr_spec.addr_spec, '"roy a bug"@example.com')
 
1378
 
 
1379
    def test_get_addr_spec_ends_at_special(self):
 
1380
        addr_spec = self._test_get_x(parser.get_addr_spec,
 
1381
                '(foo) "roy a bug"(bar)@ (bird) example.com (bog) , next',
 
1382
                '(foo) "roy a bug"(bar)@ (bird) example.com (bog) ',
 
1383
                ' "roy a bug"@example.com ',
 
1384
                [],
 
1385
                ', next')
 
1386
        self.assertEqual(addr_spec.local_part, 'roy a bug')
 
1387
        self.assertEqual(addr_spec.domain, 'example.com')
 
1388
        self.assertEqual(addr_spec.addr_spec, '"roy a bug"@example.com')
 
1389
 
 
1390
    def test_get_addr_spec_quoted_strings_in_atom_list(self):
 
1391
        addr_spec = self._test_get_x(parser.get_addr_spec,
 
1392
            '""example" example"@example.com',
 
1393
            '""example" example"@example.com',
 
1394
            'example example@example.com',
 
1395
            [errors.InvalidHeaderDefect]*3,
 
1396
            '')
 
1397
        self.assertEqual(addr_spec.local_part, 'example example')
 
1398
        self.assertEqual(addr_spec.domain, 'example.com')
 
1399
        self.assertEqual(addr_spec.addr_spec, '"example example"@example.com')
 
1400
 
 
1401
    def test_get_addr_spec_dot_atom(self):
 
1402
        addr_spec = self._test_get_x(parser.get_addr_spec,
 
1403
            'star.a.star@example.com',
 
1404
            'star.a.star@example.com',
 
1405
            'star.a.star@example.com',
 
1406
            [],
 
1407
            '')
 
1408
        self.assertEqual(addr_spec.local_part, 'star.a.star')
 
1409
        self.assertEqual(addr_spec.domain, 'example.com')
 
1410
        self.assertEqual(addr_spec.addr_spec, 'star.a.star@example.com')
 
1411
 
 
1412
    # get_obs_route
 
1413
 
 
1414
    def test_get_obs_route_simple(self):
 
1415
        obs_route = self._test_get_x(parser.get_obs_route,
 
1416
            '@example.com, @two.example.com:',
 
1417
            '@example.com, @two.example.com:',
 
1418
            '@example.com, @two.example.com:',
 
1419
            [],
 
1420
            '')
 
1421
        self.assertEqual(obs_route.token_type, 'obs-route')
 
1422
        self.assertEqual(obs_route.domains, ['example.com', 'two.example.com'])
 
1423
 
 
1424
    def test_get_obs_route_complex(self):
 
1425
        obs_route = self._test_get_x(parser.get_obs_route,
 
1426
            '(foo),, (blue)@example.com (bar),@two.(foo) example.com (bird):',
 
1427
            '(foo),, (blue)@example.com (bar),@two.(foo) example.com (bird):',
 
1428
            ' ,, @example.com ,@two. example.com :',
 
1429
            [errors.ObsoleteHeaderDefect],  # This is the obs-domain
 
1430
            '')
 
1431
        self.assertEqual(obs_route.token_type, 'obs-route')
 
1432
        self.assertEqual(obs_route.domains, ['example.com', 'two.example.com'])
 
1433
 
 
1434
    def test_get_obs_route_no_route_before_end_raises(self):
 
1435
        with self.assertRaises(errors.HeaderParseError):
 
1436
            parser.get_obs_route('(foo) @example.com,')
 
1437
 
 
1438
    def test_get_obs_route_no_route_before_special_raises(self):
 
1439
        with self.assertRaises(errors.HeaderParseError):
 
1440
            parser.get_obs_route('(foo) [abc],')
 
1441
 
 
1442
    def test_get_obs_route_no_route_before_special_raises2(self):
 
1443
        with self.assertRaises(errors.HeaderParseError):
 
1444
            parser.get_obs_route('(foo) @example.com [abc],')
 
1445
 
 
1446
    # get_angle_addr
 
1447
 
 
1448
    def test_get_angle_addr_simple(self):
 
1449
        angle_addr = self._test_get_x(parser.get_angle_addr,
 
1450
            '<dinsdale@example.com>',
 
1451
            '<dinsdale@example.com>',
 
1452
            '<dinsdale@example.com>',
 
1453
            [],
 
1454
            '')
 
1455
        self.assertEqual(angle_addr.token_type, 'angle-addr')
 
1456
        self.assertEqual(angle_addr.local_part, 'dinsdale')
 
1457
        self.assertEqual(angle_addr.domain, 'example.com')
 
1458
        self.assertIsNone(angle_addr.route)
 
1459
        self.assertEqual(angle_addr.addr_spec, 'dinsdale@example.com')
 
1460
 
 
1461
    def test_get_angle_addr_empty(self):
 
1462
        angle_addr = self._test_get_x(parser.get_angle_addr,
 
1463
            '<>',
 
1464
            '<>',
 
1465
            '<>',
 
1466
            [errors.InvalidHeaderDefect],
 
1467
            '')
 
1468
        self.assertEqual(angle_addr.token_type, 'angle-addr')
 
1469
        self.assertIsNone(angle_addr.local_part)
 
1470
        self.assertIsNone(angle_addr.domain)
 
1471
        self.assertIsNone(angle_addr.route)
 
1472
        self.assertEqual(angle_addr.addr_spec, '<>')
 
1473
 
 
1474
    def test_get_angle_addr_with_cfws(self):
 
1475
        angle_addr = self._test_get_x(parser.get_angle_addr,
 
1476
            ' (foo) <dinsdale@example.com>(bar)',
 
1477
            ' (foo) <dinsdale@example.com>(bar)',
 
1478
            ' <dinsdale@example.com> ',
 
1479
            [],
 
1480
            '')
 
1481
        self.assertEqual(angle_addr.token_type, 'angle-addr')
 
1482
        self.assertEqual(angle_addr.local_part, 'dinsdale')
 
1483
        self.assertEqual(angle_addr.domain, 'example.com')
 
1484
        self.assertIsNone(angle_addr.route)
 
1485
        self.assertEqual(angle_addr.addr_spec, 'dinsdale@example.com')
 
1486
 
 
1487
    def test_get_angle_addr_qs_and_domain_literal(self):
 
1488
        angle_addr = self._test_get_x(parser.get_angle_addr,
 
1489
            '<"Fred Perfect"@[127.0.0.1]>',
 
1490
            '<"Fred Perfect"@[127.0.0.1]>',
 
1491
            '<"Fred Perfect"@[127.0.0.1]>',
 
1492
            [],
 
1493
            '')
 
1494
        self.assertEqual(angle_addr.local_part, 'Fred Perfect')
 
1495
        self.assertEqual(angle_addr.domain, '[127.0.0.1]')
 
1496
        self.assertIsNone(angle_addr.route)
 
1497
        self.assertEqual(angle_addr.addr_spec, '"Fred Perfect"@[127.0.0.1]')
 
1498
 
 
1499
    def test_get_angle_addr_internal_cfws(self):
 
1500
        angle_addr = self._test_get_x(parser.get_angle_addr,
 
1501
            '<(foo) dinsdale@example.com(bar)>',
 
1502
            '<(foo) dinsdale@example.com(bar)>',
 
1503
            '< dinsdale@example.com >',
 
1504
            [],
 
1505
            '')
 
1506
        self.assertEqual(angle_addr.local_part, 'dinsdale')
 
1507
        self.assertEqual(angle_addr.domain, 'example.com')
 
1508
        self.assertIsNone(angle_addr.route)
 
1509
        self.assertEqual(angle_addr.addr_spec, 'dinsdale@example.com')
 
1510
 
 
1511
    def test_get_angle_addr_obs_route(self):
 
1512
        angle_addr = self._test_get_x(parser.get_angle_addr,
 
1513
            '(foo)<@example.com, (bird) @two.example.com: dinsdale@example.com> (bar) ',
 
1514
            '(foo)<@example.com, (bird) @two.example.com: dinsdale@example.com> (bar) ',
 
1515
            ' <@example.com, @two.example.com: dinsdale@example.com> ',
 
1516
            [errors.ObsoleteHeaderDefect],
 
1517
            '')
 
1518
        self.assertEqual(angle_addr.local_part, 'dinsdale')
 
1519
        self.assertEqual(angle_addr.domain, 'example.com')
 
1520
        self.assertEqual(angle_addr.route, ['example.com', 'two.example.com'])
 
1521
        self.assertEqual(angle_addr.addr_spec, 'dinsdale@example.com')
 
1522
 
 
1523
    def test_get_angle_addr_missing_closing_angle(self):
 
1524
        angle_addr = self._test_get_x(parser.get_angle_addr,
 
1525
            '<dinsdale@example.com',
 
1526
            '<dinsdale@example.com>',
 
1527
            '<dinsdale@example.com>',
 
1528
            [errors.InvalidHeaderDefect],
 
1529
            '')
 
1530
        self.assertEqual(angle_addr.local_part, 'dinsdale')
 
1531
        self.assertEqual(angle_addr.domain, 'example.com')
 
1532
        self.assertIsNone(angle_addr.route)
 
1533
        self.assertEqual(angle_addr.addr_spec, 'dinsdale@example.com')
 
1534
 
 
1535
    def test_get_angle_addr_missing_closing_angle_with_cfws(self):
 
1536
        angle_addr = self._test_get_x(parser.get_angle_addr,
 
1537
            '<dinsdale@example.com (foo)',
 
1538
            '<dinsdale@example.com (foo)>',
 
1539
            '<dinsdale@example.com >',
 
1540
            [errors.InvalidHeaderDefect],
 
1541
            '')
 
1542
        self.assertEqual(angle_addr.local_part, 'dinsdale')
 
1543
        self.assertEqual(angle_addr.domain, 'example.com')
 
1544
        self.assertIsNone(angle_addr.route)
 
1545
        self.assertEqual(angle_addr.addr_spec, 'dinsdale@example.com')
 
1546
 
 
1547
    def test_get_angle_addr_ends_at_special(self):
 
1548
        angle_addr = self._test_get_x(parser.get_angle_addr,
 
1549
            '<dinsdale@example.com> (foo), next',
 
1550
            '<dinsdale@example.com> (foo)',
 
1551
            '<dinsdale@example.com> ',
 
1552
            [],
 
1553
            ', next')
 
1554
        self.assertEqual(angle_addr.local_part, 'dinsdale')
 
1555
        self.assertEqual(angle_addr.domain, 'example.com')
 
1556
        self.assertIsNone(angle_addr.route)
 
1557
        self.assertEqual(angle_addr.addr_spec, 'dinsdale@example.com')
 
1558
 
 
1559
    def test_get_angle_addr_no_angle_raise(self):
 
1560
        with self.assertRaises(errors.HeaderParseError):
 
1561
            parser.get_angle_addr('(foo) ')
 
1562
 
 
1563
    def test_get_angle_addr_no_angle_before_special_raises(self):
 
1564
        with self.assertRaises(errors.HeaderParseError):
 
1565
            parser.get_angle_addr('(foo) , next')
 
1566
 
 
1567
    def test_get_angle_addr_no_angle_raises(self):
 
1568
        with self.assertRaises(errors.HeaderParseError):
 
1569
            parser.get_angle_addr('bar')
 
1570
 
 
1571
    def test_get_angle_addr_special_after_angle_raises(self):
 
1572
        with self.assertRaises(errors.HeaderParseError):
 
1573
            parser.get_angle_addr('(foo) <, bar')
 
1574
 
 
1575
    # get_display_name  This is phrase but with a different value.
 
1576
 
 
1577
    def test_get_display_name_simple(self):
 
1578
        display_name = self._test_get_x(parser.get_display_name,
 
1579
            'Fred A Johnson',
 
1580
            'Fred A Johnson',
 
1581
            'Fred A Johnson',
 
1582
            [],
 
1583
            '')
 
1584
        self.assertEqual(display_name.token_type, 'display-name')
 
1585
        self.assertEqual(display_name.display_name, 'Fred A Johnson')
 
1586
 
 
1587
    def test_get_display_name_complex1(self):
 
1588
        display_name = self._test_get_x(parser.get_display_name,
 
1589
            '"Fred A. Johnson" is his name, oh.',
 
1590
            '"Fred A. Johnson" is his name',
 
1591
            '"Fred A. Johnson is his name"',
 
1592
            [],
 
1593
            ', oh.')
 
1594
        self.assertEqual(display_name.token_type, 'display-name')
 
1595
        self.assertEqual(display_name.display_name, 'Fred A. Johnson is his name')
 
1596
 
 
1597
    def test_get_display_name_complex2(self):
 
1598
        display_name = self._test_get_x(parser.get_display_name,
 
1599
            ' (A) bird (in (my|your)) "hand  " is messy\t<>\t',
 
1600
            ' (A) bird (in (my|your)) "hand  " is messy\t',
 
1601
            ' "bird hand   is messy" ',
 
1602
            [],
 
1603
            '<>\t')
 
1604
        self.assertEqual(display_name[0][0].comments, ['A'])
 
1605
        self.assertEqual(display_name[0][2].comments, ['in (my|your)'])
 
1606
        self.assertEqual(display_name.display_name, 'bird hand   is messy')
 
1607
 
 
1608
    def test_get_display_name_obsolete(self):
 
1609
        display_name = self._test_get_x(parser.get_display_name,
 
1610
            'Fred A.(weird).O Johnson',
 
1611
            'Fred A.(weird).O Johnson',
 
1612
            '"Fred A. .O Johnson"',
 
1613
            [errors.ObsoleteHeaderDefect]*3,
 
1614
            '')
 
1615
        self.assertEqual(len(display_name), 7)
 
1616
        self.assertEqual(display_name[3].comments, ['weird'])
 
1617
        self.assertEqual(display_name.display_name, 'Fred A. .O Johnson')
 
1618
 
 
1619
    def test_get_display_name_pharse_must_start_with_word(self):
 
1620
        display_name = self._test_get_x(parser.get_display_name,
 
1621
            '(even weirder).name',
 
1622
            '(even weirder).name',
 
1623
            ' ".name"',
 
1624
            [errors.InvalidHeaderDefect] + [errors.ObsoleteHeaderDefect]*2,
 
1625
            '')
 
1626
        self.assertEqual(len(display_name), 3)
 
1627
        self.assertEqual(display_name[0].comments, ['even weirder'])
 
1628
        self.assertEqual(display_name.display_name, '.name')
 
1629
 
 
1630
    def test_get_display_name_ending_with_obsolete(self):
 
1631
        display_name = self._test_get_x(parser.get_display_name,
 
1632
            'simple phrase.(with trailing comment):boo',
 
1633
            'simple phrase.(with trailing comment)',
 
1634
            '"simple phrase." ',
 
1635
            [errors.ObsoleteHeaderDefect]*2,
 
1636
            ':boo')
 
1637
        self.assertEqual(len(display_name), 4)
 
1638
        self.assertEqual(display_name[3].comments, ['with trailing comment'])
 
1639
        self.assertEqual(display_name.display_name, 'simple phrase.')
 
1640
 
 
1641
    # get_name_addr
 
1642
 
 
1643
    def test_get_name_addr_angle_addr_only(self):
 
1644
        name_addr = self._test_get_x(parser.get_name_addr,
 
1645
            '<dinsdale@example.com>',
 
1646
            '<dinsdale@example.com>',
 
1647
            '<dinsdale@example.com>',
 
1648
            [],
 
1649
            '')
 
1650
        self.assertEqual(name_addr.token_type, 'name-addr')
 
1651
        self.assertIsNone(name_addr.display_name)
 
1652
        self.assertEqual(name_addr.local_part, 'dinsdale')
 
1653
        self.assertEqual(name_addr.domain, 'example.com')
 
1654
        self.assertIsNone(name_addr.route)
 
1655
        self.assertEqual(name_addr.addr_spec, 'dinsdale@example.com')
 
1656
 
 
1657
    def test_get_name_addr_atom_name(self):
 
1658
        name_addr = self._test_get_x(parser.get_name_addr,
 
1659
            'Dinsdale <dinsdale@example.com>',
 
1660
            'Dinsdale <dinsdale@example.com>',
 
1661
            'Dinsdale <dinsdale@example.com>',
 
1662
            [],
 
1663
            '')
 
1664
        self.assertEqual(name_addr.token_type, 'name-addr')
 
1665
        self.assertEqual(name_addr.display_name, 'Dinsdale')
 
1666
        self.assertEqual(name_addr.local_part, 'dinsdale')
 
1667
        self.assertEqual(name_addr.domain, 'example.com')
 
1668
        self.assertIsNone(name_addr.route)
 
1669
        self.assertEqual(name_addr.addr_spec, 'dinsdale@example.com')
 
1670
 
 
1671
    def test_get_name_addr_atom_name_with_cfws(self):
 
1672
        name_addr = self._test_get_x(parser.get_name_addr,
 
1673
            '(foo) Dinsdale (bar) <dinsdale@example.com> (bird)',
 
1674
            '(foo) Dinsdale (bar) <dinsdale@example.com> (bird)',
 
1675
            ' Dinsdale <dinsdale@example.com> ',
 
1676
            [],
 
1677
            '')
 
1678
        self.assertEqual(name_addr.display_name, 'Dinsdale')
 
1679
        self.assertEqual(name_addr.local_part, 'dinsdale')
 
1680
        self.assertEqual(name_addr.domain, 'example.com')
 
1681
        self.assertIsNone(name_addr.route)
 
1682
        self.assertEqual(name_addr.addr_spec, 'dinsdale@example.com')
 
1683
 
 
1684
    def test_get_name_addr_name_with_cfws_and_dots(self):
 
1685
        name_addr = self._test_get_x(parser.get_name_addr,
 
1686
            '(foo) Roy.A.Bear (bar) <dinsdale@example.com> (bird)',
 
1687
            '(foo) Roy.A.Bear (bar) <dinsdale@example.com> (bird)',
 
1688
            ' "Roy.A.Bear" <dinsdale@example.com> ',
 
1689
            [errors.ObsoleteHeaderDefect]*2,
 
1690
            '')
 
1691
        self.assertEqual(name_addr.display_name, 'Roy.A.Bear')
 
1692
        self.assertEqual(name_addr.local_part, 'dinsdale')
 
1693
        self.assertEqual(name_addr.domain, 'example.com')
 
1694
        self.assertIsNone(name_addr.route)
 
1695
        self.assertEqual(name_addr.addr_spec, 'dinsdale@example.com')
 
1696
 
 
1697
    def test_get_name_addr_qs_name(self):
 
1698
        name_addr = self._test_get_x(parser.get_name_addr,
 
1699
            '"Roy.A.Bear" <dinsdale@example.com>',
 
1700
            '"Roy.A.Bear" <dinsdale@example.com>',
 
1701
            '"Roy.A.Bear" <dinsdale@example.com>',
 
1702
            [],
 
1703
            '')
 
1704
        self.assertEqual(name_addr.display_name, 'Roy.A.Bear')
 
1705
        self.assertEqual(name_addr.local_part, 'dinsdale')
 
1706
        self.assertEqual(name_addr.domain, 'example.com')
 
1707
        self.assertIsNone(name_addr.route)
 
1708
        self.assertEqual(name_addr.addr_spec, 'dinsdale@example.com')
 
1709
 
 
1710
    def test_get_name_addr_with_route(self):
 
1711
        name_addr = self._test_get_x(parser.get_name_addr,
 
1712
            '"Roy.A.Bear" <@two.example.com: dinsdale@example.com>',
 
1713
            '"Roy.A.Bear" <@two.example.com: dinsdale@example.com>',
 
1714
            '"Roy.A.Bear" <@two.example.com: dinsdale@example.com>',
 
1715
            [errors.ObsoleteHeaderDefect],
 
1716
            '')
 
1717
        self.assertEqual(name_addr.display_name, 'Roy.A.Bear')
 
1718
        self.assertEqual(name_addr.local_part, 'dinsdale')
 
1719
        self.assertEqual(name_addr.domain, 'example.com')
 
1720
        self.assertEqual(name_addr.route, ['two.example.com'])
 
1721
        self.assertEqual(name_addr.addr_spec, 'dinsdale@example.com')
 
1722
 
 
1723
    def test_get_name_addr_ends_at_special(self):
 
1724
        name_addr = self._test_get_x(parser.get_name_addr,
 
1725
            '"Roy.A.Bear" <dinsdale@example.com>, next',
 
1726
            '"Roy.A.Bear" <dinsdale@example.com>',
 
1727
            '"Roy.A.Bear" <dinsdale@example.com>',
 
1728
            [],
 
1729
            ', next')
 
1730
        self.assertEqual(name_addr.display_name, 'Roy.A.Bear')
 
1731
        self.assertEqual(name_addr.local_part, 'dinsdale')
 
1732
        self.assertEqual(name_addr.domain, 'example.com')
 
1733
        self.assertIsNone(name_addr.route)
 
1734
        self.assertEqual(name_addr.addr_spec, 'dinsdale@example.com')
 
1735
 
 
1736
    def test_get_name_addr_no_content_raises(self):
 
1737
        with self.assertRaises(errors.HeaderParseError):
 
1738
            parser.get_name_addr(' (foo) ')
 
1739
 
 
1740
    def test_get_name_addr_no_content_before_special_raises(self):
 
1741
        with self.assertRaises(errors.HeaderParseError):
 
1742
            parser.get_name_addr(' (foo) ,')
 
1743
 
 
1744
    def test_get_name_addr_no_angle_after_display_name_raises(self):
 
1745
        with self.assertRaises(errors.HeaderParseError):
 
1746
            parser.get_name_addr('foo bar')
 
1747
 
 
1748
    # get_mailbox
 
1749
 
 
1750
    def test_get_mailbox_addr_spec_only(self):
 
1751
        mailbox = self._test_get_x(parser.get_mailbox,
 
1752
            'dinsdale@example.com',
 
1753
            'dinsdale@example.com',
 
1754
            'dinsdale@example.com',
 
1755
            [],
 
1756
            '')
 
1757
        self.assertEqual(mailbox.token_type, 'mailbox')
 
1758
        self.assertIsNone(mailbox.display_name)
 
1759
        self.assertEqual(mailbox.local_part, 'dinsdale')
 
1760
        self.assertEqual(mailbox.domain, 'example.com')
 
1761
        self.assertIsNone(mailbox.route)
 
1762
        self.assertEqual(mailbox.addr_spec, 'dinsdale@example.com')
 
1763
 
 
1764
    def test_get_mailbox_angle_addr_only(self):
 
1765
        mailbox = self._test_get_x(parser.get_mailbox,
 
1766
            '<dinsdale@example.com>',
 
1767
            '<dinsdale@example.com>',
 
1768
            '<dinsdale@example.com>',
 
1769
            [],
 
1770
            '')
 
1771
        self.assertEqual(mailbox.token_type, 'mailbox')
 
1772
        self.assertIsNone(mailbox.display_name)
 
1773
        self.assertEqual(mailbox.local_part, 'dinsdale')
 
1774
        self.assertEqual(mailbox.domain, 'example.com')
 
1775
        self.assertIsNone(mailbox.route)
 
1776
        self.assertEqual(mailbox.addr_spec, 'dinsdale@example.com')
 
1777
 
 
1778
    def test_get_mailbox_name_addr(self):
 
1779
        mailbox = self._test_get_x(parser.get_mailbox,
 
1780
            '"Roy A. Bear" <dinsdale@example.com>',
 
1781
            '"Roy A. Bear" <dinsdale@example.com>',
 
1782
            '"Roy A. Bear" <dinsdale@example.com>',
 
1783
            [],
 
1784
            '')
 
1785
        self.assertEqual(mailbox.token_type, 'mailbox')
 
1786
        self.assertEqual(mailbox.display_name, 'Roy A. Bear')
 
1787
        self.assertEqual(mailbox.local_part, 'dinsdale')
 
1788
        self.assertEqual(mailbox.domain, 'example.com')
 
1789
        self.assertIsNone(mailbox.route)
 
1790
        self.assertEqual(mailbox.addr_spec, 'dinsdale@example.com')
 
1791
 
 
1792
    def test_get_mailbox_ends_at_special(self):
 
1793
        mailbox = self._test_get_x(parser.get_mailbox,
 
1794
            '"Roy A. Bear" <dinsdale@example.com>, rest',
 
1795
            '"Roy A. Bear" <dinsdale@example.com>',
 
1796
            '"Roy A. Bear" <dinsdale@example.com>',
 
1797
            [],
 
1798
            ', rest')
 
1799
        self.assertEqual(mailbox.token_type, 'mailbox')
 
1800
        self.assertEqual(mailbox.display_name, 'Roy A. Bear')
 
1801
        self.assertEqual(mailbox.local_part, 'dinsdale')
 
1802
        self.assertEqual(mailbox.domain, 'example.com')
 
1803
        self.assertIsNone(mailbox.route)
 
1804
        self.assertEqual(mailbox.addr_spec, 'dinsdale@example.com')
 
1805
 
 
1806
    def test_get_mailbox_quoted_strings_in_atom_list(self):
 
1807
        mailbox = self._test_get_x(parser.get_mailbox,
 
1808
            '""example" example"@example.com',
 
1809
            '""example" example"@example.com',
 
1810
            'example example@example.com',
 
1811
            [errors.InvalidHeaderDefect]*3,
 
1812
            '')
 
1813
        self.assertEqual(mailbox.local_part, 'example example')
 
1814
        self.assertEqual(mailbox.domain, 'example.com')
 
1815
        self.assertEqual(mailbox.addr_spec, '"example example"@example.com')
 
1816
 
 
1817
    # get_mailbox_list
 
1818
 
 
1819
    def test_get_mailbox_list_single_addr(self):
 
1820
        mailbox_list = self._test_get_x(parser.get_mailbox_list,
 
1821
            'dinsdale@example.com',
 
1822
            'dinsdale@example.com',
 
1823
            'dinsdale@example.com',
 
1824
            [],
 
1825
            '')
 
1826
        self.assertEqual(mailbox_list.token_type, 'mailbox-list')
 
1827
        self.assertEqual(len(mailbox_list.mailboxes), 1)
 
1828
        mailbox = mailbox_list.mailboxes[0]
 
1829
        self.assertIsNone(mailbox.display_name)
 
1830
        self.assertEqual(mailbox.local_part, 'dinsdale')
 
1831
        self.assertEqual(mailbox.domain, 'example.com')
 
1832
        self.assertIsNone(mailbox.route)
 
1833
        self.assertEqual(mailbox.addr_spec, 'dinsdale@example.com')
 
1834
        self.assertEqual(mailbox_list.mailboxes,
 
1835
                         mailbox_list.all_mailboxes)
 
1836
 
 
1837
    def test_get_mailbox_list_two_simple_addr(self):
 
1838
        mailbox_list = self._test_get_x(parser.get_mailbox_list,
 
1839
            'dinsdale@example.com, dinsdale@test.example.com',
 
1840
            'dinsdale@example.com, dinsdale@test.example.com',
 
1841
            'dinsdale@example.com, dinsdale@test.example.com',
 
1842
            [],
 
1843
            '')
 
1844
        self.assertEqual(mailbox_list.token_type, 'mailbox-list')
 
1845
        self.assertEqual(len(mailbox_list.mailboxes), 2)
 
1846
        self.assertEqual(mailbox_list.mailboxes[0].addr_spec,
 
1847
                        'dinsdale@example.com')
 
1848
        self.assertEqual(mailbox_list.mailboxes[1].addr_spec,
 
1849
                        'dinsdale@test.example.com')
 
1850
        self.assertEqual(mailbox_list.mailboxes,
 
1851
                         mailbox_list.all_mailboxes)
 
1852
 
 
1853
    def test_get_mailbox_list_two_name_addr(self):
 
1854
        mailbox_list = self._test_get_x(parser.get_mailbox_list,
 
1855
            ('"Roy A. Bear" <dinsdale@example.com>,'
 
1856
                ' "Fred Flintstone" <dinsdale@test.example.com>'),
 
1857
            ('"Roy A. Bear" <dinsdale@example.com>,'
 
1858
                ' "Fred Flintstone" <dinsdale@test.example.com>'),
 
1859
            ('"Roy A. Bear" <dinsdale@example.com>,'
 
1860
                ' "Fred Flintstone" <dinsdale@test.example.com>'),
 
1861
            [],
 
1862
            '')
 
1863
        self.assertEqual(len(mailbox_list.mailboxes), 2)
 
1864
        self.assertEqual(mailbox_list.mailboxes[0].addr_spec,
 
1865
                        'dinsdale@example.com')
 
1866
        self.assertEqual(mailbox_list.mailboxes[0].display_name,
 
1867
                        'Roy A. Bear')
 
1868
        self.assertEqual(mailbox_list.mailboxes[1].addr_spec,
 
1869
                        'dinsdale@test.example.com')
 
1870
        self.assertEqual(mailbox_list.mailboxes[1].display_name,
 
1871
                        'Fred Flintstone')
 
1872
        self.assertEqual(mailbox_list.mailboxes,
 
1873
                         mailbox_list.all_mailboxes)
 
1874
 
 
1875
    def test_get_mailbox_list_two_complex(self):
 
1876
        mailbox_list = self._test_get_x(parser.get_mailbox_list,
 
1877
            ('(foo) "Roy A. Bear" <dinsdale@example.com>(bar),'
 
1878
                ' "Fred Flintstone" <dinsdale@test.(bird)example.com>'),
 
1879
            ('(foo) "Roy A. Bear" <dinsdale@example.com>(bar),'
 
1880
                ' "Fred Flintstone" <dinsdale@test.(bird)example.com>'),
 
1881
            (' "Roy A. Bear" <dinsdale@example.com> ,'
 
1882
                ' "Fred Flintstone" <dinsdale@test. example.com>'),
 
1883
            [errors.ObsoleteHeaderDefect],
 
1884
            '')
 
1885
        self.assertEqual(len(mailbox_list.mailboxes), 2)
 
1886
        self.assertEqual(mailbox_list.mailboxes[0].addr_spec,
 
1887
                        'dinsdale@example.com')
 
1888
        self.assertEqual(mailbox_list.mailboxes[0].display_name,
 
1889
                        'Roy A. Bear')
 
1890
        self.assertEqual(mailbox_list.mailboxes[1].addr_spec,
 
1891
                        'dinsdale@test.example.com')
 
1892
        self.assertEqual(mailbox_list.mailboxes[1].display_name,
 
1893
                        'Fred Flintstone')
 
1894
        self.assertEqual(mailbox_list.mailboxes,
 
1895
                         mailbox_list.all_mailboxes)
 
1896
 
 
1897
    def test_get_mailbox_list_unparseable_mailbox_null(self):
 
1898
        mailbox_list = self._test_get_x(parser.get_mailbox_list,
 
1899
            ('"Roy A. Bear"[] dinsdale@example.com,'
 
1900
                ' "Fred Flintstone" <dinsdale@test.(bird)example.com>'),
 
1901
            ('"Roy A. Bear"[] dinsdale@example.com,'
 
1902
                ' "Fred Flintstone" <dinsdale@test.(bird)example.com>'),
 
1903
            ('"Roy A. Bear"[] dinsdale@example.com,'
 
1904
                ' "Fred Flintstone" <dinsdale@test. example.com>'),
 
1905
            [errors.InvalidHeaderDefect,   # the 'extra' text after the local part
 
1906
             errors.InvalidHeaderDefect,   # the local part with no angle-addr
 
1907
             errors.ObsoleteHeaderDefect,  # period in extra text (example.com)
 
1908
             errors.ObsoleteHeaderDefect], # (bird) in valid address.
 
1909
            '')
 
1910
        self.assertEqual(len(mailbox_list.mailboxes), 1)
 
1911
        self.assertEqual(len(mailbox_list.all_mailboxes), 2)
 
1912
        self.assertEqual(mailbox_list.all_mailboxes[0].token_type,
 
1913
                        'invalid-mailbox')
 
1914
        self.assertIsNone(mailbox_list.all_mailboxes[0].display_name)
 
1915
        self.assertEqual(mailbox_list.all_mailboxes[0].local_part,
 
1916
                        'Roy A. Bear')
 
1917
        self.assertIsNone(mailbox_list.all_mailboxes[0].domain)
 
1918
        self.assertEqual(mailbox_list.all_mailboxes[0].addr_spec,
 
1919
                        '"Roy A. Bear"')
 
1920
        self.assertIs(mailbox_list.all_mailboxes[1],
 
1921
                        mailbox_list.mailboxes[0])
 
1922
        self.assertEqual(mailbox_list.mailboxes[0].addr_spec,
 
1923
                        'dinsdale@test.example.com')
 
1924
        self.assertEqual(mailbox_list.mailboxes[0].display_name,
 
1925
                        'Fred Flintstone')
 
1926
 
 
1927
    def test_get_mailbox_list_junk_after_valid_address(self):
 
1928
        mailbox_list = self._test_get_x(parser.get_mailbox_list,
 
1929
            ('"Roy A. Bear" <dinsdale@example.com>@@,'
 
1930
                ' "Fred Flintstone" <dinsdale@test.example.com>'),
 
1931
            ('"Roy A. Bear" <dinsdale@example.com>@@,'
 
1932
                ' "Fred Flintstone" <dinsdale@test.example.com>'),
 
1933
            ('"Roy A. Bear" <dinsdale@example.com>@@,'
 
1934
                ' "Fred Flintstone" <dinsdale@test.example.com>'),
 
1935
            [errors.InvalidHeaderDefect],
 
1936
            '')
 
1937
        self.assertEqual(len(mailbox_list.mailboxes), 1)
 
1938
        self.assertEqual(len(mailbox_list.all_mailboxes), 2)
 
1939
        self.assertEqual(mailbox_list.all_mailboxes[0].addr_spec,
 
1940
                        'dinsdale@example.com')
 
1941
        self.assertEqual(mailbox_list.all_mailboxes[0].display_name,
 
1942
                        'Roy A. Bear')
 
1943
        self.assertEqual(mailbox_list.all_mailboxes[0].token_type,
 
1944
                        'invalid-mailbox')
 
1945
        self.assertIs(mailbox_list.all_mailboxes[1],
 
1946
                        mailbox_list.mailboxes[0])
 
1947
        self.assertEqual(mailbox_list.mailboxes[0].addr_spec,
 
1948
                        'dinsdale@test.example.com')
 
1949
        self.assertEqual(mailbox_list.mailboxes[0].display_name,
 
1950
                        'Fred Flintstone')
 
1951
 
 
1952
    def test_get_mailbox_list_empty_list_element(self):
 
1953
        mailbox_list = self._test_get_x(parser.get_mailbox_list,
 
1954
            ('"Roy A. Bear" <dinsdale@example.com>, (bird),,'
 
1955
                ' "Fred Flintstone" <dinsdale@test.example.com>'),
 
1956
            ('"Roy A. Bear" <dinsdale@example.com>, (bird),,'
 
1957
                ' "Fred Flintstone" <dinsdale@test.example.com>'),
 
1958
            ('"Roy A. Bear" <dinsdale@example.com>, ,,'
 
1959
                ' "Fred Flintstone" <dinsdale@test.example.com>'),
 
1960
            [errors.ObsoleteHeaderDefect]*2,
 
1961
            '')
 
1962
        self.assertEqual(len(mailbox_list.mailboxes), 2)
 
1963
        self.assertEqual(mailbox_list.all_mailboxes,
 
1964
                         mailbox_list.mailboxes)
 
1965
        self.assertEqual(mailbox_list.all_mailboxes[0].addr_spec,
 
1966
                        'dinsdale@example.com')
 
1967
        self.assertEqual(mailbox_list.all_mailboxes[0].display_name,
 
1968
                        'Roy A. Bear')
 
1969
        self.assertEqual(mailbox_list.mailboxes[1].addr_spec,
 
1970
                        'dinsdale@test.example.com')
 
1971
        self.assertEqual(mailbox_list.mailboxes[1].display_name,
 
1972
                        'Fred Flintstone')
 
1973
 
 
1974
    def test_get_mailbox_list_only_empty_elements(self):
 
1975
        mailbox_list = self._test_get_x(parser.get_mailbox_list,
 
1976
            '(foo),, (bar)',
 
1977
            '(foo),, (bar)',
 
1978
            ' ,, ',
 
1979
            [errors.ObsoleteHeaderDefect]*3,
 
1980
            '')
 
1981
        self.assertEqual(len(mailbox_list.mailboxes), 0)
 
1982
        self.assertEqual(mailbox_list.all_mailboxes,
 
1983
                         mailbox_list.mailboxes)
 
1984
 
 
1985
    # get_group_list
 
1986
 
 
1987
    def test_get_group_list_cfws_only(self):
 
1988
        group_list = self._test_get_x(parser.get_group_list,
 
1989
            '(hidden);',
 
1990
            '(hidden)',
 
1991
            ' ',
 
1992
            [],
 
1993
            ';')
 
1994
        self.assertEqual(group_list.token_type, 'group-list')
 
1995
        self.assertEqual(len(group_list.mailboxes), 0)
 
1996
        self.assertEqual(group_list.mailboxes,
 
1997
                         group_list.all_mailboxes)
 
1998
 
 
1999
    def test_get_group_list_mailbox_list(self):
 
2000
        group_list = self._test_get_x(parser.get_group_list,
 
2001
            'dinsdale@example.org, "Fred A. Bear" <dinsdale@example.org>',
 
2002
            'dinsdale@example.org, "Fred A. Bear" <dinsdale@example.org>',
 
2003
            'dinsdale@example.org, "Fred A. Bear" <dinsdale@example.org>',
 
2004
            [],
 
2005
            '')
 
2006
        self.assertEqual(group_list.token_type, 'group-list')
 
2007
        self.assertEqual(len(group_list.mailboxes), 2)
 
2008
        self.assertEqual(group_list.mailboxes,
 
2009
                         group_list.all_mailboxes)
 
2010
        self.assertEqual(group_list.mailboxes[1].display_name,
 
2011
                         'Fred A. Bear')
 
2012
 
 
2013
    def test_get_group_list_obs_group_list(self):
 
2014
        group_list = self._test_get_x(parser.get_group_list,
 
2015
            ', (foo),,(bar)',
 
2016
            ', (foo),,(bar)',
 
2017
            ', ,, ',
 
2018
            [errors.ObsoleteHeaderDefect],
 
2019
            '')
 
2020
        self.assertEqual(group_list.token_type, 'group-list')
 
2021
        self.assertEqual(len(group_list.mailboxes), 0)
 
2022
        self.assertEqual(group_list.mailboxes,
 
2023
                         group_list.all_mailboxes)
 
2024
 
 
2025
    def test_get_group_list_comment_only_invalid(self):
 
2026
        group_list = self._test_get_x(parser.get_group_list,
 
2027
            '(bar)',
 
2028
            '(bar)',
 
2029
            ' ',
 
2030
            [errors.InvalidHeaderDefect],
 
2031
            '')
 
2032
        self.assertEqual(group_list.token_type, 'group-list')
 
2033
        self.assertEqual(len(group_list.mailboxes), 0)
 
2034
        self.assertEqual(group_list.mailboxes,
 
2035
                         group_list.all_mailboxes)
 
2036
 
 
2037
    # get_group
 
2038
 
 
2039
    def test_get_group_empty(self):
 
2040
        group = self._test_get_x(parser.get_group,
 
2041
            'Monty Python:;',
 
2042
            'Monty Python:;',
 
2043
            'Monty Python:;',
 
2044
            [],
 
2045
            '')
 
2046
        self.assertEqual(group.token_type, 'group')
 
2047
        self.assertEqual(group.display_name, 'Monty Python')
 
2048
        self.assertEqual(len(group.mailboxes), 0)
 
2049
        self.assertEqual(group.mailboxes,
 
2050
                         group.all_mailboxes)
 
2051
 
 
2052
    def test_get_group_null_addr_spec(self):
 
2053
        group = self._test_get_x(parser.get_group,
 
2054
            'foo: <>;',
 
2055
            'foo: <>;',
 
2056
            'foo: <>;',
 
2057
            [errors.InvalidHeaderDefect],
 
2058
            '')
 
2059
        self.assertEqual(group.display_name, 'foo')
 
2060
        self.assertEqual(len(group.mailboxes), 0)
 
2061
        self.assertEqual(len(group.all_mailboxes), 1)
 
2062
        self.assertEqual(group.all_mailboxes[0].value, '<>')
 
2063
 
 
2064
    def test_get_group_cfws_only(self):
 
2065
        group = self._test_get_x(parser.get_group,
 
2066
            'Monty Python: (hidden);',
 
2067
            'Monty Python: (hidden);',
 
2068
            'Monty Python: ;',
 
2069
            [],
 
2070
            '')
 
2071
        self.assertEqual(group.token_type, 'group')
 
2072
        self.assertEqual(group.display_name, 'Monty Python')
 
2073
        self.assertEqual(len(group.mailboxes), 0)
 
2074
        self.assertEqual(group.mailboxes,
 
2075
                         group.all_mailboxes)
 
2076
 
 
2077
    def test_get_group_single_mailbox(self):
 
2078
        group = self._test_get_x(parser.get_group,
 
2079
            'Monty Python: "Fred A. Bear" <dinsdale@example.com>;',
 
2080
            'Monty Python: "Fred A. Bear" <dinsdale@example.com>;',
 
2081
            'Monty Python: "Fred A. Bear" <dinsdale@example.com>;',
 
2082
            [],
 
2083
            '')
 
2084
        self.assertEqual(group.token_type, 'group')
 
2085
        self.assertEqual(group.display_name, 'Monty Python')
 
2086
        self.assertEqual(len(group.mailboxes), 1)
 
2087
        self.assertEqual(group.mailboxes,
 
2088
                         group.all_mailboxes)
 
2089
        self.assertEqual(group.mailboxes[0].addr_spec,
 
2090
                         'dinsdale@example.com')
 
2091
 
 
2092
    def test_get_group_mixed_list(self):
 
2093
        group = self._test_get_x(parser.get_group,
 
2094
            ('Monty Python: "Fred A. Bear" <dinsdale@example.com>,'
 
2095
                '(foo) Roger <ping@exampele.com>, x@test.example.com;'),
 
2096
            ('Monty Python: "Fred A. Bear" <dinsdale@example.com>,'
 
2097
                '(foo) Roger <ping@exampele.com>, x@test.example.com;'),
 
2098
            ('Monty Python: "Fred A. Bear" <dinsdale@example.com>,'
 
2099
                ' Roger <ping@exampele.com>, x@test.example.com;'),
 
2100
            [],
 
2101
            '')
 
2102
        self.assertEqual(group.token_type, 'group')
 
2103
        self.assertEqual(group.display_name, 'Monty Python')
 
2104
        self.assertEqual(len(group.mailboxes), 3)
 
2105
        self.assertEqual(group.mailboxes,
 
2106
                         group.all_mailboxes)
 
2107
        self.assertEqual(group.mailboxes[0].display_name,
 
2108
                         'Fred A. Bear')
 
2109
        self.assertEqual(group.mailboxes[1].display_name,
 
2110
                         'Roger')
 
2111
        self.assertEqual(group.mailboxes[2].local_part, 'x')
 
2112
 
 
2113
    def test_get_group_one_invalid(self):
 
2114
        group = self._test_get_x(parser.get_group,
 
2115
            ('Monty Python: "Fred A. Bear" <dinsdale@example.com>,'
 
2116
                '(foo) Roger ping@exampele.com, x@test.example.com;'),
 
2117
            ('Monty Python: "Fred A. Bear" <dinsdale@example.com>,'
 
2118
                '(foo) Roger ping@exampele.com, x@test.example.com;'),
 
2119
            ('Monty Python: "Fred A. Bear" <dinsdale@example.com>,'
 
2120
                ' Roger ping@exampele.com, x@test.example.com;'),
 
2121
            [errors.InvalidHeaderDefect,   # non-angle addr makes local part invalid
 
2122
             errors.InvalidHeaderDefect],   # and its not obs-local either: no dots.
 
2123
            '')
 
2124
        self.assertEqual(group.token_type, 'group')
 
2125
        self.assertEqual(group.display_name, 'Monty Python')
 
2126
        self.assertEqual(len(group.mailboxes), 2)
 
2127
        self.assertEqual(len(group.all_mailboxes), 3)
 
2128
        self.assertEqual(group.mailboxes[0].display_name,
 
2129
                         'Fred A. Bear')
 
2130
        self.assertEqual(group.mailboxes[1].local_part, 'x')
 
2131
        self.assertIsNone(group.all_mailboxes[1].display_name)
 
2132
 
 
2133
    # get_address
 
2134
 
 
2135
    def test_get_address_simple(self):
 
2136
        address = self._test_get_x(parser.get_address,
 
2137
            'dinsdale@example.com',
 
2138
            'dinsdale@example.com',
 
2139
            'dinsdale@example.com',
 
2140
            [],
 
2141
            '')
 
2142
        self.assertEqual(address.token_type, 'address')
 
2143
        self.assertEqual(len(address.mailboxes), 1)
 
2144
        self.assertEqual(address.mailboxes,
 
2145
                         address.all_mailboxes)
 
2146
        self.assertEqual(address.mailboxes[0].domain,
 
2147
                         'example.com')
 
2148
        self.assertEqual(address[0].token_type,
 
2149
                         'mailbox')
 
2150
 
 
2151
    def test_get_address_complex(self):
 
2152
        address = self._test_get_x(parser.get_address,
 
2153
            '(foo) "Fred A. Bear" <(bird)dinsdale@example.com>',
 
2154
            '(foo) "Fred A. Bear" <(bird)dinsdale@example.com>',
 
2155
            ' "Fred A. Bear" < dinsdale@example.com>',
 
2156
            [],
 
2157
            '')
 
2158
        self.assertEqual(address.token_type, 'address')
 
2159
        self.assertEqual(len(address.mailboxes), 1)
 
2160
        self.assertEqual(address.mailboxes,
 
2161
                         address.all_mailboxes)
 
2162
        self.assertEqual(address.mailboxes[0].display_name,
 
2163
                         'Fred A. Bear')
 
2164
        self.assertEqual(address[0].token_type,
 
2165
                         'mailbox')
 
2166
 
 
2167
    def test_get_address_rfc2047_display_name(self):
 
2168
        address = self._test_get_x(parser.get_address,
 
2169
            '=?utf-8?q?=C3=89ric?= <foo@example.com>',
 
2170
            'Éric <foo@example.com>',
 
2171
            'Éric <foo@example.com>',
 
2172
            [],
 
2173
            '')
 
2174
        self.assertEqual(address.token_type, 'address')
 
2175
        self.assertEqual(len(address.mailboxes), 1)
 
2176
        self.assertEqual(address.mailboxes,
 
2177
                         address.all_mailboxes)
 
2178
        self.assertEqual(address.mailboxes[0].display_name,
 
2179
                         'Éric')
 
2180
        self.assertEqual(address[0].token_type,
 
2181
                         'mailbox')
 
2182
 
 
2183
    def test_get_address_empty_group(self):
 
2184
        address = self._test_get_x(parser.get_address,
 
2185
            'Monty Python:;',
 
2186
            'Monty Python:;',
 
2187
            'Monty Python:;',
 
2188
            [],
 
2189
            '')
 
2190
        self.assertEqual(address.token_type, 'address')
 
2191
        self.assertEqual(len(address.mailboxes), 0)
 
2192
        self.assertEqual(address.mailboxes,
 
2193
                         address.all_mailboxes)
 
2194
        self.assertEqual(address[0].token_type,
 
2195
                         'group')
 
2196
        self.assertEqual(address[0].display_name,
 
2197
                         'Monty Python')
 
2198
 
 
2199
    def test_get_address_group(self):
 
2200
        address = self._test_get_x(parser.get_address,
 
2201
            'Monty Python: x@example.com, y@example.com;',
 
2202
            'Monty Python: x@example.com, y@example.com;',
 
2203
            'Monty Python: x@example.com, y@example.com;',
 
2204
            [],
 
2205
            '')
 
2206
        self.assertEqual(address.token_type, 'address')
 
2207
        self.assertEqual(len(address.mailboxes), 2)
 
2208
        self.assertEqual(address.mailboxes,
 
2209
                         address.all_mailboxes)
 
2210
        self.assertEqual(address[0].token_type,
 
2211
                         'group')
 
2212
        self.assertEqual(address[0].display_name,
 
2213
                         'Monty Python')
 
2214
        self.assertEqual(address.mailboxes[0].local_part, 'x')
 
2215
 
 
2216
    def test_get_address_quoted_local_part(self):
 
2217
        address = self._test_get_x(parser.get_address,
 
2218
            '"foo bar"@example.com',
 
2219
            '"foo bar"@example.com',
 
2220
            '"foo bar"@example.com',
 
2221
            [],
 
2222
            '')
 
2223
        self.assertEqual(address.token_type, 'address')
 
2224
        self.assertEqual(len(address.mailboxes), 1)
 
2225
        self.assertEqual(address.mailboxes,
 
2226
                         address.all_mailboxes)
 
2227
        self.assertEqual(address.mailboxes[0].domain,
 
2228
                         'example.com')
 
2229
        self.assertEqual(address.mailboxes[0].local_part,
 
2230
                         'foo bar')
 
2231
        self.assertEqual(address[0].token_type, 'mailbox')
 
2232
 
 
2233
    def test_get_address_ends_at_special(self):
 
2234
        address = self._test_get_x(parser.get_address,
 
2235
            'dinsdale@example.com, next',
 
2236
            'dinsdale@example.com',
 
2237
            'dinsdale@example.com',
 
2238
            [],
 
2239
            ', next')
 
2240
        self.assertEqual(address.token_type, 'address')
 
2241
        self.assertEqual(len(address.mailboxes), 1)
 
2242
        self.assertEqual(address.mailboxes,
 
2243
                         address.all_mailboxes)
 
2244
        self.assertEqual(address.mailboxes[0].domain,
 
2245
                         'example.com')
 
2246
        self.assertEqual(address[0].token_type, 'mailbox')
 
2247
 
 
2248
    def test_get_address_invalid_mailbox_invalid(self):
 
2249
        address = self._test_get_x(parser.get_address,
 
2250
            'ping example.com, next',
 
2251
            'ping example.com',
 
2252
            'ping example.com',
 
2253
            [errors.InvalidHeaderDefect,    # addr-spec with no domain
 
2254
             errors.InvalidHeaderDefect,    # invalid local-part
 
2255
             errors.InvalidHeaderDefect,    # missing .s in local-part
 
2256
            ],
 
2257
            ', next')
 
2258
        self.assertEqual(address.token_type, 'address')
 
2259
        self.assertEqual(len(address.mailboxes), 0)
 
2260
        self.assertEqual(len(address.all_mailboxes), 1)
 
2261
        self.assertIsNone(address.all_mailboxes[0].domain)
 
2262
        self.assertEqual(address.all_mailboxes[0].local_part, 'ping example.com')
 
2263
        self.assertEqual(address[0].token_type, 'invalid-mailbox')
 
2264
 
 
2265
    def test_get_address_quoted_strings_in_atom_list(self):
 
2266
        address = self._test_get_x(parser.get_address,
 
2267
            '""example" example"@example.com',
 
2268
            '""example" example"@example.com',
 
2269
            'example example@example.com',
 
2270
            [errors.InvalidHeaderDefect]*3,
 
2271
            '')
 
2272
        self.assertEqual(address.all_mailboxes[0].local_part, 'example example')
 
2273
        self.assertEqual(address.all_mailboxes[0].domain, 'example.com')
 
2274
        self.assertEqual(address.all_mailboxes[0].addr_spec, '"example example"@example.com')
 
2275
 
 
2276
 
 
2277
    # get_address_list
 
2278
 
 
2279
    def test_get_address_list_mailboxes_simple(self):
 
2280
        address_list = self._test_get_x(parser.get_address_list,
 
2281
            'dinsdale@example.com',
 
2282
            'dinsdale@example.com',
 
2283
            'dinsdale@example.com',
 
2284
            [],
 
2285
            '')
 
2286
        self.assertEqual(address_list.token_type, 'address-list')
 
2287
        self.assertEqual(len(address_list.mailboxes), 1)
 
2288
        self.assertEqual(address_list.mailboxes,
 
2289
                         address_list.all_mailboxes)
 
2290
        self.assertEqual([str(x) for x in address_list.mailboxes],
 
2291
                         [str(x) for x in address_list.addresses])
 
2292
        self.assertEqual(address_list.mailboxes[0].domain, 'example.com')
 
2293
        self.assertEqual(address_list[0].token_type, 'address')
 
2294
        self.assertIsNone(address_list[0].display_name)
 
2295
 
 
2296
    def test_get_address_list_mailboxes_two_simple(self):
 
2297
        address_list = self._test_get_x(parser.get_address_list,
 
2298
            'foo@example.com, "Fred A. Bar" <bar@example.com>',
 
2299
            'foo@example.com, "Fred A. Bar" <bar@example.com>',
 
2300
            'foo@example.com, "Fred A. Bar" <bar@example.com>',
 
2301
            [],
 
2302
            '')
 
2303
        self.assertEqual(address_list.token_type, 'address-list')
 
2304
        self.assertEqual(len(address_list.mailboxes), 2)
 
2305
        self.assertEqual(address_list.mailboxes,
 
2306
                         address_list.all_mailboxes)
 
2307
        self.assertEqual([str(x) for x in address_list.mailboxes],
 
2308
                         [str(x) for x in address_list.addresses])
 
2309
        self.assertEqual(address_list.mailboxes[0].local_part, 'foo')
 
2310
        self.assertEqual(address_list.mailboxes[1].display_name, "Fred A. Bar")
 
2311
 
 
2312
    def test_get_address_list_mailboxes_complex(self):
 
2313
        address_list = self._test_get_x(parser.get_address_list,
 
2314
            ('"Roy A. Bear" <dinsdale@example.com>, '
 
2315
                '(ping) Foo <x@example.com>,'
 
2316
                'Nobody Is. Special <y@(bird)example.(bad)com>'),
 
2317
            ('"Roy A. Bear" <dinsdale@example.com>, '
 
2318
                '(ping) Foo <x@example.com>,'
 
2319
                'Nobody Is. Special <y@(bird)example.(bad)com>'),
 
2320
            ('"Roy A. Bear" <dinsdale@example.com>, '
 
2321
                'Foo <x@example.com>,'
 
2322
                '"Nobody Is. Special" <y@example. com>'),
 
2323
            [errors.ObsoleteHeaderDefect, # period in Is.
 
2324
            errors.ObsoleteHeaderDefect], # cfws in domain
 
2325
            '')
 
2326
        self.assertEqual(address_list.token_type, 'address-list')
 
2327
        self.assertEqual(len(address_list.mailboxes), 3)
 
2328
        self.assertEqual(address_list.mailboxes,
 
2329
                         address_list.all_mailboxes)
 
2330
        self.assertEqual([str(x) for x in address_list.mailboxes],
 
2331
                         [str(x) for x in address_list.addresses])
 
2332
        self.assertEqual(address_list.mailboxes[0].domain, 'example.com')
 
2333
        self.assertEqual(address_list.mailboxes[0].token_type, 'mailbox')
 
2334
        self.assertEqual(address_list.addresses[0].token_type, 'address')
 
2335
        self.assertEqual(address_list.mailboxes[1].local_part, 'x')
 
2336
        self.assertEqual(address_list.mailboxes[2].display_name,
 
2337
                         'Nobody Is. Special')
 
2338
 
 
2339
    def test_get_address_list_mailboxes_invalid_addresses(self):
 
2340
        address_list = self._test_get_x(parser.get_address_list,
 
2341
            ('"Roy A. Bear" <dinsdale@example.com>, '
 
2342
                '(ping) Foo x@example.com[],'
 
2343
                'Nobody Is. Special <(bird)example.(bad)com>'),
 
2344
            ('"Roy A. Bear" <dinsdale@example.com>, '
 
2345
                '(ping) Foo x@example.com[],'
 
2346
                'Nobody Is. Special <(bird)example.(bad)com>'),
 
2347
            ('"Roy A. Bear" <dinsdale@example.com>, '
 
2348
                'Foo x@example.com[],'
 
2349
                '"Nobody Is. Special" < example. com>'),
 
2350
             [errors.InvalidHeaderDefect,   # invalid address in list
 
2351
              errors.InvalidHeaderDefect,   # 'Foo x' local part invalid.
 
2352
              errors.InvalidHeaderDefect,   # Missing . in 'Foo x' local part
 
2353
              errors.ObsoleteHeaderDefect,  # period in 'Is.' disp-name phrase
 
2354
              errors.InvalidHeaderDefect,   # no domain part in addr-spec
 
2355
              errors.ObsoleteHeaderDefect], # addr-spec has comment in it
 
2356
            '')
 
2357
        self.assertEqual(address_list.token_type, 'address-list')
 
2358
        self.assertEqual(len(address_list.mailboxes), 1)
 
2359
        self.assertEqual(len(address_list.all_mailboxes), 3)
 
2360
        self.assertEqual([str(x) for x in address_list.all_mailboxes],
 
2361
                         [str(x) for x in address_list.addresses])
 
2362
        self.assertEqual(address_list.mailboxes[0].domain, 'example.com')
 
2363
        self.assertEqual(address_list.mailboxes[0].token_type, 'mailbox')
 
2364
        self.assertEqual(address_list.addresses[0].token_type, 'address')
 
2365
        self.assertEqual(address_list.addresses[1].token_type, 'address')
 
2366
        self.assertEqual(len(address_list.addresses[0].mailboxes), 1)
 
2367
        self.assertEqual(len(address_list.addresses[1].mailboxes), 0)
 
2368
        self.assertEqual(len(address_list.addresses[1].mailboxes), 0)
 
2369
        self.assertEqual(
 
2370
            address_list.addresses[1].all_mailboxes[0].local_part, 'Foo x')
 
2371
        self.assertEqual(
 
2372
            address_list.addresses[2].all_mailboxes[0].display_name,
 
2373
                "Nobody Is. Special")
 
2374
 
 
2375
    def test_get_address_list_group_empty(self):
 
2376
        address_list = self._test_get_x(parser.get_address_list,
 
2377
            'Monty Python: ;',
 
2378
            'Monty Python: ;',
 
2379
            'Monty Python: ;',
 
2380
            [],
 
2381
            '')
 
2382
        self.assertEqual(address_list.token_type, 'address-list')
 
2383
        self.assertEqual(len(address_list.mailboxes), 0)
 
2384
        self.assertEqual(address_list.mailboxes,
 
2385
                         address_list.all_mailboxes)
 
2386
        self.assertEqual(len(address_list.addresses), 1)
 
2387
        self.assertEqual(address_list.addresses[0].token_type, 'address')
 
2388
        self.assertEqual(address_list.addresses[0].display_name, 'Monty Python')
 
2389
        self.assertEqual(len(address_list.addresses[0].mailboxes), 0)
 
2390
 
 
2391
    def test_get_address_list_group_simple(self):
 
2392
        address_list = self._test_get_x(parser.get_address_list,
 
2393
            'Monty Python: dinsdale@example.com;',
 
2394
            'Monty Python: dinsdale@example.com;',
 
2395
            'Monty Python: dinsdale@example.com;',
 
2396
            [],
 
2397
            '')
 
2398
        self.assertEqual(address_list.token_type, 'address-list')
 
2399
        self.assertEqual(len(address_list.mailboxes), 1)
 
2400
        self.assertEqual(address_list.mailboxes,
 
2401
                         address_list.all_mailboxes)
 
2402
        self.assertEqual(address_list.mailboxes[0].domain, 'example.com')
 
2403
        self.assertEqual(address_list.addresses[0].display_name,
 
2404
                         'Monty Python')
 
2405
        self.assertEqual(address_list.addresses[0].mailboxes[0].domain,
 
2406
                         'example.com')
 
2407
 
 
2408
    def test_get_address_list_group_and_mailboxes(self):
 
2409
        address_list = self._test_get_x(parser.get_address_list,
 
2410
            ('Monty Python: dinsdale@example.com, "Fred" <flint@example.com>;, '
 
2411
                'Abe <x@example.com>, Bee <y@example.com>'),
 
2412
            ('Monty Python: dinsdale@example.com, "Fred" <flint@example.com>;, '
 
2413
                'Abe <x@example.com>, Bee <y@example.com>'),
 
2414
            ('Monty Python: dinsdale@example.com, "Fred" <flint@example.com>;, '
 
2415
                'Abe <x@example.com>, Bee <y@example.com>'),
 
2416
            [],
 
2417
            '')
 
2418
        self.assertEqual(address_list.token_type, 'address-list')
 
2419
        self.assertEqual(len(address_list.mailboxes), 4)
 
2420
        self.assertEqual(address_list.mailboxes,
 
2421
                         address_list.all_mailboxes)
 
2422
        self.assertEqual(len(address_list.addresses), 3)
 
2423
        self.assertEqual(address_list.mailboxes[0].local_part, 'dinsdale')
 
2424
        self.assertEqual(address_list.addresses[0].display_name,
 
2425
                         'Monty Python')
 
2426
        self.assertEqual(address_list.addresses[0].mailboxes[0].domain,
 
2427
                         'example.com')
 
2428
        self.assertEqual(address_list.addresses[0].mailboxes[1].local_part,
 
2429
                         'flint')
 
2430
        self.assertEqual(address_list.addresses[1].mailboxes[0].local_part,
 
2431
                         'x')
 
2432
        self.assertEqual(address_list.addresses[2].mailboxes[0].local_part,
 
2433
                         'y')
 
2434
        self.assertEqual(str(address_list.addresses[1]),
 
2435
                         str(address_list.mailboxes[2]))
 
2436
 
 
2437
 
 
2438
@parameterize
 
2439
class Test_parse_mime_version(TestParserMixin, TestEmailBase):
 
2440
 
 
2441
    def mime_version_as_value(self,
 
2442
                              value,
 
2443
                              tl_str,
 
2444
                              tl_value,
 
2445
                              major,
 
2446
                              minor,
 
2447
                              defects):
 
2448
        mime_version = self._test_parse_x(parser.parse_mime_version,
 
2449
            value, tl_str, tl_value, defects)
 
2450
        self.assertEqual(mime_version.major, major)
 
2451
        self.assertEqual(mime_version.minor, minor)
 
2452
 
 
2453
    mime_version_params = {
 
2454
 
 
2455
        'rfc_2045_1': (
 
2456
            '1.0',
 
2457
            '1.0',
 
2458
            '1.0',
 
2459
            1,
 
2460
            0,
 
2461
            []),
 
2462
 
 
2463
        'RFC_2045_2': (
 
2464
            '1.0 (produced by MetaSend Vx.x)',
 
2465
            '1.0 (produced by MetaSend Vx.x)',
 
2466
            '1.0 ',
 
2467
            1,
 
2468
            0,
 
2469
            []),
 
2470
 
 
2471
        'RFC_2045_3': (
 
2472
            '(produced by MetaSend Vx.x) 1.0',
 
2473
            '(produced by MetaSend Vx.x) 1.0',
 
2474
            ' 1.0',
 
2475
            1,
 
2476
            0,
 
2477
            []),
 
2478
 
 
2479
        'RFC_2045_4': (
 
2480
            '1.(produced by MetaSend Vx.x)0',
 
2481
            '1.(produced by MetaSend Vx.x)0',
 
2482
            '1. 0',
 
2483
            1,
 
2484
            0,
 
2485
            []),
 
2486
 
 
2487
        'empty': (
 
2488
            '',
 
2489
            '',
 
2490
            '',
 
2491
            None,
 
2492
            None,
 
2493
            [errors.HeaderMissingRequiredValue]),
 
2494
 
 
2495
        }
 
2496
 
 
2497
 
 
2498
 
 
2499
class TestFolding(TestEmailBase):
 
2500
 
 
2501
    policy = policy.default
 
2502
 
 
2503
    def _test(self, tl, folded, policy=policy):
 
2504
        self.assertEqual(tl.fold(policy=policy), folded, tl.ppstr())
 
2505
 
 
2506
    def test_simple_unstructured_no_folds(self):
 
2507
        self._test(parser.get_unstructured("This is a test"),
 
2508
                   "This is a test\n")
 
2509
 
 
2510
    def test_simple_unstructured_folded(self):
 
2511
        self._test(parser.get_unstructured("This is also a test, but this "
 
2512
                        "time there are enough words (and even some "
 
2513
                        "symbols) to make it wrap; at least in theory."),
 
2514
                   "This is also a test, but this time there are enough "
 
2515
                        "words (and even some\n"
 
2516
                   " symbols) to make it wrap; at least in theory.\n")
 
2517
 
 
2518
    def test_unstructured_with_unicode_no_folds(self):
 
2519
        self._test(parser.get_unstructured("hübsch kleiner beißt"),
 
2520
                   "=?utf-8?q?h=C3=BCbsch_kleiner_bei=C3=9Ft?=\n")
 
2521
 
 
2522
    def test_one_ew_on_each_of_two_wrapped_lines(self):
 
2523
        self._test(parser.get_unstructured("Mein kleiner Kaktus ist sehr "
 
2524
                                           "hübsch.  Es hat viele Stacheln "
 
2525
                                           "und oft beißt mich."),
 
2526
                   "Mein kleiner Kaktus ist sehr =?utf-8?q?h=C3=BCbsch=2E?=  "
 
2527
                        "Es hat viele Stacheln\n"
 
2528
                   " und oft =?utf-8?q?bei=C3=9Ft?= mich.\n")
 
2529
 
 
2530
    def test_ews_combined_before_wrap(self):
 
2531
        self._test(parser.get_unstructured("Mein Kaktus ist hübsch.  "
 
2532
                                           "Es beißt mich.  "
 
2533
                                           "And that's all I'm sayin."),
 
2534
                   "Mein Kaktus ist =?utf-8?q?h=C3=BCbsch=2E__Es_bei=C3=9Ft?= "
 
2535
                        "mich.  And that's\n"
 
2536
                   " all I'm sayin.\n")
 
2537
 
 
2538
    # XXX Need test of an encoded word so long that it needs to be wrapped
 
2539
 
 
2540
    def test_simple_address(self):
 
2541
        self._test(parser.get_address_list("abc <xyz@example.com>")[0],
 
2542
                   "abc <xyz@example.com>\n")
 
2543
 
 
2544
    def test_address_list_folding_at_commas(self):
 
2545
        self._test(parser.get_address_list('abc <xyz@example.com>, '
 
2546
                                            '"Fred Blunt" <sharp@example.com>, '
 
2547
                                            '"J.P.Cool" <hot@example.com>, '
 
2548
                                            '"K<>y" <key@example.com>, '
 
2549
                                            'Firesale <cheap@example.com>, '
 
2550
                                            '<end@example.com>')[0],
 
2551
                    'abc <xyz@example.com>, "Fred Blunt" <sharp@example.com>,\n'
 
2552
                    ' "J.P.Cool" <hot@example.com>, "K<>y" <key@example.com>,\n'
 
2553
                    ' Firesale <cheap@example.com>, <end@example.com>\n')
 
2554
 
 
2555
    def test_address_list_with_unicode_names(self):
 
2556
        self._test(parser.get_address_list(
 
2557
            'Hübsch Kaktus <beautiful@example.com>, '
 
2558
                'beißt beißt <biter@example.com>')[0],
 
2559
            '=?utf-8?q?H=C3=BCbsch?= Kaktus <beautiful@example.com>,\n'
 
2560
                ' =?utf-8?q?bei=C3=9Ft_bei=C3=9Ft?= <biter@example.com>\n')
 
2561
 
 
2562
    def test_address_list_with_unicode_names_in_quotes(self):
 
2563
        self._test(parser.get_address_list(
 
2564
            '"Hübsch Kaktus" <beautiful@example.com>, '
 
2565
                '"beißt" beißt <biter@example.com>')[0],
 
2566
            '=?utf-8?q?H=C3=BCbsch?= Kaktus <beautiful@example.com>,\n'
 
2567
                ' =?utf-8?q?bei=C3=9Ft_bei=C3=9Ft?= <biter@example.com>\n')
 
2568
 
 
2569
    # XXX Need tests with comments on various sides of a unicode token,
 
2570
    # and with unicode tokens in the comments.  Spaces inside the quotes
 
2571
    # currently don't do the right thing.
 
2572
 
 
2573
    def test_initial_whitespace_splitting(self):
 
2574
        body = parser.get_unstructured('   ' + 'x'*77)
 
2575
        header = parser.Header([
 
2576
            parser.HeaderLabel([parser.ValueTerminal('test:', 'atext')]),
 
2577
            parser.CFWSList([parser.WhiteSpaceTerminal(' ', 'fws')]), body])
 
2578
        self._test(header, 'test:   \n ' + 'x'*77 + '\n')
 
2579
 
 
2580
    def test_whitespace_splitting(self):
 
2581
        self._test(parser.get_unstructured('xxx   ' + 'y'*77),
 
2582
                   'xxx  \n ' + 'y'*77 + '\n')
 
2583
 
 
2584
if __name__ == '__main__':
 
2585
    unittest.main()