@@ -1661,7 +1661,10 @@ def __str__(self):
1661
1661
# Test PyUnicode_FromFormat()
1662
1662
def test_from_format (self ):
1663
1663
support .import_module ('ctypes' )
1664
- from ctypes import pythonapi , py_object , c_int
1664
+ from ctypes import (
1665
+ pythonapi , py_object , sizeof ,
1666
+ c_int , c_long , c_longlong , c_ssize_t ,
1667
+ c_uint , c_ulong , c_ulonglong , c_size_t , c_void_p )
1665
1668
if sys .maxunicode == 65535 :
1666
1669
name = "PyUnicodeUCS2_FromFormat"
1667
1670
else :
@@ -1675,9 +1678,13 @@ def PyUnicode_FromFormat(format, *args):
1675
1678
for arg in args )
1676
1679
return _PyUnicode_FromFormat (format , * cargs )
1677
1680
1681
+ def check_format (expected , format , * args ):
1682
+ text = PyUnicode_FromFormat (format , * args )
1683
+ self .assertEqual (expected , text )
1684
+
1678
1685
# ascii format, non-ascii argument
1679
- text = PyUnicode_FromFormat ( b 'ascii\x7f =%U' , ' unicode\xe9 ')
1680
- self . assertEqual ( text , 'ascii\x7f =unicode\xe9 ' )
1686
+ check_format ( 'ascii\x7f =unicode\xe9 ' ,
1687
+ b 'ascii\x7f =%U' , ' unicode\xe9 ' )
1681
1688
1682
1689
# non-ascii format, ascii argument: ensure that PyUnicode_FromFormatV()
1683
1690
# raises an error
@@ -1686,25 +1693,131 @@ def PyUnicode_FromFormat(format, *args):
1686
1693
'string, got a non-ASCII byte: 0xe9$' ,
1687
1694
PyUnicode_FromFormat , b'unicode\xe9 =%s' , 'ascii' )
1688
1695
1689
- self .assertEqual (PyUnicode_FromFormat (b'%c' , c_int (0xabcd )), '\uabcd ' )
1690
- self .assertEqual (PyUnicode_FromFormat (b'%c' , c_int (0x10ffff )), '\U0010ffff ' )
1691
-
1692
- # other tests
1693
- text = PyUnicode_FromFormat (b'%%A:%A' , 'abc\xe9 \uabcd \U0010ffff ' )
1694
- self .assertEqual (text , r"%A:'abc\xe9\uabcd\U0010ffff'" )
1695
-
1696
- text = PyUnicode_FromFormat (b'repr=%V' , 'abc' , b'xyz' )
1697
- self .assertEqual (text , 'repr=abc' )
1696
+ # test "%c"
1697
+ check_format ('\uabcd ' ,
1698
+ b'%c' , c_int (0xabcd ))
1699
+ check_format ('\U0010ffff ' ,
1700
+ b'%c' , c_int (0x10ffff ))
1701
+ with self .assertRaises (OverflowError ):
1702
+ PyUnicode_FromFormat (b'%c' , c_int (0x110000 ))
1703
+ # Issue #18183
1704
+ check_format ('\U00010000 \U00100000 ' ,
1705
+ b'%c%c' , c_int (0x10000 ), c_int (0x100000 ))
1706
+
1707
+ # test "%"
1708
+ check_format ('%' ,
1709
+ b'%' )
1710
+ check_format ('%' ,
1711
+ b'%%' )
1712
+ check_format ('%s' ,
1713
+ b'%%s' )
1714
+ check_format ('[%]' ,
1715
+ b'[%%]' )
1716
+ check_format ('%abc' ,
1717
+ b'%%%s' , b'abc' )
1718
+
1719
+ # test %S
1720
+ check_format ("repr=\u20ac ABC" ,
1721
+ b'repr=%S' , '\u20ac ABC' )
1722
+
1723
+ # test %R
1724
+ check_format ("repr='\u20ac ABC'" ,
1725
+ b'repr=%R' , '\u20ac ABC' )
1726
+
1727
+ # test integer formats (%i, %d, %u)
1728
+ check_format ('010' ,
1729
+ b'%03i' , c_int (10 ))
1730
+ check_format ('0010' ,
1731
+ b'%0.4i' , c_int (10 ))
1732
+ check_format ('-123' ,
1733
+ b'%i' , c_int (- 123 ))
1734
+
1735
+ check_format ('-123' ,
1736
+ b'%d' , c_int (- 123 ))
1737
+ check_format ('-123' ,
1738
+ b'%ld' , c_long (- 123 ))
1739
+ check_format ('-123' ,
1740
+ b'%lld' , c_longlong (- 123 ))
1741
+ check_format ('-123' ,
1742
+ b'%zd' , c_ssize_t (- 123 ))
1743
+
1744
+ check_format ('123' ,
1745
+ b'%u' , c_uint (123 ))
1746
+ check_format ('123' ,
1747
+ b'%lu' , c_ulong (123 ))
1748
+ check_format ('123' ,
1749
+ b'%llu' , c_ulonglong (123 ))
1750
+ check_format ('123' ,
1751
+ b'%zu' , c_size_t (123 ))
1752
+
1753
+ # test long output
1754
+ min_longlong = - (2 ** (8 * sizeof (c_longlong ) - 1 ))
1755
+ max_longlong = - min_longlong - 1
1756
+ check_format (str (min_longlong ),
1757
+ b'%lld' , c_longlong (min_longlong ))
1758
+ check_format (str (max_longlong ),
1759
+ b'%lld' , c_longlong (max_longlong ))
1760
+ max_ulonglong = 2 ** (8 * sizeof (c_ulonglong )) - 1
1761
+ check_format (str (max_ulonglong ),
1762
+ b'%llu' , c_ulonglong (max_ulonglong ))
1763
+ PyUnicode_FromFormat (b'%p' , c_void_p (- 1 ))
1764
+
1765
+ # test padding (width and/or precision)
1766
+ check_format ('123' .rjust (10 , '0' ),
1767
+ b'%010i' , c_int (123 ))
1768
+ check_format ('123' .rjust (100 ),
1769
+ b'%100i' , c_int (123 ))
1770
+ check_format ('123' .rjust (100 , '0' ),
1771
+ b'%.100i' , c_int (123 ))
1772
+ check_format ('123' .rjust (80 , '0' ).rjust (100 ),
1773
+ b'%100.80i' , c_int (123 ))
1774
+
1775
+ check_format ('123' .rjust (10 , '0' ),
1776
+ b'%010u' , c_uint (123 ))
1777
+ check_format ('123' .rjust (100 ),
1778
+ b'%100u' , c_uint (123 ))
1779
+ check_format ('123' .rjust (100 , '0' ),
1780
+ b'%.100u' , c_uint (123 ))
1781
+ check_format ('123' .rjust (80 , '0' ).rjust (100 ),
1782
+ b'%100.80u' , c_uint (123 ))
1783
+
1784
+ check_format ('123' .rjust (10 , '0' ),
1785
+ b'%010x' , c_int (0x123 ))
1786
+ check_format ('123' .rjust (100 ),
1787
+ b'%100x' , c_int (0x123 ))
1788
+ check_format ('123' .rjust (100 , '0' ),
1789
+ b'%.100x' , c_int (0x123 ))
1790
+ check_format ('123' .rjust (80 , '0' ).rjust (100 ),
1791
+ b'%100.80x' , c_int (0x123 ))
1792
+
1793
+ # test %A
1794
+ check_format (r"%A:'abc\xe9\uabcd\U0010ffff'" ,
1795
+ b'%%A:%A' , 'abc\xe9 \uabcd \U0010ffff ' )
1796
+
1797
+ # test %V
1798
+ check_format ('repr=abc' ,
1799
+ b'repr=%V' , 'abc' , b'xyz' )
1698
1800
1699
1801
# Test string decode from parameter of %s using utf-8.
1700
1802
# b'\xe4\xba\xba\xe6\xb0\x91' is utf-8 encoded byte sequence of
1701
1803
# '\u4eba\u6c11'
1702
- text = PyUnicode_FromFormat ( b 'repr=%V' , None , b' \xe4 \xba \xba \xe6 \xb0 \x91 ' )
1703
- self . assertEqual ( text , 'repr=\u4eba \u6c11 ' )
1804
+ check_format ( 'repr=\u4eba \u6c11 ' ,
1805
+ b 'repr=%V' , None , b' \xe4 \xba \xba \xe6 \xb0 \x91 ' )
1704
1806
1705
1807
#Test replace error handler.
1706
- text = PyUnicode_FromFormat (b'repr=%V' , None , b'abc\xff ' )
1707
- self .assertEqual (text , 'repr=abc\ufffd ' )
1808
+ check_format ('repr=abc\ufffd ' ,
1809
+ b'repr=%V' , None , b'abc\xff ' )
1810
+
1811
+ # not supported: copy the raw format string. these tests are just here
1812
+ # to check for crashs and should not be considered as specifications
1813
+ check_format ('%s' ,
1814
+ b'%1%s' , b'abc' )
1815
+ check_format ('%1abc' ,
1816
+ b'%1abc' )
1817
+ check_format ('%+i' ,
1818
+ b'%+i' , c_int (10 ))
1819
+ check_format ('%s' ,
1820
+ b'%.%s' , b'abc' )
1708
1821
1709
1822
# Test PyUnicode_AsWideChar()
1710
1823
def test_aswidechar (self ):
0 commit comments