# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html
# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE
# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt

from __future__ import annotations

import textwrap

from astroid import builder, nodes


class TestNodePosition:
    """Test node ``position`` attribute."""

    @staticmethod
    def test_position_class() -> None:
        """Position should only include keyword and name.

        >>> class A(Parent):
        >>> ^^^^^^^
        """
        code = textwrap.dedent(
            """
        class A:  #@
            ...

        class B(A):  #@
            pass

        class C:  #@
            '''Docstring'''

            class D:  #@
                ...

        class E:  #@
            def f():
                ...

        @decorator
        class F:  #@
            ...
        """
        ).strip()
        ast_nodes: list[nodes.NodeNG] = builder.extract_node(code)  # type: ignore[assignment]

        a = ast_nodes[0]
        assert isinstance(a, nodes.ClassDef)
        assert a.position == (1, 0, 1, 7)

        b = ast_nodes[1]
        assert isinstance(b, nodes.ClassDef)
        assert b.position == (4, 0, 4, 7)

        c = ast_nodes[2]
        assert isinstance(c, nodes.ClassDef)
        assert c.position == (7, 0, 7, 7)

        d = ast_nodes[3]
        assert isinstance(d, nodes.ClassDef)
        assert d.position == (10, 4, 10, 11)

        e = ast_nodes[4]
        assert isinstance(e, nodes.ClassDef)
        assert e.position == (13, 0, 13, 7)

        f = ast_nodes[5]
        assert isinstance(f, nodes.ClassDef)
        assert f.position == (18, 0, 18, 7)

    @staticmethod
    def test_position_function() -> None:
        """Position should only include keyword and name.

        >>> def func(var: int = 42):
        >>> ^^^^^^^^
        """
        code = textwrap.dedent(
            """
        def a():  #@
            ...

        def b():  #@
            '''Docstring'''

        def c(  #@
            var: int = 42
        ):
            def d():  #@
                ...

        @decorator
        def e():  #@
            ...
        """
        ).strip()
        ast_nodes: list[nodes.NodeNG] = builder.extract_node(code)  # type: ignore[assignment]

        a = ast_nodes[0]
        assert isinstance(a, nodes.FunctionDef)
        assert a.position == (1, 0, 1, 5)

        b = ast_nodes[1]
        assert isinstance(b, nodes.FunctionDef)
        assert b.position == (4, 0, 4, 5)

        c = ast_nodes[2]
        assert isinstance(c, nodes.FunctionDef)
        assert c.position == (7, 0, 7, 5)

        d = ast_nodes[3]
        assert isinstance(d, nodes.FunctionDef)
        assert d.position == (10, 4, 10, 9)

        e = ast_nodes[4]
        assert isinstance(e, nodes.FunctionDef)
        assert e.position == (14, 0, 14, 5)

    @staticmethod
    def test_position_async_function() -> None:
        """Position should only include keyword and name.

        >>> async def func(var: int = 42):
        >>> ^^^^^^^^^^^^^^
        """
        code = textwrap.dedent(
            """
        async def a():  #@
            ...

        async def b():  #@
            '''Docstring'''

        async def c(  #@
            var: int = 42
        ):
            async def d():  #@
                ...

        @decorator
        async def e():  #@
            ...
        """
        ).strip()
        ast_nodes: list[nodes.NodeNG] = builder.extract_node(code)  # type: ignore[assignment]

        a = ast_nodes[0]
        assert isinstance(a, nodes.FunctionDef)
        assert a.position == (1, 0, 1, 11)

        b = ast_nodes[1]
        assert isinstance(b, nodes.FunctionDef)
        assert b.position == (4, 0, 4, 11)

        c = ast_nodes[2]
        assert isinstance(c, nodes.FunctionDef)
        assert c.position == (7, 0, 7, 11)

        d = ast_nodes[3]
        assert isinstance(d, nodes.FunctionDef)
        assert d.position == (10, 4, 10, 15)

        e = ast_nodes[4]
        assert isinstance(e, nodes.FunctionDef)
        assert e.position == (14, 0, 14, 11)
