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