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