"""
Test DIL array subscript.
"""

import lldb
from lldbsuite.test.lldbtest import *
from lldbsuite.test.decorators import *
from lldbsuite.test import lldbutil


class TestFrameVarDILArraySubscript(TestBase):
    NO_DEBUG_INFO_TESTCASE = True

    def expect_var_path(self, expr, compare_to_framevar=False, value=None, type=None):
        value_dil = super().expect_var_path(expr, value=value, type=type)
        if compare_to_framevar:
            self.runCmd("settings set target.experimental.use-DIL false")
            value_frv = super().expect_var_path(expr, value=value, type=type)
            self.runCmd("settings set target.experimental.use-DIL true")
            self.assertEqual(value_dil.GetValue(), value_frv.GetValue())

    def test_subscript(self):
        self.build()
        lldbutil.run_to_source_breakpoint(
            self, "Set a breakpoint here", lldb.SBFileSpec("main.cpp")
        )

        self.runCmd("settings set target.experimental.use-DIL true")

        # Test int[] and int*
        self.expect_var_path("int_arr[0]", True, value="1")
        self.expect_var_path("int_ptr[1]", True, value="2")
        self.expect("frame var 'int_arr[enum_one]'", error=True)

        # Test when base and index are references.
        self.expect_var_path("int_arr[0]", True, value="1")
        self.expect("frame var 'int_arr[idx_1_ref]'", error=True)
        self.expect("frame var 'int_arr[enum_ref]'", error=True)
        self.expect_var_path("int_arr_ref[0]", value="1")
        self.expect("frame var 'int_arr_ref[idx_1_ref]'", error=True)
        self.expect("frame var 'int_arr_ref[enum_ref]'", error=True)

        # Test when base and index are typedefs.
        self.expect_var_path("td_int_arr[0]", True, value="1")
        self.expect("frame var 'td_int_arr[td_int_idx_1]'", error=True)
        self.expect("frame var 'td_int_arr[td_td_int_idx_2]'", error=True)
        self.expect_var_path("td_int_ptr[0]", True, value="1")
        self.expect("frame var 'td_int_ptr[td_int_idx_1]'", error=True)
        self.expect("frame var 'td_int_ptr[td_td_int_idx_2]'", error=True)

        # Both typedefs and refs
        self.expect("frame var 'td_int_arr_ref[td_int_idx_1_ref]'", error=True)

        # Test for index out of bounds. 1 beyond the end.
        self.expect_var_path("int_arr[3]", True, type="int")
        # Far beyond the end (but not far enough to be off the top of the stack).
        self.expect_var_path("int_arr[10]", True, type="int")

        # Test address-of of the subscripted value.
        self.expect_var_path("*(&int_arr[1])", value="2")

        # Test for negative index.
        self.expect_var_path("int_ptr_1[-1]", True, value="1")

        # Test for floating point index
        self.expect(
            "frame var 'int_arr[1.0]'",
            error=True,
            substrs=["expected 'r_square', got: <'.'"],
        )

        # Base should be a "pointer to T" and index should be of an integral type.
        self.expect(
            "frame var 'idx_1[0]'",
            error=True,
            substrs=["subscripted value is not an array or pointer"],
        )
        self.expect(
            "frame var 'idx_1_ref[0]'",
            error=True,
            substrs=["subscripted value is not an array or pointer"],
        )
        self.expect(
            "frame var 'int_arr[int_ptr]'",
            error=True,
            substrs=["failed to parse integer constant"],
        )
        self.expect(
            "frame var '1[2]'",
            error=True,
            substrs=["Unexpected token"],
        )

        # Base should not be a pointer to void
        self.expect(
            "frame var 'p_void[0]'",
            error=True,
            substrs=["subscript of pointer to incomplete type 'void'"],
        )

    def test_subscript_synthetic(self):
        self.build()
        lldbutil.run_to_source_breakpoint(
            self, "Set a breakpoint here", lldb.SBFileSpec("main.cpp")
        )

        self.runCmd("settings set target.experimental.use-DIL true")

        # Test synthetic value subscription
        self.expect_var_path("vector[1]", value="2")
        self.expect(
            "frame var 'vector[100]'",
            error=True,
            substrs=["array index 100 is not valid"],
        )
