# Test the most dynamic corner cases of Python's runtime semantics.

import builtins
import sys
import unittest

from test.support import is_wasi, Py_DEBUG, swap_item, swap_attr


class RebindBuiltinsTests(unittest.TestCase):

    """Test all the ways that we can change/shadow globals/builtins."""

    def configure_func(self, func, *args):
        """Perform TestCase-specific configuration on a function before testing.

        By default, this does nothing. Example usage: spinning a function so
        that a JIT will optimize it. Subclasses should override this as needed.

        Args:
            func: function to configure.
            *args: any arguments that should be passed to func, if calling it.

        Returns:
            Nothing. Work will be performed on func in-place.
        """
        pass

    def test_globals_shadow_builtins(self):
        # Modify globals() to shadow an entry in builtins.
        def foo():
            return len([1, 2, 3])
        self.configure_func(foo)

        self.assertEqual(foo(), 3)
        with swap_item(globals(), "len", lambda x: 7):
            self.assertEqual(foo(), 7)

    def test_modify_builtins(self):
        # Modify the builtins module directly.
        def foo():
            return len([1, 2, 3])
        self.configure_func(foo)

        self.assertEqual(foo(), 3)
        with swap_attr(builtins, "len", lambda x: 7):
            self.assertEqual(foo(), 7)

    def test_modify_builtins_while_generator_active(self):
        # Modify the builtins out from under a live generator.
        def foo():
            x = range(3)
            yield len(x)
            yield len(x)
        self.configure_func(foo)

        g = foo()
        self.assertEqual(next(g), 3)
        with swap_attr(builtins, "len", lambda x: 7):
            self.assertEqual(next(g), 7)

    def test_modify_builtins_from_leaf_function(self):
        # Verify that modifications made by leaf functions percolate up the
        # callstack.
        with swap_attr(builtins, "len", len):
            def bar():
                builtins.len = lambda x: 4

            def foo(modifier):
                l = []
                l.append(len(range(7)))
                modifier()
                l.append(len(range(7)))
                return l
            self.configure_func(foo, lambda: None)

            self.assertEqual(foo(bar), [7, 4])

    def test_cannot_change_globals_or_builtins_with_eval(self):
        def foo():
            return len([1, 2, 3])
        self.configure_func(foo)

        # Note that this *doesn't* change the definition of len() seen by foo().
        builtins_dict = {"len": lambda x: 7}
        globals_dict = {"foo": foo, "__builtins__": builtins_dict,
                        "len": lambda x: 8}
        self.assertEqual(eval("foo()", globals_dict), 3)

        self.assertEqual(eval("foo()", {"foo": foo}), 3)

    def test_cannot_change_globals_or_builtins_with_exec(self):
        def foo():
            return len([1, 2, 3])
        self.configure_func(foo)

        globals_dict = {"foo": foo}
        exec("x = foo()", globals_dict)
        self.assertEqual(globals_dict["x"], 3)

        # Note that this *doesn't* change the definition of len() seen by foo().
        builtins_dict = {"len": lambda x: 7}
        globals_dict = {"foo": foo, "__builtins__": builtins_dict,
                        "len": lambda x: 8}

        exec("x = foo()", globals_dict)
        self.assertEqual(globals_dict["x"], 3)

    def test_cannot_replace_builtins_dict_while_active(self):
        def foo():
            x = range(3)
            yield len(x)
            yield len(x)
        self.configure_func(foo)

        g = foo()
        self.assertEqual(next(g), 3)
        with swap_item(globals(), "__builtins__", {"len": lambda x: 7}):
            self.assertEqual(next(g), 3)

    def test_cannot_replace_builtins_dict_between_calls(self):
        def foo():
            return len([1, 2, 3])
        self.configure_func(foo)

        self.assertEqual(foo(), 3)
        with swap_item(globals(), "__builtins__", {"len": lambda x: 7}):
            self.assertEqual(foo(), 3)

    def test_eval_gives_lambda_custom_globals(self):
        globals_dict = {"len": lambda x: 7}
        foo = eval("lambda: len([])", globals_dict)
        self.configure_func(foo)

        self.assertEqual(foo(), 7)

    @unittest.skipIf(is_wasi and Py_DEBUG, "stack depth too shallow in pydebug WASI")
    def test_load_global_specialization_failure_keeps_oparg(self):
        # https://github.com/python/cpython/issues/91625
        class MyGlobals(dict):
            def __missing__(self, key):
                return int(key.removeprefix("_number_"))

        # Need more than 256 variables to use EXTENDED_ARGS
        variables = 400
        code = "lambda: " + "+".join(f"_number_{i}" for i in range(variables))
        sum_func = eval(code, MyGlobals())
        expected = sum(range(variables))
        # Warm up the function for quickening (PEP 659)
        for _ in range(30):
            self.assertEqual(sum_func(), expected)


class TestTracing(unittest.TestCase):

    def setUp(self):
        self.addCleanup(sys.settrace, sys.gettrace())
        sys.settrace(None)

    def test_after_specialization(self):

        def trace(frame, event, arg):
            return trace

        turn_on_trace = False

        class C:
            def __init__(self, x):
                self.x = x
            def __del__(self):
                if turn_on_trace:
                    sys.settrace(trace)

        def f():
            # LOAD_GLOBAL[_BUILTIN] immediately follows the call to C.__del__
            C(0).x, len

        def g():
            # BINARY_SUSCR[_LIST_INT] immediately follows the call to C.__del__
            [0][C(0).x]

        def h():
            # BINARY_OP[_ADD_INT] immediately follows the call to C.__del__
            0 + C(0).x

        for func in (f, g, h):
            with self.subTest(func.__name__):
                for _ in range(58):
                    func()
                turn_on_trace = True
                func()
                sys.settrace(None)
                turn_on_trace = False


if __name__ == "__main__":
    unittest.main()
