1import unittest
2import struct
3import sys
4from test import test_support, string_tests
5
6
7class StrSubclass(str):
8    pass
9
10class StrTest(
11    string_tests.CommonTest,
12    string_tests.MixinStrUnicodeUserStringTest,
13    string_tests.MixinStrUserStringTest,
14    string_tests.MixinStrUnicodeTest,
15    ):
16
17    type2test = str
18
19    # We don't need to propagate to str
20    def fixtype(self, obj):
21        return obj
22
23    def test_basic_creation(self):
24        self.assertEqual(str(''), '')
25        self.assertEqual(str(0), '0')
26        self.assertEqual(str(0L), '0')
27        self.assertEqual(str(()), '()')
28        self.assertEqual(str([]), '[]')
29        self.assertEqual(str({}), '{}')
30        a = []
31        a.append(a)
32        self.assertEqual(str(a), '[[...]]')
33        a = {}
34        a[0] = a
35        self.assertEqual(str(a), '{0: {...}}')
36
37    def test_formatting(self):
38        string_tests.MixinStrUnicodeUserStringTest.test_formatting(self)
39        self.assertRaises(OverflowError, '%c'.__mod__, 0x1234)
40
41    @test_support.cpython_only
42    def test_formatting_huge_precision(self):
43        from _testcapi import INT_MAX
44        format_string = "%.{}f".format(INT_MAX + 1)
45        with self.assertRaises(ValueError):
46            result = format_string % 2.34
47
48    def test_formatting_huge_width(self):
49        format_string = "%{}f".format(sys.maxsize + 1)
50        with self.assertRaises(ValueError):
51            result = format_string % 2.34
52
53    def test_conversion(self):
54        # Make sure __str__() behaves properly
55        class Foo0:
56            def __unicode__(self):
57                return u"foo"
58
59        class Foo1:
60            def __str__(self):
61                return "foo"
62
63        class Foo2(object):
64            def __str__(self):
65                return "foo"
66
67        class Foo3(object):
68            def __str__(self):
69                return u"foo"
70
71        class Foo4(unicode):
72            def __str__(self):
73                return u"foo"
74
75        class Foo5(str):
76            def __str__(self):
77                return u"foo"
78
79        class Foo6(str):
80            def __str__(self):
81                return "foos"
82
83            def __unicode__(self):
84                return u"foou"
85
86        class Foo7(unicode):
87            def __str__(self):
88                return "foos"
89            def __unicode__(self):
90                return u"foou"
91
92        class Foo8(str):
93            def __new__(cls, content=""):
94                return str.__new__(cls, 2*content)
95            def __str__(self):
96                return self
97
98        class Foo9(str):
99            def __str__(self):
100                return "string"
101            def __unicode__(self):
102                return "not unicode"
103
104        self.assertTrue(str(Foo0()).startswith("<")) # this is different from __unicode__
105        self.assertEqual(str(Foo1()), "foo")
106        self.assertEqual(str(Foo2()), "foo")
107        self.assertEqual(str(Foo3()), "foo")
108        self.assertEqual(str(Foo4("bar")), "foo")
109        self.assertEqual(str(Foo5("bar")), "foo")
110        self.assertEqual(str(Foo6("bar")), "foos")
111        self.assertEqual(str(Foo7("bar")), "foos")
112        self.assertEqual(str(Foo8("foo")), "foofoo")
113        self.assertIs(type(str(Foo8("foo"))), Foo8)
114        self.assertEqual(StrSubclass(Foo8("foo")), "foofoo")
115        self.assertIs(type(StrSubclass(Foo8("foo"))), StrSubclass)
116        self.assertEqual(str(Foo9("foo")), "string")
117        self.assertEqual(unicode(Foo9("foo")), u"not unicode")
118
119    # This test only affects 32-bit platforms because expandtabs can only take
120    # an int as the max value, not a 64-bit C long.  If expandtabs is changed
121    # to take a 64-bit long, this test should apply to all platforms.
122    @unittest.skipIf(sys.maxint > (1 << 32) or struct.calcsize('P') != 4,
123                     'only applies to 32-bit platforms')
124    def test_expandtabs_overflows_gracefully(self):
125        self.assertRaises(OverflowError, 't\tt\t'.expandtabs, sys.maxint)
126
127    def test__format__(self):
128        def test(value, format, expected):
129            # test both with and without the trailing 's'
130            self.assertEqual(value.__format__(format), expected)
131            self.assertEqual(value.__format__(format + 's'), expected)
132
133        test('', '', '')
134        test('abc', '', 'abc')
135        test('abc', '.3', 'abc')
136        test('ab', '.3', 'ab')
137        test('abcdef', '.3', 'abc')
138        test('abcdef', '.0', '')
139        test('abc', '3.3', 'abc')
140        test('abc', '2.3', 'abc')
141        test('abc', '2.2', 'ab')
142        test('abc', '3.2', 'ab ')
143        test('result', 'x<0', 'result')
144        test('result', 'x<5', 'result')
145        test('result', 'x<6', 'result')
146        test('result', 'x<7', 'resultx')
147        test('result', 'x<8', 'resultxx')
148        test('result', ' <7', 'result ')
149        test('result', '<7', 'result ')
150        test('result', '>7', ' result')
151        test('result', '>8', '  result')
152        test('result', '^8', ' result ')
153        test('result', '^9', ' result  ')
154        test('result', '^10', '  result  ')
155        test('a', '10000', 'a' + ' ' * 9999)
156        test('', '10000', ' ' * 10000)
157        test('', '10000000', ' ' * 10000000)
158
159    def test_format(self):
160        self.assertEqual(''.format(), '')
161        self.assertEqual('a'.format(), 'a')
162        self.assertEqual('ab'.format(), 'ab')
163        self.assertEqual('a{{'.format(), 'a{')
164        self.assertEqual('a}}'.format(), 'a}')
165        self.assertEqual('{{b'.format(), '{b')
166        self.assertEqual('}}b'.format(), '}b')
167        self.assertEqual('a{{b'.format(), 'a{b')
168
169        # examples from the PEP:
170        import datetime
171        self.assertEqual("My name is {0}".format('Fred'), "My name is Fred")
172        self.assertEqual("My name is {0[name]}".format(dict(name='Fred')),
173                         "My name is Fred")
174        self.assertEqual("My name is {0} :-{{}}".format('Fred'),
175                         "My name is Fred :-{}")
176
177        d = datetime.date(2007, 8, 18)
178        self.assertEqual("The year is {0.year}".format(d),
179                         "The year is 2007")
180
181        # classes we'll use for testing
182        class C:
183            def __init__(self, x=100):
184                self._x = x
185            def __format__(self, spec):
186                return spec
187
188        class D:
189            def __init__(self, x):
190                self.x = x
191            def __format__(self, spec):
192                return str(self.x)
193
194        # class with __str__, but no __format__
195        class E:
196            def __init__(self, x):
197                self.x = x
198            def __str__(self):
199                return 'E(' + self.x + ')'
200
201        # class with __repr__, but no __format__ or __str__
202        class F:
203            def __init__(self, x):
204                self.x = x
205            def __repr__(self):
206                return 'F(' + self.x + ')'
207
208        # class with __format__ that forwards to string, for some format_spec's
209        class G:
210            def __init__(self, x):
211                self.x = x
212            def __str__(self):
213                return "string is " + self.x
214            def __format__(self, format_spec):
215                if format_spec == 'd':
216                    return 'G(' + self.x + ')'
217                return object.__format__(self, format_spec)
218
219        # class that returns a bad type from __format__
220        class H:
221            def __format__(self, format_spec):
222                return 1.0
223
224        class I(datetime.date):
225            def __format__(self, format_spec):
226                return self.strftime(format_spec)
227
228        class J(int):
229            def __format__(self, format_spec):
230                return int.__format__(self * 2, format_spec)
231
232
233        self.assertEqual(''.format(), '')
234        self.assertEqual('abc'.format(), 'abc')
235        self.assertEqual('{0}'.format('abc'), 'abc')
236        self.assertEqual('{0:}'.format('abc'), 'abc')
237        self.assertEqual('X{0}'.format('abc'), 'Xabc')
238        self.assertEqual('{0}X'.format('abc'), 'abcX')
239        self.assertEqual('X{0}Y'.format('abc'), 'XabcY')
240        self.assertEqual('{1}'.format(1, 'abc'), 'abc')
241        self.assertEqual('X{1}'.format(1, 'abc'), 'Xabc')
242        self.assertEqual('{1}X'.format(1, 'abc'), 'abcX')
243        self.assertEqual('X{1}Y'.format(1, 'abc'), 'XabcY')
244        self.assertEqual('{0}'.format(-15), '-15')
245        self.assertEqual('{0}{1}'.format(-15, 'abc'), '-15abc')
246        self.assertEqual('{0}X{1}'.format(-15, 'abc'), '-15Xabc')
247        self.assertEqual('{{'.format(), '{')
248        self.assertEqual('}}'.format(), '}')
249        self.assertEqual('{{}}'.format(), '{}')
250        self.assertEqual('{{x}}'.format(), '{x}')
251        self.assertEqual('{{{0}}}'.format(123), '{123}')
252        self.assertEqual('{{{{0}}}}'.format(), '{{0}}')
253        self.assertEqual('}}{{'.format(), '}{')
254        self.assertEqual('}}x{{'.format(), '}x{')
255
256        # weird field names
257        self.assertEqual("{0[foo-bar]}".format({'foo-bar':'baz'}), 'baz')
258        self.assertEqual("{0[foo bar]}".format({'foo bar':'baz'}), 'baz')
259        self.assertEqual("{0[ ]}".format({' ':3}), '3')
260
261        self.assertEqual('{foo._x}'.format(foo=C(20)), '20')
262        self.assertEqual('{1}{0}'.format(D(10), D(20)), '2010')
263        self.assertEqual('{0._x.x}'.format(C(D('abc'))), 'abc')
264        self.assertEqual('{0[0]}'.format(['abc', 'def']), 'abc')
265        self.assertEqual('{0[1]}'.format(['abc', 'def']), 'def')
266        self.assertEqual('{0[1][0]}'.format(['abc', ['def']]), 'def')
267        self.assertEqual('{0[1][0].x}'.format(['abc', [D('def')]]), 'def')
268
269        # strings
270        self.assertEqual('{0:.3s}'.format('abc'), 'abc')
271        self.assertEqual('{0:.3s}'.format('ab'), 'ab')
272        self.assertEqual('{0:.3s}'.format('abcdef'), 'abc')
273        self.assertEqual('{0:.0s}'.format('abcdef'), '')
274        self.assertEqual('{0:3.3s}'.format('abc'), 'abc')
275        self.assertEqual('{0:2.3s}'.format('abc'), 'abc')
276        self.assertEqual('{0:2.2s}'.format('abc'), 'ab')
277        self.assertEqual('{0:3.2s}'.format('abc'), 'ab ')
278        self.assertEqual('{0:x<0s}'.format('result'), 'result')
279        self.assertEqual('{0:x<5s}'.format('result'), 'result')
280        self.assertEqual('{0:x<6s}'.format('result'), 'result')
281        self.assertEqual('{0:x<7s}'.format('result'), 'resultx')
282        self.assertEqual('{0:x<8s}'.format('result'), 'resultxx')
283        self.assertEqual('{0: <7s}'.format('result'), 'result ')
284        self.assertEqual('{0:<7s}'.format('result'), 'result ')
285        self.assertEqual('{0:>7s}'.format('result'), ' result')
286        self.assertEqual('{0:>8s}'.format('result'), '  result')
287        self.assertEqual('{0:^8s}'.format('result'), ' result ')
288        self.assertEqual('{0:^9s}'.format('result'), ' result  ')
289        self.assertEqual('{0:^10s}'.format('result'), '  result  ')
290        self.assertEqual('{0:10000}'.format('a'), 'a' + ' ' * 9999)
291        self.assertEqual('{0:10000}'.format(''), ' ' * 10000)
292        self.assertEqual('{0:10000000}'.format(''), ' ' * 10000000)
293
294        # format specifiers for user defined type
295        self.assertEqual('{0:abc}'.format(C()), 'abc')
296
297        # !r and !s coercions
298        self.assertEqual('{0!s}'.format('Hello'), 'Hello')
299        self.assertEqual('{0!s:}'.format('Hello'), 'Hello')
300        self.assertEqual('{0!s:15}'.format('Hello'), 'Hello          ')
301        self.assertEqual('{0!s:15s}'.format('Hello'), 'Hello          ')
302        self.assertEqual('{0!r}'.format('Hello'), "'Hello'")
303        self.assertEqual('{0!r:}'.format('Hello'), "'Hello'")
304        self.assertEqual('{0!r}'.format(F('Hello')), 'F(Hello)')
305
306        # test fallback to object.__format__
307        self.assertEqual('{0}'.format({}), '{}')
308        self.assertEqual('{0}'.format([]), '[]')
309        self.assertEqual('{0}'.format([1]), '[1]')
310        self.assertEqual('{0}'.format(E('data')), 'E(data)')
311        self.assertEqual('{0:d}'.format(G('data')), 'G(data)')
312        self.assertEqual('{0!s}'.format(G('data')), 'string is data')
313
314        msg = 'object.__format__ with a non-empty format string is deprecated'
315        with test_support.check_warnings((msg, PendingDeprecationWarning)):
316            self.assertEqual('{0:^10}'.format(E('data')), ' E(data)  ')
317            self.assertEqual('{0:^10s}'.format(E('data')), ' E(data)  ')
318            self.assertEqual('{0:>15s}'.format(G('data')), ' string is data')
319
320        self.assertEqual("{0:date: %Y-%m-%d}".format(I(year=2007,
321                                                       month=8,
322                                                       day=27)),
323                         "date: 2007-08-27")
324
325        # test deriving from a builtin type and overriding __format__
326        self.assertEqual("{0}".format(J(10)), "20")
327
328
329        # string format specifiers
330        self.assertEqual('{0:}'.format('a'), 'a')
331
332        # computed format specifiers
333        self.assertEqual("{0:.{1}}".format('hello world', 5), 'hello')
334        self.assertEqual("{0:.{1}s}".format('hello world', 5), 'hello')
335        self.assertEqual("{0:.{precision}s}".format('hello world', precision=5), 'hello')
336        self.assertEqual("{0:{width}.{precision}s}".format('hello world', width=10, precision=5), 'hello     ')
337        self.assertEqual("{0:{width}.{precision}s}".format('hello world', width='10', precision='5'), 'hello     ')
338
339        # test various errors
340        self.assertRaises(ValueError, '{'.format)
341        self.assertRaises(ValueError, '}'.format)
342        self.assertRaises(ValueError, 'a{'.format)
343        self.assertRaises(ValueError, 'a}'.format)
344        self.assertRaises(ValueError, '{a'.format)
345        self.assertRaises(ValueError, '}a'.format)
346        self.assertRaises(IndexError, '{0}'.format)
347        self.assertRaises(IndexError, '{1}'.format, 'abc')
348        self.assertRaises(KeyError,   '{x}'.format)
349        self.assertRaises(ValueError, "}{".format)
350        self.assertRaises(ValueError, "{".format)
351        self.assertRaises(ValueError, "}".format)
352        self.assertRaises(ValueError, "abc{0:{}".format)
353        self.assertRaises(ValueError, "{0".format)
354        self.assertRaises(IndexError, "{0.}".format)
355        self.assertRaises(ValueError, "{0.}".format, 0)
356        self.assertRaises(IndexError, "{0[}".format)
357        self.assertRaises(ValueError, "{0[}".format, [])
358        self.assertRaises(KeyError,   "{0]}".format)
359        self.assertRaises(ValueError, "{0.[]}".format, 0)
360        self.assertRaises(ValueError, "{0..foo}".format, 0)
361        self.assertRaises(ValueError, "{0[0}".format, 0)
362        self.assertRaises(ValueError, "{0[0:foo}".format, 0)
363        self.assertRaises(KeyError,   "{c]}".format)
364        self.assertRaises(ValueError, "{{ {{{0}}".format, 0)
365        self.assertRaises(ValueError, "{0}}".format, 0)
366        self.assertRaises(KeyError,   "{foo}".format, bar=3)
367        self.assertRaises(ValueError, "{0!x}".format, 3)
368        self.assertRaises(ValueError, "{0!}".format, 0)
369        self.assertRaises(ValueError, "{0!rs}".format, 0)
370        self.assertRaises(ValueError, "{!}".format)
371        self.assertRaises(IndexError, "{:}".format)
372        self.assertRaises(IndexError, "{:s}".format)
373        self.assertRaises(IndexError, "{}".format)
374
375        # issue 6089
376        self.assertRaises(ValueError, "{0[0]x}".format, [None])
377        self.assertRaises(ValueError, "{0[0](10)}".format, [None])
378
379        # can't have a replacement on the field name portion
380        self.assertRaises(TypeError, '{0[{1}]}'.format, 'abcdefg', 4)
381
382        # exceed maximum recursion depth
383        self.assertRaises(ValueError, "{0:{1:{2}}}".format, 'abc', 's', '')
384        self.assertRaises(ValueError, "{0:{1:{2:{3:{4:{5:{6}}}}}}}".format,
385                          0, 1, 2, 3, 4, 5, 6, 7)
386
387        # string format spec errors
388        self.assertRaises(ValueError, "{0:-s}".format, '')
389        self.assertRaises(ValueError, format, "", "-")
390        self.assertRaises(ValueError, "{0:=s}".format, '')
391
392    def test_format_huge_precision(self):
393        format_string = ".{}f".format(sys.maxsize + 1)
394        with self.assertRaises(ValueError):
395            result = format(2.34, format_string)
396
397    def test_format_huge_width(self):
398        format_string = "{}f".format(sys.maxsize + 1)
399        with self.assertRaises(ValueError):
400            result = format(2.34, format_string)
401
402    def test_format_huge_item_number(self):
403        format_string = "{{{}:.6f}}".format(sys.maxsize + 1)
404        with self.assertRaises(ValueError):
405            result = format_string.format(2.34)
406
407    def test_format_auto_numbering(self):
408        class C:
409            def __init__(self, x=100):
410                self._x = x
411            def __format__(self, spec):
412                return spec
413
414        self.assertEqual('{}'.format(10), '10')
415        self.assertEqual('{:5}'.format('s'), 's    ')
416        self.assertEqual('{!r}'.format('s'), "'s'")
417        self.assertEqual('{._x}'.format(C(10)), '10')
418        self.assertEqual('{[1]}'.format([1, 2]), '2')
419        self.assertEqual('{[a]}'.format({'a':4, 'b':2}), '4')
420        self.assertEqual('a{}b{}c'.format(0, 1), 'a0b1c')
421
422        self.assertEqual('a{:{}}b'.format('x', '^10'), 'a    x     b')
423        self.assertEqual('a{:{}x}b'.format(20, '#'), 'a0x14b')
424
425        # can't mix and match numbering and auto-numbering
426        self.assertRaises(ValueError, '{}{1}'.format, 1, 2)
427        self.assertRaises(ValueError, '{1}{}'.format, 1, 2)
428        self.assertRaises(ValueError, '{:{1}}'.format, 1, 2)
429        self.assertRaises(ValueError, '{0:{}}'.format, 1, 2)
430
431        # can mix and match auto-numbering and named
432        self.assertEqual('{f}{}'.format(4, f='test'), 'test4')
433        self.assertEqual('{}{f}'.format(4, f='test'), '4test')
434        self.assertEqual('{:{f}}{g}{}'.format(1, 3, g='g', f=2), ' 1g3')
435        self.assertEqual('{f:{}}{}{g}'.format(2, 4, f=1, g='g'), ' 14g')
436
437    def test_format_c_overflow(self):
438        # issue #7267
439        self.assertRaises(OverflowError, '{0:c}'.format, -1)
440        self.assertRaises(OverflowError, '{0:c}'.format, 256)
441
442    def test_buffer_is_readonly(self):
443        self.assertRaises(TypeError, sys.stdin.readinto, b"")
444
445    def test_encode_and_decode_kwargs(self):
446        self.assertEqual('abcde'.encode('ascii', 'replace'),
447                         'abcde'.encode('ascii', errors='replace'))
448        self.assertEqual('abcde'.encode('ascii', 'ignore'),
449                         'abcde'.encode(encoding='ascii', errors='ignore'))
450        self.assertEqual('Andr\202 x'.decode('ascii', 'ignore'),
451                         'Andr\202 x'.decode('ascii', errors='ignore'))
452        self.assertEqual('Andr\202 x'.decode('ascii', 'replace'),
453                         'Andr\202 x'.decode(encoding='ascii', errors='replace'))
454
455    def test_startswith_endswith_errors(self):
456        with self.assertRaises(UnicodeDecodeError):
457            '\xff'.startswith(u'x')
458        with self.assertRaises(UnicodeDecodeError):
459            '\xff'.endswith(u'x')
460        for meth in ('foo'.startswith, 'foo'.endswith):
461            with self.assertRaises(TypeError) as cm:
462                meth(['f'])
463            exc = str(cm.exception)
464            self.assertIn('unicode', exc)
465            self.assertIn('str', exc)
466            self.assertIn('tuple', exc)
467
468    def test_issue28598_strsubclass_rhs(self):
469        # A subclass of str with an __rmod__ method should be able to hook
470        # into the % operator
471        class SubclassedStr(str):
472            def __rmod__(self, other):
473                return 'Success, self.__rmod__({!r}) was called'.format(other)
474        self.assertEqual('lhs %% %r' % SubclassedStr('rhs'),
475                         "Success, self.__rmod__('lhs %% %r') was called")
476
477
478class CAPITest(unittest.TestCase):
479
480    # Test PyString_FromFormat()
481    def test_from_format(self):
482        ctypes = test_support.import_module('ctypes')
483        _testcapi = test_support.import_module('_testcapi')
484        from ctypes import pythonapi, py_object
485        from ctypes import (
486            c_int, c_uint,
487            c_long, c_ulong,
488            c_size_t, c_ssize_t,
489            c_char_p)
490
491        PyString_FromFormat = pythonapi.PyString_FromFormat
492        PyString_FromFormat.restype = py_object
493
494        # basic tests
495        self.assertEqual(PyString_FromFormat(b'format'),
496                         b'format')
497        self.assertEqual(PyString_FromFormat(b'Hello %s !', b'world'),
498                         b'Hello world !')
499
500        # test formatters
501        self.assertEqual(PyString_FromFormat(b'c=%c', c_int(0)),
502                         b'c=\0')
503        self.assertEqual(PyString_FromFormat(b'c=%c', c_int(ord('@'))),
504                         b'c=@')
505        self.assertEqual(PyString_FromFormat(b'c=%c', c_int(255)),
506                         b'c=\xff')
507        self.assertEqual(PyString_FromFormat(b'd=%d ld=%ld zd=%zd',
508                                            c_int(1), c_long(2),
509                                            c_size_t(3)),
510                         b'd=1 ld=2 zd=3')
511        self.assertEqual(PyString_FromFormat(b'd=%d ld=%ld zd=%zd',
512                                            c_int(-1), c_long(-2),
513                                            c_size_t(-3)),
514                         b'd=-1 ld=-2 zd=-3')
515        self.assertEqual(PyString_FromFormat(b'u=%u lu=%lu zu=%zu',
516                                            c_uint(123), c_ulong(456),
517                                            c_size_t(789)),
518                         b'u=123 lu=456 zu=789')
519        self.assertEqual(PyString_FromFormat(b'i=%i', c_int(123)),
520                         b'i=123')
521        self.assertEqual(PyString_FromFormat(b'i=%i', c_int(-123)),
522                         b'i=-123')
523        self.assertEqual(PyString_FromFormat(b'x=%x', c_int(0xabc)),
524                         b'x=abc')
525
526        self.assertEqual(PyString_FromFormat(b's=%s', c_char_p(b'cstr')),
527                         b's=cstr')
528
529        # test minimum and maximum integer values
530        size_max = c_size_t(-1).value
531        for formatstr, ctypes_type, value, py_formatter in (
532            (b'%d', c_int, _testcapi.INT_MIN, str),
533            (b'%d', c_int, _testcapi.INT_MAX, str),
534            (b'%ld', c_long, _testcapi.LONG_MIN, str),
535            (b'%ld', c_long, _testcapi.LONG_MAX, str),
536            (b'%lu', c_ulong, _testcapi.ULONG_MAX, str),
537            (b'%zd', c_ssize_t, _testcapi.PY_SSIZE_T_MIN, str),
538            (b'%zd', c_ssize_t, _testcapi.PY_SSIZE_T_MAX, str),
539            (b'%zu', c_size_t, size_max, str),
540        ):
541            self.assertEqual(PyString_FromFormat(formatstr, ctypes_type(value)),
542                             py_formatter(value).encode('ascii')),
543
544        # width and precision (width is currently ignored)
545        self.assertEqual(PyString_FromFormat(b'%5s', b'a'),
546                         b'a')
547        self.assertEqual(PyString_FromFormat(b'%.3s', b'abcdef'),
548                         b'abc')
549
550        # '%%' formatter
551        self.assertEqual(PyString_FromFormat(b'%%'),
552                         b'%')
553        self.assertEqual(PyString_FromFormat(b'[%%]'),
554                         b'[%]')
555        self.assertEqual(PyString_FromFormat(b'%%%c', c_int(ord('_'))),
556                         b'%_')
557        self.assertEqual(PyString_FromFormat(b'%%s'),
558                         b'%s')
559
560        # Invalid formats and partial formatting
561        self.assertEqual(PyString_FromFormat(b'%'), b'%')
562        self.assertEqual(PyString_FromFormat(b'x=%i y=%', c_int(2), c_int(3)),
563                         b'x=2 y=%')
564
565        self.assertEqual(PyString_FromFormat(b'%c', c_int(-1)), b'\xff')
566        self.assertEqual(PyString_FromFormat(b'%c', c_int(256)), b'\0')
567
568        # Issue #33817: empty strings
569        self.assertEqual(PyString_FromFormat(b''),
570                         b'')
571        self.assertEqual(PyString_FromFormat(b'%s', b''),
572                         b'')
573
574
575def test_main():
576    test_support.run_unittest(StrTest, CAPITest)
577
578if __name__ == "__main__":
579    test_main()
580