1import builtins
2import sys
3import unittest
4from typing import Callable, List, Optional, Union
5
6import builtin_support as support
7from builtin_grammar import (
8    INVALID_UNDERSCORE_LITERALS,
9    VALID_UNDERSCORE_LITERALS,
10)
11
12from fastnumbers import int
13
14L = [
15    ("0", 0),
16    ("1", 1),
17    ("9", 9),
18    ("10", 10),
19    ("99", 99),
20    ("100", 100),
21    ("314", 314),
22    (" 314", 314),
23    ("314 ", 314),
24    ("  \t\t  314  \t\t  ", 314),
25    (repr(sys.maxsize), sys.maxsize),
26    ("  1x", ValueError),
27    ("  1  ", 1),
28    ("  1\02  ", ValueError),
29    ("", ValueError),
30    (" ", ValueError),
31    ("  \t\t  ", ValueError),
32    ("\u0200", ValueError),
33]
34
35
36class IntSubclass(builtins.int):
37    pass
38
39
40class IntTestCases(unittest.TestCase):
41    def test_basic(self) -> None:
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  # type: ignore
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, builtins.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, builtins.int)
78        x = int(-1e100)
79        self.assertIsInstance(x, builtins.int)
80
81        # SF bug 434186:  0x80000000/2 != 0x80000000>>1.
82        # Worked by accident in Windows release build, but failed in debug build.
83        # Failed in all Linux builds.
84        x = -1 - sys.maxsize
85        self.assertEqual(x >> 1, x // 2)
86
87        x = int("1" * 600)
88        self.assertIsInstance(x, builtins.int)
89
90        self.assertRaises(TypeError, int, 1, 12)
91
92        self.assertEqual(int("0o123", 0), 83)
93        self.assertEqual(int("0x123", 16), 291)
94
95        # Bug 1679: "0x" is not a valid hex literal
96        self.assertRaises(ValueError, int, "0x", 16)
97        self.assertRaises(ValueError, int, "0x", 0)
98
99        self.assertRaises(ValueError, int, "0o", 8)
100        self.assertRaises(ValueError, int, "0o", 0)
101
102        self.assertRaises(ValueError, int, "0b", 2)
103        self.assertRaises(ValueError, int, "0b", 0)
104
105        # SF bug 1334662: int(string, base) wrong answers
106        # Various representations of 2**32 evaluated to 0
107        # rather than 2**32 in previous versions
108
109        self.assertEqual(int("100000000000000000000000000000000", 2), 4294967296)
110        self.assertEqual(int("102002022201221111211", 3), 4294967296)
111        self.assertEqual(int("10000000000000000", 4), 4294967296)
112        self.assertEqual(int("32244002423141", 5), 4294967296)
113        self.assertEqual(int("1550104015504", 6), 4294967296)
114        self.assertEqual(int("211301422354", 7), 4294967296)
115        self.assertEqual(int("40000000000", 8), 4294967296)
116        self.assertEqual(int("12068657454", 9), 4294967296)
117        self.assertEqual(int("4294967296", 10), 4294967296)
118        self.assertEqual(int("1904440554", 11), 4294967296)
119        self.assertEqual(int("9ba461594", 12), 4294967296)
120        self.assertEqual(int("535a79889", 13), 4294967296)
121        self.assertEqual(int("2ca5b7464", 14), 4294967296)
122        self.assertEqual(int("1a20dcd81", 15), 4294967296)
123        self.assertEqual(int("100000000", 16), 4294967296)
124        self.assertEqual(int("a7ffda91", 17), 4294967296)
125        self.assertEqual(int("704he7g4", 18), 4294967296)
126        self.assertEqual(int("4f5aff66", 19), 4294967296)
127        self.assertEqual(int("3723ai4g", 20), 4294967296)
128        self.assertEqual(int("281d55i4", 21), 4294967296)
129        self.assertEqual(int("1fj8b184", 22), 4294967296)
130        self.assertEqual(int("1606k7ic", 23), 4294967296)
131        self.assertEqual(int("mb994ag", 24), 4294967296)
132        self.assertEqual(int("hek2mgl", 25), 4294967296)
133        self.assertEqual(int("dnchbnm", 26), 4294967296)
134        self.assertEqual(int("b28jpdm", 27), 4294967296)
135        self.assertEqual(int("8pfgih4", 28), 4294967296)
136        self.assertEqual(int("76beigg", 29), 4294967296)
137        self.assertEqual(int("5qmcpqg", 30), 4294967296)
138        self.assertEqual(int("4q0jto4", 31), 4294967296)
139        self.assertEqual(int("4000000", 32), 4294967296)
140        self.assertEqual(int("3aokq94", 33), 4294967296)
141        self.assertEqual(int("2qhxjli", 34), 4294967296)
142        self.assertEqual(int("2br45qb", 35), 4294967296)
143        self.assertEqual(int("1z141z4", 36), 4294967296)
144
145        # tests with base 0
146        # this fails on 3.0, but in 2.x the old octal syntax is allowed
147        self.assertEqual(int(" 0o123  ", 0), 83)
148        self.assertEqual(int(" 0o123  ", 0), 83)
149        self.assertEqual(int("000", 0), 0)
150        self.assertEqual(int("0o123", 0), 83)
151        self.assertEqual(int("0x123", 0), 291)
152        self.assertEqual(int("0b100", 0), 4)
153        self.assertEqual(int(" 0O123   ", 0), 83)
154        self.assertEqual(int(" 0X123  ", 0), 291)
155        self.assertEqual(int(" 0B100 ", 0), 4)
156
157        # without base still base 10
158        self.assertEqual(int("0123"), 123)
159        self.assertEqual(int("0123", 10), 123)
160
161        # tests with prefix and base != 0
162        self.assertEqual(int("0x123", 16), 291)
163        self.assertEqual(int("0o123", 8), 83)
164        self.assertEqual(int("0b100", 2), 4)
165        self.assertEqual(int("0X123", 16), 291)
166        self.assertEqual(int("0O123", 8), 83)
167        self.assertEqual(int("0B100", 2), 4)
168
169        # the code has special checks for the first character after the
170        #  type prefix
171        self.assertRaises(ValueError, int, "0b2", 2)
172        self.assertRaises(ValueError, int, "0b02", 2)
173        self.assertRaises(ValueError, int, "0B2", 2)
174        self.assertRaises(ValueError, int, "0B02", 2)
175        self.assertRaises(ValueError, int, "0o8", 8)
176        self.assertRaises(ValueError, int, "0o08", 8)
177        self.assertRaises(ValueError, int, "0O8", 8)
178        self.assertRaises(ValueError, int, "0O08", 8)
179        self.assertRaises(ValueError, int, "0xg", 16)
180        self.assertRaises(ValueError, int, "0x0g", 16)
181        self.assertRaises(ValueError, int, "0Xg", 16)
182        self.assertRaises(ValueError, int, "0X0g", 16)
183
184        # SF bug 1334662: int(string, base) wrong answers
185        # Checks for proper evaluation of 2**32 + 1
186        self.assertEqual(int("100000000000000000000000000000001", 2), 4294967297)
187        self.assertEqual(int("102002022201221111212", 3), 4294967297)
188        self.assertEqual(int("10000000000000001", 4), 4294967297)
189        self.assertEqual(int("32244002423142", 5), 4294967297)
190        self.assertEqual(int("1550104015505", 6), 4294967297)
191        self.assertEqual(int("211301422355", 7), 4294967297)
192        self.assertEqual(int("40000000001", 8), 4294967297)
193        self.assertEqual(int("12068657455", 9), 4294967297)
194        self.assertEqual(int("4294967297", 10), 4294967297)
195        self.assertEqual(int("1904440555", 11), 4294967297)
196        self.assertEqual(int("9ba461595", 12), 4294967297)
197        self.assertEqual(int("535a7988a", 13), 4294967297)
198        self.assertEqual(int("2ca5b7465", 14), 4294967297)
199        self.assertEqual(int("1a20dcd82", 15), 4294967297)
200        self.assertEqual(int("100000001", 16), 4294967297)
201        self.assertEqual(int("a7ffda92", 17), 4294967297)
202        self.assertEqual(int("704he7g5", 18), 4294967297)
203        self.assertEqual(int("4f5aff67", 19), 4294967297)
204        self.assertEqual(int("3723ai4h", 20), 4294967297)
205        self.assertEqual(int("281d55i5", 21), 4294967297)
206        self.assertEqual(int("1fj8b185", 22), 4294967297)
207        self.assertEqual(int("1606k7id", 23), 4294967297)
208        self.assertEqual(int("mb994ah", 24), 4294967297)
209        self.assertEqual(int("hek2mgm", 25), 4294967297)
210        self.assertEqual(int("dnchbnn", 26), 4294967297)
211        self.assertEqual(int("b28jpdn", 27), 4294967297)
212        self.assertEqual(int("8pfgih5", 28), 4294967297)
213        self.assertEqual(int("76beigh", 29), 4294967297)
214        self.assertEqual(int("5qmcpqh", 30), 4294967297)
215        self.assertEqual(int("4q0jto5", 31), 4294967297)
216        self.assertEqual(int("4000001", 32), 4294967297)
217        self.assertEqual(int("3aokq95", 33), 4294967297)
218        self.assertEqual(int("2qhxjlj", 34), 4294967297)
219        self.assertEqual(int("2br45qc", 35), 4294967297)
220        self.assertEqual(int("1z141z5", 36), 4294967297)
221
222    def test_underscores(self) -> None:
223        for lit in VALID_UNDERSCORE_LITERALS:
224            if any(ch in lit for ch in ".eEjJ"):
225                continue
226            self.assertEqual(int(lit, 0), eval(lit))
227            self.assertEqual(int(lit, 0), int(lit.replace("_", ""), 0))
228        for lit in INVALID_UNDERSCORE_LITERALS:
229            if any(ch in lit for ch in ".eEjJ"):
230                continue
231            self.assertRaises(ValueError, int, lit, 0)
232        # Additional test cases with bases != 0, only for the constructor:
233        self.assertEqual(int("1_00", 3), 9)
234        self.assertEqual(int("0_100"), 100)  # not valid as a literal!
235        self.assertEqual(int(b"1_00"), 100)  # byte underscore
236        self.assertRaises(ValueError, int, "_100")
237        self.assertRaises(ValueError, int, "+_100")
238        self.assertRaises(ValueError, int, "1__00")
239        self.assertRaises(ValueError, int, "100_")
240
241    @support.cpython_only
242    def test_small_ints(self) -> None:
243        # Bug #3236: Return small longs from PyLong_FromString
244        self.assertIs(int("10"), 10)
245        self.assertIs(int("-1"), -1)
246        self.assertIs(int(b"10"), 10)
247        self.assertIs(int(b"-1"), -1)
248
249    def test_no_args(self) -> None:
250        self.assertEqual(int(), 0)
251
252    def test_keyword_args(self) -> None:
253        # Test invoking int() using keyword arguments.
254        self.assertEqual(int("100", base=2), 4)
255        if sys.version_info >= (3, 7):
256            with self.assertRaisesRegex(TypeError, "keyword argument"):
257                int(x=1.2)
258            with self.assertRaisesRegex(TypeError, "keyword argument"):
259                int(x="100", base=2)
260        else:
261            self.assertEqual(int(x=1.2), 1)
262            self.assertEqual(int(x="100", base=2), 4)
263        self.assertRaises(TypeError, int, base=10)
264        self.assertRaises(TypeError, int, base=0)
265
266    def test_int_base_limits(self) -> None:
267        """Testing the supported limits of the int() base parameter."""
268        self.assertEqual(int("0", 5), 0)
269        with self.assertRaises(ValueError):
270            int("0", 1)
271        with self.assertRaises(ValueError):
272            int("0", 37)
273        with self.assertRaises(ValueError):
274            int("0", -909)  # An old magic value base from Python 2.
275        with self.assertRaises(ValueError):
276            int("0", base=0 - (2 ** 234))
277        with self.assertRaises(ValueError):
278            int("0", base=2 ** 234)
279        # Bases 2 through 36 are supported.
280        for base in range(2, 37):
281            self.assertEqual(int("0", base=base), 0)
282
283    def test_int_base_bad_types(self) -> None:
284        """Not integer types are not valid bases; issue16772."""
285        with self.assertRaises(TypeError):
286            int("0", 5.5)  # type: ignore
287        with self.assertRaises(TypeError):
288            int("0", 5.0)  # type: ignore
289
290    def test_int_base_indexable(self) -> None:
291        class MyIndexable(object):
292            def __init__(self, value: builtins.int) -> None:
293                self.value = value
294
295            def __index__(self) -> builtins.int:
296                return self.value
297
298        # Check out of range bases.
299        for base in 2 ** 100, -(2 ** 100), 1, 37:
300            with self.assertRaises(ValueError):
301                int("43", base)
302
303        # Check in-range bases.
304        self.assertEqual(int("101", base=MyIndexable(2)), 5)
305        self.assertEqual(int("101", base=MyIndexable(10)), 101)
306        self.assertEqual(int("101", base=MyIndexable(36)), 1 + 36 ** 2)
307
308    def test_non_numeric_input_types(self) -> None:
309        # Test possible non-numeric types for the argument x, including
310        # subclasses of the explicitly documented accepted types.
311        class CustomStr(str):
312            pass
313
314        class CustomBytes(bytes):
315            pass
316
317        class CustomByteArray(bytearray):
318            pass
319
320        factories: List[Callable[[bytes], Union[bytes, bytearray, str]]] = [
321            bytes,
322            bytearray,
323            lambda b: CustomStr(b.decode()),
324            CustomBytes,
325            CustomByteArray,
326            memoryview,
327        ]
328        try:
329            from array import array
330        except ImportError:
331            pass
332        else:
333            factories.append(lambda b: array("B", b))  # type: ignore
334
335        for f in factories:
336            x = f(b"100")
337            with self.subTest(type(x)):
338                self.assertEqual(int(x), 100)
339                if isinstance(x, (str, bytes, bytearray)):
340                    self.assertEqual(int(x, 2), 4)
341                else:
342                    msg = "can't convert non-string"
343                    with self.assertRaisesRegex(TypeError, msg):
344                        int(x, 2)
345                with self.assertRaisesRegex(ValueError, "invalid literal"):
346                    int(f(b"A" * 0x10))
347
348    def test_int_memoryview(self) -> None:
349        self.assertEqual(int(memoryview(b"123")[1:3]), 23)
350        self.assertEqual(int(memoryview(b"123\x00")[1:3]), 23)
351        self.assertEqual(int(memoryview(b"123 ")[1:3]), 23)
352        self.assertEqual(int(memoryview(b"123A")[1:3]), 23)
353        self.assertEqual(int(memoryview(b"1234")[1:3]), 23)
354
355    def test_string_float(self) -> None:
356        self.assertRaises(ValueError, int, "1.2")
357
358    def test_intconversion(self) -> None:
359        # Test __int__()
360        class ClassicMissingMethods:
361            pass
362
363        self.assertRaises(TypeError, int, ClassicMissingMethods())
364
365        class MissingMethods(object):
366            pass
367
368        self.assertRaises(TypeError, int, MissingMethods())
369
370        class Foo0:
371            def __int__(self) -> builtins.int:
372                return 42
373
374        self.assertEqual(int(Foo0()), 42)
375
376        class Classic:
377            pass
378
379        for base in (object, Classic):
380
381            class IntOverridesTrunc(base):  # type: ignore
382                def __int__(self) -> builtins.int:
383                    return 42
384
385                def __trunc__(self) -> builtins.int:
386                    return -12
387
388            self.assertEqual(int(IntOverridesTrunc()), 42)
389
390    @unittest.skipUnless(sys.version_info >= (3, 8), "Test introduced in Python 3.8")
391    def test_int_subclass_with_index(self) -> None:
392        class MyIndex(builtins.int):
393            def __index__(self) -> builtins.int:
394                return 42
395
396        class BadIndex(builtins.int):
397            def __index__(self) -> builtins.float:  # type: ignore
398                return 42.0
399
400        my_int = MyIndex(7)
401        self.assertEqual(my_int, 7)
402        self.assertEqual(int(my_int), 7)
403
404        self.assertEqual(int(BadIndex()), 0)
405
406    def test_int_subclass_with_int(self) -> None:
407        class MyInt(builtins.int):
408            def __int__(self) -> builtins.int:
409                return 42
410
411        class BadInt(builtins.int):
412            def __int__(self) -> builtins.float:  # type: ignore
413                return 42.0
414
415        my_int = MyInt(7)
416        self.assertEqual(my_int, 7)
417        self.assertEqual(int(my_int), 42)
418
419        if sys.version_info >= (3, 8):
420            my_int = BadInt(7)
421            self.assertEqual(my_int, 7)
422            self.assertRaises(TypeError, int, my_int)
423        else:
424            self.assertRaises(TypeError, int, BadInt())
425
426    def test_int_returns_int_subclass(self) -> None:
427        class BadIndex:
428            def __index__(self) -> bool:
429                return True
430
431        class BadIndex2(builtins.int):
432            def __index__(self) -> bool:
433                return True
434
435        class BadInt:
436            def __int__(self) -> bool:
437                return True
438
439        class BadInt2(builtins.int):
440            def __int__(self) -> bool:
441                return True
442
443        if sys.version_info >= (3, 8):
444            bad_int = BadIndex()
445            with self.assertWarns(DeprecationWarning):
446                n = int(bad_int)
447            self.assertEqual(n, 1)
448            self.assertIs(type(n), builtins.int)
449
450            bad_int = BadIndex2()
451            n = int(bad_int)
452            self.assertEqual(n, 0)
453            self.assertIs(type(n), builtins.int)
454
455        bad_int = BadInt()
456        with self.assertWarns(DeprecationWarning):
457            n = int(bad_int)
458        self.assertEqual(n, 1)
459        self.assertIs(type(n), builtins.int)
460
461        bad_int2 = BadInt2()
462        with self.assertWarns(DeprecationWarning):
463            n = int(bad_int2)
464        self.assertEqual(n, 1)
465        self.assertIs(type(n), builtins.int)
466
467    def test_error_message(self) -> None:
468        def check(s: Union[str, bytes], base: Optional[builtins.int] = None) -> None:
469            with self.assertRaises(ValueError, msg="int(%r, %r)" % (s, base)) as cm:
470                if base is None:
471                    int(s)
472                else:
473                    int(s, base)
474            self.assertEqual(
475                cm.exception.args[0],
476                "invalid literal for int() with base %d: %r"
477                % (10 if base is None else base, s),
478            )
479
480        check("\xbd")
481        check("123\xbd")
482        check("  123 456  ")
483
484        check("123\x00")
485        # SF bug 1545497: embedded NULs were not detected with explicit base
486        check("123\x00", 10)
487        check("123\x00 245", 20)
488        check("123\x00 245", 16)
489        check("123\x00245", 20)
490        check("123\x00245", 16)
491        # byte string with embedded NUL
492        check(b"123\x00")
493        check(b"123\x00", 10)
494        # non-UTF-8 byte string
495        check(b"123\xbd")
496        check(b"123\xbd", 10)
497        # lone surrogate in Unicode string
498        check("123\ud800")
499        check("123\ud800", 10)
500
501    @unittest.skipUnless(sys.version_info >= (3, 7), "Test introduced in Python 3.7")
502    def test_issue31619(self) -> None:
503        self.assertEqual(
504            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),
505            0b1010101010101010101010101010101,
506        )
507        self.assertEqual(int("1_2_3_4_5_6_7_0_1_2_3", 8), 0o12345670123)
508        self.assertEqual(int("1_2_3_4_5_6_7_8_9", 16), 0x123456789)
509        self.assertEqual(int("1_2_3_4_5_6_7", 32), 1144132807)
510
511
512if __name__ == "__main__":
513    unittest.main()
514