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

import builtins
import sys
import unittest

from test.support import swap_item, swap_attr, skip_wasi_stack_overflow


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)


    @skip_wasi_stack_overflow()
    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()
