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