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&amp;&amp;Jill"',
4797db96d56Sopenharmony_ci            'image/jpeg',
4807db96d56Sopenharmony_ci            'image',
4817db96d56Sopenharmony_ci            'jpeg',
4827db96d56Sopenharmony_ci            {'name': 'Jim&amp;&amp;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