• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import sys
2import time
3
4import unittest
5from unittest import mock
6from test import support
7from test.test_grammar import (VALID_UNDERSCORE_LITERALS,
8                               INVALID_UNDERSCORE_LITERALS)
9
10try:
11    import _pylong
12except ImportError:
13    _pylong = None
14
15L = [
16        ('0', 0),
17        ('1', 1),
18        ('9', 9),
19        ('10', 10),
20        ('99', 99),
21        ('100', 100),
22        ('314', 314),
23        (' 314', 314),
24        ('314 ', 314),
25        ('  \t\t  314  \t\t  ', 314),
26        (repr(sys.maxsize), sys.maxsize),
27        ('  1x', ValueError),
28        ('  1  ', 1),
29        ('  1\02  ', ValueError),
30        ('', ValueError),
31        (' ', ValueError),
32        ('  \t\t  ', ValueError),
33        ("\u0200", ValueError)
34]
35
36class IntSubclass(int):
37    pass
38
39class IntTestCases(unittest.TestCase):
40
41    def test_basic(self):
42        self.assertEqual(int(314), 314)
43        self.assertEqual(int(3.14), 3)
44        # Check that conversion from float truncates towards zero
45        self.assertEqual(int(-3.14), -3)
46        self.assertEqual(int(3.9), 3)
47        self.assertEqual(int(-3.9), -3)
48        self.assertEqual(int(3.5), 3)
49        self.assertEqual(int(-3.5), -3)
50        self.assertEqual(int("-3"), -3)
51        self.assertEqual(int(" -3 "), -3)
52        self.assertEqual(int("\N{EM SPACE}-3\N{EN SPACE}"), -3)
53        # Different base:
54        self.assertEqual(int("10",16), 16)
55        # Test conversion from strings and various anomalies
56        for s, v in L:
57            for sign in "", "+", "-":
58                for prefix in "", " ", "\t", "  \t\t  ":
59                    ss = prefix + sign + s
60                    vv = v
61                    if sign == "-" and v is not ValueError:
62                        vv = -v
63                    try:
64                        self.assertEqual(int(ss), vv)
65                    except ValueError:
66                        pass
67
68        s = repr(-1-sys.maxsize)
69        x = int(s)
70        self.assertEqual(x+1, -sys.maxsize)
71        self.assertIsInstance(x, int)
72        # should return int
73        self.assertEqual(int(s[1:]), sys.maxsize+1)
74
75        # should return int
76        x = int(1e100)
77        self.assertIsInstance(x, int)
78        x = int(-1e100)
79        self.assertIsInstance(x, int)
80
81
82        # SF bug 434186:  0x80000000/2 != 0x80000000>>1.
83        # Worked by accident in Windows release build, but failed in debug build.
84        # Failed in all Linux builds.
85        x = -1-sys.maxsize
86        self.assertEqual(x >> 1, x//2)
87
88        x = int('1' * 600)
89        self.assertIsInstance(x, int)
90
91
92        self.assertRaises(TypeError, int, 1, 12)
93        self.assertRaises(TypeError, int, "10", 2, 1)
94
95        self.assertEqual(int('0o123', 0), 83)
96        self.assertEqual(int('0x123', 16), 291)
97
98        # Bug 1679: "0x" is not a valid hex literal
99        self.assertRaises(ValueError, int, "0x", 16)
100        self.assertRaises(ValueError, int, "0x", 0)
101
102        self.assertRaises(ValueError, int, "0o", 8)
103        self.assertRaises(ValueError, int, "0o", 0)
104
105        self.assertRaises(ValueError, int, "0b", 2)
106        self.assertRaises(ValueError, int, "0b", 0)
107
108        # SF bug 1334662: int(string, base) wrong answers
109        # Various representations of 2**32 evaluated to 0
110        # rather than 2**32 in previous versions
111
112        self.assertEqual(int('100000000000000000000000000000000', 2), 4294967296)
113        self.assertEqual(int('102002022201221111211', 3), 4294967296)
114        self.assertEqual(int('10000000000000000', 4), 4294967296)
115        self.assertEqual(int('32244002423141', 5), 4294967296)
116        self.assertEqual(int('1550104015504', 6), 4294967296)
117        self.assertEqual(int('211301422354', 7), 4294967296)
118        self.assertEqual(int('40000000000', 8), 4294967296)
119        self.assertEqual(int('12068657454', 9), 4294967296)
120        self.assertEqual(int('4294967296', 10), 4294967296)
121        self.assertEqual(int('1904440554', 11), 4294967296)
122        self.assertEqual(int('9ba461594', 12), 4294967296)
123        self.assertEqual(int('535a79889', 13), 4294967296)
124        self.assertEqual(int('2ca5b7464', 14), 4294967296)
125        self.assertEqual(int('1a20dcd81', 15), 4294967296)
126        self.assertEqual(int('100000000', 16), 4294967296)
127        self.assertEqual(int('a7ffda91', 17), 4294967296)
128        self.assertEqual(int('704he7g4', 18), 4294967296)
129        self.assertEqual(int('4f5aff66', 19), 4294967296)
130        self.assertEqual(int('3723ai4g', 20), 4294967296)
131        self.assertEqual(int('281d55i4', 21), 4294967296)
132        self.assertEqual(int('1fj8b184', 22), 4294967296)
133        self.assertEqual(int('1606k7ic', 23), 4294967296)
134        self.assertEqual(int('mb994ag', 24), 4294967296)
135        self.assertEqual(int('hek2mgl', 25), 4294967296)
136        self.assertEqual(int('dnchbnm', 26), 4294967296)
137        self.assertEqual(int('b28jpdm', 27), 4294967296)
138        self.assertEqual(int('8pfgih4', 28), 4294967296)
139        self.assertEqual(int('76beigg', 29), 4294967296)
140        self.assertEqual(int('5qmcpqg', 30), 4294967296)
141        self.assertEqual(int('4q0jto4', 31), 4294967296)
142        self.assertEqual(int('4000000', 32), 4294967296)
143        self.assertEqual(int('3aokq94', 33), 4294967296)
144        self.assertEqual(int('2qhxjli', 34), 4294967296)
145        self.assertEqual(int('2br45qb', 35), 4294967296)
146        self.assertEqual(int('1z141z4', 36), 4294967296)
147
148        # tests with base 0
149        # this fails on 3.0, but in 2.x the old octal syntax is allowed
150        self.assertEqual(int(' 0o123  ', 0), 83)
151        self.assertEqual(int(' 0o123  ', 0), 83)
152        self.assertEqual(int('000', 0), 0)
153        self.assertEqual(int('0o123', 0), 83)
154        self.assertEqual(int('0x123', 0), 291)
155        self.assertEqual(int('0b100', 0), 4)
156        self.assertEqual(int(' 0O123   ', 0), 83)
157        self.assertEqual(int(' 0X123  ', 0), 291)
158        self.assertEqual(int(' 0B100 ', 0), 4)
159        with self.assertRaises(ValueError):
160            int('010', 0)
161
162        # without base still base 10
163        self.assertEqual(int('0123'), 123)
164        self.assertEqual(int('0123', 10), 123)
165
166        # tests with prefix and base != 0
167        self.assertEqual(int('0x123', 16), 291)
168        self.assertEqual(int('0o123', 8), 83)
169        self.assertEqual(int('0b100', 2), 4)
170        self.assertEqual(int('0X123', 16), 291)
171        self.assertEqual(int('0O123', 8), 83)
172        self.assertEqual(int('0B100', 2), 4)
173
174        # the code has special checks for the first character after the
175        #  type prefix
176        self.assertRaises(ValueError, int, '0b2', 2)
177        self.assertRaises(ValueError, int, '0b02', 2)
178        self.assertRaises(ValueError, int, '0B2', 2)
179        self.assertRaises(ValueError, int, '0B02', 2)
180        self.assertRaises(ValueError, int, '0o8', 8)
181        self.assertRaises(ValueError, int, '0o08', 8)
182        self.assertRaises(ValueError, int, '0O8', 8)
183        self.assertRaises(ValueError, int, '0O08', 8)
184        self.assertRaises(ValueError, int, '0xg', 16)
185        self.assertRaises(ValueError, int, '0x0g', 16)
186        self.assertRaises(ValueError, int, '0Xg', 16)
187        self.assertRaises(ValueError, int, '0X0g', 16)
188
189        # SF bug 1334662: int(string, base) wrong answers
190        # Checks for proper evaluation of 2**32 + 1
191        self.assertEqual(int('100000000000000000000000000000001', 2), 4294967297)
192        self.assertEqual(int('102002022201221111212', 3), 4294967297)
193        self.assertEqual(int('10000000000000001', 4), 4294967297)
194        self.assertEqual(int('32244002423142', 5), 4294967297)
195        self.assertEqual(int('1550104015505', 6), 4294967297)
196        self.assertEqual(int('211301422355', 7), 4294967297)
197        self.assertEqual(int('40000000001', 8), 4294967297)
198        self.assertEqual(int('12068657455', 9), 4294967297)
199        self.assertEqual(int('4294967297', 10), 4294967297)
200        self.assertEqual(int('1904440555', 11), 4294967297)
201        self.assertEqual(int('9ba461595', 12), 4294967297)
202        self.assertEqual(int('535a7988a', 13), 4294967297)
203        self.assertEqual(int('2ca5b7465', 14), 4294967297)
204        self.assertEqual(int('1a20dcd82', 15), 4294967297)
205        self.assertEqual(int('100000001', 16), 4294967297)
206        self.assertEqual(int('a7ffda92', 17), 4294967297)
207        self.assertEqual(int('704he7g5', 18), 4294967297)
208        self.assertEqual(int('4f5aff67', 19), 4294967297)
209        self.assertEqual(int('3723ai4h', 20), 4294967297)
210        self.assertEqual(int('281d55i5', 21), 4294967297)
211        self.assertEqual(int('1fj8b185', 22), 4294967297)
212        self.assertEqual(int('1606k7id', 23), 4294967297)
213        self.assertEqual(int('mb994ah', 24), 4294967297)
214        self.assertEqual(int('hek2mgm', 25), 4294967297)
215        self.assertEqual(int('dnchbnn', 26), 4294967297)
216        self.assertEqual(int('b28jpdn', 27), 4294967297)
217        self.assertEqual(int('8pfgih5', 28), 4294967297)
218        self.assertEqual(int('76beigh', 29), 4294967297)
219        self.assertEqual(int('5qmcpqh', 30), 4294967297)
220        self.assertEqual(int('4q0jto5', 31), 4294967297)
221        self.assertEqual(int('4000001', 32), 4294967297)
222        self.assertEqual(int('3aokq95', 33), 4294967297)
223        self.assertEqual(int('2qhxjlj', 34), 4294967297)
224        self.assertEqual(int('2br45qc', 35), 4294967297)
225        self.assertEqual(int('1z141z5', 36), 4294967297)
226
227    def test_invalid_signs(self):
228        with self.assertRaises(ValueError):
229            int('+')
230        with self.assertRaises(ValueError):
231            int('-')
232        with self.assertRaises(ValueError):
233            int('- 1')
234        with self.assertRaises(ValueError):
235            int('+ 1')
236        with self.assertRaises(ValueError):
237            int(' + 1 ')
238
239    def test_unicode(self):
240        self.assertEqual(int("१२३४५६७८९०1234567890"), 12345678901234567890)
241        self.assertEqual(int('١٢٣٤٥٦٧٨٩٠'), 1234567890)
242        self.assertEqual(int("१२३४५६७८९०1234567890", 0), 12345678901234567890)
243        self.assertEqual(int('١٢٣٤٥٦٧٨٩٠', 0), 1234567890)
244
245    def test_underscores(self):
246        for lit in VALID_UNDERSCORE_LITERALS:
247            if any(ch in lit for ch in '.eEjJ'):
248                continue
249            self.assertEqual(int(lit, 0), eval(lit))
250            self.assertEqual(int(lit, 0), int(lit.replace('_', ''), 0))
251        for lit in INVALID_UNDERSCORE_LITERALS:
252            if any(ch in lit for ch in '.eEjJ'):
253                continue
254            self.assertRaises(ValueError, int, lit, 0)
255        # Additional test cases with bases != 0, only for the constructor:
256        self.assertEqual(int("1_00", 3), 9)
257        self.assertEqual(int("0_100"), 100)  # not valid as a literal!
258        self.assertEqual(int(b"1_00"), 100)  # byte underscore
259        self.assertRaises(ValueError, int, "_100")
260        self.assertRaises(ValueError, int, "+_100")
261        self.assertRaises(ValueError, int, "1__00")
262        self.assertRaises(ValueError, int, "100_")
263
264    @support.cpython_only
265    def test_small_ints(self):
266        # Bug #3236: Return small longs from PyLong_FromString
267        self.assertIs(int('10'), 10)
268        self.assertIs(int('-1'), -1)
269        self.assertIs(int(b'10'), 10)
270        self.assertIs(int(b'-1'), -1)
271
272    def test_no_args(self):
273        self.assertEqual(int(), 0)
274
275    def test_keyword_args(self):
276        # Test invoking int() using keyword arguments.
277        self.assertEqual(int('100', base=2), 4)
278        with self.assertRaisesRegex(TypeError, 'keyword argument'):
279            int(x=1.2)
280        with self.assertRaisesRegex(TypeError, 'keyword argument'):
281            int(x='100', base=2)
282        self.assertRaises(TypeError, int, base=10)
283        self.assertRaises(TypeError, int, base=0)
284
285    def test_int_base_limits(self):
286        """Testing the supported limits of the int() base parameter."""
287        self.assertEqual(int('0', 5), 0)
288        with self.assertRaises(ValueError):
289            int('0', 1)
290        with self.assertRaises(ValueError):
291            int('0', 37)
292        with self.assertRaises(ValueError):
293            int('0', -909)  # An old magic value base from Python 2.
294        with self.assertRaises(ValueError):
295            int('0', base=0-(2**234))
296        with self.assertRaises(ValueError):
297            int('0', base=2**234)
298        # Bases 2 through 36 are supported.
299        for base in range(2,37):
300            self.assertEqual(int('0', base=base), 0)
301
302    def test_int_base_bad_types(self):
303        """Not integer types are not valid bases; issue16772."""
304        with self.assertRaises(TypeError):
305            int('0', 5.5)
306        with self.assertRaises(TypeError):
307            int('0', 5.0)
308
309    def test_int_base_indexable(self):
310        class MyIndexable(object):
311            def __init__(self, value):
312                self.value = value
313            def __index__(self):
314                return self.value
315
316        # Check out of range bases.
317        for base in 2**100, -2**100, 1, 37:
318            with self.assertRaises(ValueError):
319                int('43', base)
320
321        # Check in-range bases.
322        self.assertEqual(int('101', base=MyIndexable(2)), 5)
323        self.assertEqual(int('101', base=MyIndexable(10)), 101)
324        self.assertEqual(int('101', base=MyIndexable(36)), 1 + 36**2)
325
326    def test_non_numeric_input_types(self):
327        # Test possible non-numeric types for the argument x, including
328        # subclasses of the explicitly documented accepted types.
329        class CustomStr(str): pass
330        class CustomBytes(bytes): pass
331        class CustomByteArray(bytearray): pass
332
333        factories = [
334            bytes,
335            bytearray,
336            lambda b: CustomStr(b.decode()),
337            CustomBytes,
338            CustomByteArray,
339            memoryview,
340        ]
341        try:
342            from array import array
343        except ImportError:
344            pass
345        else:
346            factories.append(lambda b: array('B', b))
347
348        for f in factories:
349            x = f(b'100')
350            with self.subTest(type(x)):
351                self.assertEqual(int(x), 100)
352                if isinstance(x, (str, bytes, bytearray)):
353                    self.assertEqual(int(x, 2), 4)
354                else:
355                    msg = "can't convert non-string"
356                    with self.assertRaisesRegex(TypeError, msg):
357                        int(x, 2)
358                with self.assertRaisesRegex(ValueError, 'invalid literal'):
359                    int(f(b'A' * 0x10))
360
361    def test_int_memoryview(self):
362        self.assertEqual(int(memoryview(b'123')[1:3]), 23)
363        self.assertEqual(int(memoryview(b'123\x00')[1:3]), 23)
364        self.assertEqual(int(memoryview(b'123 ')[1:3]), 23)
365        self.assertEqual(int(memoryview(b'123A')[1:3]), 23)
366        self.assertEqual(int(memoryview(b'1234')[1:3]), 23)
367
368    def test_string_float(self):
369        self.assertRaises(ValueError, int, '1.2')
370
371    def test_intconversion(self):
372        # Test __int__()
373        class ClassicMissingMethods:
374            pass
375        self.assertRaises(TypeError, int, ClassicMissingMethods())
376
377        class MissingMethods(object):
378            pass
379        self.assertRaises(TypeError, int, MissingMethods())
380
381        class Foo0:
382            def __int__(self):
383                return 42
384
385        self.assertEqual(int(Foo0()), 42)
386
387        class Classic:
388            pass
389        for base in (object, Classic):
390            class IntOverridesTrunc(base):
391                def __int__(self):
392                    return 42
393                def __trunc__(self):
394                    return -12
395            self.assertEqual(int(IntOverridesTrunc()), 42)
396
397            class JustTrunc(base):
398                def __trunc__(self):
399                    return 42
400            with self.assertWarns(DeprecationWarning):
401                self.assertEqual(int(JustTrunc()), 42)
402
403            class ExceptionalTrunc(base):
404                def __trunc__(self):
405                    1 / 0
406            with self.assertRaises(ZeroDivisionError), \
407                 self.assertWarns(DeprecationWarning):
408                int(ExceptionalTrunc())
409
410            for trunc_result_base in (object, Classic):
411                class Index(trunc_result_base):
412                    def __index__(self):
413                        return 42
414
415                class TruncReturnsNonInt(base):
416                    def __trunc__(self):
417                        return Index()
418                with self.assertWarns(DeprecationWarning):
419                    self.assertEqual(int(TruncReturnsNonInt()), 42)
420
421                class Intable(trunc_result_base):
422                    def __int__(self):
423                        return 42
424
425                class TruncReturnsNonIndex(base):
426                    def __trunc__(self):
427                        return Intable()
428                with self.assertWarns(DeprecationWarning):
429                    self.assertEqual(int(TruncReturnsNonInt()), 42)
430
431                class NonIntegral(trunc_result_base):
432                    def __trunc__(self):
433                        # Check that we avoid infinite recursion.
434                        return NonIntegral()
435
436                class TruncReturnsNonIntegral(base):
437                    def __trunc__(self):
438                        return NonIntegral()
439                try:
440                    with self.assertWarns(DeprecationWarning):
441                        int(TruncReturnsNonIntegral())
442                except TypeError as e:
443                    self.assertEqual(str(e),
444                                      "__trunc__ returned non-Integral"
445                                      " (type NonIntegral)")
446                else:
447                    self.fail("Failed to raise TypeError with %s" %
448                              ((base, trunc_result_base),))
449
450                # Regression test for bugs.python.org/issue16060.
451                class BadInt(trunc_result_base):
452                    def __int__(self):
453                        return 42.0
454
455                class TruncReturnsBadInt(base):
456                    def __trunc__(self):
457                        return BadInt()
458
459                with self.assertRaises(TypeError), \
460                     self.assertWarns(DeprecationWarning):
461                    int(TruncReturnsBadInt())
462
463    def test_int_subclass_with_index(self):
464        class MyIndex(int):
465            def __index__(self):
466                return 42
467
468        class BadIndex(int):
469            def __index__(self):
470                return 42.0
471
472        my_int = MyIndex(7)
473        self.assertEqual(my_int, 7)
474        self.assertEqual(int(my_int), 7)
475
476        self.assertEqual(int(BadIndex()), 0)
477
478    def test_int_subclass_with_int(self):
479        class MyInt(int):
480            def __int__(self):
481                return 42
482
483        class BadInt(int):
484            def __int__(self):
485                return 42.0
486
487        my_int = MyInt(7)
488        self.assertEqual(my_int, 7)
489        self.assertEqual(int(my_int), 42)
490
491        my_int = BadInt(7)
492        self.assertEqual(my_int, 7)
493        self.assertRaises(TypeError, int, my_int)
494
495    def test_int_returns_int_subclass(self):
496        class BadIndex:
497            def __index__(self):
498                return True
499
500        class BadIndex2(int):
501            def __index__(self):
502                return True
503
504        class BadInt:
505            def __int__(self):
506                return True
507
508        class BadInt2(int):
509            def __int__(self):
510                return True
511
512        class TruncReturnsBadIndex:
513            def __trunc__(self):
514                return BadIndex()
515
516        class TruncReturnsBadInt:
517            def __trunc__(self):
518                return BadInt()
519
520        class TruncReturnsIntSubclass:
521            def __trunc__(self):
522                return True
523
524        bad_int = BadIndex()
525        with self.assertWarns(DeprecationWarning):
526            n = int(bad_int)
527        self.assertEqual(n, 1)
528        self.assertIs(type(n), int)
529
530        bad_int = BadIndex2()
531        n = int(bad_int)
532        self.assertEqual(n, 0)
533        self.assertIs(type(n), int)
534
535        bad_int = BadInt()
536        with self.assertWarns(DeprecationWarning):
537            n = int(bad_int)
538        self.assertEqual(n, 1)
539        self.assertIs(type(n), int)
540
541        bad_int = BadInt2()
542        with self.assertWarns(DeprecationWarning):
543            n = int(bad_int)
544        self.assertEqual(n, 1)
545        self.assertIs(type(n), int)
546
547        bad_int = TruncReturnsBadIndex()
548        with self.assertWarns(DeprecationWarning):
549            n = int(bad_int)
550        self.assertEqual(n, 1)
551        self.assertIs(type(n), int)
552
553        bad_int = TruncReturnsBadInt()
554        with self.assertWarns(DeprecationWarning):
555            self.assertRaises(TypeError, int, bad_int)
556
557        good_int = TruncReturnsIntSubclass()
558        with self.assertWarns(DeprecationWarning):
559            n = int(good_int)
560        self.assertEqual(n, 1)
561        self.assertIs(type(n), int)
562        with self.assertWarns(DeprecationWarning):
563            n = IntSubclass(good_int)
564        self.assertEqual(n, 1)
565        self.assertIs(type(n), IntSubclass)
566
567    def test_error_message(self):
568        def check(s, base=None):
569            with self.assertRaises(ValueError,
570                                   msg="int(%r, %r)" % (s, base)) as cm:
571                if base is None:
572                    int(s)
573                else:
574                    int(s, base)
575            self.assertEqual(cm.exception.args[0],
576                "invalid literal for int() with base %d: %r" %
577                (10 if base is None else base, s))
578
579        check('\xbd')
580        check('123\xbd')
581        check('  123 456  ')
582
583        check('123\x00')
584        # SF bug 1545497: embedded NULs were not detected with explicit base
585        check('123\x00', 10)
586        check('123\x00 245', 20)
587        check('123\x00 245', 16)
588        check('123\x00245', 20)
589        check('123\x00245', 16)
590        # byte string with embedded NUL
591        check(b'123\x00')
592        check(b'123\x00', 10)
593        # non-UTF-8 byte string
594        check(b'123\xbd')
595        check(b'123\xbd', 10)
596        # lone surrogate in Unicode string
597        check('123\ud800')
598        check('123\ud800', 10)
599
600    def test_issue31619(self):
601        self.assertEqual(int('1_0_1_0_1_0_1_0_1_0_1_0_1_0_1_0_1_0_1_0_1_0_1_0_1_0_1_0_1_0_1', 2),
602                         0b1010101010101010101010101010101)
603        self.assertEqual(int('1_2_3_4_5_6_7_0_1_2_3', 8), 0o12345670123)
604        self.assertEqual(int('1_2_3_4_5_6_7_8_9', 16), 0x123456789)
605        self.assertEqual(int('1_2_3_4_5_6_7', 32), 1144132807)
606
607
608class IntStrDigitLimitsTests(unittest.TestCase):
609
610    int_class = int  # Override this in subclasses to reuse the suite.
611
612    def setUp(self):
613        super().setUp()
614        self._previous_limit = sys.get_int_max_str_digits()
615        sys.set_int_max_str_digits(2048)
616
617    def tearDown(self):
618        sys.set_int_max_str_digits(self._previous_limit)
619        super().tearDown()
620
621    def test_disabled_limit(self):
622        self.assertGreater(sys.get_int_max_str_digits(), 0)
623        self.assertLess(sys.get_int_max_str_digits(), 20_000)
624        with support.adjust_int_max_str_digits(0):
625            self.assertEqual(sys.get_int_max_str_digits(), 0)
626            i = self.int_class('1' * 20_000)
627            str(i)
628        self.assertGreater(sys.get_int_max_str_digits(), 0)
629
630    def test_max_str_digits_edge_cases(self):
631        """Ignore the +/- sign and space padding."""
632        int_class = self.int_class
633        maxdigits = sys.get_int_max_str_digits()
634
635        int_class('1' * maxdigits)
636        int_class(' ' + '1' * maxdigits)
637        int_class('1' * maxdigits + ' ')
638        int_class('+' + '1' * maxdigits)
639        int_class('-' + '1' * maxdigits)
640        self.assertEqual(len(str(10 ** (maxdigits - 1))), maxdigits)
641
642    def check(self, i, base=None):
643        with self.assertRaises(ValueError):
644            if base is None:
645                self.int_class(i)
646            else:
647                self.int_class(i, base)
648
649    def test_max_str_digits(self):
650        maxdigits = sys.get_int_max_str_digits()
651
652        self.check('1' * (maxdigits + 1))
653        self.check(' ' + '1' * (maxdigits + 1))
654        self.check('1' * (maxdigits + 1) + ' ')
655        self.check('+' + '1' * (maxdigits + 1))
656        self.check('-' + '1' * (maxdigits + 1))
657        self.check('1' * (maxdigits + 1))
658
659        i = 10 ** maxdigits
660        with self.assertRaises(ValueError):
661            str(i)
662
663    def test_denial_of_service_prevented_int_to_str(self):
664        """Regression test: ensure we fail before performing O(N**2) work."""
665        maxdigits = sys.get_int_max_str_digits()
666        assert maxdigits < 50_000, maxdigits  # A test prerequisite.
667
668        huge_int = int(f'0x{"c"*65_000}', base=16)  # 78268 decimal digits.
669        digits = 78_268
670        with (
671                support.adjust_int_max_str_digits(digits),
672                support.CPUStopwatch() as sw_convert):
673            huge_decimal = str(huge_int)
674        self.assertEqual(len(huge_decimal), digits)
675        # Ensuring that we chose a slow enough conversion to measure.
676        # It takes 0.1 seconds on a Zen based cloud VM in an opt build.
677        # Some OSes have a low res 1/64s timer, skip if hard to measure.
678        if sw_convert.seconds < sw_convert.clock_info.resolution * 2:
679            raise unittest.SkipTest('"slow" conversion took only '
680                                    f'{sw_convert.seconds} seconds.')
681
682        # We test with the limit almost at the size needed to check performance.
683        # The performant limit check is slightly fuzzy, give it a some room.
684        with support.adjust_int_max_str_digits(int(.995 * digits)):
685            with (
686                    self.assertRaises(ValueError) as err,
687                    support.CPUStopwatch() as sw_fail_huge):
688                str(huge_int)
689        self.assertIn('conversion', str(err.exception))
690        self.assertLessEqual(sw_fail_huge.seconds, sw_convert.seconds/2)
691
692        # Now we test that a conversion that would take 30x as long also fails
693        # in a similarly fast fashion.
694        extra_huge_int = int(f'0x{"c"*500_000}', base=16)  # 602060 digits.
695        with (
696                self.assertRaises(ValueError) as err,
697                support.CPUStopwatch() as sw_fail_extra_huge):
698            # If not limited, 8 seconds said Zen based cloud VM.
699            str(extra_huge_int)
700        self.assertIn('conversion', str(err.exception))
701        self.assertLess(sw_fail_extra_huge.seconds, sw_convert.seconds/2)
702
703    def test_denial_of_service_prevented_str_to_int(self):
704        """Regression test: ensure we fail before performing O(N**2) work."""
705        maxdigits = sys.get_int_max_str_digits()
706        assert maxdigits < 100_000, maxdigits  # A test prerequisite.
707
708        digits = 133700
709        huge = '8'*digits
710        with (
711                support.adjust_int_max_str_digits(digits),
712                support.CPUStopwatch() as sw_convert):
713            int(huge)
714        # Ensuring that we chose a slow enough conversion to measure.
715        # It takes 0.1 seconds on a Zen based cloud VM in an opt build.
716        # Some OSes have a low res 1/64s timer, skip if hard to measure.
717        if sw_convert.seconds < sw_convert.clock_info.resolution * 2:
718            raise unittest.SkipTest('"slow" conversion took only '
719                                    f'{sw_convert.seconds} seconds.')
720
721        with support.adjust_int_max_str_digits(digits - 1):
722            with (
723                    self.assertRaises(ValueError) as err,
724                    support.CPUStopwatch() as sw_fail_huge):
725                int(huge)
726        self.assertIn('conversion', str(err.exception))
727        self.assertLessEqual(sw_fail_huge.seconds, sw_convert.seconds/2)
728
729        # Now we test that a conversion that would take 30x as long also fails
730        # in a similarly fast fashion.
731        extra_huge = '7'*1_200_000
732        with (
733                self.assertRaises(ValueError) as err,
734                support.CPUStopwatch() as sw_fail_extra_huge):
735            # If not limited, 8 seconds in the Zen based cloud VM.
736            int(extra_huge)
737        self.assertIn('conversion', str(err.exception))
738        self.assertLessEqual(sw_fail_extra_huge.seconds, sw_convert.seconds/2)
739
740    def test_power_of_two_bases_unlimited(self):
741        """The limit does not apply to power of 2 bases."""
742        maxdigits = sys.get_int_max_str_digits()
743
744        for base in (2, 4, 8, 16, 32):
745            with self.subTest(base=base):
746                self.int_class('1' * (maxdigits + 1), base)
747                assert maxdigits < 100_000
748                self.int_class('1' * 100_000, base)
749
750    def test_underscores_ignored(self):
751        maxdigits = sys.get_int_max_str_digits()
752
753        triples = maxdigits // 3
754        s = '111' * triples
755        s_ = '1_11' * triples
756        self.int_class(s)  # succeeds
757        self.int_class(s_)  # succeeds
758        self.check(f'{s}111')
759        self.check(f'{s_}_111')
760
761    def test_sign_not_counted(self):
762        int_class = self.int_class
763        max_digits = sys.get_int_max_str_digits()
764        s = '5' * max_digits
765        i = int_class(s)
766        pos_i = int_class(f'+{s}')
767        assert i == pos_i
768        neg_i = int_class(f'-{s}')
769        assert -pos_i == neg_i
770        str(pos_i)
771        str(neg_i)
772
773    def _other_base_helper(self, base):
774        int_class = self.int_class
775        max_digits = sys.get_int_max_str_digits()
776        s = '2' * max_digits
777        i = int_class(s, base)
778        if base > 10:
779            with self.assertRaises(ValueError):
780                str(i)
781        elif base < 10:
782            str(i)
783        with self.assertRaises(ValueError) as err:
784            int_class(f'{s}1', base)
785
786    def test_int_from_other_bases(self):
787        base = 3
788        with self.subTest(base=base):
789            self._other_base_helper(base)
790        base = 36
791        with self.subTest(base=base):
792            self._other_base_helper(base)
793
794    def test_int_max_str_digits_is_per_interpreter(self):
795        # Changing the limit in one interpreter does not change others.
796        code = """if 1:
797        # Subinterpreters maintain and enforce their own limit
798        import sys
799        sys.set_int_max_str_digits(2323)
800        try:
801            int('3'*3333)
802        except ValueError:
803            pass
804        else:
805            raise AssertionError('Expected a int max str digits ValueError.')
806        """
807        with support.adjust_int_max_str_digits(4000):
808            before_value = sys.get_int_max_str_digits()
809            self.assertEqual(support.run_in_subinterp(code), 0,
810                             'subinterp code failure, check stderr.')
811            after_value = sys.get_int_max_str_digits()
812            self.assertEqual(before_value, after_value)
813
814
815class IntSubclassStrDigitLimitsTests(IntStrDigitLimitsTests):
816    int_class = IntSubclass
817
818
819class PyLongModuleTests(unittest.TestCase):
820    # Tests of the functions in _pylong.py.  Those get used when the
821    # number of digits in the input values are large enough.
822
823    def setUp(self):
824        super().setUp()
825        self._previous_limit = sys.get_int_max_str_digits()
826        sys.set_int_max_str_digits(0)
827
828    def tearDown(self):
829        sys.set_int_max_str_digits(self._previous_limit)
830        super().tearDown()
831
832    def _test_pylong_int_to_decimal(self, n, suffix):
833        s = str(n)
834        self.assertEqual(s[-10:], suffix)
835        s2 = str(-n)
836        self.assertEqual(s2, '-' + s)
837        s3 = '%d' % n
838        self.assertEqual(s3, s)
839        s4 = b'%d' % n
840        self.assertEqual(s4, s.encode('ascii'))
841
842    def test_pylong_int_to_decimal(self):
843        self._test_pylong_int_to_decimal((1 << 100_000), '9883109376')
844        self._test_pylong_int_to_decimal((1 << 100_000) - 1, '9883109375')
845        self._test_pylong_int_to_decimal(10**30_000, '0000000000')
846        self._test_pylong_int_to_decimal(10**30_000 - 1, '9999999999')
847        self._test_pylong_int_to_decimal(3**60_000, '9313200001')
848
849    @support.requires_resource('cpu')
850    def test_pylong_int_to_decimal_2(self):
851        self._test_pylong_int_to_decimal(2**1_000_000, '2747109376')
852        self._test_pylong_int_to_decimal(10**300_000, '0000000000')
853        self._test_pylong_int_to_decimal(3**600_000, '3132000001')
854
855    def test_pylong_int_divmod(self):
856        n = (1 << 100_000)
857        a, b = divmod(n*3 + 1, n)
858        assert a == 3 and b == 1
859
860    def test_pylong_str_to_int(self):
861        v1 = 1 << 100_000
862        s = str(v1)
863        v2 = int(s)
864        assert v1 == v2
865        v3 = int(' -' + s)
866        assert -v1 == v3
867        v4 = int(' +' + s + ' ')
868        assert v1 == v4
869        with self.assertRaises(ValueError) as err:
870            int(s + 'z')
871        with self.assertRaises(ValueError) as err:
872            int(s + '_')
873        with self.assertRaises(ValueError) as err:
874            int('_' + s)
875
876    @support.cpython_only  # tests implementation details of CPython.
877    @unittest.skipUnless(_pylong, "_pylong module required")
878    @mock.patch.object(_pylong, "int_to_decimal_string")
879    def test_pylong_misbehavior_error_path_to_str(
880            self, mock_int_to_str):
881        with support.adjust_int_max_str_digits(20_000):
882            big_value = int('7'*19_999)
883            mock_int_to_str.return_value = None  # not a str
884            with self.assertRaises(TypeError) as ctx:
885                str(big_value)
886            self.assertIn('_pylong.int_to_decimal_string did not',
887                          str(ctx.exception))
888            mock_int_to_str.side_effect = RuntimeError("testABC")
889            with self.assertRaises(RuntimeError):
890                str(big_value)
891
892    @support.cpython_only  # tests implementation details of CPython.
893    @unittest.skipUnless(_pylong, "_pylong module required")
894    @mock.patch.object(_pylong, "int_from_string")
895    def test_pylong_misbehavior_error_path_from_str(
896            self, mock_int_from_str):
897        big_value = '7'*19_999
898        with support.adjust_int_max_str_digits(20_000):
899            mock_int_from_str.return_value = b'not an int'
900            with self.assertRaises(TypeError) as ctx:
901                int(big_value)
902            self.assertIn('_pylong.int_from_string did not',
903                          str(ctx.exception))
904
905            mock_int_from_str.side_effect = RuntimeError("test123")
906            with self.assertRaises(RuntimeError):
907                int(big_value)
908
909    def test_pylong_roundtrip(self):
910        from random import randrange, getrandbits
911        bits = 5000
912        while bits <= 1_000_000:
913            bits += randrange(-100, 101) # break bitlength patterns
914            hibit = 1 << (bits - 1)
915            n = hibit | getrandbits(bits - 1)
916            assert n.bit_length() == bits
917            sn = str(n)
918            self.assertFalse(sn.startswith('0'))
919            self.assertEqual(n, int(sn))
920            bits <<= 1
921
922if __name__ == "__main__":
923    unittest.main()
924