17db96d56Sopenharmony_ciimport datetime 27db96d56Sopenharmony_ciimport textwrap 37db96d56Sopenharmony_ciimport unittest 47db96d56Sopenharmony_cifrom email import errors 57db96d56Sopenharmony_cifrom email import policy 67db96d56Sopenharmony_cifrom email.message import Message 77db96d56Sopenharmony_cifrom test.test_email import TestEmailBase, parameterize 87db96d56Sopenharmony_cifrom email import headerregistry 97db96d56Sopenharmony_cifrom email.headerregistry import Address, Group 107db96d56Sopenharmony_cifrom test.support import ALWAYS_EQ 117db96d56Sopenharmony_ci 127db96d56Sopenharmony_ci 137db96d56Sopenharmony_ciDITTO = object() 147db96d56Sopenharmony_ci 157db96d56Sopenharmony_ci 167db96d56Sopenharmony_ciclass TestHeaderRegistry(TestEmailBase): 177db96d56Sopenharmony_ci 187db96d56Sopenharmony_ci def test_arbitrary_name_unstructured(self): 197db96d56Sopenharmony_ci factory = headerregistry.HeaderRegistry() 207db96d56Sopenharmony_ci h = factory('foobar', 'test') 217db96d56Sopenharmony_ci self.assertIsInstance(h, headerregistry.BaseHeader) 227db96d56Sopenharmony_ci self.assertIsInstance(h, headerregistry.UnstructuredHeader) 237db96d56Sopenharmony_ci 247db96d56Sopenharmony_ci def test_name_case_ignored(self): 257db96d56Sopenharmony_ci factory = headerregistry.HeaderRegistry() 267db96d56Sopenharmony_ci # Whitebox check that test is valid 277db96d56Sopenharmony_ci self.assertNotIn('Subject', factory.registry) 287db96d56Sopenharmony_ci h = factory('Subject', 'test') 297db96d56Sopenharmony_ci self.assertIsInstance(h, headerregistry.BaseHeader) 307db96d56Sopenharmony_ci self.assertIsInstance(h, headerregistry.UniqueUnstructuredHeader) 317db96d56Sopenharmony_ci 327db96d56Sopenharmony_ci class FooBase: 337db96d56Sopenharmony_ci def __init__(self, *args, **kw): 347db96d56Sopenharmony_ci pass 357db96d56Sopenharmony_ci 367db96d56Sopenharmony_ci def test_override_default_base_class(self): 377db96d56Sopenharmony_ci factory = headerregistry.HeaderRegistry(base_class=self.FooBase) 387db96d56Sopenharmony_ci h = factory('foobar', 'test') 397db96d56Sopenharmony_ci self.assertIsInstance(h, self.FooBase) 407db96d56Sopenharmony_ci self.assertIsInstance(h, headerregistry.UnstructuredHeader) 417db96d56Sopenharmony_ci 427db96d56Sopenharmony_ci class FooDefault: 437db96d56Sopenharmony_ci parse = headerregistry.UnstructuredHeader.parse 447db96d56Sopenharmony_ci 457db96d56Sopenharmony_ci def test_override_default_class(self): 467db96d56Sopenharmony_ci factory = headerregistry.HeaderRegistry(default_class=self.FooDefault) 477db96d56Sopenharmony_ci h = factory('foobar', 'test') 487db96d56Sopenharmony_ci self.assertIsInstance(h, headerregistry.BaseHeader) 497db96d56Sopenharmony_ci self.assertIsInstance(h, self.FooDefault) 507db96d56Sopenharmony_ci 517db96d56Sopenharmony_ci def test_override_default_class_only_overrides_default(self): 527db96d56Sopenharmony_ci factory = headerregistry.HeaderRegistry(default_class=self.FooDefault) 537db96d56Sopenharmony_ci h = factory('subject', 'test') 547db96d56Sopenharmony_ci self.assertIsInstance(h, headerregistry.BaseHeader) 557db96d56Sopenharmony_ci self.assertIsInstance(h, headerregistry.UniqueUnstructuredHeader) 567db96d56Sopenharmony_ci 577db96d56Sopenharmony_ci def test_dont_use_default_map(self): 587db96d56Sopenharmony_ci factory = headerregistry.HeaderRegistry(use_default_map=False) 597db96d56Sopenharmony_ci h = factory('subject', 'test') 607db96d56Sopenharmony_ci self.assertIsInstance(h, headerregistry.BaseHeader) 617db96d56Sopenharmony_ci self.assertIsInstance(h, headerregistry.UnstructuredHeader) 627db96d56Sopenharmony_ci 637db96d56Sopenharmony_ci def test_map_to_type(self): 647db96d56Sopenharmony_ci factory = headerregistry.HeaderRegistry() 657db96d56Sopenharmony_ci h1 = factory('foobar', 'test') 667db96d56Sopenharmony_ci factory.map_to_type('foobar', headerregistry.UniqueUnstructuredHeader) 677db96d56Sopenharmony_ci h2 = factory('foobar', 'test') 687db96d56Sopenharmony_ci self.assertIsInstance(h1, headerregistry.BaseHeader) 697db96d56Sopenharmony_ci self.assertIsInstance(h1, headerregistry.UnstructuredHeader) 707db96d56Sopenharmony_ci self.assertIsInstance(h2, headerregistry.BaseHeader) 717db96d56Sopenharmony_ci self.assertIsInstance(h2, headerregistry.UniqueUnstructuredHeader) 727db96d56Sopenharmony_ci 737db96d56Sopenharmony_ci 747db96d56Sopenharmony_ciclass TestHeaderBase(TestEmailBase): 757db96d56Sopenharmony_ci 767db96d56Sopenharmony_ci factory = headerregistry.HeaderRegistry() 777db96d56Sopenharmony_ci 787db96d56Sopenharmony_ci def make_header(self, name, value): 797db96d56Sopenharmony_ci return self.factory(name, value) 807db96d56Sopenharmony_ci 817db96d56Sopenharmony_ci 827db96d56Sopenharmony_ciclass TestBaseHeaderFeatures(TestHeaderBase): 837db96d56Sopenharmony_ci 847db96d56Sopenharmony_ci def test_str(self): 857db96d56Sopenharmony_ci h = self.make_header('subject', 'this is a test') 867db96d56Sopenharmony_ci self.assertIsInstance(h, str) 877db96d56Sopenharmony_ci self.assertEqual(h, 'this is a test') 887db96d56Sopenharmony_ci self.assertEqual(str(h), 'this is a test') 897db96d56Sopenharmony_ci 907db96d56Sopenharmony_ci def test_substr(self): 917db96d56Sopenharmony_ci h = self.make_header('subject', 'this is a test') 927db96d56Sopenharmony_ci self.assertEqual(h[5:7], 'is') 937db96d56Sopenharmony_ci 947db96d56Sopenharmony_ci def test_has_name(self): 957db96d56Sopenharmony_ci h = self.make_header('subject', 'this is a test') 967db96d56Sopenharmony_ci self.assertEqual(h.name, 'subject') 977db96d56Sopenharmony_ci 987db96d56Sopenharmony_ci def _test_attr_ro(self, attr): 997db96d56Sopenharmony_ci h = self.make_header('subject', 'this is a test') 1007db96d56Sopenharmony_ci with self.assertRaises(AttributeError): 1017db96d56Sopenharmony_ci setattr(h, attr, 'foo') 1027db96d56Sopenharmony_ci 1037db96d56Sopenharmony_ci def test_name_read_only(self): 1047db96d56Sopenharmony_ci self._test_attr_ro('name') 1057db96d56Sopenharmony_ci 1067db96d56Sopenharmony_ci def test_defects_read_only(self): 1077db96d56Sopenharmony_ci self._test_attr_ro('defects') 1087db96d56Sopenharmony_ci 1097db96d56Sopenharmony_ci def test_defects_is_tuple(self): 1107db96d56Sopenharmony_ci h = self.make_header('subject', 'this is a test') 1117db96d56Sopenharmony_ci self.assertEqual(len(h.defects), 0) 1127db96d56Sopenharmony_ci self.assertIsInstance(h.defects, tuple) 1137db96d56Sopenharmony_ci # Make sure it is still true when there are defects. 1147db96d56Sopenharmony_ci h = self.make_header('date', '') 1157db96d56Sopenharmony_ci self.assertEqual(len(h.defects), 1) 1167db96d56Sopenharmony_ci self.assertIsInstance(h.defects, tuple) 1177db96d56Sopenharmony_ci 1187db96d56Sopenharmony_ci # XXX: FIXME 1197db96d56Sopenharmony_ci #def test_CR_in_value(self): 1207db96d56Sopenharmony_ci # # XXX: this also re-raises the issue of embedded headers, 1217db96d56Sopenharmony_ci # # need test and solution for that. 1227db96d56Sopenharmony_ci # value = '\r'.join(['this is', ' a test']) 1237db96d56Sopenharmony_ci # h = self.make_header('subject', value) 1247db96d56Sopenharmony_ci # self.assertEqual(h, value) 1257db96d56Sopenharmony_ci # self.assertDefectsEqual(h.defects, [errors.ObsoleteHeaderDefect]) 1267db96d56Sopenharmony_ci 1277db96d56Sopenharmony_ci 1287db96d56Sopenharmony_ci@parameterize 1297db96d56Sopenharmony_ciclass TestUnstructuredHeader(TestHeaderBase): 1307db96d56Sopenharmony_ci 1317db96d56Sopenharmony_ci def string_as_value(self, 1327db96d56Sopenharmony_ci source, 1337db96d56Sopenharmony_ci decoded, 1347db96d56Sopenharmony_ci *args): 1357db96d56Sopenharmony_ci l = len(args) 1367db96d56Sopenharmony_ci defects = args[0] if l>0 else [] 1377db96d56Sopenharmony_ci header = 'Subject:' + (' ' if source else '') 1387db96d56Sopenharmony_ci folded = header + (args[1] if l>1 else source) + '\n' 1397db96d56Sopenharmony_ci h = self.make_header('Subject', source) 1407db96d56Sopenharmony_ci self.assertEqual(h, decoded) 1417db96d56Sopenharmony_ci self.assertDefectsEqual(h.defects, defects) 1427db96d56Sopenharmony_ci self.assertEqual(h.fold(policy=policy.default), folded) 1437db96d56Sopenharmony_ci 1447db96d56Sopenharmony_ci string_params = { 1457db96d56Sopenharmony_ci 1467db96d56Sopenharmony_ci 'rfc2047_simple_quopri': ( 1477db96d56Sopenharmony_ci '=?utf-8?q?this_is_a_test?=', 1487db96d56Sopenharmony_ci 'this is a test', 1497db96d56Sopenharmony_ci [], 1507db96d56Sopenharmony_ci 'this is a test'), 1517db96d56Sopenharmony_ci 1527db96d56Sopenharmony_ci 'rfc2047_gb2312_base64': ( 1537db96d56Sopenharmony_ci '=?gb2312?b?1eLKx9bQzsSy4srUo6E=?=', 1547db96d56Sopenharmony_ci '\u8fd9\u662f\u4e2d\u6587\u6d4b\u8bd5\uff01', 1557db96d56Sopenharmony_ci [], 1567db96d56Sopenharmony_ci '=?utf-8?b?6L+Z5piv5Lit5paH5rWL6K+V77yB?='), 1577db96d56Sopenharmony_ci 1587db96d56Sopenharmony_ci 'rfc2047_simple_nonascii_quopri': ( 1597db96d56Sopenharmony_ci '=?utf-8?q?=C3=89ric?=', 1607db96d56Sopenharmony_ci 'Éric'), 1617db96d56Sopenharmony_ci 1627db96d56Sopenharmony_ci 'rfc2047_quopri_with_regular_text': ( 1637db96d56Sopenharmony_ci 'The =?utf-8?q?=C3=89ric=2C?= Himself', 1647db96d56Sopenharmony_ci 'The Éric, Himself'), 1657db96d56Sopenharmony_ci 1667db96d56Sopenharmony_ci } 1677db96d56Sopenharmony_ci 1687db96d56Sopenharmony_ci 1697db96d56Sopenharmony_ci@parameterize 1707db96d56Sopenharmony_ciclass TestDateHeader(TestHeaderBase): 1717db96d56Sopenharmony_ci 1727db96d56Sopenharmony_ci datestring = 'Sun, 23 Sep 2001 20:10:55 -0700' 1737db96d56Sopenharmony_ci utcoffset = datetime.timedelta(hours=-7) 1747db96d56Sopenharmony_ci tz = datetime.timezone(utcoffset) 1757db96d56Sopenharmony_ci dt = datetime.datetime(2001, 9, 23, 20, 10, 55, tzinfo=tz) 1767db96d56Sopenharmony_ci 1777db96d56Sopenharmony_ci def test_parse_date(self): 1787db96d56Sopenharmony_ci h = self.make_header('date', self.datestring) 1797db96d56Sopenharmony_ci self.assertEqual(h, self.datestring) 1807db96d56Sopenharmony_ci self.assertEqual(h.datetime, self.dt) 1817db96d56Sopenharmony_ci self.assertEqual(h.datetime.utcoffset(), self.utcoffset) 1827db96d56Sopenharmony_ci self.assertEqual(h.defects, ()) 1837db96d56Sopenharmony_ci 1847db96d56Sopenharmony_ci def test_set_from_datetime(self): 1857db96d56Sopenharmony_ci h = self.make_header('date', self.dt) 1867db96d56Sopenharmony_ci self.assertEqual(h, self.datestring) 1877db96d56Sopenharmony_ci self.assertEqual(h.datetime, self.dt) 1887db96d56Sopenharmony_ci self.assertEqual(h.defects, ()) 1897db96d56Sopenharmony_ci 1907db96d56Sopenharmony_ci def test_date_header_properties(self): 1917db96d56Sopenharmony_ci h = self.make_header('date', self.datestring) 1927db96d56Sopenharmony_ci self.assertIsInstance(h, headerregistry.UniqueDateHeader) 1937db96d56Sopenharmony_ci self.assertEqual(h.max_count, 1) 1947db96d56Sopenharmony_ci self.assertEqual(h.defects, ()) 1957db96d56Sopenharmony_ci 1967db96d56Sopenharmony_ci def test_resent_date_header_properties(self): 1977db96d56Sopenharmony_ci h = self.make_header('resent-date', self.datestring) 1987db96d56Sopenharmony_ci self.assertIsInstance(h, headerregistry.DateHeader) 1997db96d56Sopenharmony_ci self.assertEqual(h.max_count, None) 2007db96d56Sopenharmony_ci self.assertEqual(h.defects, ()) 2017db96d56Sopenharmony_ci 2027db96d56Sopenharmony_ci def test_no_value_is_defect(self): 2037db96d56Sopenharmony_ci h = self.make_header('date', '') 2047db96d56Sopenharmony_ci self.assertEqual(len(h.defects), 1) 2057db96d56Sopenharmony_ci self.assertIsInstance(h.defects[0], errors.HeaderMissingRequiredValue) 2067db96d56Sopenharmony_ci 2077db96d56Sopenharmony_ci def test_invalid_date_format(self): 2087db96d56Sopenharmony_ci s = 'Not a date header' 2097db96d56Sopenharmony_ci h = self.make_header('date', s) 2107db96d56Sopenharmony_ci self.assertEqual(h, s) 2117db96d56Sopenharmony_ci self.assertIsNone(h.datetime) 2127db96d56Sopenharmony_ci self.assertEqual(len(h.defects), 1) 2137db96d56Sopenharmony_ci self.assertIsInstance(h.defects[0], errors.InvalidDateDefect) 2147db96d56Sopenharmony_ci 2157db96d56Sopenharmony_ci def test_invalid_date_value(self): 2167db96d56Sopenharmony_ci s = 'Tue, 06 Jun 2017 27:39:33 +0600' 2177db96d56Sopenharmony_ci h = self.make_header('date', s) 2187db96d56Sopenharmony_ci self.assertEqual(h, s) 2197db96d56Sopenharmony_ci self.assertIsNone(h.datetime) 2207db96d56Sopenharmony_ci self.assertEqual(len(h.defects), 1) 2217db96d56Sopenharmony_ci self.assertIsInstance(h.defects[0], errors.InvalidDateDefect) 2227db96d56Sopenharmony_ci 2237db96d56Sopenharmony_ci def test_datetime_read_only(self): 2247db96d56Sopenharmony_ci h = self.make_header('date', self.datestring) 2257db96d56Sopenharmony_ci with self.assertRaises(AttributeError): 2267db96d56Sopenharmony_ci h.datetime = 'foo' 2277db96d56Sopenharmony_ci 2287db96d56Sopenharmony_ci def test_set_date_header_from_datetime(self): 2297db96d56Sopenharmony_ci m = Message(policy=policy.default) 2307db96d56Sopenharmony_ci m['Date'] = self.dt 2317db96d56Sopenharmony_ci self.assertEqual(m['Date'], self.datestring) 2327db96d56Sopenharmony_ci self.assertEqual(m['Date'].datetime, self.dt) 2337db96d56Sopenharmony_ci 2347db96d56Sopenharmony_ci 2357db96d56Sopenharmony_ci@parameterize 2367db96d56Sopenharmony_ciclass TestContentTypeHeader(TestHeaderBase): 2377db96d56Sopenharmony_ci 2387db96d56Sopenharmony_ci def content_type_as_value(self, 2397db96d56Sopenharmony_ci source, 2407db96d56Sopenharmony_ci content_type, 2417db96d56Sopenharmony_ci maintype, 2427db96d56Sopenharmony_ci subtype, 2437db96d56Sopenharmony_ci *args): 2447db96d56Sopenharmony_ci l = len(args) 2457db96d56Sopenharmony_ci parmdict = args[0] if l>0 else {} 2467db96d56Sopenharmony_ci defects = args[1] if l>1 else [] 2477db96d56Sopenharmony_ci decoded = args[2] if l>2 and args[2] is not DITTO else source 2487db96d56Sopenharmony_ci header = 'Content-Type:' + ' ' if source else '' 2497db96d56Sopenharmony_ci folded = args[3] if l>3 else header + decoded + '\n' 2507db96d56Sopenharmony_ci h = self.make_header('Content-Type', source) 2517db96d56Sopenharmony_ci self.assertEqual(h.content_type, content_type) 2527db96d56Sopenharmony_ci self.assertEqual(h.maintype, maintype) 2537db96d56Sopenharmony_ci self.assertEqual(h.subtype, subtype) 2547db96d56Sopenharmony_ci self.assertEqual(h.params, parmdict) 2557db96d56Sopenharmony_ci with self.assertRaises(TypeError): 2567db96d56Sopenharmony_ci h.params['abc'] = 'xyz' # make sure params is read-only. 2577db96d56Sopenharmony_ci self.assertDefectsEqual(h.defects, defects) 2587db96d56Sopenharmony_ci self.assertEqual(h, decoded) 2597db96d56Sopenharmony_ci self.assertEqual(h.fold(policy=policy.default), folded) 2607db96d56Sopenharmony_ci 2617db96d56Sopenharmony_ci content_type_params = { 2627db96d56Sopenharmony_ci 2637db96d56Sopenharmony_ci # Examples from RFC 2045. 2647db96d56Sopenharmony_ci 2657db96d56Sopenharmony_ci 'RFC_2045_1': ( 2667db96d56Sopenharmony_ci 'text/plain; charset=us-ascii (Plain text)', 2677db96d56Sopenharmony_ci 'text/plain', 2687db96d56Sopenharmony_ci 'text', 2697db96d56Sopenharmony_ci 'plain', 2707db96d56Sopenharmony_ci {'charset': 'us-ascii'}, 2717db96d56Sopenharmony_ci [], 2727db96d56Sopenharmony_ci 'text/plain; charset="us-ascii"'), 2737db96d56Sopenharmony_ci 2747db96d56Sopenharmony_ci 'RFC_2045_2': ( 2757db96d56Sopenharmony_ci 'text/plain; charset=us-ascii', 2767db96d56Sopenharmony_ci 'text/plain', 2777db96d56Sopenharmony_ci 'text', 2787db96d56Sopenharmony_ci 'plain', 2797db96d56Sopenharmony_ci {'charset': 'us-ascii'}, 2807db96d56Sopenharmony_ci [], 2817db96d56Sopenharmony_ci 'text/plain; charset="us-ascii"'), 2827db96d56Sopenharmony_ci 2837db96d56Sopenharmony_ci 'RFC_2045_3': ( 2847db96d56Sopenharmony_ci 'text/plain; charset="us-ascii"', 2857db96d56Sopenharmony_ci 'text/plain', 2867db96d56Sopenharmony_ci 'text', 2877db96d56Sopenharmony_ci 'plain', 2887db96d56Sopenharmony_ci {'charset': 'us-ascii'}), 2897db96d56Sopenharmony_ci 2907db96d56Sopenharmony_ci # RFC 2045 5.2 says syntactically invalid values are to be treated as 2917db96d56Sopenharmony_ci # text/plain. 2927db96d56Sopenharmony_ci 2937db96d56Sopenharmony_ci 'no_subtype_in_content_type': ( 2947db96d56Sopenharmony_ci 'text/', 2957db96d56Sopenharmony_ci 'text/plain', 2967db96d56Sopenharmony_ci 'text', 2977db96d56Sopenharmony_ci 'plain', 2987db96d56Sopenharmony_ci {}, 2997db96d56Sopenharmony_ci [errors.InvalidHeaderDefect]), 3007db96d56Sopenharmony_ci 3017db96d56Sopenharmony_ci 'no_slash_in_content_type': ( 3027db96d56Sopenharmony_ci 'foo', 3037db96d56Sopenharmony_ci 'text/plain', 3047db96d56Sopenharmony_ci 'text', 3057db96d56Sopenharmony_ci 'plain', 3067db96d56Sopenharmony_ci {}, 3077db96d56Sopenharmony_ci [errors.InvalidHeaderDefect]), 3087db96d56Sopenharmony_ci 3097db96d56Sopenharmony_ci 'junk_text_in_content_type': ( 3107db96d56Sopenharmony_ci '<crazy "stuff">', 3117db96d56Sopenharmony_ci 'text/plain', 3127db96d56Sopenharmony_ci 'text', 3137db96d56Sopenharmony_ci 'plain', 3147db96d56Sopenharmony_ci {}, 3157db96d56Sopenharmony_ci [errors.InvalidHeaderDefect]), 3167db96d56Sopenharmony_ci 3177db96d56Sopenharmony_ci 'too_many_slashes_in_content_type': ( 3187db96d56Sopenharmony_ci 'image/jpeg/foo', 3197db96d56Sopenharmony_ci 'text/plain', 3207db96d56Sopenharmony_ci 'text', 3217db96d56Sopenharmony_ci 'plain', 3227db96d56Sopenharmony_ci {}, 3237db96d56Sopenharmony_ci [errors.InvalidHeaderDefect]), 3247db96d56Sopenharmony_ci 3257db96d56Sopenharmony_ci # But unknown names are OK. We could make non-IANA names a defect, but 3267db96d56Sopenharmony_ci # by not doing so we make ourselves future proof. The fact that they 3277db96d56Sopenharmony_ci # are unknown will be detectable by the fact that they don't appear in 3287db96d56Sopenharmony_ci # the mime_registry...and the application is free to extend that list 3297db96d56Sopenharmony_ci # to handle them even if the core library doesn't. 3307db96d56Sopenharmony_ci 3317db96d56Sopenharmony_ci 'unknown_content_type': ( 3327db96d56Sopenharmony_ci 'bad/names', 3337db96d56Sopenharmony_ci 'bad/names', 3347db96d56Sopenharmony_ci 'bad', 3357db96d56Sopenharmony_ci 'names'), 3367db96d56Sopenharmony_ci 3377db96d56Sopenharmony_ci # The content type is case insensitive, and CFWS is ignored. 3387db96d56Sopenharmony_ci 3397db96d56Sopenharmony_ci 'mixed_case_content_type': ( 3407db96d56Sopenharmony_ci 'ImAge/JPeg', 3417db96d56Sopenharmony_ci 'image/jpeg', 3427db96d56Sopenharmony_ci 'image', 3437db96d56Sopenharmony_ci 'jpeg'), 3447db96d56Sopenharmony_ci 3457db96d56Sopenharmony_ci 'spaces_in_content_type': ( 3467db96d56Sopenharmony_ci ' text / plain ', 3477db96d56Sopenharmony_ci 'text/plain', 3487db96d56Sopenharmony_ci 'text', 3497db96d56Sopenharmony_ci 'plain'), 3507db96d56Sopenharmony_ci 3517db96d56Sopenharmony_ci 'cfws_in_content_type': ( 3527db96d56Sopenharmony_ci '(foo) text (bar)/(baz)plain(stuff)', 3537db96d56Sopenharmony_ci 'text/plain', 3547db96d56Sopenharmony_ci 'text', 3557db96d56Sopenharmony_ci 'plain'), 3567db96d56Sopenharmony_ci 3577db96d56Sopenharmony_ci # test some parameters (more tests could be added for parameters 3587db96d56Sopenharmony_ci # associated with other content types, but since parameter parsing is 3597db96d56Sopenharmony_ci # generic they would be redundant for the current implementation). 3607db96d56Sopenharmony_ci 3617db96d56Sopenharmony_ci 'charset_param': ( 3627db96d56Sopenharmony_ci 'text/plain; charset="utf-8"', 3637db96d56Sopenharmony_ci 'text/plain', 3647db96d56Sopenharmony_ci 'text', 3657db96d56Sopenharmony_ci 'plain', 3667db96d56Sopenharmony_ci {'charset': 'utf-8'}), 3677db96d56Sopenharmony_ci 3687db96d56Sopenharmony_ci 'capitalized_charset': ( 3697db96d56Sopenharmony_ci 'text/plain; charset="US-ASCII"', 3707db96d56Sopenharmony_ci 'text/plain', 3717db96d56Sopenharmony_ci 'text', 3727db96d56Sopenharmony_ci 'plain', 3737db96d56Sopenharmony_ci {'charset': 'US-ASCII'}), 3747db96d56Sopenharmony_ci 3757db96d56Sopenharmony_ci 'unknown_charset': ( 3767db96d56Sopenharmony_ci 'text/plain; charset="fOo"', 3777db96d56Sopenharmony_ci 'text/plain', 3787db96d56Sopenharmony_ci 'text', 3797db96d56Sopenharmony_ci 'plain', 3807db96d56Sopenharmony_ci {'charset': 'fOo'}), 3817db96d56Sopenharmony_ci 3827db96d56Sopenharmony_ci 'capitalized_charset_param_name_and_comment': ( 3837db96d56Sopenharmony_ci 'text/plain; (interjection) Charset="utf-8"', 3847db96d56Sopenharmony_ci 'text/plain', 3857db96d56Sopenharmony_ci 'text', 3867db96d56Sopenharmony_ci 'plain', 3877db96d56Sopenharmony_ci {'charset': 'utf-8'}, 3887db96d56Sopenharmony_ci [], 3897db96d56Sopenharmony_ci # Should the parameter name be lowercased here? 3907db96d56Sopenharmony_ci 'text/plain; Charset="utf-8"'), 3917db96d56Sopenharmony_ci 3927db96d56Sopenharmony_ci # Since this is pretty much the ur-mimeheader, we'll put all the tests 3937db96d56Sopenharmony_ci # that exercise the parameter parsing and formatting here. Note that 3947db96d56Sopenharmony_ci # when we refold we may canonicalize, so things like whitespace, 3957db96d56Sopenharmony_ci # quoting, and rfc2231 encoding may change from what was in the input 3967db96d56Sopenharmony_ci # header. 3977db96d56Sopenharmony_ci 3987db96d56Sopenharmony_ci 'unquoted_param_value': ( 3997db96d56Sopenharmony_ci 'text/plain; title=foo', 4007db96d56Sopenharmony_ci 'text/plain', 4017db96d56Sopenharmony_ci 'text', 4027db96d56Sopenharmony_ci 'plain', 4037db96d56Sopenharmony_ci {'title': 'foo'}, 4047db96d56Sopenharmony_ci [], 4057db96d56Sopenharmony_ci 'text/plain; title="foo"', 4067db96d56Sopenharmony_ci ), 4077db96d56Sopenharmony_ci 4087db96d56Sopenharmony_ci 'param_value_with_tspecials': ( 4097db96d56Sopenharmony_ci 'text/plain; title="(bar)foo blue"', 4107db96d56Sopenharmony_ci 'text/plain', 4117db96d56Sopenharmony_ci 'text', 4127db96d56Sopenharmony_ci 'plain', 4137db96d56Sopenharmony_ci {'title': '(bar)foo blue'}), 4147db96d56Sopenharmony_ci 4157db96d56Sopenharmony_ci 'param_with_extra_quoted_whitespace': ( 4167db96d56Sopenharmony_ci 'text/plain; title=" a loong way \t home "', 4177db96d56Sopenharmony_ci 'text/plain', 4187db96d56Sopenharmony_ci 'text', 4197db96d56Sopenharmony_ci 'plain', 4207db96d56Sopenharmony_ci {'title': ' a loong way \t home '}), 4217db96d56Sopenharmony_ci 4227db96d56Sopenharmony_ci 'bad_params': ( 4237db96d56Sopenharmony_ci 'blarg; baz; boo', 4247db96d56Sopenharmony_ci 'text/plain', 4257db96d56Sopenharmony_ci 'text', 4267db96d56Sopenharmony_ci 'plain', 4277db96d56Sopenharmony_ci {'baz': '', 'boo': ''}, 4287db96d56Sopenharmony_ci [errors.InvalidHeaderDefect]*3), 4297db96d56Sopenharmony_ci 4307db96d56Sopenharmony_ci 'spaces_around_param_equals': ( 4317db96d56Sopenharmony_ci 'Multipart/mixed; boundary = "CPIMSSMTPC06p5f3tG"', 4327db96d56Sopenharmony_ci 'multipart/mixed', 4337db96d56Sopenharmony_ci 'multipart', 4347db96d56Sopenharmony_ci 'mixed', 4357db96d56Sopenharmony_ci {'boundary': 'CPIMSSMTPC06p5f3tG'}, 4367db96d56Sopenharmony_ci [], 4377db96d56Sopenharmony_ci 'Multipart/mixed; boundary="CPIMSSMTPC06p5f3tG"', 4387db96d56Sopenharmony_ci ), 4397db96d56Sopenharmony_ci 4407db96d56Sopenharmony_ci 'spaces_around_semis': ( 4417db96d56Sopenharmony_ci ('image/jpeg; name="wibble.JPG" ; x-mac-type="4A504547" ; ' 4427db96d56Sopenharmony_ci 'x-mac-creator="474B4F4E"'), 4437db96d56Sopenharmony_ci 'image/jpeg', 4447db96d56Sopenharmony_ci 'image', 4457db96d56Sopenharmony_ci 'jpeg', 4467db96d56Sopenharmony_ci {'name': 'wibble.JPG', 4477db96d56Sopenharmony_ci 'x-mac-type': '4A504547', 4487db96d56Sopenharmony_ci 'x-mac-creator': '474B4F4E'}, 4497db96d56Sopenharmony_ci [], 4507db96d56Sopenharmony_ci ('image/jpeg; name="wibble.JPG"; x-mac-type="4A504547"; ' 4517db96d56Sopenharmony_ci 'x-mac-creator="474B4F4E"'), 4527db96d56Sopenharmony_ci ('Content-Type: image/jpeg; name="wibble.JPG";' 4537db96d56Sopenharmony_ci ' x-mac-type="4A504547";\n' 4547db96d56Sopenharmony_ci ' x-mac-creator="474B4F4E"\n'), 4557db96d56Sopenharmony_ci ), 4567db96d56Sopenharmony_ci 4577db96d56Sopenharmony_ci 'lots_of_mime_params': ( 4587db96d56Sopenharmony_ci ('image/jpeg; name="wibble.JPG"; x-mac-type="4A504547"; ' 4597db96d56Sopenharmony_ci 'x-mac-creator="474B4F4E"; x-extrastuff="make it longer"'), 4607db96d56Sopenharmony_ci 'image/jpeg', 4617db96d56Sopenharmony_ci 'image', 4627db96d56Sopenharmony_ci 'jpeg', 4637db96d56Sopenharmony_ci {'name': 'wibble.JPG', 4647db96d56Sopenharmony_ci 'x-mac-type': '4A504547', 4657db96d56Sopenharmony_ci 'x-mac-creator': '474B4F4E', 4667db96d56Sopenharmony_ci 'x-extrastuff': 'make it longer'}, 4677db96d56Sopenharmony_ci [], 4687db96d56Sopenharmony_ci ('image/jpeg; name="wibble.JPG"; x-mac-type="4A504547"; ' 4697db96d56Sopenharmony_ci 'x-mac-creator="474B4F4E"; x-extrastuff="make it longer"'), 4707db96d56Sopenharmony_ci # In this case the whole of the MimeParameters does *not* fit 4717db96d56Sopenharmony_ci # one one line, so we break at a lower syntactic level. 4727db96d56Sopenharmony_ci ('Content-Type: image/jpeg; name="wibble.JPG";' 4737db96d56Sopenharmony_ci ' x-mac-type="4A504547";\n' 4747db96d56Sopenharmony_ci ' x-mac-creator="474B4F4E"; x-extrastuff="make it longer"\n'), 4757db96d56Sopenharmony_ci ), 4767db96d56Sopenharmony_ci 4777db96d56Sopenharmony_ci 'semis_inside_quotes': ( 4787db96d56Sopenharmony_ci 'image/jpeg; name="Jim&&Jill"', 4797db96d56Sopenharmony_ci 'image/jpeg', 4807db96d56Sopenharmony_ci 'image', 4817db96d56Sopenharmony_ci 'jpeg', 4827db96d56Sopenharmony_ci {'name': 'Jim&&Jill'}), 4837db96d56Sopenharmony_ci 4847db96d56Sopenharmony_ci 'single_quotes_inside_quotes': ( 4857db96d56Sopenharmony_ci 'image/jpeg; name="Jim \'Bob\' Jill"', 4867db96d56Sopenharmony_ci 'image/jpeg', 4877db96d56Sopenharmony_ci 'image', 4887db96d56Sopenharmony_ci 'jpeg', 4897db96d56Sopenharmony_ci {'name': "Jim 'Bob' Jill"}), 4907db96d56Sopenharmony_ci 4917db96d56Sopenharmony_ci 'double_quotes_inside_quotes': ( 4927db96d56Sopenharmony_ci r'image/jpeg; name="Jim \"Bob\" Jill"', 4937db96d56Sopenharmony_ci 'image/jpeg', 4947db96d56Sopenharmony_ci 'image', 4957db96d56Sopenharmony_ci 'jpeg', 4967db96d56Sopenharmony_ci {'name': 'Jim "Bob" Jill'}, 4977db96d56Sopenharmony_ci [], 4987db96d56Sopenharmony_ci r'image/jpeg; name="Jim \"Bob\" Jill"'), 4997db96d56Sopenharmony_ci 5007db96d56Sopenharmony_ci 'non_ascii_in_params': ( 5017db96d56Sopenharmony_ci ('foo\xa7/bar; b\xa7r=two; ' 5027db96d56Sopenharmony_ci 'baz=thr\xa7e'.encode('latin-1').decode('us-ascii', 5037db96d56Sopenharmony_ci 'surrogateescape')), 5047db96d56Sopenharmony_ci 'foo\uFFFD/bar', 5057db96d56Sopenharmony_ci 'foo\uFFFD', 5067db96d56Sopenharmony_ci 'bar', 5077db96d56Sopenharmony_ci {'b\uFFFDr': 'two', 'baz': 'thr\uFFFDe'}, 5087db96d56Sopenharmony_ci [errors.UndecodableBytesDefect]*3, 5097db96d56Sopenharmony_ci 'foo�/bar; b�r="two"; baz="thr�e"', 5107db96d56Sopenharmony_ci # XXX Two bugs here: the mime type is not allowed to be an encoded 5117db96d56Sopenharmony_ci # word, and we shouldn't be emitting surrogates in the parameter 5127db96d56Sopenharmony_ci # names. But I don't know what the behavior should be here, so I'm 5137db96d56Sopenharmony_ci # punting for now. In practice this is unlikely to be encountered 5147db96d56Sopenharmony_ci # since headers with binary in them only come from a binary source 5157db96d56Sopenharmony_ci # and are almost certain to be re-emitted without refolding. 5167db96d56Sopenharmony_ci 'Content-Type: =?unknown-8bit?q?foo=A7?=/bar; b\udca7r="two";\n' 5177db96d56Sopenharmony_ci " baz*=unknown-8bit''thr%A7e\n", 5187db96d56Sopenharmony_ci ), 5197db96d56Sopenharmony_ci 5207db96d56Sopenharmony_ci # RFC 2231 parameter tests. 5217db96d56Sopenharmony_ci 5227db96d56Sopenharmony_ci 'rfc2231_segmented_normal_values': ( 5237db96d56Sopenharmony_ci 'image/jpeg; name*0="abc"; name*1=".html"', 5247db96d56Sopenharmony_ci 'image/jpeg', 5257db96d56Sopenharmony_ci 'image', 5267db96d56Sopenharmony_ci 'jpeg', 5277db96d56Sopenharmony_ci {'name': "abc.html"}, 5287db96d56Sopenharmony_ci [], 5297db96d56Sopenharmony_ci 'image/jpeg; name="abc.html"'), 5307db96d56Sopenharmony_ci 5317db96d56Sopenharmony_ci 'quotes_inside_rfc2231_value': ( 5327db96d56Sopenharmony_ci r'image/jpeg; bar*0="baz\"foobar"; bar*1="\"baz"', 5337db96d56Sopenharmony_ci 'image/jpeg', 5347db96d56Sopenharmony_ci 'image', 5357db96d56Sopenharmony_ci 'jpeg', 5367db96d56Sopenharmony_ci {'bar': 'baz"foobar"baz'}, 5377db96d56Sopenharmony_ci [], 5387db96d56Sopenharmony_ci r'image/jpeg; bar="baz\"foobar\"baz"'), 5397db96d56Sopenharmony_ci 5407db96d56Sopenharmony_ci 'non_ascii_rfc2231_value': ( 5417db96d56Sopenharmony_ci ('text/plain; charset=us-ascii; ' 5427db96d56Sopenharmony_ci "title*=us-ascii'en'This%20is%20" 5437db96d56Sopenharmony_ci 'not%20f\xa7n').encode('latin-1').decode('us-ascii', 5447db96d56Sopenharmony_ci 'surrogateescape'), 5457db96d56Sopenharmony_ci 'text/plain', 5467db96d56Sopenharmony_ci 'text', 5477db96d56Sopenharmony_ci 'plain', 5487db96d56Sopenharmony_ci {'charset': 'us-ascii', 'title': 'This is not f\uFFFDn'}, 5497db96d56Sopenharmony_ci [errors.UndecodableBytesDefect], 5507db96d56Sopenharmony_ci 'text/plain; charset="us-ascii"; title="This is not f�n"', 5517db96d56Sopenharmony_ci 'Content-Type: text/plain; charset="us-ascii";\n' 5527db96d56Sopenharmony_ci " title*=unknown-8bit''This%20is%20not%20f%A7n\n", 5537db96d56Sopenharmony_ci ), 5547db96d56Sopenharmony_ci 5557db96d56Sopenharmony_ci 'rfc2231_encoded_charset': ( 5567db96d56Sopenharmony_ci 'text/plain; charset*=ansi-x3.4-1968\'\'us-ascii', 5577db96d56Sopenharmony_ci 'text/plain', 5587db96d56Sopenharmony_ci 'text', 5597db96d56Sopenharmony_ci 'plain', 5607db96d56Sopenharmony_ci {'charset': 'us-ascii'}, 5617db96d56Sopenharmony_ci [], 5627db96d56Sopenharmony_ci 'text/plain; charset="us-ascii"'), 5637db96d56Sopenharmony_ci 5647db96d56Sopenharmony_ci # This follows the RFC: no double quotes around encoded values. 5657db96d56Sopenharmony_ci 'rfc2231_encoded_no_double_quotes': ( 5667db96d56Sopenharmony_ci ("text/plain;" 5677db96d56Sopenharmony_ci "\tname*0*=''This%20is%20;" 5687db96d56Sopenharmony_ci "\tname*1*=%2A%2A%2Afun%2A%2A%2A%20;" 5697db96d56Sopenharmony_ci '\tname*2="is it not.pdf"'), 5707db96d56Sopenharmony_ci 'text/plain', 5717db96d56Sopenharmony_ci 'text', 5727db96d56Sopenharmony_ci 'plain', 5737db96d56Sopenharmony_ci {'name': 'This is ***fun*** is it not.pdf'}, 5747db96d56Sopenharmony_ci [], 5757db96d56Sopenharmony_ci 'text/plain; name="This is ***fun*** is it not.pdf"', 5767db96d56Sopenharmony_ci ), 5777db96d56Sopenharmony_ci 5787db96d56Sopenharmony_ci # Make sure we also handle it if there are spurious double quotes. 5797db96d56Sopenharmony_ci 'rfc2231_encoded_with_double_quotes': ( 5807db96d56Sopenharmony_ci ("text/plain;" 5817db96d56Sopenharmony_ci '\tname*0*="us-ascii\'\'This%20is%20even%20more%20";' 5827db96d56Sopenharmony_ci '\tname*1*="%2A%2A%2Afun%2A%2A%2A%20";' 5837db96d56Sopenharmony_ci '\tname*2="is it not.pdf"'), 5847db96d56Sopenharmony_ci 'text/plain', 5857db96d56Sopenharmony_ci 'text', 5867db96d56Sopenharmony_ci 'plain', 5877db96d56Sopenharmony_ci {'name': 'This is even more ***fun*** is it not.pdf'}, 5887db96d56Sopenharmony_ci [errors.InvalidHeaderDefect]*2, 5897db96d56Sopenharmony_ci 'text/plain; name="This is even more ***fun*** is it not.pdf"', 5907db96d56Sopenharmony_ci ), 5917db96d56Sopenharmony_ci 5927db96d56Sopenharmony_ci 'rfc2231_single_quote_inside_double_quotes': ( 5937db96d56Sopenharmony_ci ('text/plain; charset=us-ascii;' 5947db96d56Sopenharmony_ci '\ttitle*0*="us-ascii\'en\'This%20is%20really%20";' 5957db96d56Sopenharmony_ci '\ttitle*1*="%2A%2A%2Afun%2A%2A%2A%20";' 5967db96d56Sopenharmony_ci '\ttitle*2="isn\'t it!"'), 5977db96d56Sopenharmony_ci 'text/plain', 5987db96d56Sopenharmony_ci 'text', 5997db96d56Sopenharmony_ci 'plain', 6007db96d56Sopenharmony_ci {'charset': 'us-ascii', 'title': "This is really ***fun*** isn't it!"}, 6017db96d56Sopenharmony_ci [errors.InvalidHeaderDefect]*2, 6027db96d56Sopenharmony_ci ('text/plain; charset="us-ascii"; ' 6037db96d56Sopenharmony_ci 'title="This is really ***fun*** isn\'t it!"'), 6047db96d56Sopenharmony_ci ('Content-Type: text/plain; charset="us-ascii";\n' 6057db96d56Sopenharmony_ci ' title="This is really ***fun*** isn\'t it!"\n'), 6067db96d56Sopenharmony_ci ), 6077db96d56Sopenharmony_ci 6087db96d56Sopenharmony_ci 'rfc2231_single_quote_in_value_with_charset_and_lang': ( 6097db96d56Sopenharmony_ci ('application/x-foo;' 6107db96d56Sopenharmony_ci "\tname*0*=\"us-ascii'en-us'Frank's\"; name*1*=\" Document\""), 6117db96d56Sopenharmony_ci 'application/x-foo', 6127db96d56Sopenharmony_ci 'application', 6137db96d56Sopenharmony_ci 'x-foo', 6147db96d56Sopenharmony_ci {'name': "Frank's Document"}, 6157db96d56Sopenharmony_ci [errors.InvalidHeaderDefect]*2, 6167db96d56Sopenharmony_ci 'application/x-foo; name="Frank\'s Document"', 6177db96d56Sopenharmony_ci ), 6187db96d56Sopenharmony_ci 6197db96d56Sopenharmony_ci 'rfc2231_single_quote_in_non_encoded_value': ( 6207db96d56Sopenharmony_ci ('application/x-foo;' 6217db96d56Sopenharmony_ci "\tname*0=\"us-ascii'en-us'Frank's\"; name*1=\" Document\""), 6227db96d56Sopenharmony_ci 'application/x-foo', 6237db96d56Sopenharmony_ci 'application', 6247db96d56Sopenharmony_ci 'x-foo', 6257db96d56Sopenharmony_ci {'name': "us-ascii'en-us'Frank's Document"}, 6267db96d56Sopenharmony_ci [], 6277db96d56Sopenharmony_ci 'application/x-foo; name="us-ascii\'en-us\'Frank\'s Document"', 6287db96d56Sopenharmony_ci ), 6297db96d56Sopenharmony_ci 6307db96d56Sopenharmony_ci 'rfc2231_no_language_or_charset': ( 6317db96d56Sopenharmony_ci 'text/plain; NAME*0*=english_is_the_default.html', 6327db96d56Sopenharmony_ci 'text/plain', 6337db96d56Sopenharmony_ci 'text', 6347db96d56Sopenharmony_ci 'plain', 6357db96d56Sopenharmony_ci {'name': 'english_is_the_default.html'}, 6367db96d56Sopenharmony_ci [errors.InvalidHeaderDefect], 6377db96d56Sopenharmony_ci 'text/plain; NAME="english_is_the_default.html"'), 6387db96d56Sopenharmony_ci 6397db96d56Sopenharmony_ci 'rfc2231_encoded_no_charset': ( 6407db96d56Sopenharmony_ci ("text/plain;" 6417db96d56Sopenharmony_ci '\tname*0*="\'\'This%20is%20even%20more%20";' 6427db96d56Sopenharmony_ci '\tname*1*="%2A%2A%2Afun%2A%2A%2A%20";' 6437db96d56Sopenharmony_ci '\tname*2="is it.pdf"'), 6447db96d56Sopenharmony_ci 'text/plain', 6457db96d56Sopenharmony_ci 'text', 6467db96d56Sopenharmony_ci 'plain', 6477db96d56Sopenharmony_ci {'name': 'This is even more ***fun*** is it.pdf'}, 6487db96d56Sopenharmony_ci [errors.InvalidHeaderDefect]*2, 6497db96d56Sopenharmony_ci 'text/plain; name="This is even more ***fun*** is it.pdf"', 6507db96d56Sopenharmony_ci ), 6517db96d56Sopenharmony_ci 6527db96d56Sopenharmony_ci 'rfc2231_partly_encoded': ( 6537db96d56Sopenharmony_ci ("text/plain;" 6547db96d56Sopenharmony_ci '\tname*0*="\'\'This%20is%20even%20more%20";' 6557db96d56Sopenharmony_ci '\tname*1*="%2A%2A%2Afun%2A%2A%2A%20";' 6567db96d56Sopenharmony_ci '\tname*2="is it.pdf"'), 6577db96d56Sopenharmony_ci 'text/plain', 6587db96d56Sopenharmony_ci 'text', 6597db96d56Sopenharmony_ci 'plain', 6607db96d56Sopenharmony_ci {'name': 'This is even more ***fun*** is it.pdf'}, 6617db96d56Sopenharmony_ci [errors.InvalidHeaderDefect]*2, 6627db96d56Sopenharmony_ci 'text/plain; name="This is even more ***fun*** is it.pdf"', 6637db96d56Sopenharmony_ci ), 6647db96d56Sopenharmony_ci 6657db96d56Sopenharmony_ci 'rfc2231_partly_encoded_2': ( 6667db96d56Sopenharmony_ci ("text/plain;" 6677db96d56Sopenharmony_ci '\tname*0*="\'\'This%20is%20even%20more%20";' 6687db96d56Sopenharmony_ci '\tname*1="%2A%2A%2Afun%2A%2A%2A%20";' 6697db96d56Sopenharmony_ci '\tname*2="is it.pdf"'), 6707db96d56Sopenharmony_ci 'text/plain', 6717db96d56Sopenharmony_ci 'text', 6727db96d56Sopenharmony_ci 'plain', 6737db96d56Sopenharmony_ci {'name': 'This is even more %2A%2A%2Afun%2A%2A%2A%20is it.pdf'}, 6747db96d56Sopenharmony_ci [errors.InvalidHeaderDefect], 6757db96d56Sopenharmony_ci ('text/plain;' 6767db96d56Sopenharmony_ci ' name="This is even more %2A%2A%2Afun%2A%2A%2A%20is it.pdf"'), 6777db96d56Sopenharmony_ci ('Content-Type: text/plain;\n' 6787db96d56Sopenharmony_ci ' name="This is even more %2A%2A%2Afun%2A%2A%2A%20is' 6797db96d56Sopenharmony_ci ' it.pdf"\n'), 6807db96d56Sopenharmony_ci ), 6817db96d56Sopenharmony_ci 6827db96d56Sopenharmony_ci 'rfc2231_unknown_charset_treated_as_ascii': ( 6837db96d56Sopenharmony_ci "text/plain; name*0*=bogus'xx'ascii_is_the_default", 6847db96d56Sopenharmony_ci 'text/plain', 6857db96d56Sopenharmony_ci 'text', 6867db96d56Sopenharmony_ci 'plain', 6877db96d56Sopenharmony_ci {'name': 'ascii_is_the_default'}, 6887db96d56Sopenharmony_ci [], 6897db96d56Sopenharmony_ci 'text/plain; name="ascii_is_the_default"'), 6907db96d56Sopenharmony_ci 6917db96d56Sopenharmony_ci 'rfc2231_bad_character_in_charset_parameter_value': ( 6927db96d56Sopenharmony_ci "text/plain; charset*=ascii''utf-8%F1%F2%F3", 6937db96d56Sopenharmony_ci 'text/plain', 6947db96d56Sopenharmony_ci 'text', 6957db96d56Sopenharmony_ci 'plain', 6967db96d56Sopenharmony_ci {'charset': 'utf-8\uFFFD\uFFFD\uFFFD'}, 6977db96d56Sopenharmony_ci [errors.UndecodableBytesDefect], 6987db96d56Sopenharmony_ci 'text/plain; charset="utf-8\uFFFD\uFFFD\uFFFD"', 6997db96d56Sopenharmony_ci "Content-Type: text/plain;" 7007db96d56Sopenharmony_ci " charset*=unknown-8bit''utf-8%F1%F2%F3\n", 7017db96d56Sopenharmony_ci ), 7027db96d56Sopenharmony_ci 7037db96d56Sopenharmony_ci 'rfc2231_utf8_in_supposedly_ascii_charset_parameter_value': ( 7047db96d56Sopenharmony_ci "text/plain; charset*=ascii''utf-8%E2%80%9D", 7057db96d56Sopenharmony_ci 'text/plain', 7067db96d56Sopenharmony_ci 'text', 7077db96d56Sopenharmony_ci 'plain', 7087db96d56Sopenharmony_ci {'charset': 'utf-8”'}, 7097db96d56Sopenharmony_ci [errors.UndecodableBytesDefect], 7107db96d56Sopenharmony_ci 'text/plain; charset="utf-8”"', 7117db96d56Sopenharmony_ci # XXX Should folding change the charset to utf8? Currently it just 7127db96d56Sopenharmony_ci # reproduces the original, which is arguably fine. 7137db96d56Sopenharmony_ci "Content-Type: text/plain;" 7147db96d56Sopenharmony_ci " charset*=unknown-8bit''utf-8%E2%80%9D\n", 7157db96d56Sopenharmony_ci ), 7167db96d56Sopenharmony_ci 7177db96d56Sopenharmony_ci 'rfc2231_nonascii_in_charset_of_charset_parameter_value': ( 7187db96d56Sopenharmony_ci "text/plain; charset*=utf-8”''utf-8%E2%80%9D", 7197db96d56Sopenharmony_ci 'text/plain', 7207db96d56Sopenharmony_ci 'text', 7217db96d56Sopenharmony_ci 'plain', 7227db96d56Sopenharmony_ci {'charset': 'utf-8”'}, 7237db96d56Sopenharmony_ci [], 7247db96d56Sopenharmony_ci 'text/plain; charset="utf-8”"', 7257db96d56Sopenharmony_ci "Content-Type: text/plain;" 7267db96d56Sopenharmony_ci " charset*=utf-8''utf-8%E2%80%9D\n", 7277db96d56Sopenharmony_ci ), 7287db96d56Sopenharmony_ci 7297db96d56Sopenharmony_ci 'rfc2231_encoded_then_unencoded_segments': ( 7307db96d56Sopenharmony_ci ('application/x-foo;' 7317db96d56Sopenharmony_ci '\tname*0*="us-ascii\'en-us\'My";' 7327db96d56Sopenharmony_ci '\tname*1=" Document";' 7337db96d56Sopenharmony_ci '\tname*2=" For You"'), 7347db96d56Sopenharmony_ci 'application/x-foo', 7357db96d56Sopenharmony_ci 'application', 7367db96d56Sopenharmony_ci 'x-foo', 7377db96d56Sopenharmony_ci {'name': 'My Document For You'}, 7387db96d56Sopenharmony_ci [errors.InvalidHeaderDefect], 7397db96d56Sopenharmony_ci 'application/x-foo; name="My Document For You"', 7407db96d56Sopenharmony_ci ), 7417db96d56Sopenharmony_ci 7427db96d56Sopenharmony_ci # My reading of the RFC is that this is an invalid header. The RFC 7437db96d56Sopenharmony_ci # says that if charset and language information is given, the first 7447db96d56Sopenharmony_ci # segment *must* be encoded. 7457db96d56Sopenharmony_ci 'rfc2231_unencoded_then_encoded_segments': ( 7467db96d56Sopenharmony_ci ('application/x-foo;' 7477db96d56Sopenharmony_ci '\tname*0=us-ascii\'en-us\'My;' 7487db96d56Sopenharmony_ci '\tname*1*=" Document";' 7497db96d56Sopenharmony_ci '\tname*2*=" For You"'), 7507db96d56Sopenharmony_ci 'application/x-foo', 7517db96d56Sopenharmony_ci 'application', 7527db96d56Sopenharmony_ci 'x-foo', 7537db96d56Sopenharmony_ci {'name': 'My Document For You'}, 7547db96d56Sopenharmony_ci [errors.InvalidHeaderDefect]*3, 7557db96d56Sopenharmony_ci 'application/x-foo; name="My Document For You"', 7567db96d56Sopenharmony_ci ), 7577db96d56Sopenharmony_ci 7587db96d56Sopenharmony_ci # XXX: I would say this one should default to ascii/en for the 7597db96d56Sopenharmony_ci # "encoded" segment, since the first segment is not encoded and is 7607db96d56Sopenharmony_ci # in double quotes, making the value a valid non-encoded string. The 7617db96d56Sopenharmony_ci # old parser decodes this just like the previous case, which may be the 7627db96d56Sopenharmony_ci # better Postel rule, but could equally result in borking headers that 7637db96d56Sopenharmony_ci # intentionally have quoted quotes in them. We could get this 98% 7647db96d56Sopenharmony_ci # right if we treat it as a quoted string *unless* it matches the 7657db96d56Sopenharmony_ci # charset'lang'value pattern exactly *and* there is at least one 7667db96d56Sopenharmony_ci # encoded segment. Implementing that algorithm will require some 7677db96d56Sopenharmony_ci # refactoring, so I haven't done it (yet). 7687db96d56Sopenharmony_ci 'rfc2231_quoted_unencoded_then_encoded_segments': ( 7697db96d56Sopenharmony_ci ('application/x-foo;' 7707db96d56Sopenharmony_ci '\tname*0="us-ascii\'en-us\'My";' 7717db96d56Sopenharmony_ci '\tname*1*=" Document";' 7727db96d56Sopenharmony_ci '\tname*2*=" For You"'), 7737db96d56Sopenharmony_ci 'application/x-foo', 7747db96d56Sopenharmony_ci 'application', 7757db96d56Sopenharmony_ci 'x-foo', 7767db96d56Sopenharmony_ci {'name': "us-ascii'en-us'My Document For You"}, 7777db96d56Sopenharmony_ci [errors.InvalidHeaderDefect]*2, 7787db96d56Sopenharmony_ci 'application/x-foo; name="us-ascii\'en-us\'My Document For You"', 7797db96d56Sopenharmony_ci ), 7807db96d56Sopenharmony_ci 7817db96d56Sopenharmony_ci # Make sure our folding algorithm produces multiple sections correctly. 7827db96d56Sopenharmony_ci # We could mix encoded and non-encoded segments, but we don't, we just 7837db96d56Sopenharmony_ci # make them all encoded. It might be worth fixing that, since the 7847db96d56Sopenharmony_ci # sections can get used for wrapping ascii text. 7857db96d56Sopenharmony_ci 'rfc2231_folded_segments_correctly_formatted': ( 7867db96d56Sopenharmony_ci ('application/x-foo;' 7877db96d56Sopenharmony_ci '\tname="' + "with spaces"*8 + '"'), 7887db96d56Sopenharmony_ci 'application/x-foo', 7897db96d56Sopenharmony_ci 'application', 7907db96d56Sopenharmony_ci 'x-foo', 7917db96d56Sopenharmony_ci {'name': "with spaces"*8}, 7927db96d56Sopenharmony_ci [], 7937db96d56Sopenharmony_ci 'application/x-foo; name="' + "with spaces"*8 + '"', 7947db96d56Sopenharmony_ci "Content-Type: application/x-foo;\n" 7957db96d56Sopenharmony_ci " name*0*=us-ascii''with%20spaceswith%20spaceswith%20spaceswith" 7967db96d56Sopenharmony_ci "%20spaceswith;\n" 7977db96d56Sopenharmony_ci " name*1*=%20spaceswith%20spaceswith%20spaceswith%20spaces\n" 7987db96d56Sopenharmony_ci ), 7997db96d56Sopenharmony_ci 8007db96d56Sopenharmony_ci } 8017db96d56Sopenharmony_ci 8027db96d56Sopenharmony_ci 8037db96d56Sopenharmony_ci@parameterize 8047db96d56Sopenharmony_ciclass TestContentTransferEncoding(TestHeaderBase): 8057db96d56Sopenharmony_ci 8067db96d56Sopenharmony_ci def cte_as_value(self, 8077db96d56Sopenharmony_ci source, 8087db96d56Sopenharmony_ci cte, 8097db96d56Sopenharmony_ci *args): 8107db96d56Sopenharmony_ci l = len(args) 8117db96d56Sopenharmony_ci defects = args[0] if l>0 else [] 8127db96d56Sopenharmony_ci decoded = args[1] if l>1 and args[1] is not DITTO else source 8137db96d56Sopenharmony_ci header = 'Content-Transfer-Encoding:' + ' ' if source else '' 8147db96d56Sopenharmony_ci folded = args[2] if l>2 else header + source + '\n' 8157db96d56Sopenharmony_ci h = self.make_header('Content-Transfer-Encoding', source) 8167db96d56Sopenharmony_ci self.assertEqual(h.cte, cte) 8177db96d56Sopenharmony_ci self.assertDefectsEqual(h.defects, defects) 8187db96d56Sopenharmony_ci self.assertEqual(h, decoded) 8197db96d56Sopenharmony_ci self.assertEqual(h.fold(policy=policy.default), folded) 8207db96d56Sopenharmony_ci 8217db96d56Sopenharmony_ci cte_params = { 8227db96d56Sopenharmony_ci 8237db96d56Sopenharmony_ci 'RFC_2183_1': ( 8247db96d56Sopenharmony_ci 'base64', 8257db96d56Sopenharmony_ci 'base64',), 8267db96d56Sopenharmony_ci 8277db96d56Sopenharmony_ci 'no_value': ( 8287db96d56Sopenharmony_ci '', 8297db96d56Sopenharmony_ci '7bit', 8307db96d56Sopenharmony_ci [errors.HeaderMissingRequiredValue], 8317db96d56Sopenharmony_ci '', 8327db96d56Sopenharmony_ci 'Content-Transfer-Encoding:\n', 8337db96d56Sopenharmony_ci ), 8347db96d56Sopenharmony_ci 8357db96d56Sopenharmony_ci 'junk_after_cte': ( 8367db96d56Sopenharmony_ci '7bit and a bunch more', 8377db96d56Sopenharmony_ci '7bit', 8387db96d56Sopenharmony_ci [errors.InvalidHeaderDefect]), 8397db96d56Sopenharmony_ci 8407db96d56Sopenharmony_ci } 8417db96d56Sopenharmony_ci 8427db96d56Sopenharmony_ci 8437db96d56Sopenharmony_ci@parameterize 8447db96d56Sopenharmony_ciclass TestContentDisposition(TestHeaderBase): 8457db96d56Sopenharmony_ci 8467db96d56Sopenharmony_ci def content_disp_as_value(self, 8477db96d56Sopenharmony_ci source, 8487db96d56Sopenharmony_ci content_disposition, 8497db96d56Sopenharmony_ci *args): 8507db96d56Sopenharmony_ci l = len(args) 8517db96d56Sopenharmony_ci parmdict = args[0] if l>0 else {} 8527db96d56Sopenharmony_ci defects = args[1] if l>1 else [] 8537db96d56Sopenharmony_ci decoded = args[2] if l>2 and args[2] is not DITTO else source 8547db96d56Sopenharmony_ci header = 'Content-Disposition:' + ' ' if source else '' 8557db96d56Sopenharmony_ci folded = args[3] if l>3 else header + source + '\n' 8567db96d56Sopenharmony_ci h = self.make_header('Content-Disposition', source) 8577db96d56Sopenharmony_ci self.assertEqual(h.content_disposition, content_disposition) 8587db96d56Sopenharmony_ci self.assertEqual(h.params, parmdict) 8597db96d56Sopenharmony_ci self.assertDefectsEqual(h.defects, defects) 8607db96d56Sopenharmony_ci self.assertEqual(h, decoded) 8617db96d56Sopenharmony_ci self.assertEqual(h.fold(policy=policy.default), folded) 8627db96d56Sopenharmony_ci 8637db96d56Sopenharmony_ci content_disp_params = { 8647db96d56Sopenharmony_ci 8657db96d56Sopenharmony_ci # Examples from RFC 2183. 8667db96d56Sopenharmony_ci 8677db96d56Sopenharmony_ci 'RFC_2183_1': ( 8687db96d56Sopenharmony_ci 'inline', 8697db96d56Sopenharmony_ci 'inline',), 8707db96d56Sopenharmony_ci 8717db96d56Sopenharmony_ci 'RFC_2183_2': ( 8727db96d56Sopenharmony_ci ('attachment; filename=genome.jpeg;' 8737db96d56Sopenharmony_ci ' modification-date="Wed, 12 Feb 1997 16:29:51 -0500";'), 8747db96d56Sopenharmony_ci 'attachment', 8757db96d56Sopenharmony_ci {'filename': 'genome.jpeg', 8767db96d56Sopenharmony_ci 'modification-date': 'Wed, 12 Feb 1997 16:29:51 -0500'}, 8777db96d56Sopenharmony_ci [], 8787db96d56Sopenharmony_ci ('attachment; filename="genome.jpeg"; ' 8797db96d56Sopenharmony_ci 'modification-date="Wed, 12 Feb 1997 16:29:51 -0500"'), 8807db96d56Sopenharmony_ci ('Content-Disposition: attachment; filename="genome.jpeg";\n' 8817db96d56Sopenharmony_ci ' modification-date="Wed, 12 Feb 1997 16:29:51 -0500"\n'), 8827db96d56Sopenharmony_ci ), 8837db96d56Sopenharmony_ci 8847db96d56Sopenharmony_ci 'no_value': ( 8857db96d56Sopenharmony_ci '', 8867db96d56Sopenharmony_ci None, 8877db96d56Sopenharmony_ci {}, 8887db96d56Sopenharmony_ci [errors.HeaderMissingRequiredValue], 8897db96d56Sopenharmony_ci '', 8907db96d56Sopenharmony_ci 'Content-Disposition:\n'), 8917db96d56Sopenharmony_ci 8927db96d56Sopenharmony_ci 'invalid_value': ( 8937db96d56Sopenharmony_ci 'ab./k', 8947db96d56Sopenharmony_ci 'ab.', 8957db96d56Sopenharmony_ci {}, 8967db96d56Sopenharmony_ci [errors.InvalidHeaderDefect]), 8977db96d56Sopenharmony_ci 8987db96d56Sopenharmony_ci 'invalid_value_with_params': ( 8997db96d56Sopenharmony_ci 'ab./k; filename="foo"', 9007db96d56Sopenharmony_ci 'ab.', 9017db96d56Sopenharmony_ci {'filename': 'foo'}, 9027db96d56Sopenharmony_ci [errors.InvalidHeaderDefect]), 9037db96d56Sopenharmony_ci 9047db96d56Sopenharmony_ci 'invalid_parameter_value_with_fws_between_ew': ( 9057db96d56Sopenharmony_ci 'attachment; filename="=?UTF-8?Q?Schulbesuchsbest=C3=A4ttigung=2E?=' 9067db96d56Sopenharmony_ci ' =?UTF-8?Q?pdf?="', 9077db96d56Sopenharmony_ci 'attachment', 9087db96d56Sopenharmony_ci {'filename': 'Schulbesuchsbestättigung.pdf'}, 9097db96d56Sopenharmony_ci [errors.InvalidHeaderDefect]*3, 9107db96d56Sopenharmony_ci ('attachment; filename="Schulbesuchsbestättigung.pdf"'), 9117db96d56Sopenharmony_ci ('Content-Disposition: attachment;\n' 9127db96d56Sopenharmony_ci ' filename*=utf-8\'\'Schulbesuchsbest%C3%A4ttigung.pdf\n'), 9137db96d56Sopenharmony_ci ), 9147db96d56Sopenharmony_ci 9157db96d56Sopenharmony_ci 'parameter_value_with_fws_between_tokens': ( 9167db96d56Sopenharmony_ci 'attachment; filename="File =?utf-8?q?Name?= With Spaces.pdf"', 9177db96d56Sopenharmony_ci 'attachment', 9187db96d56Sopenharmony_ci {'filename': 'File Name With Spaces.pdf'}, 9197db96d56Sopenharmony_ci [errors.InvalidHeaderDefect], 9207db96d56Sopenharmony_ci 'attachment; filename="File Name With Spaces.pdf"', 9217db96d56Sopenharmony_ci ('Content-Disposition: attachment; filename="File Name With Spaces.pdf"\n'), 9227db96d56Sopenharmony_ci ) 9237db96d56Sopenharmony_ci } 9247db96d56Sopenharmony_ci 9257db96d56Sopenharmony_ci 9267db96d56Sopenharmony_ci@parameterize 9277db96d56Sopenharmony_ciclass TestMIMEVersionHeader(TestHeaderBase): 9287db96d56Sopenharmony_ci 9297db96d56Sopenharmony_ci def version_string_as_MIME_Version(self, 9307db96d56Sopenharmony_ci source, 9317db96d56Sopenharmony_ci decoded, 9327db96d56Sopenharmony_ci version, 9337db96d56Sopenharmony_ci major, 9347db96d56Sopenharmony_ci minor, 9357db96d56Sopenharmony_ci defects): 9367db96d56Sopenharmony_ci h = self.make_header('MIME-Version', source) 9377db96d56Sopenharmony_ci self.assertEqual(h, decoded) 9387db96d56Sopenharmony_ci self.assertEqual(h.version, version) 9397db96d56Sopenharmony_ci self.assertEqual(h.major, major) 9407db96d56Sopenharmony_ci self.assertEqual(h.minor, minor) 9417db96d56Sopenharmony_ci self.assertDefectsEqual(h.defects, defects) 9427db96d56Sopenharmony_ci if source: 9437db96d56Sopenharmony_ci source = ' ' + source 9447db96d56Sopenharmony_ci self.assertEqual(h.fold(policy=policy.default), 9457db96d56Sopenharmony_ci 'MIME-Version:' + source + '\n') 9467db96d56Sopenharmony_ci 9477db96d56Sopenharmony_ci version_string_params = { 9487db96d56Sopenharmony_ci 9497db96d56Sopenharmony_ci # Examples from the RFC. 9507db96d56Sopenharmony_ci 9517db96d56Sopenharmony_ci 'RFC_2045_1': ( 9527db96d56Sopenharmony_ci '1.0', 9537db96d56Sopenharmony_ci '1.0', 9547db96d56Sopenharmony_ci '1.0', 9557db96d56Sopenharmony_ci 1, 9567db96d56Sopenharmony_ci 0, 9577db96d56Sopenharmony_ci []), 9587db96d56Sopenharmony_ci 9597db96d56Sopenharmony_ci 'RFC_2045_2': ( 9607db96d56Sopenharmony_ci '1.0 (produced by MetaSend Vx.x)', 9617db96d56Sopenharmony_ci '1.0 (produced by MetaSend Vx.x)', 9627db96d56Sopenharmony_ci '1.0', 9637db96d56Sopenharmony_ci 1, 9647db96d56Sopenharmony_ci 0, 9657db96d56Sopenharmony_ci []), 9667db96d56Sopenharmony_ci 9677db96d56Sopenharmony_ci 'RFC_2045_3': ( 9687db96d56Sopenharmony_ci '(produced by MetaSend Vx.x) 1.0', 9697db96d56Sopenharmony_ci '(produced by MetaSend Vx.x) 1.0', 9707db96d56Sopenharmony_ci '1.0', 9717db96d56Sopenharmony_ci 1, 9727db96d56Sopenharmony_ci 0, 9737db96d56Sopenharmony_ci []), 9747db96d56Sopenharmony_ci 9757db96d56Sopenharmony_ci 'RFC_2045_4': ( 9767db96d56Sopenharmony_ci '1.(produced by MetaSend Vx.x)0', 9777db96d56Sopenharmony_ci '1.(produced by MetaSend Vx.x)0', 9787db96d56Sopenharmony_ci '1.0', 9797db96d56Sopenharmony_ci 1, 9807db96d56Sopenharmony_ci 0, 9817db96d56Sopenharmony_ci []), 9827db96d56Sopenharmony_ci 9837db96d56Sopenharmony_ci # Other valid values. 9847db96d56Sopenharmony_ci 9857db96d56Sopenharmony_ci '1_1': ( 9867db96d56Sopenharmony_ci '1.1', 9877db96d56Sopenharmony_ci '1.1', 9887db96d56Sopenharmony_ci '1.1', 9897db96d56Sopenharmony_ci 1, 9907db96d56Sopenharmony_ci 1, 9917db96d56Sopenharmony_ci []), 9927db96d56Sopenharmony_ci 9937db96d56Sopenharmony_ci '2_1': ( 9947db96d56Sopenharmony_ci '2.1', 9957db96d56Sopenharmony_ci '2.1', 9967db96d56Sopenharmony_ci '2.1', 9977db96d56Sopenharmony_ci 2, 9987db96d56Sopenharmony_ci 1, 9997db96d56Sopenharmony_ci []), 10007db96d56Sopenharmony_ci 10017db96d56Sopenharmony_ci 'whitespace': ( 10027db96d56Sopenharmony_ci '1 .0', 10037db96d56Sopenharmony_ci '1 .0', 10047db96d56Sopenharmony_ci '1.0', 10057db96d56Sopenharmony_ci 1, 10067db96d56Sopenharmony_ci 0, 10077db96d56Sopenharmony_ci []), 10087db96d56Sopenharmony_ci 10097db96d56Sopenharmony_ci 'leading_trailing_whitespace_ignored': ( 10107db96d56Sopenharmony_ci ' 1.0 ', 10117db96d56Sopenharmony_ci ' 1.0 ', 10127db96d56Sopenharmony_ci '1.0', 10137db96d56Sopenharmony_ci 1, 10147db96d56Sopenharmony_ci 0, 10157db96d56Sopenharmony_ci []), 10167db96d56Sopenharmony_ci 10177db96d56Sopenharmony_ci # Recoverable invalid values. We can recover here only because we 10187db96d56Sopenharmony_ci # already have a valid value by the time we encounter the garbage. 10197db96d56Sopenharmony_ci # Anywhere else, and we don't know where the garbage ends. 10207db96d56Sopenharmony_ci 10217db96d56Sopenharmony_ci 'non_comment_garbage_after': ( 10227db96d56Sopenharmony_ci '1.0 <abc>', 10237db96d56Sopenharmony_ci '1.0 <abc>', 10247db96d56Sopenharmony_ci '1.0', 10257db96d56Sopenharmony_ci 1, 10267db96d56Sopenharmony_ci 0, 10277db96d56Sopenharmony_ci [errors.InvalidHeaderDefect]), 10287db96d56Sopenharmony_ci 10297db96d56Sopenharmony_ci # Unrecoverable invalid values. We *could* apply more heuristics to 10307db96d56Sopenharmony_ci # get something out of the first two, but doing so is not worth the 10317db96d56Sopenharmony_ci # effort. 10327db96d56Sopenharmony_ci 10337db96d56Sopenharmony_ci 'non_comment_garbage_before': ( 10347db96d56Sopenharmony_ci '<abc> 1.0', 10357db96d56Sopenharmony_ci '<abc> 1.0', 10367db96d56Sopenharmony_ci None, 10377db96d56Sopenharmony_ci None, 10387db96d56Sopenharmony_ci None, 10397db96d56Sopenharmony_ci [errors.InvalidHeaderDefect]), 10407db96d56Sopenharmony_ci 10417db96d56Sopenharmony_ci 'non_comment_garbage_inside': ( 10427db96d56Sopenharmony_ci '1.<abc>0', 10437db96d56Sopenharmony_ci '1.<abc>0', 10447db96d56Sopenharmony_ci None, 10457db96d56Sopenharmony_ci None, 10467db96d56Sopenharmony_ci None, 10477db96d56Sopenharmony_ci [errors.InvalidHeaderDefect]), 10487db96d56Sopenharmony_ci 10497db96d56Sopenharmony_ci 'two_periods': ( 10507db96d56Sopenharmony_ci '1..0', 10517db96d56Sopenharmony_ci '1..0', 10527db96d56Sopenharmony_ci None, 10537db96d56Sopenharmony_ci None, 10547db96d56Sopenharmony_ci None, 10557db96d56Sopenharmony_ci [errors.InvalidHeaderDefect]), 10567db96d56Sopenharmony_ci 10577db96d56Sopenharmony_ci '2_x': ( 10587db96d56Sopenharmony_ci '2.x', 10597db96d56Sopenharmony_ci '2.x', 10607db96d56Sopenharmony_ci None, # This could be 2, but it seems safer to make it None. 10617db96d56Sopenharmony_ci None, 10627db96d56Sopenharmony_ci None, 10637db96d56Sopenharmony_ci [errors.InvalidHeaderDefect]), 10647db96d56Sopenharmony_ci 10657db96d56Sopenharmony_ci 'foo': ( 10667db96d56Sopenharmony_ci 'foo', 10677db96d56Sopenharmony_ci 'foo', 10687db96d56Sopenharmony_ci None, 10697db96d56Sopenharmony_ci None, 10707db96d56Sopenharmony_ci None, 10717db96d56Sopenharmony_ci [errors.InvalidHeaderDefect]), 10727db96d56Sopenharmony_ci 10737db96d56Sopenharmony_ci 'missing': ( 10747db96d56Sopenharmony_ci '', 10757db96d56Sopenharmony_ci '', 10767db96d56Sopenharmony_ci None, 10777db96d56Sopenharmony_ci None, 10787db96d56Sopenharmony_ci None, 10797db96d56Sopenharmony_ci [errors.HeaderMissingRequiredValue]), 10807db96d56Sopenharmony_ci 10817db96d56Sopenharmony_ci } 10827db96d56Sopenharmony_ci 10837db96d56Sopenharmony_ci 10847db96d56Sopenharmony_ci@parameterize 10857db96d56Sopenharmony_ciclass TestAddressHeader(TestHeaderBase): 10867db96d56Sopenharmony_ci 10877db96d56Sopenharmony_ci example_params = { 10887db96d56Sopenharmony_ci 10897db96d56Sopenharmony_ci 'empty': 10907db96d56Sopenharmony_ci ('<>', 10917db96d56Sopenharmony_ci [errors.InvalidHeaderDefect], 10927db96d56Sopenharmony_ci '<>', 10937db96d56Sopenharmony_ci '', 10947db96d56Sopenharmony_ci '<>', 10957db96d56Sopenharmony_ci '', 10967db96d56Sopenharmony_ci '', 10977db96d56Sopenharmony_ci None), 10987db96d56Sopenharmony_ci 10997db96d56Sopenharmony_ci 'address_only': 11007db96d56Sopenharmony_ci ('zippy@pinhead.com', 11017db96d56Sopenharmony_ci [], 11027db96d56Sopenharmony_ci 'zippy@pinhead.com', 11037db96d56Sopenharmony_ci '', 11047db96d56Sopenharmony_ci 'zippy@pinhead.com', 11057db96d56Sopenharmony_ci 'zippy', 11067db96d56Sopenharmony_ci 'pinhead.com', 11077db96d56Sopenharmony_ci None), 11087db96d56Sopenharmony_ci 11097db96d56Sopenharmony_ci 'name_and_address': 11107db96d56Sopenharmony_ci ('Zaphrod Beblebrux <zippy@pinhead.com>', 11117db96d56Sopenharmony_ci [], 11127db96d56Sopenharmony_ci 'Zaphrod Beblebrux <zippy@pinhead.com>', 11137db96d56Sopenharmony_ci 'Zaphrod Beblebrux', 11147db96d56Sopenharmony_ci 'zippy@pinhead.com', 11157db96d56Sopenharmony_ci 'zippy', 11167db96d56Sopenharmony_ci 'pinhead.com', 11177db96d56Sopenharmony_ci None), 11187db96d56Sopenharmony_ci 11197db96d56Sopenharmony_ci 'quoted_local_part': 11207db96d56Sopenharmony_ci ('Zaphrod Beblebrux <"foo bar"@pinhead.com>', 11217db96d56Sopenharmony_ci [], 11227db96d56Sopenharmony_ci 'Zaphrod Beblebrux <"foo bar"@pinhead.com>', 11237db96d56Sopenharmony_ci 'Zaphrod Beblebrux', 11247db96d56Sopenharmony_ci '"foo bar"@pinhead.com', 11257db96d56Sopenharmony_ci 'foo bar', 11267db96d56Sopenharmony_ci 'pinhead.com', 11277db96d56Sopenharmony_ci None), 11287db96d56Sopenharmony_ci 11297db96d56Sopenharmony_ci 'quoted_parens_in_name': 11307db96d56Sopenharmony_ci (r'"A \(Special\) Person" <person@dom.ain>', 11317db96d56Sopenharmony_ci [], 11327db96d56Sopenharmony_ci '"A (Special) Person" <person@dom.ain>', 11337db96d56Sopenharmony_ci 'A (Special) Person', 11347db96d56Sopenharmony_ci 'person@dom.ain', 11357db96d56Sopenharmony_ci 'person', 11367db96d56Sopenharmony_ci 'dom.ain', 11377db96d56Sopenharmony_ci None), 11387db96d56Sopenharmony_ci 11397db96d56Sopenharmony_ci 'quoted_backslashes_in_name': 11407db96d56Sopenharmony_ci (r'"Arthur \\Backslash\\ Foobar" <person@dom.ain>', 11417db96d56Sopenharmony_ci [], 11427db96d56Sopenharmony_ci r'"Arthur \\Backslash\\ Foobar" <person@dom.ain>', 11437db96d56Sopenharmony_ci r'Arthur \Backslash\ Foobar', 11447db96d56Sopenharmony_ci 'person@dom.ain', 11457db96d56Sopenharmony_ci 'person', 11467db96d56Sopenharmony_ci 'dom.ain', 11477db96d56Sopenharmony_ci None), 11487db96d56Sopenharmony_ci 11497db96d56Sopenharmony_ci 'name_with_dot': 11507db96d56Sopenharmony_ci ('John X. Doe <jxd@example.com>', 11517db96d56Sopenharmony_ci [errors.ObsoleteHeaderDefect], 11527db96d56Sopenharmony_ci '"John X. Doe" <jxd@example.com>', 11537db96d56Sopenharmony_ci 'John X. Doe', 11547db96d56Sopenharmony_ci 'jxd@example.com', 11557db96d56Sopenharmony_ci 'jxd', 11567db96d56Sopenharmony_ci 'example.com', 11577db96d56Sopenharmony_ci None), 11587db96d56Sopenharmony_ci 11597db96d56Sopenharmony_ci 'quoted_strings_in_local_part': 11607db96d56Sopenharmony_ci ('""example" example"@example.com', 11617db96d56Sopenharmony_ci [errors.InvalidHeaderDefect]*3, 11627db96d56Sopenharmony_ci '"example example"@example.com', 11637db96d56Sopenharmony_ci '', 11647db96d56Sopenharmony_ci '"example example"@example.com', 11657db96d56Sopenharmony_ci 'example example', 11667db96d56Sopenharmony_ci 'example.com', 11677db96d56Sopenharmony_ci None), 11687db96d56Sopenharmony_ci 11697db96d56Sopenharmony_ci 'escaped_quoted_strings_in_local_part': 11707db96d56Sopenharmony_ci (r'"\"example\" example"@example.com', 11717db96d56Sopenharmony_ci [], 11727db96d56Sopenharmony_ci r'"\"example\" example"@example.com', 11737db96d56Sopenharmony_ci '', 11747db96d56Sopenharmony_ci r'"\"example\" example"@example.com', 11757db96d56Sopenharmony_ci r'"example" example', 11767db96d56Sopenharmony_ci 'example.com', 11777db96d56Sopenharmony_ci None), 11787db96d56Sopenharmony_ci 11797db96d56Sopenharmony_ci 'escaped_escapes_in_local_part': 11807db96d56Sopenharmony_ci (r'"\\"example\\" example"@example.com', 11817db96d56Sopenharmony_ci [errors.InvalidHeaderDefect]*5, 11827db96d56Sopenharmony_ci r'"\\example\\\\ example"@example.com', 11837db96d56Sopenharmony_ci '', 11847db96d56Sopenharmony_ci r'"\\example\\\\ example"@example.com', 11857db96d56Sopenharmony_ci r'\example\\ example', 11867db96d56Sopenharmony_ci 'example.com', 11877db96d56Sopenharmony_ci None), 11887db96d56Sopenharmony_ci 11897db96d56Sopenharmony_ci 'spaces_in_unquoted_local_part_collapsed': 11907db96d56Sopenharmony_ci ('merwok wok @example.com', 11917db96d56Sopenharmony_ci [errors.InvalidHeaderDefect]*2, 11927db96d56Sopenharmony_ci '"merwok wok"@example.com', 11937db96d56Sopenharmony_ci '', 11947db96d56Sopenharmony_ci '"merwok wok"@example.com', 11957db96d56Sopenharmony_ci 'merwok wok', 11967db96d56Sopenharmony_ci 'example.com', 11977db96d56Sopenharmony_ci None), 11987db96d56Sopenharmony_ci 11997db96d56Sopenharmony_ci 'spaces_around_dots_in_local_part_removed': 12007db96d56Sopenharmony_ci ('merwok. wok . wok@example.com', 12017db96d56Sopenharmony_ci [errors.ObsoleteHeaderDefect], 12027db96d56Sopenharmony_ci 'merwok.wok.wok@example.com', 12037db96d56Sopenharmony_ci '', 12047db96d56Sopenharmony_ci 'merwok.wok.wok@example.com', 12057db96d56Sopenharmony_ci 'merwok.wok.wok', 12067db96d56Sopenharmony_ci 'example.com', 12077db96d56Sopenharmony_ci None), 12087db96d56Sopenharmony_ci 12097db96d56Sopenharmony_ci 'rfc2047_atom_is_decoded': 12107db96d56Sopenharmony_ci ('=?utf-8?q?=C3=89ric?= <foo@example.com>', 12117db96d56Sopenharmony_ci [], 12127db96d56Sopenharmony_ci 'Éric <foo@example.com>', 12137db96d56Sopenharmony_ci 'Éric', 12147db96d56Sopenharmony_ci 'foo@example.com', 12157db96d56Sopenharmony_ci 'foo', 12167db96d56Sopenharmony_ci 'example.com', 12177db96d56Sopenharmony_ci None), 12187db96d56Sopenharmony_ci 12197db96d56Sopenharmony_ci 'rfc2047_atom_in_phrase_is_decoded': 12207db96d56Sopenharmony_ci ('The =?utf-8?q?=C3=89ric=2C?= Himself <foo@example.com>', 12217db96d56Sopenharmony_ci [], 12227db96d56Sopenharmony_ci '"The Éric, Himself" <foo@example.com>', 12237db96d56Sopenharmony_ci 'The Éric, Himself', 12247db96d56Sopenharmony_ci 'foo@example.com', 12257db96d56Sopenharmony_ci 'foo', 12267db96d56Sopenharmony_ci 'example.com', 12277db96d56Sopenharmony_ci None), 12287db96d56Sopenharmony_ci 12297db96d56Sopenharmony_ci 'rfc2047_atom_in_quoted_string_is_decoded': 12307db96d56Sopenharmony_ci ('"=?utf-8?q?=C3=89ric?=" <foo@example.com>', 12317db96d56Sopenharmony_ci [errors.InvalidHeaderDefect, 12327db96d56Sopenharmony_ci errors.InvalidHeaderDefect], 12337db96d56Sopenharmony_ci 'Éric <foo@example.com>', 12347db96d56Sopenharmony_ci 'Éric', 12357db96d56Sopenharmony_ci 'foo@example.com', 12367db96d56Sopenharmony_ci 'foo', 12377db96d56Sopenharmony_ci 'example.com', 12387db96d56Sopenharmony_ci None), 12397db96d56Sopenharmony_ci 12407db96d56Sopenharmony_ci } 12417db96d56Sopenharmony_ci 12427db96d56Sopenharmony_ci # XXX: Need many more examples, and in particular some with names in 12437db96d56Sopenharmony_ci # trailing comments, which aren't currently handled. comments in 12447db96d56Sopenharmony_ci # general are not handled yet. 12457db96d56Sopenharmony_ci 12467db96d56Sopenharmony_ci def example_as_address(self, source, defects, decoded, display_name, 12477db96d56Sopenharmony_ci addr_spec, username, domain, comment): 12487db96d56Sopenharmony_ci h = self.make_header('sender', source) 12497db96d56Sopenharmony_ci self.assertEqual(h, decoded) 12507db96d56Sopenharmony_ci self.assertDefectsEqual(h.defects, defects) 12517db96d56Sopenharmony_ci a = h.address 12527db96d56Sopenharmony_ci self.assertEqual(str(a), decoded) 12537db96d56Sopenharmony_ci self.assertEqual(len(h.groups), 1) 12547db96d56Sopenharmony_ci self.assertEqual([a], list(h.groups[0].addresses)) 12557db96d56Sopenharmony_ci self.assertEqual([a], list(h.addresses)) 12567db96d56Sopenharmony_ci self.assertEqual(a.display_name, display_name) 12577db96d56Sopenharmony_ci self.assertEqual(a.addr_spec, addr_spec) 12587db96d56Sopenharmony_ci self.assertEqual(a.username, username) 12597db96d56Sopenharmony_ci self.assertEqual(a.domain, domain) 12607db96d56Sopenharmony_ci # XXX: we have no comment support yet. 12617db96d56Sopenharmony_ci #self.assertEqual(a.comment, comment) 12627db96d56Sopenharmony_ci 12637db96d56Sopenharmony_ci def example_as_group(self, source, defects, decoded, display_name, 12647db96d56Sopenharmony_ci addr_spec, username, domain, comment): 12657db96d56Sopenharmony_ci source = 'foo: {};'.format(source) 12667db96d56Sopenharmony_ci gdecoded = 'foo: {};'.format(decoded) if decoded else 'foo:;' 12677db96d56Sopenharmony_ci h = self.make_header('to', source) 12687db96d56Sopenharmony_ci self.assertEqual(h, gdecoded) 12697db96d56Sopenharmony_ci self.assertDefectsEqual(h.defects, defects) 12707db96d56Sopenharmony_ci self.assertEqual(h.groups[0].addresses, h.addresses) 12717db96d56Sopenharmony_ci self.assertEqual(len(h.groups), 1) 12727db96d56Sopenharmony_ci self.assertEqual(len(h.addresses), 1) 12737db96d56Sopenharmony_ci a = h.addresses[0] 12747db96d56Sopenharmony_ci self.assertEqual(str(a), decoded) 12757db96d56Sopenharmony_ci self.assertEqual(a.display_name, display_name) 12767db96d56Sopenharmony_ci self.assertEqual(a.addr_spec, addr_spec) 12777db96d56Sopenharmony_ci self.assertEqual(a.username, username) 12787db96d56Sopenharmony_ci self.assertEqual(a.domain, domain) 12797db96d56Sopenharmony_ci 12807db96d56Sopenharmony_ci def test_simple_address_list(self): 12817db96d56Sopenharmony_ci value = ('Fred <dinsdale@python.org>, foo@example.com, ' 12827db96d56Sopenharmony_ci '"Harry W. Hastings" <hasty@example.com>') 12837db96d56Sopenharmony_ci h = self.make_header('to', value) 12847db96d56Sopenharmony_ci self.assertEqual(h, value) 12857db96d56Sopenharmony_ci self.assertEqual(len(h.groups), 3) 12867db96d56Sopenharmony_ci self.assertEqual(len(h.addresses), 3) 12877db96d56Sopenharmony_ci for i in range(3): 12887db96d56Sopenharmony_ci self.assertEqual(h.groups[i].addresses[0], h.addresses[i]) 12897db96d56Sopenharmony_ci self.assertEqual(str(h.addresses[0]), 'Fred <dinsdale@python.org>') 12907db96d56Sopenharmony_ci self.assertEqual(str(h.addresses[1]), 'foo@example.com') 12917db96d56Sopenharmony_ci self.assertEqual(str(h.addresses[2]), 12927db96d56Sopenharmony_ci '"Harry W. Hastings" <hasty@example.com>') 12937db96d56Sopenharmony_ci self.assertEqual(h.addresses[2].display_name, 12947db96d56Sopenharmony_ci 'Harry W. Hastings') 12957db96d56Sopenharmony_ci 12967db96d56Sopenharmony_ci def test_complex_address_list(self): 12977db96d56Sopenharmony_ci examples = list(self.example_params.values()) 12987db96d56Sopenharmony_ci source = ('dummy list:;, another: (empty);,' + 12997db96d56Sopenharmony_ci ', '.join([x[0] for x in examples[:4]]) + ', ' + 13007db96d56Sopenharmony_ci r'"A \"list\"": ' + 13017db96d56Sopenharmony_ci ', '.join([x[0] for x in examples[4:6]]) + ';,' + 13027db96d56Sopenharmony_ci ', '.join([x[0] for x in examples[6:]]) 13037db96d56Sopenharmony_ci ) 13047db96d56Sopenharmony_ci # XXX: the fact that (empty) disappears here is a potential API design 13057db96d56Sopenharmony_ci # bug. We don't currently have a way to preserve comments. 13067db96d56Sopenharmony_ci expected = ('dummy list:;, another:;, ' + 13077db96d56Sopenharmony_ci ', '.join([x[2] for x in examples[:4]]) + ', ' + 13087db96d56Sopenharmony_ci r'"A \"list\"": ' + 13097db96d56Sopenharmony_ci ', '.join([x[2] for x in examples[4:6]]) + ';, ' + 13107db96d56Sopenharmony_ci ', '.join([x[2] for x in examples[6:]]) 13117db96d56Sopenharmony_ci ) 13127db96d56Sopenharmony_ci 13137db96d56Sopenharmony_ci h = self.make_header('to', source) 13147db96d56Sopenharmony_ci self.assertEqual(h.split(','), expected.split(',')) 13157db96d56Sopenharmony_ci self.assertEqual(h, expected) 13167db96d56Sopenharmony_ci self.assertEqual(len(h.groups), 7 + len(examples) - 6) 13177db96d56Sopenharmony_ci self.assertEqual(h.groups[0].display_name, 'dummy list') 13187db96d56Sopenharmony_ci self.assertEqual(h.groups[1].display_name, 'another') 13197db96d56Sopenharmony_ci self.assertEqual(h.groups[6].display_name, 'A "list"') 13207db96d56Sopenharmony_ci self.assertEqual(len(h.addresses), len(examples)) 13217db96d56Sopenharmony_ci for i in range(4): 13227db96d56Sopenharmony_ci self.assertIsNone(h.groups[i+2].display_name) 13237db96d56Sopenharmony_ci self.assertEqual(str(h.groups[i+2].addresses[0]), examples[i][2]) 13247db96d56Sopenharmony_ci for i in range(7, 7 + len(examples) - 6): 13257db96d56Sopenharmony_ci self.assertIsNone(h.groups[i].display_name) 13267db96d56Sopenharmony_ci self.assertEqual(str(h.groups[i].addresses[0]), examples[i-1][2]) 13277db96d56Sopenharmony_ci for i in range(len(examples)): 13287db96d56Sopenharmony_ci self.assertEqual(str(h.addresses[i]), examples[i][2]) 13297db96d56Sopenharmony_ci self.assertEqual(h.addresses[i].addr_spec, examples[i][4]) 13307db96d56Sopenharmony_ci 13317db96d56Sopenharmony_ci def test_address_read_only(self): 13327db96d56Sopenharmony_ci h = self.make_header('sender', 'abc@xyz.com') 13337db96d56Sopenharmony_ci with self.assertRaises(AttributeError): 13347db96d56Sopenharmony_ci h.address = 'foo' 13357db96d56Sopenharmony_ci 13367db96d56Sopenharmony_ci def test_addresses_read_only(self): 13377db96d56Sopenharmony_ci h = self.make_header('sender', 'abc@xyz.com') 13387db96d56Sopenharmony_ci with self.assertRaises(AttributeError): 13397db96d56Sopenharmony_ci h.addresses = 'foo' 13407db96d56Sopenharmony_ci 13417db96d56Sopenharmony_ci def test_groups_read_only(self): 13427db96d56Sopenharmony_ci h = self.make_header('sender', 'abc@xyz.com') 13437db96d56Sopenharmony_ci with self.assertRaises(AttributeError): 13447db96d56Sopenharmony_ci h.groups = 'foo' 13457db96d56Sopenharmony_ci 13467db96d56Sopenharmony_ci def test_addresses_types(self): 13477db96d56Sopenharmony_ci source = 'me <who@example.com>' 13487db96d56Sopenharmony_ci h = self.make_header('to', source) 13497db96d56Sopenharmony_ci self.assertIsInstance(h.addresses, tuple) 13507db96d56Sopenharmony_ci self.assertIsInstance(h.addresses[0], Address) 13517db96d56Sopenharmony_ci 13527db96d56Sopenharmony_ci def test_groups_types(self): 13537db96d56Sopenharmony_ci source = 'me <who@example.com>' 13547db96d56Sopenharmony_ci h = self.make_header('to', source) 13557db96d56Sopenharmony_ci self.assertIsInstance(h.groups, tuple) 13567db96d56Sopenharmony_ci self.assertIsInstance(h.groups[0], Group) 13577db96d56Sopenharmony_ci 13587db96d56Sopenharmony_ci def test_set_from_Address(self): 13597db96d56Sopenharmony_ci h = self.make_header('to', Address('me', 'foo', 'example.com')) 13607db96d56Sopenharmony_ci self.assertEqual(h, 'me <foo@example.com>') 13617db96d56Sopenharmony_ci 13627db96d56Sopenharmony_ci def test_set_from_Address_list(self): 13637db96d56Sopenharmony_ci h = self.make_header('to', [Address('me', 'foo', 'example.com'), 13647db96d56Sopenharmony_ci Address('you', 'bar', 'example.com')]) 13657db96d56Sopenharmony_ci self.assertEqual(h, 'me <foo@example.com>, you <bar@example.com>') 13667db96d56Sopenharmony_ci 13677db96d56Sopenharmony_ci def test_set_from_Address_and_Group_list(self): 13687db96d56Sopenharmony_ci h = self.make_header('to', [Address('me', 'foo', 'example.com'), 13697db96d56Sopenharmony_ci Group('bing', [Address('fiz', 'z', 'b.com'), 13707db96d56Sopenharmony_ci Address('zif', 'f', 'c.com')]), 13717db96d56Sopenharmony_ci Address('you', 'bar', 'example.com')]) 13727db96d56Sopenharmony_ci self.assertEqual(h, 'me <foo@example.com>, bing: fiz <z@b.com>, ' 13737db96d56Sopenharmony_ci 'zif <f@c.com>;, you <bar@example.com>') 13747db96d56Sopenharmony_ci self.assertEqual(h.fold(policy=policy.default.clone(max_line_length=40)), 13757db96d56Sopenharmony_ci 'to: me <foo@example.com>,\n' 13767db96d56Sopenharmony_ci ' bing: fiz <z@b.com>, zif <f@c.com>;,\n' 13777db96d56Sopenharmony_ci ' you <bar@example.com>\n') 13787db96d56Sopenharmony_ci 13797db96d56Sopenharmony_ci def test_set_from_Group_list(self): 13807db96d56Sopenharmony_ci h = self.make_header('to', [Group('bing', [Address('fiz', 'z', 'b.com'), 13817db96d56Sopenharmony_ci Address('zif', 'f', 'c.com')])]) 13827db96d56Sopenharmony_ci self.assertEqual(h, 'bing: fiz <z@b.com>, zif <f@c.com>;') 13837db96d56Sopenharmony_ci 13847db96d56Sopenharmony_ci 13857db96d56Sopenharmony_ciclass TestAddressAndGroup(TestEmailBase): 13867db96d56Sopenharmony_ci 13877db96d56Sopenharmony_ci def _test_attr_ro(self, obj, attr): 13887db96d56Sopenharmony_ci with self.assertRaises(AttributeError): 13897db96d56Sopenharmony_ci setattr(obj, attr, 'foo') 13907db96d56Sopenharmony_ci 13917db96d56Sopenharmony_ci def test_address_display_name_ro(self): 13927db96d56Sopenharmony_ci self._test_attr_ro(Address('foo', 'bar', 'baz'), 'display_name') 13937db96d56Sopenharmony_ci 13947db96d56Sopenharmony_ci def test_address_username_ro(self): 13957db96d56Sopenharmony_ci self._test_attr_ro(Address('foo', 'bar', 'baz'), 'username') 13967db96d56Sopenharmony_ci 13977db96d56Sopenharmony_ci def test_address_domain_ro(self): 13987db96d56Sopenharmony_ci self._test_attr_ro(Address('foo', 'bar', 'baz'), 'domain') 13997db96d56Sopenharmony_ci 14007db96d56Sopenharmony_ci def test_group_display_name_ro(self): 14017db96d56Sopenharmony_ci self._test_attr_ro(Group('foo'), 'display_name') 14027db96d56Sopenharmony_ci 14037db96d56Sopenharmony_ci def test_group_addresses_ro(self): 14047db96d56Sopenharmony_ci self._test_attr_ro(Group('foo'), 'addresses') 14057db96d56Sopenharmony_ci 14067db96d56Sopenharmony_ci def test_address_from_username_domain(self): 14077db96d56Sopenharmony_ci a = Address('foo', 'bar', 'baz') 14087db96d56Sopenharmony_ci self.assertEqual(a.display_name, 'foo') 14097db96d56Sopenharmony_ci self.assertEqual(a.username, 'bar') 14107db96d56Sopenharmony_ci self.assertEqual(a.domain, 'baz') 14117db96d56Sopenharmony_ci self.assertEqual(a.addr_spec, 'bar@baz') 14127db96d56Sopenharmony_ci self.assertEqual(str(a), 'foo <bar@baz>') 14137db96d56Sopenharmony_ci 14147db96d56Sopenharmony_ci def test_address_from_addr_spec(self): 14157db96d56Sopenharmony_ci a = Address('foo', addr_spec='bar@baz') 14167db96d56Sopenharmony_ci self.assertEqual(a.display_name, 'foo') 14177db96d56Sopenharmony_ci self.assertEqual(a.username, 'bar') 14187db96d56Sopenharmony_ci self.assertEqual(a.domain, 'baz') 14197db96d56Sopenharmony_ci self.assertEqual(a.addr_spec, 'bar@baz') 14207db96d56Sopenharmony_ci self.assertEqual(str(a), 'foo <bar@baz>') 14217db96d56Sopenharmony_ci 14227db96d56Sopenharmony_ci def test_address_with_no_display_name(self): 14237db96d56Sopenharmony_ci a = Address(addr_spec='bar@baz') 14247db96d56Sopenharmony_ci self.assertEqual(a.display_name, '') 14257db96d56Sopenharmony_ci self.assertEqual(a.username, 'bar') 14267db96d56Sopenharmony_ci self.assertEqual(a.domain, 'baz') 14277db96d56Sopenharmony_ci self.assertEqual(a.addr_spec, 'bar@baz') 14287db96d56Sopenharmony_ci self.assertEqual(str(a), 'bar@baz') 14297db96d56Sopenharmony_ci 14307db96d56Sopenharmony_ci def test_null_address(self): 14317db96d56Sopenharmony_ci a = Address() 14327db96d56Sopenharmony_ci self.assertEqual(a.display_name, '') 14337db96d56Sopenharmony_ci self.assertEqual(a.username, '') 14347db96d56Sopenharmony_ci self.assertEqual(a.domain, '') 14357db96d56Sopenharmony_ci self.assertEqual(a.addr_spec, '<>') 14367db96d56Sopenharmony_ci self.assertEqual(str(a), '<>') 14377db96d56Sopenharmony_ci 14387db96d56Sopenharmony_ci def test_domain_only(self): 14397db96d56Sopenharmony_ci # This isn't really a valid address. 14407db96d56Sopenharmony_ci a = Address(domain='buzz') 14417db96d56Sopenharmony_ci self.assertEqual(a.display_name, '') 14427db96d56Sopenharmony_ci self.assertEqual(a.username, '') 14437db96d56Sopenharmony_ci self.assertEqual(a.domain, 'buzz') 14447db96d56Sopenharmony_ci self.assertEqual(a.addr_spec, '@buzz') 14457db96d56Sopenharmony_ci self.assertEqual(str(a), '@buzz') 14467db96d56Sopenharmony_ci 14477db96d56Sopenharmony_ci def test_username_only(self): 14487db96d56Sopenharmony_ci # This isn't really a valid address. 14497db96d56Sopenharmony_ci a = Address(username='buzz') 14507db96d56Sopenharmony_ci self.assertEqual(a.display_name, '') 14517db96d56Sopenharmony_ci self.assertEqual(a.username, 'buzz') 14527db96d56Sopenharmony_ci self.assertEqual(a.domain, '') 14537db96d56Sopenharmony_ci self.assertEqual(a.addr_spec, 'buzz') 14547db96d56Sopenharmony_ci self.assertEqual(str(a), 'buzz') 14557db96d56Sopenharmony_ci 14567db96d56Sopenharmony_ci def test_display_name_only(self): 14577db96d56Sopenharmony_ci a = Address('buzz') 14587db96d56Sopenharmony_ci self.assertEqual(a.display_name, 'buzz') 14597db96d56Sopenharmony_ci self.assertEqual(a.username, '') 14607db96d56Sopenharmony_ci self.assertEqual(a.domain, '') 14617db96d56Sopenharmony_ci self.assertEqual(a.addr_spec, '<>') 14627db96d56Sopenharmony_ci self.assertEqual(str(a), 'buzz <>') 14637db96d56Sopenharmony_ci 14647db96d56Sopenharmony_ci def test_quoting(self): 14657db96d56Sopenharmony_ci # Ideally we'd check every special individually, but I'm not up for 14667db96d56Sopenharmony_ci # writing that many tests. 14677db96d56Sopenharmony_ci a = Address('Sara J.', 'bad name', 'example.com') 14687db96d56Sopenharmony_ci self.assertEqual(a.display_name, 'Sara J.') 14697db96d56Sopenharmony_ci self.assertEqual(a.username, 'bad name') 14707db96d56Sopenharmony_ci self.assertEqual(a.domain, 'example.com') 14717db96d56Sopenharmony_ci self.assertEqual(a.addr_spec, '"bad name"@example.com') 14727db96d56Sopenharmony_ci self.assertEqual(str(a), '"Sara J." <"bad name"@example.com>') 14737db96d56Sopenharmony_ci 14747db96d56Sopenharmony_ci def test_il8n(self): 14757db96d56Sopenharmony_ci a = Address('Éric', 'wok', 'exàmple.com') 14767db96d56Sopenharmony_ci self.assertEqual(a.display_name, 'Éric') 14777db96d56Sopenharmony_ci self.assertEqual(a.username, 'wok') 14787db96d56Sopenharmony_ci self.assertEqual(a.domain, 'exàmple.com') 14797db96d56Sopenharmony_ci self.assertEqual(a.addr_spec, 'wok@exàmple.com') 14807db96d56Sopenharmony_ci self.assertEqual(str(a), 'Éric <wok@exàmple.com>') 14817db96d56Sopenharmony_ci 14827db96d56Sopenharmony_ci # XXX: there is an API design issue that needs to be solved here. 14837db96d56Sopenharmony_ci #def test_non_ascii_username_raises(self): 14847db96d56Sopenharmony_ci # with self.assertRaises(ValueError): 14857db96d56Sopenharmony_ci # Address('foo', 'wők', 'example.com') 14867db96d56Sopenharmony_ci 14877db96d56Sopenharmony_ci def test_crlf_in_constructor_args_raises(self): 14887db96d56Sopenharmony_ci cases = ( 14897db96d56Sopenharmony_ci dict(display_name='foo\r'), 14907db96d56Sopenharmony_ci dict(display_name='foo\n'), 14917db96d56Sopenharmony_ci dict(display_name='foo\r\n'), 14927db96d56Sopenharmony_ci dict(domain='example.com\r'), 14937db96d56Sopenharmony_ci dict(domain='example.com\n'), 14947db96d56Sopenharmony_ci dict(domain='example.com\r\n'), 14957db96d56Sopenharmony_ci dict(username='wok\r'), 14967db96d56Sopenharmony_ci dict(username='wok\n'), 14977db96d56Sopenharmony_ci dict(username='wok\r\n'), 14987db96d56Sopenharmony_ci dict(addr_spec='wok@example.com\r'), 14997db96d56Sopenharmony_ci dict(addr_spec='wok@example.com\n'), 15007db96d56Sopenharmony_ci dict(addr_spec='wok@example.com\r\n') 15017db96d56Sopenharmony_ci ) 15027db96d56Sopenharmony_ci for kwargs in cases: 15037db96d56Sopenharmony_ci with self.subTest(kwargs=kwargs), self.assertRaisesRegex(ValueError, "invalid arguments"): 15047db96d56Sopenharmony_ci Address(**kwargs) 15057db96d56Sopenharmony_ci 15067db96d56Sopenharmony_ci def test_non_ascii_username_in_addr_spec_raises(self): 15077db96d56Sopenharmony_ci with self.assertRaises(ValueError): 15087db96d56Sopenharmony_ci Address('foo', addr_spec='wők@example.com') 15097db96d56Sopenharmony_ci 15107db96d56Sopenharmony_ci def test_address_addr_spec_and_username_raises(self): 15117db96d56Sopenharmony_ci with self.assertRaises(TypeError): 15127db96d56Sopenharmony_ci Address('foo', username='bing', addr_spec='bar@baz') 15137db96d56Sopenharmony_ci 15147db96d56Sopenharmony_ci def test_address_addr_spec_and_domain_raises(self): 15157db96d56Sopenharmony_ci with self.assertRaises(TypeError): 15167db96d56Sopenharmony_ci Address('foo', domain='bing', addr_spec='bar@baz') 15177db96d56Sopenharmony_ci 15187db96d56Sopenharmony_ci def test_address_addr_spec_and_username_and_domain_raises(self): 15197db96d56Sopenharmony_ci with self.assertRaises(TypeError): 15207db96d56Sopenharmony_ci Address('foo', username='bong', domain='bing', addr_spec='bar@baz') 15217db96d56Sopenharmony_ci 15227db96d56Sopenharmony_ci def test_space_in_addr_spec_username_raises(self): 15237db96d56Sopenharmony_ci with self.assertRaises(ValueError): 15247db96d56Sopenharmony_ci Address('foo', addr_spec="bad name@example.com") 15257db96d56Sopenharmony_ci 15267db96d56Sopenharmony_ci def test_bad_addr_sepc_raises(self): 15277db96d56Sopenharmony_ci with self.assertRaises(ValueError): 15287db96d56Sopenharmony_ci Address('foo', addr_spec="name@ex[]ample.com") 15297db96d56Sopenharmony_ci 15307db96d56Sopenharmony_ci def test_empty_group(self): 15317db96d56Sopenharmony_ci g = Group('foo') 15327db96d56Sopenharmony_ci self.assertEqual(g.display_name, 'foo') 15337db96d56Sopenharmony_ci self.assertEqual(g.addresses, tuple()) 15347db96d56Sopenharmony_ci self.assertEqual(str(g), 'foo:;') 15357db96d56Sopenharmony_ci 15367db96d56Sopenharmony_ci def test_empty_group_list(self): 15377db96d56Sopenharmony_ci g = Group('foo', addresses=[]) 15387db96d56Sopenharmony_ci self.assertEqual(g.display_name, 'foo') 15397db96d56Sopenharmony_ci self.assertEqual(g.addresses, tuple()) 15407db96d56Sopenharmony_ci self.assertEqual(str(g), 'foo:;') 15417db96d56Sopenharmony_ci 15427db96d56Sopenharmony_ci def test_null_group(self): 15437db96d56Sopenharmony_ci g = Group() 15447db96d56Sopenharmony_ci self.assertIsNone(g.display_name) 15457db96d56Sopenharmony_ci self.assertEqual(g.addresses, tuple()) 15467db96d56Sopenharmony_ci self.assertEqual(str(g), 'None:;') 15477db96d56Sopenharmony_ci 15487db96d56Sopenharmony_ci def test_group_with_addresses(self): 15497db96d56Sopenharmony_ci addrs = [Address('b', 'b', 'c'), Address('a', 'b','c')] 15507db96d56Sopenharmony_ci g = Group('foo', addrs) 15517db96d56Sopenharmony_ci self.assertEqual(g.display_name, 'foo') 15527db96d56Sopenharmony_ci self.assertEqual(g.addresses, tuple(addrs)) 15537db96d56Sopenharmony_ci self.assertEqual(str(g), 'foo: b <b@c>, a <b@c>;') 15547db96d56Sopenharmony_ci 15557db96d56Sopenharmony_ci def test_group_with_addresses_no_display_name(self): 15567db96d56Sopenharmony_ci addrs = [Address('b', 'b', 'c'), Address('a', 'b','c')] 15577db96d56Sopenharmony_ci g = Group(addresses=addrs) 15587db96d56Sopenharmony_ci self.assertIsNone(g.display_name) 15597db96d56Sopenharmony_ci self.assertEqual(g.addresses, tuple(addrs)) 15607db96d56Sopenharmony_ci self.assertEqual(str(g), 'None: b <b@c>, a <b@c>;') 15617db96d56Sopenharmony_ci 15627db96d56Sopenharmony_ci def test_group_with_one_address_no_display_name(self): 15637db96d56Sopenharmony_ci addrs = [Address('b', 'b', 'c')] 15647db96d56Sopenharmony_ci g = Group(addresses=addrs) 15657db96d56Sopenharmony_ci self.assertIsNone(g.display_name) 15667db96d56Sopenharmony_ci self.assertEqual(g.addresses, tuple(addrs)) 15677db96d56Sopenharmony_ci self.assertEqual(str(g), 'b <b@c>') 15687db96d56Sopenharmony_ci 15697db96d56Sopenharmony_ci def test_display_name_quoting(self): 15707db96d56Sopenharmony_ci g = Group('foo.bar') 15717db96d56Sopenharmony_ci self.assertEqual(g.display_name, 'foo.bar') 15727db96d56Sopenharmony_ci self.assertEqual(g.addresses, tuple()) 15737db96d56Sopenharmony_ci self.assertEqual(str(g), '"foo.bar":;') 15747db96d56Sopenharmony_ci 15757db96d56Sopenharmony_ci def test_display_name_blanks_not_quoted(self): 15767db96d56Sopenharmony_ci g = Group('foo bar') 15777db96d56Sopenharmony_ci self.assertEqual(g.display_name, 'foo bar') 15787db96d56Sopenharmony_ci self.assertEqual(g.addresses, tuple()) 15797db96d56Sopenharmony_ci self.assertEqual(str(g), 'foo bar:;') 15807db96d56Sopenharmony_ci 15817db96d56Sopenharmony_ci def test_set_message_header_from_address(self): 15827db96d56Sopenharmony_ci a = Address('foo', 'bar', 'example.com') 15837db96d56Sopenharmony_ci m = Message(policy=policy.default) 15847db96d56Sopenharmony_ci m['To'] = a 15857db96d56Sopenharmony_ci self.assertEqual(m['to'], 'foo <bar@example.com>') 15867db96d56Sopenharmony_ci self.assertEqual(m['to'].addresses, (a,)) 15877db96d56Sopenharmony_ci 15887db96d56Sopenharmony_ci def test_set_message_header_from_group(self): 15897db96d56Sopenharmony_ci g = Group('foo bar') 15907db96d56Sopenharmony_ci m = Message(policy=policy.default) 15917db96d56Sopenharmony_ci m['To'] = g 15927db96d56Sopenharmony_ci self.assertEqual(m['to'], 'foo bar:;') 15937db96d56Sopenharmony_ci self.assertEqual(m['to'].addresses, g.addresses) 15947db96d56Sopenharmony_ci 15957db96d56Sopenharmony_ci def test_address_comparison(self): 15967db96d56Sopenharmony_ci a = Address('foo', 'bar', 'example.com') 15977db96d56Sopenharmony_ci self.assertEqual(Address('foo', 'bar', 'example.com'), a) 15987db96d56Sopenharmony_ci self.assertNotEqual(Address('baz', 'bar', 'example.com'), a) 15997db96d56Sopenharmony_ci self.assertNotEqual(Address('foo', 'baz', 'example.com'), a) 16007db96d56Sopenharmony_ci self.assertNotEqual(Address('foo', 'bar', 'baz'), a) 16017db96d56Sopenharmony_ci self.assertFalse(a == object()) 16027db96d56Sopenharmony_ci self.assertTrue(a == ALWAYS_EQ) 16037db96d56Sopenharmony_ci 16047db96d56Sopenharmony_ci def test_group_comparison(self): 16057db96d56Sopenharmony_ci a = Address('foo', 'bar', 'example.com') 16067db96d56Sopenharmony_ci g = Group('foo bar', [a]) 16077db96d56Sopenharmony_ci self.assertEqual(Group('foo bar', (a,)), g) 16087db96d56Sopenharmony_ci self.assertNotEqual(Group('baz', [a]), g) 16097db96d56Sopenharmony_ci self.assertNotEqual(Group('foo bar', []), g) 16107db96d56Sopenharmony_ci self.assertFalse(g == object()) 16117db96d56Sopenharmony_ci self.assertTrue(g == ALWAYS_EQ) 16127db96d56Sopenharmony_ci 16137db96d56Sopenharmony_ci 16147db96d56Sopenharmony_ciclass TestFolding(TestHeaderBase): 16157db96d56Sopenharmony_ci 16167db96d56Sopenharmony_ci def test_address_display_names(self): 16177db96d56Sopenharmony_ci """Test the folding and encoding of address headers.""" 16187db96d56Sopenharmony_ci for name, result in ( 16197db96d56Sopenharmony_ci ('Foo Bar, France', '"Foo Bar, France"'), 16207db96d56Sopenharmony_ci ('Foo Bar (France)', '"Foo Bar (France)"'), 16217db96d56Sopenharmony_ci ('Foo Bar, España', 'Foo =?utf-8?q?Bar=2C_Espa=C3=B1a?='), 16227db96d56Sopenharmony_ci ('Foo Bar (España)', 'Foo Bar =?utf-8?b?KEVzcGHDsWEp?='), 16237db96d56Sopenharmony_ci ('Foo, Bar España', '=?utf-8?q?Foo=2C_Bar_Espa=C3=B1a?='), 16247db96d56Sopenharmony_ci ('Foo, Bar [España]', '=?utf-8?q?Foo=2C_Bar_=5BEspa=C3=B1a=5D?='), 16257db96d56Sopenharmony_ci ('Foo Bär, France', 'Foo =?utf-8?q?B=C3=A4r=2C?= France'), 16267db96d56Sopenharmony_ci ('Foo Bär <France>', 'Foo =?utf-8?q?B=C3=A4r_=3CFrance=3E?='), 16277db96d56Sopenharmony_ci ( 16287db96d56Sopenharmony_ci 'Lôrem ipsum dôlôr sit amet, cônsectetuer adipiscing. ' 16297db96d56Sopenharmony_ci 'Suspendisse pôtenti. Aliquam nibh. Suspendisse pôtenti.', 16307db96d56Sopenharmony_ci '=?utf-8?q?L=C3=B4rem_ipsum_d=C3=B4l=C3=B4r_sit_amet=2C_c' 16317db96d56Sopenharmony_ci '=C3=B4nsectetuer?=\n =?utf-8?q?adipiscing=2E_Suspendisse' 16327db96d56Sopenharmony_ci '_p=C3=B4tenti=2E_Aliquam_nibh=2E?=\n Suspendisse =?utf-8' 16337db96d56Sopenharmony_ci '?q?p=C3=B4tenti=2E?=', 16347db96d56Sopenharmony_ci ), 16357db96d56Sopenharmony_ci ): 16367db96d56Sopenharmony_ci h = self.make_header('To', Address(name, addr_spec='a@b.com')) 16377db96d56Sopenharmony_ci self.assertEqual(h.fold(policy=policy.default), 16387db96d56Sopenharmony_ci 'To: %s <a@b.com>\n' % result) 16397db96d56Sopenharmony_ci 16407db96d56Sopenharmony_ci def test_short_unstructured(self): 16417db96d56Sopenharmony_ci h = self.make_header('subject', 'this is a test') 16427db96d56Sopenharmony_ci self.assertEqual(h.fold(policy=policy.default), 16437db96d56Sopenharmony_ci 'subject: this is a test\n') 16447db96d56Sopenharmony_ci 16457db96d56Sopenharmony_ci def test_long_unstructured(self): 16467db96d56Sopenharmony_ci h = self.make_header('Subject', 'This is a long header ' 16477db96d56Sopenharmony_ci 'line that will need to be folded into two lines ' 16487db96d56Sopenharmony_ci 'and will demonstrate basic folding') 16497db96d56Sopenharmony_ci self.assertEqual(h.fold(policy=policy.default), 16507db96d56Sopenharmony_ci 'Subject: This is a long header line that will ' 16517db96d56Sopenharmony_ci 'need to be folded into two lines\n' 16527db96d56Sopenharmony_ci ' and will demonstrate basic folding\n') 16537db96d56Sopenharmony_ci 16547db96d56Sopenharmony_ci def test_unstructured_short_max_line_length(self): 16557db96d56Sopenharmony_ci h = self.make_header('Subject', 'this is a short header ' 16567db96d56Sopenharmony_ci 'that will be folded anyway') 16577db96d56Sopenharmony_ci self.assertEqual( 16587db96d56Sopenharmony_ci h.fold(policy=policy.default.clone(max_line_length=20)), 16597db96d56Sopenharmony_ci textwrap.dedent("""\ 16607db96d56Sopenharmony_ci Subject: this is a 16617db96d56Sopenharmony_ci short header that 16627db96d56Sopenharmony_ci will be folded 16637db96d56Sopenharmony_ci anyway 16647db96d56Sopenharmony_ci """)) 16657db96d56Sopenharmony_ci 16667db96d56Sopenharmony_ci def test_fold_unstructured_single_word(self): 16677db96d56Sopenharmony_ci h = self.make_header('Subject', 'test') 16687db96d56Sopenharmony_ci self.assertEqual(h.fold(policy=policy.default), 'Subject: test\n') 16697db96d56Sopenharmony_ci 16707db96d56Sopenharmony_ci def test_fold_unstructured_short(self): 16717db96d56Sopenharmony_ci h = self.make_header('Subject', 'test test test') 16727db96d56Sopenharmony_ci self.assertEqual(h.fold(policy=policy.default), 16737db96d56Sopenharmony_ci 'Subject: test test test\n') 16747db96d56Sopenharmony_ci 16757db96d56Sopenharmony_ci def test_fold_unstructured_with_overlong_word(self): 16767db96d56Sopenharmony_ci h = self.make_header('Subject', 'thisisaverylonglineconsistingofa' 16777db96d56Sopenharmony_ci 'singlewordthatwontfit') 16787db96d56Sopenharmony_ci self.assertEqual( 16797db96d56Sopenharmony_ci h.fold(policy=policy.default.clone(max_line_length=20)), 16807db96d56Sopenharmony_ci 'Subject: \n' 16817db96d56Sopenharmony_ci ' =?utf-8?q?thisisa?=\n' 16827db96d56Sopenharmony_ci ' =?utf-8?q?verylon?=\n' 16837db96d56Sopenharmony_ci ' =?utf-8?q?glineco?=\n' 16847db96d56Sopenharmony_ci ' =?utf-8?q?nsistin?=\n' 16857db96d56Sopenharmony_ci ' =?utf-8?q?gofasin?=\n' 16867db96d56Sopenharmony_ci ' =?utf-8?q?gleword?=\n' 16877db96d56Sopenharmony_ci ' =?utf-8?q?thatwon?=\n' 16887db96d56Sopenharmony_ci ' =?utf-8?q?tfit?=\n' 16897db96d56Sopenharmony_ci ) 16907db96d56Sopenharmony_ci 16917db96d56Sopenharmony_ci def test_fold_unstructured_with_two_overlong_words(self): 16927db96d56Sopenharmony_ci h = self.make_header('Subject', 'thisisaverylonglineconsistingofa' 16937db96d56Sopenharmony_ci 'singlewordthatwontfit plusanotherverylongwordthatwontfit') 16947db96d56Sopenharmony_ci self.assertEqual( 16957db96d56Sopenharmony_ci h.fold(policy=policy.default.clone(max_line_length=20)), 16967db96d56Sopenharmony_ci 'Subject: \n' 16977db96d56Sopenharmony_ci ' =?utf-8?q?thisisa?=\n' 16987db96d56Sopenharmony_ci ' =?utf-8?q?verylon?=\n' 16997db96d56Sopenharmony_ci ' =?utf-8?q?glineco?=\n' 17007db96d56Sopenharmony_ci ' =?utf-8?q?nsistin?=\n' 17017db96d56Sopenharmony_ci ' =?utf-8?q?gofasin?=\n' 17027db96d56Sopenharmony_ci ' =?utf-8?q?gleword?=\n' 17037db96d56Sopenharmony_ci ' =?utf-8?q?thatwon?=\n' 17047db96d56Sopenharmony_ci ' =?utf-8?q?tfit_pl?=\n' 17057db96d56Sopenharmony_ci ' =?utf-8?q?usanoth?=\n' 17067db96d56Sopenharmony_ci ' =?utf-8?q?erveryl?=\n' 17077db96d56Sopenharmony_ci ' =?utf-8?q?ongword?=\n' 17087db96d56Sopenharmony_ci ' =?utf-8?q?thatwon?=\n' 17097db96d56Sopenharmony_ci ' =?utf-8?q?tfit?=\n' 17107db96d56Sopenharmony_ci ) 17117db96d56Sopenharmony_ci 17127db96d56Sopenharmony_ci # XXX Need test for when max_line_length is less than the chrome size. 17137db96d56Sopenharmony_ci 17147db96d56Sopenharmony_ci def test_fold_unstructured_with_slightly_long_word(self): 17157db96d56Sopenharmony_ci h = self.make_header('Subject', 'thislongwordislessthanmaxlinelen') 17167db96d56Sopenharmony_ci self.assertEqual( 17177db96d56Sopenharmony_ci h.fold(policy=policy.default.clone(max_line_length=35)), 17187db96d56Sopenharmony_ci 'Subject:\n thislongwordislessthanmaxlinelen\n') 17197db96d56Sopenharmony_ci 17207db96d56Sopenharmony_ci def test_fold_unstructured_with_commas(self): 17217db96d56Sopenharmony_ci # The old wrapper would fold this at the commas. 17227db96d56Sopenharmony_ci h = self.make_header('Subject', "This header is intended to " 17237db96d56Sopenharmony_ci "demonstrate, in a fairly succinct way, that we now do " 17247db96d56Sopenharmony_ci "not give a , special treatment in unstructured headers.") 17257db96d56Sopenharmony_ci self.assertEqual( 17267db96d56Sopenharmony_ci h.fold(policy=policy.default.clone(max_line_length=60)), 17277db96d56Sopenharmony_ci textwrap.dedent("""\ 17287db96d56Sopenharmony_ci Subject: This header is intended to demonstrate, in a fairly 17297db96d56Sopenharmony_ci succinct way, that we now do not give a , special treatment 17307db96d56Sopenharmony_ci in unstructured headers. 17317db96d56Sopenharmony_ci """)) 17327db96d56Sopenharmony_ci 17337db96d56Sopenharmony_ci def test_fold_address_list(self): 17347db96d56Sopenharmony_ci h = self.make_header('To', '"Theodore H. Perfect" <yes@man.com>, ' 17357db96d56Sopenharmony_ci '"My address is very long because my name is long" <foo@bar.com>, ' 17367db96d56Sopenharmony_ci '"Only A. Friend" <no@yes.com>') 17377db96d56Sopenharmony_ci self.assertEqual(h.fold(policy=policy.default), textwrap.dedent("""\ 17387db96d56Sopenharmony_ci To: "Theodore H. Perfect" <yes@man.com>, 17397db96d56Sopenharmony_ci "My address is very long because my name is long" <foo@bar.com>, 17407db96d56Sopenharmony_ci "Only A. Friend" <no@yes.com> 17417db96d56Sopenharmony_ci """)) 17427db96d56Sopenharmony_ci 17437db96d56Sopenharmony_ci def test_fold_date_header(self): 17447db96d56Sopenharmony_ci h = self.make_header('Date', 'Sat, 2 Feb 2002 17:00:06 -0800') 17457db96d56Sopenharmony_ci self.assertEqual(h.fold(policy=policy.default), 17467db96d56Sopenharmony_ci 'Date: Sat, 02 Feb 2002 17:00:06 -0800\n') 17477db96d56Sopenharmony_ci 17487db96d56Sopenharmony_ci def test_fold_overlong_words_using_RFC2047(self): 17497db96d56Sopenharmony_ci h = self.make_header( 17507db96d56Sopenharmony_ci 'X-Report-Abuse', 17517db96d56Sopenharmony_ci '<https://www.mailitapp.com/report_abuse.php?' 17527db96d56Sopenharmony_ci 'mid=xxx-xxx-xxxxxxxxxxxxxxxxxxxxxxxx==-xxx-xx-xx>') 17537db96d56Sopenharmony_ci self.assertEqual( 17547db96d56Sopenharmony_ci h.fold(policy=policy.default), 17557db96d56Sopenharmony_ci 'X-Report-Abuse: =?utf-8?q?=3Chttps=3A//www=2Emailitapp=2E' 17567db96d56Sopenharmony_ci 'com/report=5Fabuse?=\n' 17577db96d56Sopenharmony_ci ' =?utf-8?q?=2Ephp=3Fmid=3Dxxx-xxx-xxxx' 17587db96d56Sopenharmony_ci 'xxxxxxxxxxxxxxxxxxxx=3D=3D-xxx-xx-xx?=\n' 17597db96d56Sopenharmony_ci ' =?utf-8?q?=3E?=\n') 17607db96d56Sopenharmony_ci 17617db96d56Sopenharmony_ci def test_message_id_header_is_not_folded(self): 17627db96d56Sopenharmony_ci h = self.make_header( 17637db96d56Sopenharmony_ci 'Message-ID', 17647db96d56Sopenharmony_ci '<somemessageidlongerthan@maxlinelength.com>') 17657db96d56Sopenharmony_ci self.assertEqual( 17667db96d56Sopenharmony_ci h.fold(policy=policy.default.clone(max_line_length=20)), 17677db96d56Sopenharmony_ci 'Message-ID: <somemessageidlongerthan@maxlinelength.com>\n') 17687db96d56Sopenharmony_ci 17697db96d56Sopenharmony_ci # Test message-id isn't folded when id-right is no-fold-literal. 17707db96d56Sopenharmony_ci h = self.make_header( 17717db96d56Sopenharmony_ci 'Message-ID', 17727db96d56Sopenharmony_ci '<somemessageidlongerthan@[127.0.0.0.0.0.0.0.0.1]>') 17737db96d56Sopenharmony_ci self.assertEqual( 17747db96d56Sopenharmony_ci h.fold(policy=policy.default.clone(max_line_length=20)), 17757db96d56Sopenharmony_ci 'Message-ID: <somemessageidlongerthan@[127.0.0.0.0.0.0.0.0.1]>\n') 17767db96d56Sopenharmony_ci 17777db96d56Sopenharmony_ci # Test message-id isn't folded when id-right is non-ascii characters. 17787db96d56Sopenharmony_ci h = self.make_header('Message-ID', '<ईमेल@wők.com>') 17797db96d56Sopenharmony_ci self.assertEqual( 17807db96d56Sopenharmony_ci h.fold(policy=policy.default.clone(max_line_length=30)), 17817db96d56Sopenharmony_ci 'Message-ID: <ईमेल@wők.com>\n') 17827db96d56Sopenharmony_ci 17837db96d56Sopenharmony_ci # Test message-id is folded without breaking the msg-id token into 17847db96d56Sopenharmony_ci # encoded words, *even* if they don't fit into max_line_length. 17857db96d56Sopenharmony_ci h = self.make_header('Message-ID', '<ईमेलfromMessage@wők.com>') 17867db96d56Sopenharmony_ci self.assertEqual( 17877db96d56Sopenharmony_ci h.fold(policy=policy.default.clone(max_line_length=20)), 17887db96d56Sopenharmony_ci 'Message-ID:\n <ईमेलfromMessage@wők.com>\n') 17897db96d56Sopenharmony_ci 17907db96d56Sopenharmony_ciif __name__ == '__main__': 17917db96d56Sopenharmony_ci unittest.main() 1792