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