blob: 5cdc4bcecad44769c57889b98032ba15568a28ce [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
jayyyinaa218d12018-01-29 13:07:44 -0500493 def test_get_bare_quoted_string_only_quotes(self):
494 self._test_get_x(parser.get_bare_quoted_string,
495 '""', '""', '', [], '')
496
R David Murray0b6f6c82012-05-25 18:42:14 -0400497 def test_get_bare_quoted_string_following_wsp_preserved(self):
498 self._test_get_x(parser.get_bare_quoted_string,
499 '"foo"\t bar', '"foo"', 'foo', [], '\t bar')
500
501 def test_get_bare_quoted_string_multiple_words(self):
502 self._test_get_x(parser.get_bare_quoted_string,
503 '"foo bar moo"', '"foo bar moo"', 'foo bar moo', [], '')
504
505 def test_get_bare_quoted_string_multiple_words_wsp_preserved(self):
506 self._test_get_x(parser.get_bare_quoted_string,
507 '" foo moo\t"', '" foo moo\t"', ' foo moo\t', [], '')
508
509 def test_get_bare_quoted_string_end_dquote_mid_word(self):
510 self._test_get_x(parser.get_bare_quoted_string,
511 '"foo"bar', '"foo"', 'foo', [], 'bar')
512
513 def test_get_bare_quoted_string_quoted_dquote(self):
514 self._test_get_x(parser.get_bare_quoted_string,
515 r'"foo\"in"a', r'"foo\"in"', 'foo"in', [], 'a')
516
517 def test_get_bare_quoted_string_non_printables(self):
518 self._test_get_x(parser.get_bare_quoted_string,
519 '"a\x01a"', '"a\x01a"', 'a\x01a',
520 [errors.NonPrintableDefect], '')
521
522 def test_get_bare_quoted_string_no_end_dquote(self):
523 self._test_get_x(parser.get_bare_quoted_string,
524 '"foo', '"foo"', 'foo',
525 [errors.InvalidHeaderDefect], '')
526 self._test_get_x(parser.get_bare_quoted_string,
527 '"foo ', '"foo "', 'foo ',
528 [errors.InvalidHeaderDefect], '')
529
530 def test_get_bare_quoted_string_empty_quotes(self):
531 self._test_get_x(parser.get_bare_quoted_string,
532 '""', '""', '', [], '')
533
R David Murray0400d332014-02-08 13:12:00 -0500534 # Issue 16983: apply postel's law to some bad encoding.
535 def test_encoded_word_inside_quotes(self):
536 self._test_get_x(parser.get_bare_quoted_string,
537 '"=?utf-8?Q?not_really_valid?="',
538 '"not really valid"',
539 'not really valid',
540 [errors.InvalidHeaderDefect],
541 '')
542
R David Murray0b6f6c82012-05-25 18:42:14 -0400543 # get_comment
544
545 def test_get_comment_only(self):
546 comment = self._test_get_x(parser.get_comment,
547 '(comment)', '(comment)', ' ', [], '', ['comment'])
548 self.assertEqual(comment.token_type, 'comment')
549
550 def test_get_comment_must_start_with_paren(self):
551 with self.assertRaises(errors.HeaderParseError):
552 parser.get_comment('foo"')
553 with self.assertRaises(errors.HeaderParseError):
554 parser.get_comment(' (foo"')
555
556 def test_get_comment_following_wsp_preserved(self):
557 self._test_get_x(parser.get_comment,
558 '(comment) \t', '(comment)', ' ', [], ' \t', ['comment'])
559
560 def test_get_comment_multiple_words(self):
561 self._test_get_x(parser.get_comment,
562 '(foo bar) \t', '(foo bar)', ' ', [], ' \t', ['foo bar'])
563
564 def test_get_comment_multiple_words_wsp_preserved(self):
565 self._test_get_x(parser.get_comment,
566 '( foo bar\t ) \t', '( foo bar\t )', ' ', [], ' \t',
567 [' foo bar\t '])
568
569 def test_get_comment_end_paren_mid_word(self):
570 self._test_get_x(parser.get_comment,
571 '(foo)bar', '(foo)', ' ', [], 'bar', ['foo'])
572
573 def test_get_comment_quoted_parens(self):
574 self._test_get_x(parser.get_comment,
R David Murray44b548d2016-09-08 13:59:53 -0400575 r'(foo\) \(\)bar)', r'(foo\) \(\)bar)', ' ', [], '', ['foo) ()bar'])
R David Murray0b6f6c82012-05-25 18:42:14 -0400576
577 def test_get_comment_non_printable(self):
578 self._test_get_x(parser.get_comment,
579 '(foo\x7Fbar)', '(foo\x7Fbar)', ' ',
580 [errors.NonPrintableDefect], '', ['foo\x7Fbar'])
581
582 def test_get_comment_no_end_paren(self):
583 self._test_get_x(parser.get_comment,
584 '(foo bar', '(foo bar)', ' ',
585 [errors.InvalidHeaderDefect], '', ['foo bar'])
586 self._test_get_x(parser.get_comment,
587 '(foo bar ', '(foo bar )', ' ',
588 [errors.InvalidHeaderDefect], '', ['foo bar '])
589
590 def test_get_comment_nested_comment(self):
591 comment = self._test_get_x(parser.get_comment,
592 '(foo(bar))', '(foo(bar))', ' ', [], '', ['foo(bar)'])
593 self.assertEqual(comment[1].content, 'bar')
594
595 def test_get_comment_nested_comment_wsp(self):
596 comment = self._test_get_x(parser.get_comment,
597 '(foo ( bar ) )', '(foo ( bar ) )', ' ', [], '', ['foo ( bar ) '])
598 self.assertEqual(comment[2].content, ' bar ')
599
600 def test_get_comment_empty_comment(self):
601 self._test_get_x(parser.get_comment,
602 '()', '()', ' ', [], '', [''])
603
604 def test_get_comment_multiple_nesting(self):
605 comment = self._test_get_x(parser.get_comment,
606 '(((((foo)))))', '(((((foo)))))', ' ', [], '', ['((((foo))))'])
607 for i in range(4, 0, -1):
608 self.assertEqual(comment[0].content, '('*(i-1)+'foo'+')'*(i-1))
609 comment = comment[0]
610 self.assertEqual(comment.content, 'foo')
611
612 def test_get_comment_missing_end_of_nesting(self):
613 self._test_get_x(parser.get_comment,
614 '(((((foo)))', '(((((foo)))))', ' ',
615 [errors.InvalidHeaderDefect]*2, '', ['((((foo))))'])
616
617 def test_get_comment_qs_in_nested_comment(self):
618 comment = self._test_get_x(parser.get_comment,
R David Murray44b548d2016-09-08 13:59:53 -0400619 r'(foo (b\)))', r'(foo (b\)))', ' ', [], '', [r'foo (b\))'])
R David Murray0b6f6c82012-05-25 18:42:14 -0400620 self.assertEqual(comment[2].content, 'b)')
621
622 # get_cfws
623
624 def test_get_cfws_only_ws(self):
625 cfws = self._test_get_x(parser.get_cfws,
626 ' \t \t', ' \t \t', ' ', [], '', [])
627 self.assertEqual(cfws.token_type, 'cfws')
628
629 def test_get_cfws_only_comment(self):
630 cfws = self._test_get_x(parser.get_cfws,
631 '(foo)', '(foo)', ' ', [], '', ['foo'])
632 self.assertEqual(cfws[0].content, 'foo')
633
634 def test_get_cfws_only_mixed(self):
635 cfws = self._test_get_x(parser.get_cfws,
636 ' (foo ) ( bar) ', ' (foo ) ( bar) ', ' ', [], '',
637 ['foo ', ' bar'])
638 self.assertEqual(cfws[1].content, 'foo ')
639 self.assertEqual(cfws[3].content, ' bar')
640
641 def test_get_cfws_ends_at_non_leader(self):
642 cfws = self._test_get_x(parser.get_cfws,
643 '(foo) bar', '(foo) ', ' ', [], 'bar', ['foo'])
644 self.assertEqual(cfws[0].content, 'foo')
645
646 def test_get_cfws_ends_at_non_printable(self):
647 cfws = self._test_get_x(parser.get_cfws,
648 '(foo) \x07', '(foo) ', ' ', [], '\x07', ['foo'])
649 self.assertEqual(cfws[0].content, 'foo')
650
651 def test_get_cfws_non_printable_in_comment(self):
652 cfws = self._test_get_x(parser.get_cfws,
653 '(foo \x07) "test"', '(foo \x07) ', ' ',
654 [errors.NonPrintableDefect], '"test"', ['foo \x07'])
655 self.assertEqual(cfws[0].content, 'foo \x07')
656
657 def test_get_cfws_header_ends_in_comment(self):
658 cfws = self._test_get_x(parser.get_cfws,
659 ' (foo ', ' (foo )', ' ',
660 [errors.InvalidHeaderDefect], '', ['foo '])
661 self.assertEqual(cfws[1].content, 'foo ')
662
663 def test_get_cfws_multiple_nested_comments(self):
664 cfws = self._test_get_x(parser.get_cfws,
665 '(foo (bar)) ((a)(a))', '(foo (bar)) ((a)(a))', ' ', [],
666 '', ['foo (bar)', '(a)(a)'])
667 self.assertEqual(cfws[0].comments, ['foo (bar)'])
668 self.assertEqual(cfws[2].comments, ['(a)(a)'])
669
670 # get_quoted_string
671
672 def test_get_quoted_string_only(self):
673 qs = self._test_get_x(parser.get_quoted_string,
674 '"bob"', '"bob"', 'bob', [], '')
675 self.assertEqual(qs.token_type, 'quoted-string')
676 self.assertEqual(qs.quoted_value, '"bob"')
677 self.assertEqual(qs.content, 'bob')
678
679 def test_get_quoted_string_with_wsp(self):
680 qs = self._test_get_x(parser.get_quoted_string,
681 '\t "bob" ', '\t "bob" ', ' bob ', [], '')
682 self.assertEqual(qs.quoted_value, ' "bob" ')
683 self.assertEqual(qs.content, 'bob')
684
685 def test_get_quoted_string_with_comments_and_wsp(self):
686 qs = self._test_get_x(parser.get_quoted_string,
687 ' (foo) "bob"(bar)', ' (foo) "bob"(bar)', ' bob ', [], '')
688 self.assertEqual(qs[0][1].content, 'foo')
689 self.assertEqual(qs[2][0].content, 'bar')
690 self.assertEqual(qs.content, 'bob')
691 self.assertEqual(qs.quoted_value, ' "bob" ')
692
693 def test_get_quoted_string_with_multiple_comments(self):
694 qs = self._test_get_x(parser.get_quoted_string,
695 ' (foo) (bar) "bob"(bird)', ' (foo) (bar) "bob"(bird)', ' bob ',
696 [], '')
697 self.assertEqual(qs[0].comments, ['foo', 'bar'])
698 self.assertEqual(qs[2].comments, ['bird'])
699 self.assertEqual(qs.content, 'bob')
700 self.assertEqual(qs.quoted_value, ' "bob" ')
701
702 def test_get_quoted_string_non_printable_in_comment(self):
703 qs = self._test_get_x(parser.get_quoted_string,
704 ' (\x0A) "bob"', ' (\x0A) "bob"', ' bob',
705 [errors.NonPrintableDefect], '')
706 self.assertEqual(qs[0].comments, ['\x0A'])
707 self.assertEqual(qs.content, 'bob')
708 self.assertEqual(qs.quoted_value, ' "bob"')
709
710 def test_get_quoted_string_non_printable_in_qcontent(self):
711 qs = self._test_get_x(parser.get_quoted_string,
712 ' (a) "a\x0B"', ' (a) "a\x0B"', ' a\x0B',
713 [errors.NonPrintableDefect], '')
714 self.assertEqual(qs[0].comments, ['a'])
715 self.assertEqual(qs.content, 'a\x0B')
716 self.assertEqual(qs.quoted_value, ' "a\x0B"')
717
718 def test_get_quoted_string_internal_ws(self):
719 qs = self._test_get_x(parser.get_quoted_string,
720 ' (a) "foo bar "', ' (a) "foo bar "', ' foo bar ',
721 [], '')
722 self.assertEqual(qs[0].comments, ['a'])
723 self.assertEqual(qs.content, 'foo bar ')
724 self.assertEqual(qs.quoted_value, ' "foo bar "')
725
726 def test_get_quoted_string_header_ends_in_comment(self):
727 qs = self._test_get_x(parser.get_quoted_string,
728 ' (a) "bob" (a', ' (a) "bob" (a)', ' bob ',
729 [errors.InvalidHeaderDefect], '')
730 self.assertEqual(qs[0].comments, ['a'])
731 self.assertEqual(qs[2].comments, ['a'])
732 self.assertEqual(qs.content, 'bob')
733 self.assertEqual(qs.quoted_value, ' "bob" ')
734
735 def test_get_quoted_string_header_ends_in_qcontent(self):
736 qs = self._test_get_x(parser.get_quoted_string,
737 ' (a) "bob', ' (a) "bob"', ' bob',
738 [errors.InvalidHeaderDefect], '')
739 self.assertEqual(qs[0].comments, ['a'])
740 self.assertEqual(qs.content, 'bob')
741 self.assertEqual(qs.quoted_value, ' "bob"')
742
743 def test_get_quoted_string_no_quoted_string(self):
744 with self.assertRaises(errors.HeaderParseError):
745 parser.get_quoted_string(' (ab) xyz')
746
747 def test_get_quoted_string_qs_ends_at_noncfws(self):
748 qs = self._test_get_x(parser.get_quoted_string,
749 '\t "bob" fee', '\t "bob" ', ' bob ', [], 'fee')
750 self.assertEqual(qs.content, 'bob')
751 self.assertEqual(qs.quoted_value, ' "bob" ')
752
753 # get_atom
754
755 def test_get_atom_only(self):
756 atom = self._test_get_x(parser.get_atom,
757 'bob', 'bob', 'bob', [], '')
758 self.assertEqual(atom.token_type, 'atom')
759
760 def test_get_atom_with_wsp(self):
761 self._test_get_x(parser.get_atom,
762 '\t bob ', '\t bob ', ' bob ', [], '')
763
764 def test_get_atom_with_comments_and_wsp(self):
765 atom = self._test_get_x(parser.get_atom,
766 ' (foo) bob(bar)', ' (foo) bob(bar)', ' bob ', [], '')
767 self.assertEqual(atom[0][1].content, 'foo')
768 self.assertEqual(atom[2][0].content, 'bar')
769
770 def test_get_atom_with_multiple_comments(self):
771 atom = self._test_get_x(parser.get_atom,
772 ' (foo) (bar) bob(bird)', ' (foo) (bar) bob(bird)', ' bob ',
773 [], '')
774 self.assertEqual(atom[0].comments, ['foo', 'bar'])
775 self.assertEqual(atom[2].comments, ['bird'])
776
777 def test_get_atom_non_printable_in_comment(self):
778 atom = self._test_get_x(parser.get_atom,
779 ' (\x0A) bob', ' (\x0A) bob', ' bob',
780 [errors.NonPrintableDefect], '')
781 self.assertEqual(atom[0].comments, ['\x0A'])
782
783 def test_get_atom_non_printable_in_atext(self):
784 atom = self._test_get_x(parser.get_atom,
785 ' (a) a\x0B', ' (a) a\x0B', ' a\x0B',
786 [errors.NonPrintableDefect], '')
787 self.assertEqual(atom[0].comments, ['a'])
788
789 def test_get_atom_header_ends_in_comment(self):
790 atom = self._test_get_x(parser.get_atom,
791 ' (a) bob (a', ' (a) bob (a)', ' bob ',
792 [errors.InvalidHeaderDefect], '')
793 self.assertEqual(atom[0].comments, ['a'])
794 self.assertEqual(atom[2].comments, ['a'])
795
796 def test_get_atom_no_atom(self):
797 with self.assertRaises(errors.HeaderParseError):
798 parser.get_atom(' (ab) ')
799
800 def test_get_atom_no_atom_before_special(self):
801 with self.assertRaises(errors.HeaderParseError):
802 parser.get_atom(' (ab) @')
803
804 def test_get_atom_atom_ends_at_special(self):
805 atom = self._test_get_x(parser.get_atom,
806 ' (foo) bob(bar) @bang', ' (foo) bob(bar) ', ' bob ', [], '@bang')
807 self.assertEqual(atom[0].comments, ['foo'])
808 self.assertEqual(atom[2].comments, ['bar'])
809
810 def test_get_atom_atom_ends_at_noncfws(self):
R David Murray923512f2013-07-12 16:00:28 -0400811 self._test_get_x(parser.get_atom,
R David Murray0b6f6c82012-05-25 18:42:14 -0400812 'bob fred', 'bob ', 'bob ', [], 'fred')
813
R David Murray923512f2013-07-12 16:00:28 -0400814 def test_get_atom_rfc2047_atom(self):
815 self._test_get_x(parser.get_atom,
816 '=?utf-8?q?=20bob?=', ' bob', ' bob', [], '')
817
R David Murray0b6f6c82012-05-25 18:42:14 -0400818 # get_dot_atom_text
819
820 def test_get_dot_atom_text(self):
821 dot_atom_text = self._test_get_x(parser.get_dot_atom_text,
822 'foo.bar.bang', 'foo.bar.bang', 'foo.bar.bang', [], '')
823 self.assertEqual(dot_atom_text.token_type, 'dot-atom-text')
824 self.assertEqual(len(dot_atom_text), 5)
825
826 def test_get_dot_atom_text_lone_atom_is_valid(self):
827 dot_atom_text = self._test_get_x(parser.get_dot_atom_text,
828 'foo', 'foo', 'foo', [], '')
829
830 def test_get_dot_atom_text_raises_on_leading_dot(self):
831 with self.assertRaises(errors.HeaderParseError):
832 parser.get_dot_atom_text('.foo.bar')
833
834 def test_get_dot_atom_text_raises_on_trailing_dot(self):
835 with self.assertRaises(errors.HeaderParseError):
836 parser.get_dot_atom_text('foo.bar.')
837
838 def test_get_dot_atom_text_raises_on_leading_non_atext(self):
839 with self.assertRaises(errors.HeaderParseError):
840 parser.get_dot_atom_text(' foo.bar')
841 with self.assertRaises(errors.HeaderParseError):
842 parser.get_dot_atom_text('@foo.bar')
843 with self.assertRaises(errors.HeaderParseError):
844 parser.get_dot_atom_text('"foo.bar"')
845
846 def test_get_dot_atom_text_trailing_text_preserved(self):
847 dot_atom_text = self._test_get_x(parser.get_dot_atom_text,
848 'foo@bar', 'foo', 'foo', [], '@bar')
849
850 def test_get_dot_atom_text_trailing_ws_preserved(self):
851 dot_atom_text = self._test_get_x(parser.get_dot_atom_text,
852 'foo .bar', 'foo', 'foo', [], ' .bar')
853
854 # get_dot_atom
855
856 def test_get_dot_atom_only(self):
857 dot_atom = self._test_get_x(parser.get_dot_atom,
858 'foo.bar.bing', 'foo.bar.bing', 'foo.bar.bing', [], '')
859 self.assertEqual(dot_atom.token_type, 'dot-atom')
860 self.assertEqual(len(dot_atom), 1)
861
862 def test_get_dot_atom_with_wsp(self):
863 self._test_get_x(parser.get_dot_atom,
864 '\t foo.bar.bing ', '\t foo.bar.bing ', ' foo.bar.bing ', [], '')
865
866 def test_get_dot_atom_with_comments_and_wsp(self):
867 self._test_get_x(parser.get_dot_atom,
868 ' (sing) foo.bar.bing (here) ', ' (sing) foo.bar.bing (here) ',
869 ' foo.bar.bing ', [], '')
870
871 def test_get_dot_atom_space_ends_dot_atom(self):
872 self._test_get_x(parser.get_dot_atom,
873 ' (sing) foo.bar .bing (here) ', ' (sing) foo.bar ',
874 ' foo.bar ', [], '.bing (here) ')
875
876 def test_get_dot_atom_no_atom_raises(self):
877 with self.assertRaises(errors.HeaderParseError):
878 parser.get_dot_atom(' (foo) ')
879
880 def test_get_dot_atom_leading_dot_raises(self):
881 with self.assertRaises(errors.HeaderParseError):
882 parser.get_dot_atom(' (foo) .bar')
883
884 def test_get_dot_atom_two_dots_raises(self):
885 with self.assertRaises(errors.HeaderParseError):
886 parser.get_dot_atom('bar..bang')
887
888 def test_get_dot_atom_trailing_dot_raises(self):
889 with self.assertRaises(errors.HeaderParseError):
890 parser.get_dot_atom(' (foo) bar.bang. foo')
891
R David Murray923512f2013-07-12 16:00:28 -0400892 def test_get_dot_atom_rfc2047_atom(self):
893 self._test_get_x(parser.get_dot_atom,
894 '=?utf-8?q?=20bob?=', ' bob', ' bob', [], '')
895
R David Murray0b6f6c82012-05-25 18:42:14 -0400896 # get_word (if this were black box we'd repeat all the qs/atom tests)
897
898 def test_get_word_atom_yields_atom(self):
899 word = self._test_get_x(parser.get_word,
900 ' (foo) bar (bang) :ah', ' (foo) bar (bang) ', ' bar ', [], ':ah')
901 self.assertEqual(word.token_type, 'atom')
902 self.assertEqual(word[0].token_type, 'cfws')
903
904 def test_get_word_qs_yields_qs(self):
905 word = self._test_get_x(parser.get_word,
906 '"bar " (bang) ah', '"bar " (bang) ', 'bar ', [], 'ah')
907 self.assertEqual(word.token_type, 'quoted-string')
908 self.assertEqual(word[0].token_type, 'bare-quoted-string')
909 self.assertEqual(word[0].value, 'bar ')
910 self.assertEqual(word.content, 'bar ')
911
912 def test_get_word_ends_at_dot(self):
913 self._test_get_x(parser.get_word,
914 'foo.', 'foo', 'foo', [], '.')
915
916 # get_phrase
917
918 def test_get_phrase_simple(self):
919 phrase = self._test_get_x(parser.get_phrase,
920 '"Fred A. Johnson" is his name, oh.',
921 '"Fred A. Johnson" is his name',
922 'Fred A. Johnson is his name',
923 [],
924 ', oh.')
925 self.assertEqual(phrase.token_type, 'phrase')
926
927 def test_get_phrase_complex(self):
928 phrase = self._test_get_x(parser.get_phrase,
929 ' (A) bird (in (my|your)) "hand " is messy\t<>\t',
930 ' (A) bird (in (my|your)) "hand " is messy\t',
931 ' bird hand is messy ',
932 [],
933 '<>\t')
934 self.assertEqual(phrase[0][0].comments, ['A'])
935 self.assertEqual(phrase[0][2].comments, ['in (my|your)'])
936
937 def test_get_phrase_obsolete(self):
938 phrase = self._test_get_x(parser.get_phrase,
939 'Fred A.(weird).O Johnson',
940 'Fred A.(weird).O Johnson',
941 'Fred A. .O Johnson',
942 [errors.ObsoleteHeaderDefect]*3,
943 '')
944 self.assertEqual(len(phrase), 7)
945 self.assertEqual(phrase[3].comments, ['weird'])
946
947 def test_get_phrase_pharse_must_start_with_word(self):
948 phrase = self._test_get_x(parser.get_phrase,
949 '(even weirder).name',
950 '(even weirder).name',
951 ' .name',
952 [errors.InvalidHeaderDefect] + [errors.ObsoleteHeaderDefect]*2,
953 '')
954 self.assertEqual(len(phrase), 3)
955 self.assertEqual(phrase[0].comments, ['even weirder'])
956
957 def test_get_phrase_ending_with_obsolete(self):
958 phrase = self._test_get_x(parser.get_phrase,
959 'simple phrase.(with trailing comment):boo',
960 'simple phrase.(with trailing comment)',
961 'simple phrase. ',
962 [errors.ObsoleteHeaderDefect]*2,
963 ':boo')
964 self.assertEqual(len(phrase), 4)
965 self.assertEqual(phrase[3].comments, ['with trailing comment'])
966
967 def get_phrase_cfws_only_raises(self):
968 with self.assertRaises(errors.HeaderParseError):
969 parser.get_phrase(' (foo) ')
970
971 # get_local_part
972
973 def test_get_local_part_simple(self):
974 local_part = self._test_get_x(parser.get_local_part,
975 'dinsdale@python.org', 'dinsdale', 'dinsdale', [], '@python.org')
976 self.assertEqual(local_part.token_type, 'local-part')
977 self.assertEqual(local_part.local_part, 'dinsdale')
978
979 def test_get_local_part_with_dot(self):
980 local_part = self._test_get_x(parser.get_local_part,
981 'Fred.A.Johnson@python.org',
982 'Fred.A.Johnson',
983 'Fred.A.Johnson',
984 [],
985 '@python.org')
986 self.assertEqual(local_part.local_part, 'Fred.A.Johnson')
987
988 def test_get_local_part_with_whitespace(self):
989 local_part = self._test_get_x(parser.get_local_part,
990 ' Fred.A.Johnson @python.org',
991 ' Fred.A.Johnson ',
992 ' Fred.A.Johnson ',
993 [],
994 '@python.org')
995 self.assertEqual(local_part.local_part, 'Fred.A.Johnson')
996
997 def test_get_local_part_with_cfws(self):
998 local_part = self._test_get_x(parser.get_local_part,
999 ' (foo) Fred.A.Johnson (bar (bird)) @python.org',
1000 ' (foo) Fred.A.Johnson (bar (bird)) ',
1001 ' Fred.A.Johnson ',
1002 [],
1003 '@python.org')
1004 self.assertEqual(local_part.local_part, 'Fred.A.Johnson')
1005 self.assertEqual(local_part[0][0].comments, ['foo'])
1006 self.assertEqual(local_part[0][2].comments, ['bar (bird)'])
1007
1008 def test_get_local_part_simple_quoted(self):
1009 local_part = self._test_get_x(parser.get_local_part,
1010 '"dinsdale"@python.org', '"dinsdale"', '"dinsdale"', [], '@python.org')
1011 self.assertEqual(local_part.token_type, 'local-part')
1012 self.assertEqual(local_part.local_part, 'dinsdale')
1013
1014 def test_get_local_part_with_quoted_dot(self):
1015 local_part = self._test_get_x(parser.get_local_part,
1016 '"Fred.A.Johnson"@python.org',
1017 '"Fred.A.Johnson"',
1018 '"Fred.A.Johnson"',
1019 [],
1020 '@python.org')
1021 self.assertEqual(local_part.local_part, 'Fred.A.Johnson')
1022
1023 def test_get_local_part_quoted_with_whitespace(self):
1024 local_part = self._test_get_x(parser.get_local_part,
1025 ' "Fred A. Johnson" @python.org',
1026 ' "Fred A. Johnson" ',
1027 ' "Fred A. Johnson" ',
1028 [],
1029 '@python.org')
1030 self.assertEqual(local_part.local_part, 'Fred A. Johnson')
1031
1032 def test_get_local_part_quoted_with_cfws(self):
1033 local_part = self._test_get_x(parser.get_local_part,
1034 ' (foo) " Fred A. Johnson " (bar (bird)) @python.org',
1035 ' (foo) " Fred A. Johnson " (bar (bird)) ',
1036 ' " Fred A. Johnson " ',
1037 [],
1038 '@python.org')
1039 self.assertEqual(local_part.local_part, ' Fred A. Johnson ')
1040 self.assertEqual(local_part[0][0].comments, ['foo'])
1041 self.assertEqual(local_part[0][2].comments, ['bar (bird)'])
1042
1043
1044 def test_get_local_part_simple_obsolete(self):
1045 local_part = self._test_get_x(parser.get_local_part,
1046 'Fred. A.Johnson@python.org',
1047 'Fred. A.Johnson',
1048 'Fred. A.Johnson',
1049 [errors.ObsoleteHeaderDefect],
1050 '@python.org')
1051 self.assertEqual(local_part.local_part, 'Fred.A.Johnson')
1052
1053 def test_get_local_part_complex_obsolete_1(self):
1054 local_part = self._test_get_x(parser.get_local_part,
1055 ' (foo )Fred (bar).(bird) A.(sheep)Johnson."and dogs "@python.org',
1056 ' (foo )Fred (bar).(bird) A.(sheep)Johnson."and dogs "',
1057 ' Fred . A. Johnson.and dogs ',
1058 [errors.ObsoleteHeaderDefect],
1059 '@python.org')
1060 self.assertEqual(local_part.local_part, 'Fred.A.Johnson.and dogs ')
1061
1062 def test_get_local_part_complex_obsolete_invalid(self):
1063 local_part = self._test_get_x(parser.get_local_part,
1064 ' (foo )Fred (bar).(bird) A.(sheep)Johnson "and dogs"@python.org',
1065 ' (foo )Fred (bar).(bird) A.(sheep)Johnson "and dogs"',
1066 ' Fred . A. Johnson and dogs',
1067 [errors.InvalidHeaderDefect]*2,
1068 '@python.org')
1069 self.assertEqual(local_part.local_part, 'Fred.A.Johnson and dogs')
1070
1071 def test_get_local_part_no_part_raises(self):
1072 with self.assertRaises(errors.HeaderParseError):
1073 parser.get_local_part(' (foo) ')
1074
1075 def test_get_local_part_special_instead_raises(self):
1076 with self.assertRaises(errors.HeaderParseError):
1077 parser.get_local_part(' (foo) @python.org')
1078
1079 def test_get_local_part_trailing_dot(self):
1080 local_part = self._test_get_x(parser.get_local_part,
1081 ' borris.@python.org',
1082 ' borris.',
1083 ' borris.',
1084 [errors.InvalidHeaderDefect]*2,
1085 '@python.org')
1086 self.assertEqual(local_part.local_part, 'borris.')
1087
1088 def test_get_local_part_trailing_dot_with_ws(self):
1089 local_part = self._test_get_x(parser.get_local_part,
1090 ' borris. @python.org',
1091 ' borris. ',
1092 ' borris. ',
1093 [errors.InvalidHeaderDefect]*2,
1094 '@python.org')
1095 self.assertEqual(local_part.local_part, 'borris.')
1096
1097 def test_get_local_part_leading_dot(self):
1098 local_part = self._test_get_x(parser.get_local_part,
1099 '.borris@python.org',
1100 '.borris',
1101 '.borris',
1102 [errors.InvalidHeaderDefect]*2,
1103 '@python.org')
1104 self.assertEqual(local_part.local_part, '.borris')
1105
1106 def test_get_local_part_leading_dot_after_ws(self):
1107 local_part = self._test_get_x(parser.get_local_part,
1108 ' .borris@python.org',
1109 ' .borris',
1110 ' .borris',
1111 [errors.InvalidHeaderDefect]*2,
1112 '@python.org')
1113 self.assertEqual(local_part.local_part, '.borris')
1114
1115 def test_get_local_part_double_dot_raises(self):
1116 local_part = self._test_get_x(parser.get_local_part,
1117 ' borris.(foo).natasha@python.org',
1118 ' borris.(foo).natasha',
1119 ' borris. .natasha',
1120 [errors.InvalidHeaderDefect]*2,
1121 '@python.org')
1122 self.assertEqual(local_part.local_part, 'borris..natasha')
1123
1124 def test_get_local_part_quoted_strings_in_atom_list(self):
1125 local_part = self._test_get_x(parser.get_local_part,
1126 '""example" example"@example.com',
1127 '""example" example"',
1128 'example example',
1129 [errors.InvalidHeaderDefect]*3,
1130 '@example.com')
1131 self.assertEqual(local_part.local_part, 'example example')
1132
1133 def test_get_local_part_valid_and_invalid_qp_in_atom_list(self):
1134 local_part = self._test_get_x(parser.get_local_part,
1135 r'"\\"example\\" example"@example.com',
1136 r'"\\"example\\" example"',
1137 r'\example\\ example',
1138 [errors.InvalidHeaderDefect]*5,
1139 '@example.com')
1140 self.assertEqual(local_part.local_part, r'\example\\ example')
1141
1142 def test_get_local_part_unicode_defect(self):
1143 # Currently this only happens when parsing unicode, not when parsing
1144 # stuff that was originally binary.
1145 local_part = self._test_get_x(parser.get_local_part,
1146 'exámple@example.com',
1147 'exámple',
1148 'exámple',
1149 [errors.NonASCIILocalPartDefect],
1150 '@example.com')
1151 self.assertEqual(local_part.local_part, 'exámple')
1152
1153 # get_dtext
1154
1155 def test_get_dtext_only(self):
1156 dtext = self._test_get_x(parser.get_dtext,
1157 'foobar', 'foobar', 'foobar', [], '')
1158 self.assertEqual(dtext.token_type, 'ptext')
1159
1160 def test_get_dtext_all_dtext(self):
1161 dtext = self._test_get_x(parser.get_dtext, self.rfc_dtext_chars,
1162 self.rfc_dtext_chars,
1163 self.rfc_dtext_chars, [], '')
1164
1165 def test_get_dtext_two_words_gets_first(self):
1166 self._test_get_x(parser.get_dtext,
1167 'foo bar', 'foo', 'foo', [], ' bar')
1168
1169 def test_get_dtext_following_wsp_preserved(self):
1170 self._test_get_x(parser.get_dtext,
1171 'foo \t\tbar', 'foo', 'foo', [], ' \t\tbar')
1172
1173 def test_get_dtext_non_printables(self):
1174 dtext = self._test_get_x(parser.get_dtext,
1175 'foo\x00bar]', 'foo\x00bar', 'foo\x00bar',
1176 [errors.NonPrintableDefect], ']')
1177 self.assertEqual(dtext.defects[0].non_printables[0], '\x00')
1178
1179 def test_get_dtext_with_qp(self):
1180 ptext = self._test_get_x(parser.get_dtext,
1181 r'foo\]\[\\bar\b\e\l\l',
1182 r'foo][\barbell',
1183 r'foo][\barbell',
1184 [errors.ObsoleteHeaderDefect],
1185 '')
1186
1187 def test_get_dtext_up_to_close_bracket_only(self):
1188 self._test_get_x(parser.get_dtext,
1189 'foo]', 'foo', 'foo', [], ']')
1190
1191 def test_get_dtext_wsp_before_close_bracket_preserved(self):
1192 self._test_get_x(parser.get_dtext,
1193 'foo ]', 'foo', 'foo', [], ' ]')
1194
1195 def test_get_dtext_close_bracket_mid_word(self):
1196 self._test_get_x(parser.get_dtext,
1197 'foo]bar', 'foo', 'foo', [], ']bar')
1198
1199 def test_get_dtext_up_to_open_bracket_only(self):
1200 self._test_get_x(parser.get_dtext,
1201 'foo[', 'foo', 'foo', [], '[')
1202
1203 def test_get_dtext_wsp_before_open_bracket_preserved(self):
1204 self._test_get_x(parser.get_dtext,
1205 'foo [', 'foo', 'foo', [], ' [')
1206
1207 def test_get_dtext_open_bracket_mid_word(self):
1208 self._test_get_x(parser.get_dtext,
1209 'foo[bar', 'foo', 'foo', [], '[bar')
1210
1211 # get_domain_literal
1212
1213 def test_get_domain_literal_only(self):
1214 domain_literal = domain_literal = self._test_get_x(parser.get_domain_literal,
1215 '[127.0.0.1]',
1216 '[127.0.0.1]',
1217 '[127.0.0.1]',
1218 [],
1219 '')
1220 self.assertEqual(domain_literal.token_type, 'domain-literal')
1221 self.assertEqual(domain_literal.domain, '[127.0.0.1]')
1222 self.assertEqual(domain_literal.ip, '127.0.0.1')
1223
1224 def test_get_domain_literal_with_internal_ws(self):
1225 domain_literal = self._test_get_x(parser.get_domain_literal,
1226 '[ 127.0.0.1\t ]',
1227 '[ 127.0.0.1\t ]',
1228 '[ 127.0.0.1 ]',
1229 [],
1230 '')
1231 self.assertEqual(domain_literal.domain, '[127.0.0.1]')
1232 self.assertEqual(domain_literal.ip, '127.0.0.1')
1233
1234 def test_get_domain_literal_with_surrounding_cfws(self):
1235 domain_literal = self._test_get_x(parser.get_domain_literal,
1236 '(foo)[ 127.0.0.1] (bar)',
1237 '(foo)[ 127.0.0.1] (bar)',
1238 ' [ 127.0.0.1] ',
1239 [],
1240 '')
1241 self.assertEqual(domain_literal.domain, '[127.0.0.1]')
1242 self.assertEqual(domain_literal.ip, '127.0.0.1')
1243
1244 def test_get_domain_literal_no_start_char_raises(self):
1245 with self.assertRaises(errors.HeaderParseError):
1246 parser.get_domain_literal('(foo) ')
1247
1248 def test_get_domain_literal_no_start_char_before_special_raises(self):
1249 with self.assertRaises(errors.HeaderParseError):
1250 parser.get_domain_literal('(foo) @')
1251
1252 def test_get_domain_literal_bad_dtext_char_before_special_raises(self):
1253 with self.assertRaises(errors.HeaderParseError):
1254 parser.get_domain_literal('(foo) [abc[@')
1255
1256 # get_domain
1257
1258 def test_get_domain_regular_domain_only(self):
1259 domain = self._test_get_x(parser.get_domain,
1260 'example.com',
1261 'example.com',
1262 'example.com',
1263 [],
1264 '')
1265 self.assertEqual(domain.token_type, 'domain')
1266 self.assertEqual(domain.domain, 'example.com')
1267
1268 def test_get_domain_domain_literal_only(self):
1269 domain = self._test_get_x(parser.get_domain,
1270 '[127.0.0.1]',
1271 '[127.0.0.1]',
1272 '[127.0.0.1]',
1273 [],
1274 '')
1275 self.assertEqual(domain.token_type, 'domain')
1276 self.assertEqual(domain.domain, '[127.0.0.1]')
1277
1278 def test_get_domain_with_cfws(self):
1279 domain = self._test_get_x(parser.get_domain,
1280 '(foo) example.com(bar)\t',
1281 '(foo) example.com(bar)\t',
1282 ' example.com ',
1283 [],
1284 '')
1285 self.assertEqual(domain.domain, 'example.com')
1286
1287 def test_get_domain_domain_literal_with_cfws(self):
1288 domain = self._test_get_x(parser.get_domain,
1289 '(foo)[127.0.0.1]\t(bar)',
1290 '(foo)[127.0.0.1]\t(bar)',
1291 ' [127.0.0.1] ',
1292 [],
1293 '')
1294 self.assertEqual(domain.domain, '[127.0.0.1]')
1295
1296 def test_get_domain_domain_with_cfws_ends_at_special(self):
1297 domain = self._test_get_x(parser.get_domain,
1298 '(foo)example.com\t(bar), next',
1299 '(foo)example.com\t(bar)',
1300 ' example.com ',
1301 [],
1302 ', next')
1303 self.assertEqual(domain.domain, 'example.com')
1304
1305 def test_get_domain_domain_literal_with_cfws_ends_at_special(self):
1306 domain = self._test_get_x(parser.get_domain,
1307 '(foo)[127.0.0.1]\t(bar), next',
1308 '(foo)[127.0.0.1]\t(bar)',
1309 ' [127.0.0.1] ',
1310 [],
1311 ', next')
1312 self.assertEqual(domain.domain, '[127.0.0.1]')
1313
1314 def test_get_domain_obsolete(self):
1315 domain = self._test_get_x(parser.get_domain,
1316 '(foo) example . (bird)com(bar)\t',
1317 '(foo) example . (bird)com(bar)\t',
1318 ' example . com ',
1319 [errors.ObsoleteHeaderDefect],
1320 '')
1321 self.assertEqual(domain.domain, 'example.com')
1322
1323 def test_get_domain_no_non_cfws_raises(self):
1324 with self.assertRaises(errors.HeaderParseError):
1325 parser.get_domain(" (foo)\t")
1326
1327 def test_get_domain_no_atom_raises(self):
1328 with self.assertRaises(errors.HeaderParseError):
1329 parser.get_domain(" (foo)\t, broken")
1330
1331
1332 # get_addr_spec
1333
1334 def test_get_addr_spec_normal(self):
1335 addr_spec = self._test_get_x(parser.get_addr_spec,
1336 'dinsdale@example.com',
1337 'dinsdale@example.com',
1338 'dinsdale@example.com',
1339 [],
1340 '')
1341 self.assertEqual(addr_spec.token_type, 'addr-spec')
1342 self.assertEqual(addr_spec.local_part, 'dinsdale')
1343 self.assertEqual(addr_spec.domain, 'example.com')
1344 self.assertEqual(addr_spec.addr_spec, 'dinsdale@example.com')
1345
1346 def test_get_addr_spec_with_doamin_literal(self):
1347 addr_spec = self._test_get_x(parser.get_addr_spec,
1348 'dinsdale@[127.0.0.1]',
1349 'dinsdale@[127.0.0.1]',
1350 'dinsdale@[127.0.0.1]',
1351 [],
1352 '')
1353 self.assertEqual(addr_spec.local_part, 'dinsdale')
1354 self.assertEqual(addr_spec.domain, '[127.0.0.1]')
1355 self.assertEqual(addr_spec.addr_spec, 'dinsdale@[127.0.0.1]')
1356
1357 def test_get_addr_spec_with_cfws(self):
1358 addr_spec = self._test_get_x(parser.get_addr_spec,
1359 '(foo) dinsdale(bar)@ (bird) example.com (bog)',
1360 '(foo) dinsdale(bar)@ (bird) example.com (bog)',
1361 ' dinsdale@example.com ',
1362 [],
1363 '')
1364 self.assertEqual(addr_spec.local_part, 'dinsdale')
1365 self.assertEqual(addr_spec.domain, 'example.com')
1366 self.assertEqual(addr_spec.addr_spec, 'dinsdale@example.com')
1367
1368 def test_get_addr_spec_with_qouoted_string_and_cfws(self):
1369 addr_spec = self._test_get_x(parser.get_addr_spec,
1370 '(foo) "roy a bug"(bar)@ (bird) example.com (bog)',
1371 '(foo) "roy a bug"(bar)@ (bird) example.com (bog)',
1372 ' "roy a bug"@example.com ',
1373 [],
1374 '')
1375 self.assertEqual(addr_spec.local_part, 'roy a bug')
1376 self.assertEqual(addr_spec.domain, 'example.com')
1377 self.assertEqual(addr_spec.addr_spec, '"roy a bug"@example.com')
1378
1379 def test_get_addr_spec_ends_at_special(self):
1380 addr_spec = self._test_get_x(parser.get_addr_spec,
1381 '(foo) "roy a bug"(bar)@ (bird) example.com (bog) , next',
1382 '(foo) "roy a bug"(bar)@ (bird) example.com (bog) ',
1383 ' "roy a bug"@example.com ',
1384 [],
1385 ', next')
1386 self.assertEqual(addr_spec.local_part, 'roy a bug')
1387 self.assertEqual(addr_spec.domain, 'example.com')
1388 self.assertEqual(addr_spec.addr_spec, '"roy a bug"@example.com')
1389
1390 def test_get_addr_spec_quoted_strings_in_atom_list(self):
1391 addr_spec = self._test_get_x(parser.get_addr_spec,
1392 '""example" example"@example.com',
1393 '""example" example"@example.com',
1394 'example example@example.com',
1395 [errors.InvalidHeaderDefect]*3,
1396 '')
1397 self.assertEqual(addr_spec.local_part, 'example example')
1398 self.assertEqual(addr_spec.domain, 'example.com')
1399 self.assertEqual(addr_spec.addr_spec, '"example example"@example.com')
1400
1401 def test_get_addr_spec_dot_atom(self):
1402 addr_spec = self._test_get_x(parser.get_addr_spec,
1403 'star.a.star@example.com',
1404 'star.a.star@example.com',
1405 'star.a.star@example.com',
1406 [],
1407 '')
1408 self.assertEqual(addr_spec.local_part, 'star.a.star')
1409 self.assertEqual(addr_spec.domain, 'example.com')
1410 self.assertEqual(addr_spec.addr_spec, 'star.a.star@example.com')
1411
1412 # get_obs_route
1413
1414 def test_get_obs_route_simple(self):
1415 obs_route = self._test_get_x(parser.get_obs_route,
1416 '@example.com, @two.example.com:',
1417 '@example.com, @two.example.com:',
1418 '@example.com, @two.example.com:',
1419 [],
1420 '')
1421 self.assertEqual(obs_route.token_type, 'obs-route')
1422 self.assertEqual(obs_route.domains, ['example.com', 'two.example.com'])
1423
1424 def test_get_obs_route_complex(self):
1425 obs_route = self._test_get_x(parser.get_obs_route,
1426 '(foo),, (blue)@example.com (bar),@two.(foo) example.com (bird):',
1427 '(foo),, (blue)@example.com (bar),@two.(foo) example.com (bird):',
1428 ' ,, @example.com ,@two. example.com :',
1429 [errors.ObsoleteHeaderDefect], # This is the obs-domain
1430 '')
1431 self.assertEqual(obs_route.token_type, 'obs-route')
1432 self.assertEqual(obs_route.domains, ['example.com', 'two.example.com'])
1433
1434 def test_get_obs_route_no_route_before_end_raises(self):
1435 with self.assertRaises(errors.HeaderParseError):
1436 parser.get_obs_route('(foo) @example.com,')
1437
1438 def test_get_obs_route_no_route_before_special_raises(self):
1439 with self.assertRaises(errors.HeaderParseError):
1440 parser.get_obs_route('(foo) [abc],')
1441
1442 def test_get_obs_route_no_route_before_special_raises2(self):
1443 with self.assertRaises(errors.HeaderParseError):
1444 parser.get_obs_route('(foo) @example.com [abc],')
1445
1446 # get_angle_addr
1447
1448 def test_get_angle_addr_simple(self):
1449 angle_addr = self._test_get_x(parser.get_angle_addr,
1450 '<dinsdale@example.com>',
1451 '<dinsdale@example.com>',
1452 '<dinsdale@example.com>',
1453 [],
1454 '')
1455 self.assertEqual(angle_addr.token_type, 'angle-addr')
1456 self.assertEqual(angle_addr.local_part, 'dinsdale')
1457 self.assertEqual(angle_addr.domain, 'example.com')
1458 self.assertIsNone(angle_addr.route)
1459 self.assertEqual(angle_addr.addr_spec, 'dinsdale@example.com')
1460
R David Murray032eed32012-05-26 14:31:12 -04001461 def test_get_angle_addr_empty(self):
1462 angle_addr = self._test_get_x(parser.get_angle_addr,
1463 '<>',
1464 '<>',
1465 '<>',
1466 [errors.InvalidHeaderDefect],
1467 '')
1468 self.assertEqual(angle_addr.token_type, 'angle-addr')
1469 self.assertIsNone(angle_addr.local_part)
1470 self.assertIsNone(angle_addr.domain)
1471 self.assertIsNone(angle_addr.route)
1472 self.assertEqual(angle_addr.addr_spec, '<>')
1473
jayyyinaa218d12018-01-29 13:07:44 -05001474 def test_get_angle_addr_qs_only_quotes(self):
1475 angle_addr = self._test_get_x(parser.get_angle_addr,
1476 '<""@example.com>',
1477 '<""@example.com>',
1478 '<""@example.com>',
1479 [],
1480 '')
1481 self.assertEqual(angle_addr.token_type, 'angle-addr')
1482 self.assertEqual(angle_addr.local_part, '')
1483 self.assertEqual(angle_addr.domain, 'example.com')
1484 self.assertIsNone(angle_addr.route)
1485 self.assertEqual(angle_addr.addr_spec, '""@example.com')
1486
R David Murray0b6f6c82012-05-25 18:42:14 -04001487 def test_get_angle_addr_with_cfws(self):
1488 angle_addr = self._test_get_x(parser.get_angle_addr,
1489 ' (foo) <dinsdale@example.com>(bar)',
1490 ' (foo) <dinsdale@example.com>(bar)',
1491 ' <dinsdale@example.com> ',
1492 [],
1493 '')
1494 self.assertEqual(angle_addr.token_type, 'angle-addr')
1495 self.assertEqual(angle_addr.local_part, 'dinsdale')
1496 self.assertEqual(angle_addr.domain, 'example.com')
1497 self.assertIsNone(angle_addr.route)
1498 self.assertEqual(angle_addr.addr_spec, 'dinsdale@example.com')
1499
1500 def test_get_angle_addr_qs_and_domain_literal(self):
1501 angle_addr = self._test_get_x(parser.get_angle_addr,
1502 '<"Fred Perfect"@[127.0.0.1]>',
1503 '<"Fred Perfect"@[127.0.0.1]>',
1504 '<"Fred Perfect"@[127.0.0.1]>',
1505 [],
1506 '')
1507 self.assertEqual(angle_addr.local_part, 'Fred Perfect')
1508 self.assertEqual(angle_addr.domain, '[127.0.0.1]')
1509 self.assertIsNone(angle_addr.route)
1510 self.assertEqual(angle_addr.addr_spec, '"Fred Perfect"@[127.0.0.1]')
1511
1512 def test_get_angle_addr_internal_cfws(self):
1513 angle_addr = self._test_get_x(parser.get_angle_addr,
1514 '<(foo) dinsdale@example.com(bar)>',
1515 '<(foo) dinsdale@example.com(bar)>',
1516 '< dinsdale@example.com >',
1517 [],
1518 '')
1519 self.assertEqual(angle_addr.local_part, 'dinsdale')
1520 self.assertEqual(angle_addr.domain, 'example.com')
1521 self.assertIsNone(angle_addr.route)
1522 self.assertEqual(angle_addr.addr_spec, 'dinsdale@example.com')
1523
1524 def test_get_angle_addr_obs_route(self):
1525 angle_addr = self._test_get_x(parser.get_angle_addr,
1526 '(foo)<@example.com, (bird) @two.example.com: dinsdale@example.com> (bar) ',
1527 '(foo)<@example.com, (bird) @two.example.com: dinsdale@example.com> (bar) ',
1528 ' <@example.com, @two.example.com: dinsdale@example.com> ',
1529 [errors.ObsoleteHeaderDefect],
1530 '')
1531 self.assertEqual(angle_addr.local_part, 'dinsdale')
1532 self.assertEqual(angle_addr.domain, 'example.com')
1533 self.assertEqual(angle_addr.route, ['example.com', 'two.example.com'])
1534 self.assertEqual(angle_addr.addr_spec, 'dinsdale@example.com')
1535
1536 def test_get_angle_addr_missing_closing_angle(self):
1537 angle_addr = self._test_get_x(parser.get_angle_addr,
1538 '<dinsdale@example.com',
1539 '<dinsdale@example.com>',
1540 '<dinsdale@example.com>',
1541 [errors.InvalidHeaderDefect],
1542 '')
1543 self.assertEqual(angle_addr.local_part, 'dinsdale')
1544 self.assertEqual(angle_addr.domain, 'example.com')
1545 self.assertIsNone(angle_addr.route)
1546 self.assertEqual(angle_addr.addr_spec, 'dinsdale@example.com')
1547
1548 def test_get_angle_addr_missing_closing_angle_with_cfws(self):
1549 angle_addr = self._test_get_x(parser.get_angle_addr,
1550 '<dinsdale@example.com (foo)',
1551 '<dinsdale@example.com (foo)>',
1552 '<dinsdale@example.com >',
1553 [errors.InvalidHeaderDefect],
1554 '')
1555 self.assertEqual(angle_addr.local_part, 'dinsdale')
1556 self.assertEqual(angle_addr.domain, 'example.com')
1557 self.assertIsNone(angle_addr.route)
1558 self.assertEqual(angle_addr.addr_spec, 'dinsdale@example.com')
1559
1560 def test_get_angle_addr_ends_at_special(self):
1561 angle_addr = self._test_get_x(parser.get_angle_addr,
1562 '<dinsdale@example.com> (foo), next',
1563 '<dinsdale@example.com> (foo)',
1564 '<dinsdale@example.com> ',
1565 [],
1566 ', next')
1567 self.assertEqual(angle_addr.local_part, 'dinsdale')
1568 self.assertEqual(angle_addr.domain, 'example.com')
1569 self.assertIsNone(angle_addr.route)
1570 self.assertEqual(angle_addr.addr_spec, 'dinsdale@example.com')
1571
1572 def test_get_angle_addr_no_angle_raise(self):
1573 with self.assertRaises(errors.HeaderParseError):
1574 parser.get_angle_addr('(foo) ')
1575
1576 def test_get_angle_addr_no_angle_before_special_raises(self):
1577 with self.assertRaises(errors.HeaderParseError):
1578 parser.get_angle_addr('(foo) , next')
1579
1580 def test_get_angle_addr_no_angle_raises(self):
1581 with self.assertRaises(errors.HeaderParseError):
1582 parser.get_angle_addr('bar')
1583
1584 def test_get_angle_addr_special_after_angle_raises(self):
1585 with self.assertRaises(errors.HeaderParseError):
1586 parser.get_angle_addr('(foo) <, bar')
1587
1588 # get_display_name This is phrase but with a different value.
1589
1590 def test_get_display_name_simple(self):
1591 display_name = self._test_get_x(parser.get_display_name,
1592 'Fred A Johnson',
1593 'Fred A Johnson',
1594 'Fred A Johnson',
1595 [],
1596 '')
1597 self.assertEqual(display_name.token_type, 'display-name')
1598 self.assertEqual(display_name.display_name, 'Fred A Johnson')
1599
1600 def test_get_display_name_complex1(self):
1601 display_name = self._test_get_x(parser.get_display_name,
1602 '"Fred A. Johnson" is his name, oh.',
1603 '"Fred A. Johnson" is his name',
1604 '"Fred A. Johnson is his name"',
1605 [],
1606 ', oh.')
1607 self.assertEqual(display_name.token_type, 'display-name')
1608 self.assertEqual(display_name.display_name, 'Fred A. Johnson is his name')
1609
1610 def test_get_display_name_complex2(self):
1611 display_name = self._test_get_x(parser.get_display_name,
1612 ' (A) bird (in (my|your)) "hand " is messy\t<>\t',
1613 ' (A) bird (in (my|your)) "hand " is messy\t',
1614 ' "bird hand is messy" ',
1615 [],
1616 '<>\t')
1617 self.assertEqual(display_name[0][0].comments, ['A'])
1618 self.assertEqual(display_name[0][2].comments, ['in (my|your)'])
1619 self.assertEqual(display_name.display_name, 'bird hand is messy')
1620
1621 def test_get_display_name_obsolete(self):
1622 display_name = self._test_get_x(parser.get_display_name,
1623 'Fred A.(weird).O Johnson',
1624 'Fred A.(weird).O Johnson',
1625 '"Fred A. .O Johnson"',
1626 [errors.ObsoleteHeaderDefect]*3,
1627 '')
1628 self.assertEqual(len(display_name), 7)
1629 self.assertEqual(display_name[3].comments, ['weird'])
1630 self.assertEqual(display_name.display_name, 'Fred A. .O Johnson')
1631
1632 def test_get_display_name_pharse_must_start_with_word(self):
1633 display_name = self._test_get_x(parser.get_display_name,
1634 '(even weirder).name',
1635 '(even weirder).name',
1636 ' ".name"',
1637 [errors.InvalidHeaderDefect] + [errors.ObsoleteHeaderDefect]*2,
1638 '')
1639 self.assertEqual(len(display_name), 3)
1640 self.assertEqual(display_name[0].comments, ['even weirder'])
1641 self.assertEqual(display_name.display_name, '.name')
1642
1643 def test_get_display_name_ending_with_obsolete(self):
1644 display_name = self._test_get_x(parser.get_display_name,
1645 'simple phrase.(with trailing comment):boo',
1646 'simple phrase.(with trailing comment)',
1647 '"simple phrase." ',
1648 [errors.ObsoleteHeaderDefect]*2,
1649 ':boo')
1650 self.assertEqual(len(display_name), 4)
1651 self.assertEqual(display_name[3].comments, ['with trailing comment'])
1652 self.assertEqual(display_name.display_name, 'simple phrase.')
1653
1654 # get_name_addr
1655
1656 def test_get_name_addr_angle_addr_only(self):
1657 name_addr = self._test_get_x(parser.get_name_addr,
1658 '<dinsdale@example.com>',
1659 '<dinsdale@example.com>',
1660 '<dinsdale@example.com>',
1661 [],
1662 '')
1663 self.assertEqual(name_addr.token_type, 'name-addr')
1664 self.assertIsNone(name_addr.display_name)
1665 self.assertEqual(name_addr.local_part, 'dinsdale')
1666 self.assertEqual(name_addr.domain, 'example.com')
1667 self.assertIsNone(name_addr.route)
1668 self.assertEqual(name_addr.addr_spec, 'dinsdale@example.com')
1669
1670 def test_get_name_addr_atom_name(self):
1671 name_addr = self._test_get_x(parser.get_name_addr,
1672 'Dinsdale <dinsdale@example.com>',
1673 'Dinsdale <dinsdale@example.com>',
1674 'Dinsdale <dinsdale@example.com>',
1675 [],
1676 '')
1677 self.assertEqual(name_addr.token_type, 'name-addr')
1678 self.assertEqual(name_addr.display_name, 'Dinsdale')
1679 self.assertEqual(name_addr.local_part, 'dinsdale')
1680 self.assertEqual(name_addr.domain, 'example.com')
1681 self.assertIsNone(name_addr.route)
1682 self.assertEqual(name_addr.addr_spec, 'dinsdale@example.com')
1683
1684 def test_get_name_addr_atom_name_with_cfws(self):
1685 name_addr = self._test_get_x(parser.get_name_addr,
1686 '(foo) Dinsdale (bar) <dinsdale@example.com> (bird)',
1687 '(foo) Dinsdale (bar) <dinsdale@example.com> (bird)',
1688 ' Dinsdale <dinsdale@example.com> ',
1689 [],
1690 '')
1691 self.assertEqual(name_addr.display_name, 'Dinsdale')
1692 self.assertEqual(name_addr.local_part, 'dinsdale')
1693 self.assertEqual(name_addr.domain, 'example.com')
1694 self.assertIsNone(name_addr.route)
1695 self.assertEqual(name_addr.addr_spec, 'dinsdale@example.com')
1696
1697 def test_get_name_addr_name_with_cfws_and_dots(self):
1698 name_addr = self._test_get_x(parser.get_name_addr,
1699 '(foo) Roy.A.Bear (bar) <dinsdale@example.com> (bird)',
1700 '(foo) Roy.A.Bear (bar) <dinsdale@example.com> (bird)',
1701 ' "Roy.A.Bear" <dinsdale@example.com> ',
1702 [errors.ObsoleteHeaderDefect]*2,
1703 '')
1704 self.assertEqual(name_addr.display_name, 'Roy.A.Bear')
1705 self.assertEqual(name_addr.local_part, 'dinsdale')
1706 self.assertEqual(name_addr.domain, 'example.com')
1707 self.assertIsNone(name_addr.route)
1708 self.assertEqual(name_addr.addr_spec, 'dinsdale@example.com')
1709
1710 def test_get_name_addr_qs_name(self):
1711 name_addr = self._test_get_x(parser.get_name_addr,
1712 '"Roy.A.Bear" <dinsdale@example.com>',
1713 '"Roy.A.Bear" <dinsdale@example.com>',
1714 '"Roy.A.Bear" <dinsdale@example.com>',
1715 [],
1716 '')
1717 self.assertEqual(name_addr.display_name, 'Roy.A.Bear')
1718 self.assertEqual(name_addr.local_part, 'dinsdale')
1719 self.assertEqual(name_addr.domain, 'example.com')
1720 self.assertIsNone(name_addr.route)
1721 self.assertEqual(name_addr.addr_spec, 'dinsdale@example.com')
1722
1723 def test_get_name_addr_with_route(self):
1724 name_addr = self._test_get_x(parser.get_name_addr,
1725 '"Roy.A.Bear" <@two.example.com: dinsdale@example.com>',
1726 '"Roy.A.Bear" <@two.example.com: dinsdale@example.com>',
1727 '"Roy.A.Bear" <@two.example.com: dinsdale@example.com>',
1728 [errors.ObsoleteHeaderDefect],
1729 '')
1730 self.assertEqual(name_addr.display_name, 'Roy.A.Bear')
1731 self.assertEqual(name_addr.local_part, 'dinsdale')
1732 self.assertEqual(name_addr.domain, 'example.com')
1733 self.assertEqual(name_addr.route, ['two.example.com'])
1734 self.assertEqual(name_addr.addr_spec, 'dinsdale@example.com')
1735
1736 def test_get_name_addr_ends_at_special(self):
1737 name_addr = self._test_get_x(parser.get_name_addr,
1738 '"Roy.A.Bear" <dinsdale@example.com>, next',
1739 '"Roy.A.Bear" <dinsdale@example.com>',
1740 '"Roy.A.Bear" <dinsdale@example.com>',
1741 [],
1742 ', next')
1743 self.assertEqual(name_addr.display_name, 'Roy.A.Bear')
1744 self.assertEqual(name_addr.local_part, 'dinsdale')
1745 self.assertEqual(name_addr.domain, 'example.com')
1746 self.assertIsNone(name_addr.route)
1747 self.assertEqual(name_addr.addr_spec, 'dinsdale@example.com')
1748
1749 def test_get_name_addr_no_content_raises(self):
1750 with self.assertRaises(errors.HeaderParseError):
1751 parser.get_name_addr(' (foo) ')
1752
1753 def test_get_name_addr_no_content_before_special_raises(self):
1754 with self.assertRaises(errors.HeaderParseError):
1755 parser.get_name_addr(' (foo) ,')
1756
1757 def test_get_name_addr_no_angle_after_display_name_raises(self):
1758 with self.assertRaises(errors.HeaderParseError):
1759 parser.get_name_addr('foo bar')
1760
1761 # get_mailbox
1762
1763 def test_get_mailbox_addr_spec_only(self):
1764 mailbox = self._test_get_x(parser.get_mailbox,
1765 'dinsdale@example.com',
1766 'dinsdale@example.com',
1767 'dinsdale@example.com',
1768 [],
1769 '')
1770 self.assertEqual(mailbox.token_type, 'mailbox')
1771 self.assertIsNone(mailbox.display_name)
1772 self.assertEqual(mailbox.local_part, 'dinsdale')
1773 self.assertEqual(mailbox.domain, 'example.com')
1774 self.assertIsNone(mailbox.route)
1775 self.assertEqual(mailbox.addr_spec, 'dinsdale@example.com')
1776
1777 def test_get_mailbox_angle_addr_only(self):
1778 mailbox = self._test_get_x(parser.get_mailbox,
1779 '<dinsdale@example.com>',
1780 '<dinsdale@example.com>',
1781 '<dinsdale@example.com>',
1782 [],
1783 '')
1784 self.assertEqual(mailbox.token_type, 'mailbox')
1785 self.assertIsNone(mailbox.display_name)
1786 self.assertEqual(mailbox.local_part, 'dinsdale')
1787 self.assertEqual(mailbox.domain, 'example.com')
1788 self.assertIsNone(mailbox.route)
1789 self.assertEqual(mailbox.addr_spec, 'dinsdale@example.com')
1790
1791 def test_get_mailbox_name_addr(self):
1792 mailbox = self._test_get_x(parser.get_mailbox,
1793 '"Roy A. Bear" <dinsdale@example.com>',
1794 '"Roy A. Bear" <dinsdale@example.com>',
1795 '"Roy A. Bear" <dinsdale@example.com>',
1796 [],
1797 '')
1798 self.assertEqual(mailbox.token_type, 'mailbox')
1799 self.assertEqual(mailbox.display_name, 'Roy A. Bear')
1800 self.assertEqual(mailbox.local_part, 'dinsdale')
1801 self.assertEqual(mailbox.domain, 'example.com')
1802 self.assertIsNone(mailbox.route)
1803 self.assertEqual(mailbox.addr_spec, 'dinsdale@example.com')
1804
1805 def test_get_mailbox_ends_at_special(self):
1806 mailbox = self._test_get_x(parser.get_mailbox,
1807 '"Roy A. Bear" <dinsdale@example.com>, rest',
1808 '"Roy A. Bear" <dinsdale@example.com>',
1809 '"Roy A. Bear" <dinsdale@example.com>',
1810 [],
1811 ', rest')
1812 self.assertEqual(mailbox.token_type, 'mailbox')
1813 self.assertEqual(mailbox.display_name, 'Roy A. Bear')
1814 self.assertEqual(mailbox.local_part, 'dinsdale')
1815 self.assertEqual(mailbox.domain, 'example.com')
1816 self.assertIsNone(mailbox.route)
1817 self.assertEqual(mailbox.addr_spec, 'dinsdale@example.com')
1818
1819 def test_get_mailbox_quoted_strings_in_atom_list(self):
1820 mailbox = self._test_get_x(parser.get_mailbox,
1821 '""example" example"@example.com',
1822 '""example" example"@example.com',
1823 'example example@example.com',
1824 [errors.InvalidHeaderDefect]*3,
1825 '')
1826 self.assertEqual(mailbox.local_part, 'example example')
1827 self.assertEqual(mailbox.domain, 'example.com')
1828 self.assertEqual(mailbox.addr_spec, '"example example"@example.com')
1829
1830 # get_mailbox_list
1831
1832 def test_get_mailbox_list_single_addr(self):
1833 mailbox_list = self._test_get_x(parser.get_mailbox_list,
1834 'dinsdale@example.com',
1835 'dinsdale@example.com',
1836 'dinsdale@example.com',
1837 [],
1838 '')
1839 self.assertEqual(mailbox_list.token_type, 'mailbox-list')
1840 self.assertEqual(len(mailbox_list.mailboxes), 1)
1841 mailbox = mailbox_list.mailboxes[0]
1842 self.assertIsNone(mailbox.display_name)
1843 self.assertEqual(mailbox.local_part, 'dinsdale')
1844 self.assertEqual(mailbox.domain, 'example.com')
1845 self.assertIsNone(mailbox.route)
1846 self.assertEqual(mailbox.addr_spec, 'dinsdale@example.com')
1847 self.assertEqual(mailbox_list.mailboxes,
1848 mailbox_list.all_mailboxes)
1849
1850 def test_get_mailbox_list_two_simple_addr(self):
1851 mailbox_list = self._test_get_x(parser.get_mailbox_list,
1852 'dinsdale@example.com, dinsdale@test.example.com',
1853 'dinsdale@example.com, dinsdale@test.example.com',
1854 'dinsdale@example.com, dinsdale@test.example.com',
1855 [],
1856 '')
1857 self.assertEqual(mailbox_list.token_type, 'mailbox-list')
1858 self.assertEqual(len(mailbox_list.mailboxes), 2)
1859 self.assertEqual(mailbox_list.mailboxes[0].addr_spec,
1860 'dinsdale@example.com')
1861 self.assertEqual(mailbox_list.mailboxes[1].addr_spec,
1862 'dinsdale@test.example.com')
1863 self.assertEqual(mailbox_list.mailboxes,
1864 mailbox_list.all_mailboxes)
1865
1866 def test_get_mailbox_list_two_name_addr(self):
1867 mailbox_list = self._test_get_x(parser.get_mailbox_list,
1868 ('"Roy A. Bear" <dinsdale@example.com>,'
1869 ' "Fred Flintstone" <dinsdale@test.example.com>'),
1870 ('"Roy A. Bear" <dinsdale@example.com>,'
1871 ' "Fred Flintstone" <dinsdale@test.example.com>'),
1872 ('"Roy A. Bear" <dinsdale@example.com>,'
1873 ' "Fred Flintstone" <dinsdale@test.example.com>'),
1874 [],
1875 '')
1876 self.assertEqual(len(mailbox_list.mailboxes), 2)
1877 self.assertEqual(mailbox_list.mailboxes[0].addr_spec,
1878 'dinsdale@example.com')
1879 self.assertEqual(mailbox_list.mailboxes[0].display_name,
1880 'Roy A. Bear')
1881 self.assertEqual(mailbox_list.mailboxes[1].addr_spec,
1882 'dinsdale@test.example.com')
1883 self.assertEqual(mailbox_list.mailboxes[1].display_name,
1884 'Fred Flintstone')
1885 self.assertEqual(mailbox_list.mailboxes,
1886 mailbox_list.all_mailboxes)
1887
1888 def test_get_mailbox_list_two_complex(self):
1889 mailbox_list = self._test_get_x(parser.get_mailbox_list,
1890 ('(foo) "Roy A. Bear" <dinsdale@example.com>(bar),'
1891 ' "Fred Flintstone" <dinsdale@test.(bird)example.com>'),
1892 ('(foo) "Roy A. Bear" <dinsdale@example.com>(bar),'
1893 ' "Fred Flintstone" <dinsdale@test.(bird)example.com>'),
1894 (' "Roy A. Bear" <dinsdale@example.com> ,'
1895 ' "Fred Flintstone" <dinsdale@test. example.com>'),
1896 [errors.ObsoleteHeaderDefect],
1897 '')
1898 self.assertEqual(len(mailbox_list.mailboxes), 2)
1899 self.assertEqual(mailbox_list.mailboxes[0].addr_spec,
1900 'dinsdale@example.com')
1901 self.assertEqual(mailbox_list.mailboxes[0].display_name,
1902 'Roy A. Bear')
1903 self.assertEqual(mailbox_list.mailboxes[1].addr_spec,
1904 'dinsdale@test.example.com')
1905 self.assertEqual(mailbox_list.mailboxes[1].display_name,
1906 'Fred Flintstone')
1907 self.assertEqual(mailbox_list.mailboxes,
1908 mailbox_list.all_mailboxes)
1909
1910 def test_get_mailbox_list_unparseable_mailbox_null(self):
1911 mailbox_list = self._test_get_x(parser.get_mailbox_list,
1912 ('"Roy A. Bear"[] dinsdale@example.com,'
1913 ' "Fred Flintstone" <dinsdale@test.(bird)example.com>'),
1914 ('"Roy A. Bear"[] dinsdale@example.com,'
1915 ' "Fred Flintstone" <dinsdale@test.(bird)example.com>'),
1916 ('"Roy A. Bear"[] dinsdale@example.com,'
1917 ' "Fred Flintstone" <dinsdale@test. example.com>'),
1918 [errors.InvalidHeaderDefect, # the 'extra' text after the local part
1919 errors.InvalidHeaderDefect, # the local part with no angle-addr
1920 errors.ObsoleteHeaderDefect, # period in extra text (example.com)
1921 errors.ObsoleteHeaderDefect], # (bird) in valid address.
1922 '')
1923 self.assertEqual(len(mailbox_list.mailboxes), 1)
1924 self.assertEqual(len(mailbox_list.all_mailboxes), 2)
1925 self.assertEqual(mailbox_list.all_mailboxes[0].token_type,
1926 'invalid-mailbox')
1927 self.assertIsNone(mailbox_list.all_mailboxes[0].display_name)
1928 self.assertEqual(mailbox_list.all_mailboxes[0].local_part,
1929 'Roy A. Bear')
1930 self.assertIsNone(mailbox_list.all_mailboxes[0].domain)
1931 self.assertEqual(mailbox_list.all_mailboxes[0].addr_spec,
1932 '"Roy A. Bear"')
1933 self.assertIs(mailbox_list.all_mailboxes[1],
1934 mailbox_list.mailboxes[0])
1935 self.assertEqual(mailbox_list.mailboxes[0].addr_spec,
1936 'dinsdale@test.example.com')
1937 self.assertEqual(mailbox_list.mailboxes[0].display_name,
1938 'Fred Flintstone')
1939
1940 def test_get_mailbox_list_junk_after_valid_address(self):
1941 mailbox_list = self._test_get_x(parser.get_mailbox_list,
1942 ('"Roy A. Bear" <dinsdale@example.com>@@,'
1943 ' "Fred Flintstone" <dinsdale@test.example.com>'),
1944 ('"Roy A. Bear" <dinsdale@example.com>@@,'
1945 ' "Fred Flintstone" <dinsdale@test.example.com>'),
1946 ('"Roy A. Bear" <dinsdale@example.com>@@,'
1947 ' "Fred Flintstone" <dinsdale@test.example.com>'),
1948 [errors.InvalidHeaderDefect],
1949 '')
1950 self.assertEqual(len(mailbox_list.mailboxes), 1)
1951 self.assertEqual(len(mailbox_list.all_mailboxes), 2)
1952 self.assertEqual(mailbox_list.all_mailboxes[0].addr_spec,
1953 'dinsdale@example.com')
1954 self.assertEqual(mailbox_list.all_mailboxes[0].display_name,
1955 'Roy A. Bear')
1956 self.assertEqual(mailbox_list.all_mailboxes[0].token_type,
1957 'invalid-mailbox')
1958 self.assertIs(mailbox_list.all_mailboxes[1],
1959 mailbox_list.mailboxes[0])
1960 self.assertEqual(mailbox_list.mailboxes[0].addr_spec,
1961 'dinsdale@test.example.com')
1962 self.assertEqual(mailbox_list.mailboxes[0].display_name,
1963 'Fred Flintstone')
1964
1965 def test_get_mailbox_list_empty_list_element(self):
1966 mailbox_list = self._test_get_x(parser.get_mailbox_list,
1967 ('"Roy A. Bear" <dinsdale@example.com>, (bird),,'
1968 ' "Fred Flintstone" <dinsdale@test.example.com>'),
1969 ('"Roy A. Bear" <dinsdale@example.com>, (bird),,'
1970 ' "Fred Flintstone" <dinsdale@test.example.com>'),
1971 ('"Roy A. Bear" <dinsdale@example.com>, ,,'
1972 ' "Fred Flintstone" <dinsdale@test.example.com>'),
1973 [errors.ObsoleteHeaderDefect]*2,
1974 '')
1975 self.assertEqual(len(mailbox_list.mailboxes), 2)
1976 self.assertEqual(mailbox_list.all_mailboxes,
1977 mailbox_list.mailboxes)
1978 self.assertEqual(mailbox_list.all_mailboxes[0].addr_spec,
1979 'dinsdale@example.com')
1980 self.assertEqual(mailbox_list.all_mailboxes[0].display_name,
1981 'Roy A. Bear')
1982 self.assertEqual(mailbox_list.mailboxes[1].addr_spec,
1983 'dinsdale@test.example.com')
1984 self.assertEqual(mailbox_list.mailboxes[1].display_name,
1985 'Fred Flintstone')
1986
1987 def test_get_mailbox_list_only_empty_elements(self):
1988 mailbox_list = self._test_get_x(parser.get_mailbox_list,
1989 '(foo),, (bar)',
1990 '(foo),, (bar)',
1991 ' ,, ',
1992 [errors.ObsoleteHeaderDefect]*3,
1993 '')
1994 self.assertEqual(len(mailbox_list.mailboxes), 0)
1995 self.assertEqual(mailbox_list.all_mailboxes,
1996 mailbox_list.mailboxes)
1997
1998 # get_group_list
1999
2000 def test_get_group_list_cfws_only(self):
2001 group_list = self._test_get_x(parser.get_group_list,
2002 '(hidden);',
2003 '(hidden)',
2004 ' ',
2005 [],
2006 ';')
2007 self.assertEqual(group_list.token_type, 'group-list')
2008 self.assertEqual(len(group_list.mailboxes), 0)
2009 self.assertEqual(group_list.mailboxes,
2010 group_list.all_mailboxes)
2011
2012 def test_get_group_list_mailbox_list(self):
2013 group_list = self._test_get_x(parser.get_group_list,
2014 'dinsdale@example.org, "Fred A. Bear" <dinsdale@example.org>',
2015 'dinsdale@example.org, "Fred A. Bear" <dinsdale@example.org>',
2016 'dinsdale@example.org, "Fred A. Bear" <dinsdale@example.org>',
2017 [],
2018 '')
2019 self.assertEqual(group_list.token_type, 'group-list')
2020 self.assertEqual(len(group_list.mailboxes), 2)
2021 self.assertEqual(group_list.mailboxes,
2022 group_list.all_mailboxes)
2023 self.assertEqual(group_list.mailboxes[1].display_name,
2024 'Fred A. Bear')
2025
2026 def test_get_group_list_obs_group_list(self):
2027 group_list = self._test_get_x(parser.get_group_list,
2028 ', (foo),,(bar)',
2029 ', (foo),,(bar)',
2030 ', ,, ',
2031 [errors.ObsoleteHeaderDefect],
2032 '')
2033 self.assertEqual(group_list.token_type, 'group-list')
2034 self.assertEqual(len(group_list.mailboxes), 0)
2035 self.assertEqual(group_list.mailboxes,
2036 group_list.all_mailboxes)
2037
2038 def test_get_group_list_comment_only_invalid(self):
2039 group_list = self._test_get_x(parser.get_group_list,
2040 '(bar)',
2041 '(bar)',
2042 ' ',
2043 [errors.InvalidHeaderDefect],
2044 '')
2045 self.assertEqual(group_list.token_type, 'group-list')
2046 self.assertEqual(len(group_list.mailboxes), 0)
2047 self.assertEqual(group_list.mailboxes,
2048 group_list.all_mailboxes)
2049
2050 # get_group
2051
2052 def test_get_group_empty(self):
2053 group = self._test_get_x(parser.get_group,
2054 'Monty Python:;',
2055 'Monty Python:;',
2056 'Monty Python:;',
2057 [],
2058 '')
2059 self.assertEqual(group.token_type, 'group')
2060 self.assertEqual(group.display_name, 'Monty Python')
2061 self.assertEqual(len(group.mailboxes), 0)
2062 self.assertEqual(group.mailboxes,
2063 group.all_mailboxes)
2064
R David Murray032eed32012-05-26 14:31:12 -04002065 def test_get_group_null_addr_spec(self):
R David Murray0b6f6c82012-05-25 18:42:14 -04002066 group = self._test_get_x(parser.get_group,
2067 'foo: <>;',
2068 'foo: <>;',
2069 'foo: <>;',
2070 [errors.InvalidHeaderDefect],
2071 '')
2072 self.assertEqual(group.display_name, 'foo')
2073 self.assertEqual(len(group.mailboxes), 0)
2074 self.assertEqual(len(group.all_mailboxes), 1)
2075 self.assertEqual(group.all_mailboxes[0].value, '<>')
2076
2077 def test_get_group_cfws_only(self):
2078 group = self._test_get_x(parser.get_group,
2079 'Monty Python: (hidden);',
2080 'Monty Python: (hidden);',
2081 'Monty Python: ;',
2082 [],
2083 '')
2084 self.assertEqual(group.token_type, 'group')
2085 self.assertEqual(group.display_name, 'Monty Python')
2086 self.assertEqual(len(group.mailboxes), 0)
2087 self.assertEqual(group.mailboxes,
2088 group.all_mailboxes)
2089
2090 def test_get_group_single_mailbox(self):
2091 group = self._test_get_x(parser.get_group,
2092 'Monty Python: "Fred A. Bear" <dinsdale@example.com>;',
2093 'Monty Python: "Fred A. Bear" <dinsdale@example.com>;',
2094 'Monty Python: "Fred A. Bear" <dinsdale@example.com>;',
2095 [],
2096 '')
2097 self.assertEqual(group.token_type, 'group')
2098 self.assertEqual(group.display_name, 'Monty Python')
2099 self.assertEqual(len(group.mailboxes), 1)
2100 self.assertEqual(group.mailboxes,
2101 group.all_mailboxes)
2102 self.assertEqual(group.mailboxes[0].addr_spec,
2103 'dinsdale@example.com')
2104
2105 def test_get_group_mixed_list(self):
2106 group = self._test_get_x(parser.get_group,
2107 ('Monty Python: "Fred A. Bear" <dinsdale@example.com>,'
2108 '(foo) Roger <ping@exampele.com>, x@test.example.com;'),
2109 ('Monty Python: "Fred A. Bear" <dinsdale@example.com>,'
2110 '(foo) Roger <ping@exampele.com>, x@test.example.com;'),
2111 ('Monty Python: "Fred A. Bear" <dinsdale@example.com>,'
2112 ' Roger <ping@exampele.com>, x@test.example.com;'),
2113 [],
2114 '')
2115 self.assertEqual(group.token_type, 'group')
2116 self.assertEqual(group.display_name, 'Monty Python')
2117 self.assertEqual(len(group.mailboxes), 3)
2118 self.assertEqual(group.mailboxes,
2119 group.all_mailboxes)
2120 self.assertEqual(group.mailboxes[0].display_name,
2121 'Fred A. Bear')
2122 self.assertEqual(group.mailboxes[1].display_name,
2123 'Roger')
2124 self.assertEqual(group.mailboxes[2].local_part, 'x')
2125
2126 def test_get_group_one_invalid(self):
2127 group = self._test_get_x(parser.get_group,
2128 ('Monty Python: "Fred A. Bear" <dinsdale@example.com>,'
2129 '(foo) Roger ping@exampele.com, x@test.example.com;'),
2130 ('Monty Python: "Fred A. Bear" <dinsdale@example.com>,'
2131 '(foo) Roger ping@exampele.com, x@test.example.com;'),
2132 ('Monty Python: "Fred A. Bear" <dinsdale@example.com>,'
2133 ' Roger ping@exampele.com, x@test.example.com;'),
2134 [errors.InvalidHeaderDefect, # non-angle addr makes local part invalid
2135 errors.InvalidHeaderDefect], # and its not obs-local either: no dots.
2136 '')
2137 self.assertEqual(group.token_type, 'group')
2138 self.assertEqual(group.display_name, 'Monty Python')
2139 self.assertEqual(len(group.mailboxes), 2)
2140 self.assertEqual(len(group.all_mailboxes), 3)
2141 self.assertEqual(group.mailboxes[0].display_name,
2142 'Fred A. Bear')
2143 self.assertEqual(group.mailboxes[1].local_part, 'x')
2144 self.assertIsNone(group.all_mailboxes[1].display_name)
2145
2146 # get_address
2147
2148 def test_get_address_simple(self):
2149 address = self._test_get_x(parser.get_address,
2150 'dinsdale@example.com',
2151 'dinsdale@example.com',
2152 'dinsdale@example.com',
2153 [],
2154 '')
2155 self.assertEqual(address.token_type, 'address')
2156 self.assertEqual(len(address.mailboxes), 1)
2157 self.assertEqual(address.mailboxes,
2158 address.all_mailboxes)
2159 self.assertEqual(address.mailboxes[0].domain,
2160 'example.com')
2161 self.assertEqual(address[0].token_type,
2162 'mailbox')
2163
2164 def test_get_address_complex(self):
2165 address = self._test_get_x(parser.get_address,
2166 '(foo) "Fred A. Bear" <(bird)dinsdale@example.com>',
2167 '(foo) "Fred A. Bear" <(bird)dinsdale@example.com>',
2168 ' "Fred A. Bear" < dinsdale@example.com>',
2169 [],
2170 '')
2171 self.assertEqual(address.token_type, 'address')
2172 self.assertEqual(len(address.mailboxes), 1)
2173 self.assertEqual(address.mailboxes,
2174 address.all_mailboxes)
2175 self.assertEqual(address.mailboxes[0].display_name,
2176 'Fred A. Bear')
2177 self.assertEqual(address[0].token_type,
2178 'mailbox')
2179
R David Murray923512f2013-07-12 16:00:28 -04002180 def test_get_address_rfc2047_display_name(self):
2181 address = self._test_get_x(parser.get_address,
2182 '=?utf-8?q?=C3=89ric?= <foo@example.com>',
2183 'Éric <foo@example.com>',
2184 'Éric <foo@example.com>',
2185 [],
2186 '')
2187 self.assertEqual(address.token_type, 'address')
2188 self.assertEqual(len(address.mailboxes), 1)
2189 self.assertEqual(address.mailboxes,
2190 address.all_mailboxes)
2191 self.assertEqual(address.mailboxes[0].display_name,
2192 'Éric')
2193 self.assertEqual(address[0].token_type,
2194 'mailbox')
2195
R David Murray0b6f6c82012-05-25 18:42:14 -04002196 def test_get_address_empty_group(self):
2197 address = self._test_get_x(parser.get_address,
2198 'Monty Python:;',
2199 'Monty Python:;',
2200 'Monty Python:;',
2201 [],
2202 '')
2203 self.assertEqual(address.token_type, 'address')
2204 self.assertEqual(len(address.mailboxes), 0)
2205 self.assertEqual(address.mailboxes,
2206 address.all_mailboxes)
2207 self.assertEqual(address[0].token_type,
2208 'group')
2209 self.assertEqual(address[0].display_name,
2210 'Monty Python')
2211
2212 def test_get_address_group(self):
2213 address = self._test_get_x(parser.get_address,
2214 'Monty Python: x@example.com, y@example.com;',
2215 'Monty Python: x@example.com, y@example.com;',
2216 'Monty Python: x@example.com, y@example.com;',
2217 [],
2218 '')
2219 self.assertEqual(address.token_type, 'address')
2220 self.assertEqual(len(address.mailboxes), 2)
2221 self.assertEqual(address.mailboxes,
2222 address.all_mailboxes)
2223 self.assertEqual(address[0].token_type,
2224 'group')
2225 self.assertEqual(address[0].display_name,
2226 'Monty Python')
2227 self.assertEqual(address.mailboxes[0].local_part, 'x')
2228
2229 def test_get_address_quoted_local_part(self):
2230 address = self._test_get_x(parser.get_address,
2231 '"foo bar"@example.com',
2232 '"foo bar"@example.com',
2233 '"foo bar"@example.com',
2234 [],
2235 '')
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.mailboxes[0].local_part,
2243 'foo bar')
2244 self.assertEqual(address[0].token_type, 'mailbox')
2245
2246 def test_get_address_ends_at_special(self):
2247 address = self._test_get_x(parser.get_address,
2248 'dinsdale@example.com, next',
2249 'dinsdale@example.com',
2250 'dinsdale@example.com',
2251 [],
2252 ', next')
2253 self.assertEqual(address.token_type, 'address')
2254 self.assertEqual(len(address.mailboxes), 1)
2255 self.assertEqual(address.mailboxes,
2256 address.all_mailboxes)
2257 self.assertEqual(address.mailboxes[0].domain,
2258 'example.com')
2259 self.assertEqual(address[0].token_type, 'mailbox')
2260
2261 def test_get_address_invalid_mailbox_invalid(self):
2262 address = self._test_get_x(parser.get_address,
2263 'ping example.com, next',
2264 'ping example.com',
2265 'ping example.com',
2266 [errors.InvalidHeaderDefect, # addr-spec with no domain
2267 errors.InvalidHeaderDefect, # invalid local-part
2268 errors.InvalidHeaderDefect, # missing .s in local-part
2269 ],
2270 ', next')
2271 self.assertEqual(address.token_type, 'address')
2272 self.assertEqual(len(address.mailboxes), 0)
2273 self.assertEqual(len(address.all_mailboxes), 1)
2274 self.assertIsNone(address.all_mailboxes[0].domain)
2275 self.assertEqual(address.all_mailboxes[0].local_part, 'ping example.com')
2276 self.assertEqual(address[0].token_type, 'invalid-mailbox')
2277
2278 def test_get_address_quoted_strings_in_atom_list(self):
2279 address = self._test_get_x(parser.get_address,
2280 '""example" example"@example.com',
2281 '""example" example"@example.com',
2282 'example example@example.com',
2283 [errors.InvalidHeaderDefect]*3,
2284 '')
2285 self.assertEqual(address.all_mailboxes[0].local_part, 'example example')
2286 self.assertEqual(address.all_mailboxes[0].domain, 'example.com')
2287 self.assertEqual(address.all_mailboxes[0].addr_spec, '"example example"@example.com')
2288
2289
2290 # get_address_list
2291
2292 def test_get_address_list_mailboxes_simple(self):
2293 address_list = self._test_get_x(parser.get_address_list,
2294 'dinsdale@example.com',
2295 'dinsdale@example.com',
2296 'dinsdale@example.com',
2297 [],
2298 '')
2299 self.assertEqual(address_list.token_type, 'address-list')
2300 self.assertEqual(len(address_list.mailboxes), 1)
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].domain, 'example.com')
2306 self.assertEqual(address_list[0].token_type, 'address')
2307 self.assertIsNone(address_list[0].display_name)
2308
2309 def test_get_address_list_mailboxes_two_simple(self):
2310 address_list = self._test_get_x(parser.get_address_list,
2311 'foo@example.com, "Fred A. Bar" <bar@example.com>',
2312 'foo@example.com, "Fred A. Bar" <bar@example.com>',
2313 'foo@example.com, "Fred A. Bar" <bar@example.com>',
2314 [],
2315 '')
2316 self.assertEqual(address_list.token_type, 'address-list')
2317 self.assertEqual(len(address_list.mailboxes), 2)
2318 self.assertEqual(address_list.mailboxes,
2319 address_list.all_mailboxes)
2320 self.assertEqual([str(x) for x in address_list.mailboxes],
2321 [str(x) for x in address_list.addresses])
2322 self.assertEqual(address_list.mailboxes[0].local_part, 'foo')
2323 self.assertEqual(address_list.mailboxes[1].display_name, "Fred A. Bar")
2324
2325 def test_get_address_list_mailboxes_complex(self):
2326 address_list = self._test_get_x(parser.get_address_list,
2327 ('"Roy A. Bear" <dinsdale@example.com>, '
2328 '(ping) Foo <x@example.com>,'
2329 'Nobody Is. Special <y@(bird)example.(bad)com>'),
2330 ('"Roy A. Bear" <dinsdale@example.com>, '
2331 '(ping) Foo <x@example.com>,'
2332 'Nobody Is. Special <y@(bird)example.(bad)com>'),
2333 ('"Roy A. Bear" <dinsdale@example.com>, '
2334 'Foo <x@example.com>,'
2335 '"Nobody Is. Special" <y@example. com>'),
2336 [errors.ObsoleteHeaderDefect, # period in Is.
2337 errors.ObsoleteHeaderDefect], # cfws in domain
2338 '')
2339 self.assertEqual(address_list.token_type, 'address-list')
2340 self.assertEqual(len(address_list.mailboxes), 3)
2341 self.assertEqual(address_list.mailboxes,
2342 address_list.all_mailboxes)
2343 self.assertEqual([str(x) for x in address_list.mailboxes],
2344 [str(x) for x in address_list.addresses])
2345 self.assertEqual(address_list.mailboxes[0].domain, 'example.com')
2346 self.assertEqual(address_list.mailboxes[0].token_type, 'mailbox')
2347 self.assertEqual(address_list.addresses[0].token_type, 'address')
2348 self.assertEqual(address_list.mailboxes[1].local_part, 'x')
2349 self.assertEqual(address_list.mailboxes[2].display_name,
2350 'Nobody Is. Special')
2351
2352 def test_get_address_list_mailboxes_invalid_addresses(self):
2353 address_list = self._test_get_x(parser.get_address_list,
2354 ('"Roy A. Bear" <dinsdale@example.com>, '
2355 '(ping) Foo x@example.com[],'
2356 'Nobody Is. Special <(bird)example.(bad)com>'),
2357 ('"Roy A. Bear" <dinsdale@example.com>, '
2358 '(ping) Foo x@example.com[],'
2359 'Nobody Is. Special <(bird)example.(bad)com>'),
2360 ('"Roy A. Bear" <dinsdale@example.com>, '
2361 'Foo x@example.com[],'
2362 '"Nobody Is. Special" < example. com>'),
2363 [errors.InvalidHeaderDefect, # invalid address in list
2364 errors.InvalidHeaderDefect, # 'Foo x' local part invalid.
2365 errors.InvalidHeaderDefect, # Missing . in 'Foo x' local part
2366 errors.ObsoleteHeaderDefect, # period in 'Is.' disp-name phrase
2367 errors.InvalidHeaderDefect, # no domain part in addr-spec
2368 errors.ObsoleteHeaderDefect], # addr-spec has comment in it
2369 '')
2370 self.assertEqual(address_list.token_type, 'address-list')
2371 self.assertEqual(len(address_list.mailboxes), 1)
2372 self.assertEqual(len(address_list.all_mailboxes), 3)
2373 self.assertEqual([str(x) for x in address_list.all_mailboxes],
2374 [str(x) for x in address_list.addresses])
2375 self.assertEqual(address_list.mailboxes[0].domain, 'example.com')
2376 self.assertEqual(address_list.mailboxes[0].token_type, 'mailbox')
2377 self.assertEqual(address_list.addresses[0].token_type, 'address')
2378 self.assertEqual(address_list.addresses[1].token_type, 'address')
2379 self.assertEqual(len(address_list.addresses[0].mailboxes), 1)
2380 self.assertEqual(len(address_list.addresses[1].mailboxes), 0)
2381 self.assertEqual(len(address_list.addresses[1].mailboxes), 0)
2382 self.assertEqual(
2383 address_list.addresses[1].all_mailboxes[0].local_part, 'Foo x')
2384 self.assertEqual(
2385 address_list.addresses[2].all_mailboxes[0].display_name,
2386 "Nobody Is. Special")
2387
2388 def test_get_address_list_group_empty(self):
2389 address_list = self._test_get_x(parser.get_address_list,
2390 'Monty Python: ;',
2391 'Monty Python: ;',
2392 'Monty Python: ;',
2393 [],
2394 '')
2395 self.assertEqual(address_list.token_type, 'address-list')
2396 self.assertEqual(len(address_list.mailboxes), 0)
2397 self.assertEqual(address_list.mailboxes,
2398 address_list.all_mailboxes)
2399 self.assertEqual(len(address_list.addresses), 1)
2400 self.assertEqual(address_list.addresses[0].token_type, 'address')
2401 self.assertEqual(address_list.addresses[0].display_name, 'Monty Python')
2402 self.assertEqual(len(address_list.addresses[0].mailboxes), 0)
2403
2404 def test_get_address_list_group_simple(self):
2405 address_list = self._test_get_x(parser.get_address_list,
2406 'Monty Python: dinsdale@example.com;',
2407 'Monty Python: dinsdale@example.com;',
2408 'Monty Python: dinsdale@example.com;',
2409 [],
2410 '')
2411 self.assertEqual(address_list.token_type, 'address-list')
2412 self.assertEqual(len(address_list.mailboxes), 1)
2413 self.assertEqual(address_list.mailboxes,
2414 address_list.all_mailboxes)
2415 self.assertEqual(address_list.mailboxes[0].domain, 'example.com')
2416 self.assertEqual(address_list.addresses[0].display_name,
2417 'Monty Python')
2418 self.assertEqual(address_list.addresses[0].mailboxes[0].domain,
2419 'example.com')
2420
2421 def test_get_address_list_group_and_mailboxes(self):
2422 address_list = self._test_get_x(parser.get_address_list,
2423 ('Monty Python: dinsdale@example.com, "Fred" <flint@example.com>;, '
2424 'Abe <x@example.com>, Bee <y@example.com>'),
2425 ('Monty Python: dinsdale@example.com, "Fred" <flint@example.com>;, '
2426 'Abe <x@example.com>, Bee <y@example.com>'),
2427 ('Monty Python: dinsdale@example.com, "Fred" <flint@example.com>;, '
2428 'Abe <x@example.com>, Bee <y@example.com>'),
2429 [],
2430 '')
2431 self.assertEqual(address_list.token_type, 'address-list')
2432 self.assertEqual(len(address_list.mailboxes), 4)
2433 self.assertEqual(address_list.mailboxes,
2434 address_list.all_mailboxes)
2435 self.assertEqual(len(address_list.addresses), 3)
2436 self.assertEqual(address_list.mailboxes[0].local_part, 'dinsdale')
2437 self.assertEqual(address_list.addresses[0].display_name,
2438 'Monty Python')
2439 self.assertEqual(address_list.addresses[0].mailboxes[0].domain,
2440 'example.com')
2441 self.assertEqual(address_list.addresses[0].mailboxes[1].local_part,
2442 'flint')
2443 self.assertEqual(address_list.addresses[1].mailboxes[0].local_part,
2444 'x')
2445 self.assertEqual(address_list.addresses[2].mailboxes[0].local_part,
2446 'y')
2447 self.assertEqual(str(address_list.addresses[1]),
2448 str(address_list.mailboxes[2]))
2449
Ezio Melottid5774802014-08-04 17:16:49 +03002450 def test_invalid_content_disposition(self):
2451 content_disp = self._test_parse_x(
2452 parser.parse_content_disposition_header,
2453 ";attachment", "; attachment", ";attachment",
2454 [errors.InvalidHeaderDefect]*2
2455 )
2456
2457 def test_invalid_content_transfer_encoding(self):
2458 cte = self._test_parse_x(
2459 parser.parse_content_transfer_encoding_header,
2460 ";foo", ";foo", ";foo", [errors.InvalidHeaderDefect]*3
2461 )
R David Murray0b6f6c82012-05-25 18:42:14 -04002462
R David Murray7d0325d2015-03-29 21:53:05 -04002463
2464@parameterize
2465class Test_parse_mime_parameters(TestParserMixin, TestEmailBase):
2466
2467 def mime_parameters_as_value(self,
2468 value,
2469 tl_str,
2470 tl_value,
2471 params,
2472 defects):
2473 mime_parameters = self._test_parse_x(parser.parse_mime_parameters,
2474 value, tl_str, tl_value, defects)
2475 self.assertEqual(mime_parameters.token_type, 'mime-parameters')
2476 self.assertEqual(list(mime_parameters.params), params)
2477
2478
2479 mime_parameters_params = {
2480
2481 'simple': (
2482 'filename="abc.py"',
2483 ' filename="abc.py"',
2484 'filename=abc.py',
2485 [('filename', 'abc.py')],
2486 []),
2487
2488 'multiple_keys': (
2489 'filename="abc.py"; xyz=abc',
2490 ' filename="abc.py"; xyz="abc"',
2491 'filename=abc.py; xyz=abc',
2492 [('filename', 'abc.py'), ('xyz', 'abc')],
2493 []),
2494
2495 'split_value': (
2496 "filename*0*=iso-8859-1''%32%30%31%2E; filename*1*=%74%69%66",
2497 ' filename="201.tif"',
2498 "filename*0*=iso-8859-1''%32%30%31%2E; filename*1*=%74%69%66",
2499 [('filename', '201.tif')],
2500 []),
2501
2502 # Note that it is undefined what we should do for error recovery when
2503 # there are duplicate parameter names or duplicate parts in a split
2504 # part. We choose to ignore all duplicate parameters after the first
Martin Panter46f50722016-05-26 05:35:26 +00002505 # and to take duplicate or missing rfc 2231 parts in appearance order.
R David Murray7d0325d2015-03-29 21:53:05 -04002506 # This is backward compatible with get_param's behavior, but the
2507 # decisions are arbitrary.
2508
2509 'duplicate_key': (
2510 'filename=abc.gif; filename=def.tiff',
2511 ' filename="abc.gif"',
2512 "filename=abc.gif; filename=def.tiff",
2513 [('filename', 'abc.gif')],
2514 [errors.InvalidHeaderDefect]),
2515
2516 'duplicate_key_with_split_value': (
2517 "filename*0*=iso-8859-1''%32%30%31%2E; filename*1*=%74%69%66;"
2518 " filename=abc.gif",
2519 ' filename="201.tif"',
2520 "filename*0*=iso-8859-1''%32%30%31%2E; filename*1*=%74%69%66;"
2521 " filename=abc.gif",
2522 [('filename', '201.tif')],
2523 [errors.InvalidHeaderDefect]),
2524
2525 'duplicate_key_with_split_value_other_order': (
2526 "filename=abc.gif; "
2527 " filename*0*=iso-8859-1''%32%30%31%2E; filename*1*=%74%69%66",
2528 ' filename="abc.gif"',
2529 "filename=abc.gif;"
2530 " filename*0*=iso-8859-1''%32%30%31%2E; filename*1*=%74%69%66",
2531 [('filename', 'abc.gif')],
2532 [errors.InvalidHeaderDefect]),
2533
2534 'duplicate_in_split_value': (
2535 "filename*0*=iso-8859-1''%32%30%31%2E; filename*1*=%74%69%66;"
2536 " filename*1*=abc.gif",
2537 ' filename="201.tifabc.gif"',
2538 "filename*0*=iso-8859-1''%32%30%31%2E; filename*1*=%74%69%66;"
2539 " filename*1*=abc.gif",
2540 [('filename', '201.tifabc.gif')],
2541 [errors.InvalidHeaderDefect]),
2542
2543 'missing_split_value': (
2544 "filename*0*=iso-8859-1''%32%30%31%2E; filename*3*=%74%69%66;",
2545 ' filename="201.tif"',
2546 "filename*0*=iso-8859-1''%32%30%31%2E; filename*3*=%74%69%66;",
2547 [('filename', '201.tif')],
2548 [errors.InvalidHeaderDefect]),
2549
2550 'duplicate_and_missing_split_value': (
2551 "filename*0*=iso-8859-1''%32%30%31%2E; filename*3*=%74%69%66;"
2552 " filename*3*=abc.gif",
2553 ' filename="201.tifabc.gif"',
2554 "filename*0*=iso-8859-1''%32%30%31%2E; filename*3*=%74%69%66;"
2555 " filename*3*=abc.gif",
2556 [('filename', '201.tifabc.gif')],
2557 [errors.InvalidHeaderDefect]*2),
2558
2559 # Here we depart from get_param and assume the *0* was missing.
2560 'duplicate_with_broken_split_value': (
2561 "filename=abc.gif; "
2562 " filename*2*=iso-8859-1''%32%30%31%2E; filename*3*=%74%69%66",
2563 ' filename="abc.gif201.tif"',
2564 "filename=abc.gif;"
2565 " filename*2*=iso-8859-1''%32%30%31%2E; filename*3*=%74%69%66",
2566 [('filename', 'abc.gif201.tif')],
2567 # Defects are apparent missing *0*, and two 'out of sequence'.
2568 [errors.InvalidHeaderDefect]*3),
2569
2570 }
2571
R David Murray97f43c02012-06-24 05:03:27 -04002572@parameterize
2573class Test_parse_mime_version(TestParserMixin, TestEmailBase):
2574
2575 def mime_version_as_value(self,
2576 value,
2577 tl_str,
2578 tl_value,
2579 major,
2580 minor,
2581 defects):
2582 mime_version = self._test_parse_x(parser.parse_mime_version,
2583 value, tl_str, tl_value, defects)
2584 self.assertEqual(mime_version.major, major)
2585 self.assertEqual(mime_version.minor, minor)
2586
2587 mime_version_params = {
2588
2589 'rfc_2045_1': (
2590 '1.0',
2591 '1.0',
2592 '1.0',
2593 1,
2594 0,
2595 []),
2596
2597 'RFC_2045_2': (
2598 '1.0 (produced by MetaSend Vx.x)',
2599 '1.0 (produced by MetaSend Vx.x)',
2600 '1.0 ',
2601 1,
2602 0,
2603 []),
2604
2605 'RFC_2045_3': (
2606 '(produced by MetaSend Vx.x) 1.0',
2607 '(produced by MetaSend Vx.x) 1.0',
2608 ' 1.0',
2609 1,
2610 0,
2611 []),
2612
2613 'RFC_2045_4': (
2614 '1.(produced by MetaSend Vx.x)0',
2615 '1.(produced by MetaSend Vx.x)0',
2616 '1. 0',
2617 1,
2618 0,
2619 []),
2620
2621 'empty': (
2622 '',
2623 '',
2624 '',
2625 None,
2626 None,
2627 [errors.HeaderMissingRequiredValue]),
2628
2629 }
2630
2631
2632
R David Murray0b6f6c82012-05-25 18:42:14 -04002633class TestFolding(TestEmailBase):
2634
2635 policy = policy.default
2636
2637 def _test(self, tl, folded, policy=policy):
2638 self.assertEqual(tl.fold(policy=policy), folded, tl.ppstr())
2639
2640 def test_simple_unstructured_no_folds(self):
2641 self._test(parser.get_unstructured("This is a test"),
2642 "This is a test\n")
2643
2644 def test_simple_unstructured_folded(self):
2645 self._test(parser.get_unstructured("This is also a test, but this "
2646 "time there are enough words (and even some "
2647 "symbols) to make it wrap; at least in theory."),
2648 "This is also a test, but this time there are enough "
2649 "words (and even some\n"
2650 " symbols) to make it wrap; at least in theory.\n")
2651
2652 def test_unstructured_with_unicode_no_folds(self):
2653 self._test(parser.get_unstructured("hübsch kleiner beißt"),
2654 "=?utf-8?q?h=C3=BCbsch_kleiner_bei=C3=9Ft?=\n")
2655
2656 def test_one_ew_on_each_of_two_wrapped_lines(self):
2657 self._test(parser.get_unstructured("Mein kleiner Kaktus ist sehr "
2658 "hübsch. Es hat viele Stacheln "
2659 "und oft beißt mich."),
2660 "Mein kleiner Kaktus ist sehr =?utf-8?q?h=C3=BCbsch=2E?= "
2661 "Es hat viele Stacheln\n"
2662 " und oft =?utf-8?q?bei=C3=9Ft?= mich.\n")
2663
2664 def test_ews_combined_before_wrap(self):
2665 self._test(parser.get_unstructured("Mein Kaktus ist hübsch. "
2666 "Es beißt mich. "
2667 "And that's all I'm sayin."),
2668 "Mein Kaktus ist =?utf-8?q?h=C3=BCbsch=2E__Es_bei=C3=9Ft?= "
2669 "mich. And that's\n"
2670 " all I'm sayin.\n")
2671
2672 # XXX Need test of an encoded word so long that it needs to be wrapped
2673
2674 def test_simple_address(self):
2675 self._test(parser.get_address_list("abc <xyz@example.com>")[0],
2676 "abc <xyz@example.com>\n")
2677
2678 def test_address_list_folding_at_commas(self):
2679 self._test(parser.get_address_list('abc <xyz@example.com>, '
2680 '"Fred Blunt" <sharp@example.com>, '
2681 '"J.P.Cool" <hot@example.com>, '
2682 '"K<>y" <key@example.com>, '
2683 'Firesale <cheap@example.com>, '
2684 '<end@example.com>')[0],
2685 'abc <xyz@example.com>, "Fred Blunt" <sharp@example.com>,\n'
2686 ' "J.P.Cool" <hot@example.com>, "K<>y" <key@example.com>,\n'
2687 ' Firesale <cheap@example.com>, <end@example.com>\n')
2688
2689 def test_address_list_with_unicode_names(self):
2690 self._test(parser.get_address_list(
2691 'Hübsch Kaktus <beautiful@example.com>, '
2692 'beißt beißt <biter@example.com>')[0],
2693 '=?utf-8?q?H=C3=BCbsch?= Kaktus <beautiful@example.com>,\n'
2694 ' =?utf-8?q?bei=C3=9Ft_bei=C3=9Ft?= <biter@example.com>\n')
2695
2696 def test_address_list_with_unicode_names_in_quotes(self):
2697 self._test(parser.get_address_list(
2698 '"Hübsch Kaktus" <beautiful@example.com>, '
2699 '"beißt" beißt <biter@example.com>')[0],
2700 '=?utf-8?q?H=C3=BCbsch?= Kaktus <beautiful@example.com>,\n'
2701 ' =?utf-8?q?bei=C3=9Ft_bei=C3=9Ft?= <biter@example.com>\n')
2702
2703 # XXX Need tests with comments on various sides of a unicode token,
2704 # and with unicode tokens in the comments. Spaces inside the quotes
2705 # currently don't do the right thing.
2706
R. David Murray85d5c182017-12-03 18:51:41 -05002707 def test_split_at_whitespace_after_header_before_long_token(self):
R David Murray0b6f6c82012-05-25 18:42:14 -04002708 body = parser.get_unstructured(' ' + 'x'*77)
2709 header = parser.Header([
2710 parser.HeaderLabel([parser.ValueTerminal('test:', 'atext')]),
2711 parser.CFWSList([parser.WhiteSpaceTerminal(' ', 'fws')]), body])
2712 self._test(header, 'test: \n ' + 'x'*77 + '\n')
2713
R. David Murray85d5c182017-12-03 18:51:41 -05002714 def test_split_at_whitespace_before_long_token(self):
R David Murray0b6f6c82012-05-25 18:42:14 -04002715 self._test(parser.get_unstructured('xxx ' + 'y'*77),
2716 'xxx \n ' + 'y'*77 + '\n')
2717
R. David Murray85d5c182017-12-03 18:51:41 -05002718 def test_overlong_encodeable_is_wrapped(self):
2719 first_token_with_whitespace = 'xxx '
2720 chrome_leader = '=?utf-8?q?'
2721 len_chrome = len(chrome_leader) + 2
2722 len_non_y = len_chrome + len(first_token_with_whitespace)
2723 self._test(parser.get_unstructured(first_token_with_whitespace +
2724 'y'*80),
2725 first_token_with_whitespace + chrome_leader +
2726 'y'*(78-len_non_y) + '?=\n' +
2727 ' ' + chrome_leader + 'y'*(80-(78-len_non_y)) + '?=\n')
2728
Joel Hillacreb350c222017-06-26 15:41:35 -06002729 def test_long_filename_attachment(self):
R. David Murray85d5c182017-12-03 18:51:41 -05002730 self._test(parser.parse_content_disposition_header(
2731 'attachment; filename="TEST_TEST_TEST_TEST'
2732 '_TEST_TEST_TEST_TEST_TEST_TEST_TEST_TEST_TES.txt"'),
2733 "attachment;\n"
2734 " filename*0*=us-ascii''TEST_TEST_TEST_TEST_TEST_TEST"
2735 "_TEST_TEST_TEST_TEST_TEST;\n"
2736 " filename*1*=_TEST_TES.txt\n",
2737 )
Joel Hillacreb350c222017-06-26 15:41:35 -06002738
R David Murray0b6f6c82012-05-25 18:42:14 -04002739if __name__ == '__main__':
2740 unittest.main()