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